001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.web.wizards;
043:
044: import java.util.ArrayList;
045: import java.util.Iterator;
046: import java.util.StringTokenizer;
047:
048: import java.util.regex.Pattern;
049: import org.openide.util.NbBundle;
050:
051: import org.netbeans.modules.j2ee.dd.api.common.InitParam;
052: import org.netbeans.modules.j2ee.dd.api.web.Filter;
053: import org.netbeans.modules.j2ee.dd.api.web.FilterMapping;
054: import org.netbeans.modules.j2ee.dd.api.web.Servlet;
055: import org.netbeans.modules.j2ee.dd.api.web.ServletMapping;
056:
057: // PENDING - it would be better to have a FilterData which extends
058: // ServletData, and keep the filter specific code in that class.
059:
060: /**
061: * Deployment data validator object for servlets.
062: * @author ana.von.klopp@sun.com
063: */
064: class ServletData extends DeployData {
065:
066: private static final Pattern VALID_URI_PATTERN = Pattern
067: .compile("[-_.!~*'();/?:@&=+$,a-zA-Z0-9]+"); // NOI18N
068:
069: private String errorMessage = null;
070: private String name = null;
071: // These are URL mappings - they're used by both Servlets and Filters
072: private String[] urlMappings = null;
073: // These are mappings to servlet names - used by Filters only
074: private ArrayList filterMappings = null;
075: private String[][] initparams = null;
076: private boolean paramOK = true;
077: private FileType fileType = null;
078: private static final boolean debug = false;
079: private boolean addToDD = true;
080:
081: ServletData(FileType fileType) {
082: this .fileType = fileType;
083: }
084:
085: String getName() {
086: if (name == null)
087: return "";
088: return name;
089: }
090:
091: void setName(String name) {
092: if (name != this .name) {
093: if (fileType == FileType.FILTER)
094: updateFilterMappings(getName(), name);
095: this .name = name;
096: }
097: }
098:
099: String[] getServletNames() {
100: if (webApp == null)
101: return new String[0];
102: Servlet[] ss = webApp.getServlet();
103: String[] names = new String[ss.length];
104: for (int i = 0; i < ss.length; i++) {
105: try {
106: names[i] = ss[i].getServletName();
107: } catch (Exception e) {
108: names[i] = "";
109: }
110: }
111: return names;
112: }
113:
114: java.util.List getUrlPatterns() {
115: if (webApp == null) {
116: if (debug)
117: log("\tNo web app, return null"); //NOI18N
118: return new ArrayList();
119: }
120: ServletMapping[] maps = webApp.getServletMapping();
121: java.util.List l = new ArrayList();
122: for (int i = 0; i < maps.length; i++) {
123: l.add(maps[i].getUrlPattern());
124: }
125: return l;
126: }
127:
128: ArrayList getFilterMappings() {
129:
130: if (debug)
131: log("::getFilterMappings()"); //NOI18N
132: if (webApp == null) {
133: if (debug)
134: log("\tNo web app, return null"); //NOI18N
135: return new ArrayList();
136: }
137: if (filterMappings != null) {
138: if (debug)
139: log("\tFilter mappings already exist"); //NOI18N
140: return filterMappings;
141: }
142:
143: if (debug)
144: log("\tCreating the filter mapping list"); //NOI18N
145: FilterMapping[] fm = webApp.getFilterMapping();
146: if (debug) {
147: log("\tOrder of mappings according to DD APIs"); //NOI18N
148: for (int i = 0; i < fm.length; ++i)
149: log("\tServlet name: " + fm[i].getFilterName()); //NOI18N
150: }
151:
152: filterMappings = new ArrayList();
153: filterMappings.add(new FilterMappingData(getName()));
154:
155: String string;
156: String[] d = null;
157: FilterMappingData fmd;
158: FilterMappingData.Dispatcher[] dispatchList;
159:
160: for (int i = 0; i < fm.length; i++) {
161: fmd = new FilterMappingData();
162: fmd.setName(fm[i].getFilterName());
163:
164: string = fm[i].getUrlPattern();
165: if (string == null || string.length() == 0) {
166: fmd.setType(FilterMappingData.Type.SERVLET);
167: fmd.setPattern(fm[i].getServletName());
168: } else {
169: fmd.setType(FilterMappingData.Type.URL);
170: fmd.setPattern(string);
171: }
172:
173: try {
174: if (fm[i].sizeDispatcher() == 0) {
175: filterMappings.add(fmd);
176: continue;
177: }
178: } catch (Exception ex) {
179: // Not supported
180: filterMappings.add(fmd);
181: continue;
182: }
183:
184: try {
185: d = fm[i].getDispatcher();
186: } catch (Exception ex) {
187: if (debug) {
188: log(ex.toString());
189: ex.printStackTrace();
190: }
191: // PENDING ...
192: // Servlet 2.3
193: }
194: if (d == null)
195:
196: dispatchList = new FilterMappingData.Dispatcher[0];
197: else {
198: dispatchList = new FilterMappingData.Dispatcher[d.length];
199: for (int j = 0; j < d.length; ++j) {
200: dispatchList[j] = FilterMappingData.Dispatcher
201: .findDispatcher(d[j]);
202: if (debug)
203: log("\tDispatch: " + dispatchList[j]);//NOI18N
204: }
205: }
206: fmd.setDispatcher(dispatchList);
207: filterMappings.add(fmd);
208: }
209: return filterMappings;
210: }
211:
212: void setFilterMappings(ArrayList fmds) {
213: if (debug)
214: log("::setFilterMappings()");
215: filterMappings = fmds;
216: }
217:
218: void updateFilterMappings(String oldName, String newName) {
219: if (debug)
220: log("::updateFilterMappings(" + oldName + ", " + newName
221: + "),"); //NOI18N
222: Iterator i = getFilterMappings().iterator();
223: // No web app
224: if (i == null)
225: return;
226: FilterMappingData fmd;
227: while (i.hasNext()) {
228: fmd = (FilterMappingData) i.next();
229: if (fmd.getName().equals(oldName))
230: fmd.setName(newName);
231: }
232: }
233:
234: boolean isNameUnique() {
235: if (webApp == null)
236: return true;
237: Servlet[] ss = webApp.getServlet();
238: for (int i = 0; i < ss.length; i++) {
239: if (name.equals(ss[i].getServletName())) {
240: return false;
241: }
242: }
243:
244: Filter[] ff = webApp.getFilter();
245: for (int i = 0; i < ff.length; i++) {
246: if (name.equals(ff[i].getFilterName())) {
247: return false;
248: }
249: }
250: return true;
251: }
252:
253: String[] getUrlMappings() {
254: if (urlMappings == null)
255: return new String[0];
256: return urlMappings;
257: }
258:
259: String createDDServletName(String className) {
260: if (webApp == null)
261: return null;
262: String result = className;
263: Servlet servlet = (Servlet) webApp.findBeanByName("Servlet",
264: "ServletName", result); //NOI18N
265: while (servlet != null) {
266: result = findNextId(result);
267: servlet = (Servlet) webApp.findBeanByName("Servlet",
268: "ServletName", result); //NOI18N
269: }
270: setName(result);
271: return result;
272: }
273:
274: void createDDServletMapping(String servletName) {
275: if (webApp == null)
276: return;
277: String result = getRFC2396URI("/" + servletName);
278: ServletMapping mapping = (ServletMapping) webApp
279: .findBeanByName("ServletMapping", "UrlPattern", result); //NOI18N
280: while (mapping != null) {
281: result = findNextId(result);
282: mapping = (ServletMapping) webApp.findBeanByName(
283: "ServletMapping", "UrlPattern", result); //NOI18N
284: }
285: urlMappings = new String[] { result };
286: }
287:
288: /** Compute the next proper value for the id
289: */
290: private String findNextId(String id) {
291: char ch = id.charAt(id.length() - 1);
292: String result = null;
293: if (Character.isDigit(ch)) {
294: String lastDigit = id.substring(id.length() - 1);
295: int num = new Integer(lastDigit).intValue() + 1;
296: result = id.substring(0, id.length() - 1)
297: + new Integer(num).toString();
298: } else {
299: return result = id + "_1"; //NOI18N
300: }
301: return result;
302: }
303:
304: String getUrlMappingsAsString() {
305:
306: if (urlMappings == null || urlMappings.length == 0)
307: return ""; //NOI18N
308: StringBuffer buf = new StringBuffer();
309: int index = 0;
310: while (index < urlMappings.length - 1) {
311: buf.append(urlMappings[index]);
312: buf.append(", "); //NOI18N
313: index++;
314: }
315:
316: buf.append(urlMappings[index]);
317: return buf.toString();
318: }
319:
320: void parseUrlMappingString(String raw) {
321:
322: urlMappings = null;
323: StringTokenizer st = new StringTokenizer(raw, ",");
324: ArrayList list = new ArrayList();
325: String mapping;
326: String[] names = getServletNames();
327:
328: while (st.hasMoreTokens()) {
329: mapping = st.nextToken().trim();
330: if (mapping.length() == 0)
331: continue;
332: list.add(mapping);
333: }
334:
335: urlMappings = new String[list.size()];
336: list.toArray(urlMappings);
337: }
338:
339: String[][] getInitParams() {
340: if (initparams == null)
341: return new String[0][2];
342: return initparams;
343: }
344:
345: void setInitParams(String[][] initparams, boolean paramOK) {
346: this .initparams = initparams;
347: this .paramOK = paramOK;
348: }
349:
350: int getNumInitParams() {
351: if (initparams == null)
352: return 0;
353: return initparams.length;
354: }
355:
356: boolean isParamOK() {
357: return paramOK;
358: }
359:
360: void setParamOK(boolean paramOK) {
361: this .paramOK = paramOK;
362: }
363:
364: boolean isValid() {
365: if (debug)
366: log("::isValid()"); //NOI18N
367: errorMessage = new String();
368: if (webApp == null)
369: return true;
370: if (!isAddToDD())
371: return true;
372:
373: if (getName().length() == 0) {
374: errorMessage = NbBundle.getMessage(ServletData.class,
375: "MSG_no_name");
376: return false;
377: }
378:
379: if (!isNameUnique()) {
380: errorMessage = NbBundle.getMessage(ServletData.class,
381: "MSG_name_unique");
382: return false;
383: }
384:
385: if (debug)
386: log("\tname is fine"); //NOI18N
387:
388: if (fileType == FileType.SERVLET) {
389: if (!checkMappingsForServlet())
390: return false;
391: if (!checkServletDuplicitMappings())
392: return false;
393: } else if (fileType == FileType.FILTER) {
394: if (!checkMappingsForFilter())
395: return false;
396: }
397:
398: if (!isParamOK()) {
399: errorMessage = NbBundle.getMessage(ServletData.class,
400: "MSG_invalid_param");
401: return false;
402: }
403:
404: if (debug)
405: log("\tparams are fine"); //NOI18N
406: return true;
407: }
408:
409: boolean checkMappingsForServlet() {
410:
411: errorMessage = new String();
412: String[] mappings = getUrlMappings();
413: if (mappings == null || mappings.length == 0) {
414:
415: if (debug)
416: log("\tNo URL mappings"); //NOI18N
417: errorMessage = NbBundle.getMessage(ServletData.class,
418: "MSG_no_mapping");
419: return false;
420: }
421: for (int i = 0; i < mappings.length; i++) {
422: String errMessage = checkServletMappig(mappings[i]);
423: if (errMessage != null) {
424: errorMessage = errMessage;
425: return false;
426: }
427: }
428: if (debug)
429: log("\tmappings are fine"); //NOI18N
430: return true;
431: }
432:
433: boolean checkServletDuplicitMappings() {
434: errorMessage = new String();
435: String[] newMappings = getUrlMappings();
436: java.util.List urlPatterns = getUrlPatterns();
437: for (int i = 0; i < newMappings.length; i++) {
438: Iterator it = urlPatterns.iterator();
439: while (it.hasNext()) {
440: String urlPattern = (String) it.next();
441: if (newMappings[i].equals(urlPattern)) {
442: if (debug)
443: log("\tDuplicit URL mappings"); //NOI18N
444: errorMessage = NbBundle
445: .getMessage(ServletData.class,
446: "MSG_url_pattern_unique");
447: return false;
448: }
449: }
450: // new Url Patterns need to be compare to each other
451: urlPatterns.add(newMappings[i]);
452: }
453: if (debug)
454: log("\tmappings- duplicity - is fine"); //NOI18N
455: return true;
456: }
457:
458: boolean checkMappingsForFilter() {
459: errorMessage = new String();
460: if (filterMappings == null || filterMappings.size() == 0) {
461: if (debug)
462: log("\tNo mappings"); //NOI18N
463: errorMessage = NbBundle.getMessage(ServletData.class,
464: "MSG_no_mapping");
465: return false;
466: }
467: Iterator i = getFilterMappings().iterator();
468: boolean found = false;
469: FilterMappingData fmd;
470: while (i.hasNext()) {
471: fmd = (FilterMappingData) (i.next());
472: if (fmd.getName().equals(getName())) {
473: found = true;
474: break;
475: }
476: }
477: if (!found) {
478: errorMessage = NbBundle.getMessage(ServletData.class,
479: "MSG_no_mapping");
480: return false;
481: }
482: return true;
483: }
484:
485: void createDDEntries() {
486: if (debug)
487: log("::createDDEntries()");
488: if (webApp == null)
489: return;
490: if (debug)
491: log("\t...adding");
492:
493: if (fileType == FileType.SERVLET) {
494: boolean added = addServlet();
495: if (added) {
496: addUrlMappings();
497: if (debug)
498: log("\t...writing changes");
499: try {
500: writeChanges();
501: } catch (java.io.IOException ex) {
502: if (debug)
503: ex.printStackTrace();
504: }
505: }
506: } else if (fileType == FileType.FILTER) {
507: boolean added = addFilter();
508: if (added) {
509: addFilterMappings();
510: if (debug)
511: log("\t...writing changes");
512: try {
513: writeChanges();
514: } catch (java.io.IOException ex) {
515: if (debug)
516: ex.printStackTrace();
517: }
518: }
519: }
520: }
521:
522: private boolean addServlet() {
523:
524: if (debug)
525: log("::addServlet()"); //NOI18N
526: if (webApp == null)
527: return false;
528: Servlet s;
529: try {
530: s = (Servlet) webApp.createBean("Servlet"); //NOI18N
531: if (debug)
532: log("\tCreated servlet"); //NOI18N
533: }
534:
535: catch (ClassNotFoundException cnfe) {
536: if (debug)
537: cnfe.printStackTrace();
538: return false;
539: }
540:
541: s.setServletName(name);
542: s.setServletClass(className);
543:
544: int numInitParams = getInitParams().length;
545:
546: if (debug)
547: log("\tnum params " + String.valueOf(numInitParams));//NOI18N
548:
549: for (int i = 0; i < numInitParams; ++i) {
550: InitParam param;
551: try {
552: param = (InitParam) s.createBean("InitParam"); //NOI18N
553: if (debug)
554: log("\tCreated initparam"); //NOI18N
555: }
556:
557: catch (ClassNotFoundException cnfe) {
558: if (debug)
559: cnfe.printStackTrace();
560: continue;
561: }
562:
563: param.setParamName(initparams[i][0]);
564: param.setParamValue(initparams[i][1]);
565: s.addInitParam(param);
566: }
567:
568: if (debug)
569: log("\tnum params " + String.valueOf(s.sizeInitParam())); //NOI18N
570:
571: webApp.addServlet(s);
572: return true;
573: }
574:
575: private boolean addFilter() {
576:
577: if (debug)
578: log("::addFilter()"); //NOI18N
579: if (webApp == null)
580: return false;
581: Filter f;
582: try {
583: f = (Filter) webApp.createBean("Filter"); //NOI18N
584: if (debug)
585: log("\tCreated filter"); //NOI18N
586: }
587:
588: catch (ClassNotFoundException cnfe) {
589: if (debug)
590: cnfe.printStackTrace();
591: return false;
592: }
593:
594: f.setFilterName(name);
595: f.setFilterClass(className);
596:
597: int numInitParams = getInitParams().length;
598:
599: if (debug)
600: log("\tnum params " + String.valueOf(numInitParams));//NOI18N
601:
602: for (int i = 0; i < numInitParams; ++i) {
603: InitParam param;
604: try {
605: param = (InitParam) f.createBean("InitParam"); //NOI18N
606: if (debug)
607: log("\tCreated initparam"); //NOI18N
608: }
609:
610: catch (ClassNotFoundException cnfe) {
611: if (debug)
612: cnfe.printStackTrace();
613: continue;
614: }
615:
616: param.setParamName(initparams[i][0]);
617: param.setParamValue(initparams[i][1]);
618: f.addInitParam(param);
619: }
620:
621: if (debug)
622: log("\tnum params " + String.valueOf(f.sizeInitParam())); //NOI18N
623:
624: webApp.addFilter(f);
625: return true;
626: }
627:
628: private void addUrlMappings() {
629:
630: if (webApp == null)
631: return;
632: int numMappings = getUrlMappings().length;
633: for (int i = 0; i < numMappings; ++i) {
634: ServletMapping m;
635: try {
636: m = (ServletMapping) webApp
637: .createBean("ServletMapping"); //NOI18N
638: } catch (ClassNotFoundException cnfe) {
639: return;
640: }
641: m.setServletName(name);
642: m.setUrlPattern(urlMappings[i]);
643: webApp.addServletMapping(m);
644: }
645: }
646:
647: private void addFilterMappings() {
648:
649: if (debug)
650: log("::addFilterMappings()");
651: if (webApp == null)
652: return;
653:
654: // filterMappings cannot be null, or of size zero
655: int numFilterMappings = filterMappings.size();
656: Iterator iterator = filterMappings.iterator();
657:
658: FilterMapping[] fm = new FilterMapping[numFilterMappings];
659:
660: FilterMappingData fmd;
661: for (int i = 0; i < numFilterMappings; ++i) {
662:
663: fmd = (FilterMappingData) (iterator.next());
664:
665: try {
666: fm[i] = (FilterMapping) webApp
667: .createBean("FilterMapping"); //NOI18N
668: if (debug)
669: log("\tCreated filter mapping"); //NOI18N
670: } catch (ClassNotFoundException cnfe) {
671: return;
672: }
673:
674: fm[i].setFilterName(fmd.getName());
675: if (debug)
676: log("\tFilter name: " + fmd.getName()); //NOI18N
677: if (fmd.getType() == FilterMappingData.Type.URL) {
678: fm[i].setUrlPattern(fmd.getPattern());
679: if (debug)
680: log("URL pattern " + fmd.getPattern()); //NOI18N
681: } else {
682: fm[i].setServletName(fmd.getPattern());
683: if (debug)
684: log("Servlet pattern " + fmd.getPattern()); //NOI18N
685: }
686:
687: int length = fmd.getDispatcher().length;
688: if (length == 0) {
689: if (debug)
690: log("\tNo dispatcher, continue"); //NOI18N
691: continue;
692: }
693:
694: String[] s = new String[length];
695: FilterMappingData.Dispatcher[] d = fmd.getDispatcher();
696: for (int j = 0; j < length; ++j) {
697: if (debug)
698: log("\tDispatcher: " + d[j].toString()); //NOI18N
699: s[j] = d[j].toString();
700: }
701: try {
702: fm[i].setDispatcher(s);
703: } catch (Exception e) {
704: if (debug)
705: log("\tFailed to set dispatcher"); //NOI18N
706: // do nothing, wrong version
707: }
708: if (debug)
709: log(fm[i].toString());
710: }
711: webApp.setFilterMapping(fm);
712: }
713:
714: void setAddToDD(boolean addToDD) {
715: this .addToDD = addToDD;
716: }
717:
718: boolean isAddToDD() {
719: return addToDD;
720: }
721:
722: String getErrorMessage() {
723: return errorMessage;
724: }
725:
726: void log(String s) {
727: System.out.println("ServletData" + s);
728: }
729:
730: private String checkServletMappig(String uri) {
731: if (!uri.matches("[\\*/].*")) { //NOI18N
732: return NbBundle.getMessage(ServletData.class,
733: "MSG_WrongUriStart");
734: } else if (uri.length() > 1 && uri.endsWith("/")) {
735: return NbBundle.getMessage(ServletData.class,
736: "MSG_WrongUriEnd");
737: } else if (uri.matches(".*\\*.*\\*.*")) { //NOI18N
738: return NbBundle.getMessage(ServletData.class,
739: "MSG_TwoAsterisks");
740: } else if (uri.matches("..*\\*..*")) { //NOI18N
741: return NbBundle.getMessage(ServletData.class,
742: "MSG_AsteriskInTheMiddle");
743: } else if (uri.length() > 1 && !isRFC2396URI(uri.substring(1))) {
744: return NbBundle.getMessage(ServletData.class,
745: "MSG_WrongUri");
746: }
747: return null;
748: }
749:
750: /**
751: * Get the valid URI according to <a href="http://www.ietf.org/rfc/rfc2396.txt">the RFC 2396</a>.
752: * @param uri URI to be checked.
753: * @return valid URI according to <a href="http://www.ietf.org/rfc/rfc2396.txt">the RFC 2396</a>.
754: */
755: static String getRFC2396URI(String uri) {
756: if (isRFC2396URI(uri)) {
757: return uri;
758: }
759: StringBuilder sb = new StringBuilder(uri);
760: for (int i = 0; i < sb.length(); i++) {
761: if (!isRFC2396URI(sb.substring(i, i + 1))) {
762: sb.replace(i, i + 1, "_"); // NOI18N
763: }
764: }
765: return sb.toString();
766: }
767:
768: private static boolean isRFC2396URI(String uri) {
769: return VALID_URI_PATTERN.matcher(uri).matches();
770: }
771: }
|