001: /* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
002: * This code is licensed under the GPL 2.0 license, availible at the root
003: * application directory.
004: */
005: package org.vfny.geoserver.wms.requests;
006:
007: import com.vividsolutions.jts.geom.Coordinate;
008: import org.geotools.data.DefaultQuery;
009: import org.geotools.data.FeatureReader;
010: import org.geotools.data.Query;
011: import org.geotools.data.Transaction;
012: import org.geotools.data.crs.ForceCoordinateSystemFeatureReader;
013: import org.geotools.data.memory.MemoryDataStore;
014: import org.geotools.feature.FeatureType;
015: import org.geotools.filter.ExpressionDOMParser;
016: import org.geotools.referencing.CRS;
017: import org.geotools.referencing.crs.DefaultGeographicCRS;
018: import org.geotools.styling.SLDParser;
019: import org.geotools.styling.StyleFactory;
020: import org.geotools.styling.StyleFactoryFinder;
021: import org.geotools.styling.StyledLayer;
022: import org.geotools.styling.StyledLayerDescriptor;
023: import org.geotools.styling.UserLayer;
024: import org.opengis.referencing.crs.CoordinateReferenceSystem;
025: import org.vfny.geoserver.Request;
026: import org.vfny.geoserver.global.MapLayerInfo;
027: import org.vfny.geoserver.global.TemporaryFeatureTypeInfo;
028: import org.vfny.geoserver.util.GETMAPValidator;
029: import org.vfny.geoserver.util.SLDValidator;
030: import org.vfny.geoserver.util.requests.readers.XmlRequestReader;
031: import org.vfny.geoserver.wms.WmsException;
032: import org.vfny.geoserver.wms.servlets.WMService;
033: import org.w3c.dom.NamedNodeMap;
034: import org.w3c.dom.Node;
035: import org.w3c.dom.NodeList;
036: import org.xml.sax.InputSource;
037: import org.xml.sax.SAXParseException;
038: import java.awt.Color;
039: import java.io.BufferedOutputStream;
040: import java.io.BufferedReader;
041: import java.io.File;
042: import java.io.FileInputStream;
043: import java.io.FileOutputStream;
044: import java.io.FileReader;
045: import java.io.IOException;
046: import java.io.Reader;
047: import java.util.ArrayList;
048: import java.util.Enumeration;
049: import java.util.HashMap;
050: import java.util.Iterator;
051: import java.util.List;
052: import java.util.Map;
053: import java.util.logging.Level;
054: import javax.servlet.http.HttpServletRequest;
055:
056: /**
057: * reads in a GetFeature XML WFS request from a XML stream
058: *
059: * @author Rob Hranac, TOPP
060: * @author Chris Holmes, TOPP
061: * @version $Id: GetMapXmlReader.java 7749 2007-11-13 20:52:54Z jdeolive $
062: */
063: public class GetMapXmlReader extends XmlRequestReader {
064: private static final StyleFactory styleFactory = StyleFactoryFinder
065: .createStyleFactory();
066:
067: /**
068: * Creates a new GetMapXmlReader object.
069: * @param service this is the service that handles the request
070: */
071: public GetMapXmlReader(WMService service) {
072: super (service);
073: }
074:
075: /**
076: * Reads the GetMap XML request into a GetMap Request object.
077: *
078: * @param reader The plain POST text from the client.
079: * @param req DOCUMENT ME!
080: *
081: * @return The GetMap Request from the xml reader.
082: *
083: * @throws WmsException For any problems reading the request.
084: */
085: public Request read(Reader reader, HttpServletRequest req)
086: throws WmsException {
087: GetMapRequest getMapRequest = new GetMapRequest(
088: (WMService) getServiceRef());
089: getMapRequest.setHttpServletRequest(req);
090:
091: boolean validateSchema = wantToValidate(req);
092:
093: try {
094: parseGetMapXML(reader, getMapRequest, validateSchema);
095: } catch (java.net.UnknownHostException unh) {
096: //J--
097: //http://www.oreilly.com/catalog/jenut2/chapter/ch19.html ---
098: // There is one complication to this example. Most web.xml files contain a <!DOCTYPE> tag that specifies
099: //the document type (or DTD). Despite the fact that Example 19.1 specifies that the parser should not
100: //validate the document, a conforming XML parser must still read the DTD for any document that has a
101: //<!DOCTYPE> declaration. Most web.xml have a declaration like this:
102: //..
103: //In order to read the DTD, the parser must be able to read the specified URL. If your system is not
104: //connected to the Internet when you run the example, it will hang.
105: //. Another workaround to this DTD problem is to simply remove (or comment out) the <!DOCTYPE> declaration from the web.xml file you process with ListServlets1./
106: //
107: //also see:
108: //http://doctypechanger.sourceforge.net/
109: //J+
110: throw new WmsException(
111: "unknown host - "
112: + unh.getLocalizedMessage()
113: + " - if its in a !DOCTYPE, remove the !DOCTYPE tag.");
114: } catch (SAXParseException se) {
115: throw new WmsException("line " + se.getLineNumber()
116: + " column " + se.getColumnNumber() + " -- "
117: + se.getLocalizedMessage());
118: } catch (Exception e) {
119: throw new WmsException(e);
120: }
121:
122: return getMapRequest;
123: }
124:
125: /**
126: * Actually read in the XML request and stick it in the request object. We
127: * do this using the DOM parser (because the SLD parser is DOM based and
128: * we can integrate). 1. parse into DOM 2. parse the SLD 3. grab the
129: * rest of the attribute 4. stuff #3 attributes in the request object 5.
130: * stuff the SLD info into the request object 6. return GetMap schema is
131: * at http://www.opengeospatial.org/docs/02-017r1.pdf (page 18) NOTE: see
132: * handlePostGet() for people who put the SLD in the POST and the
133: * parameters in the GET.
134: *
135: * @param xml
136: * @param getMapRequest
137: * @param validateSchema DOCUMENT ME!
138: *
139: * @throws Exception DOCUMENT ME!
140: */
141: private void parseGetMapXML(Reader xml,
142: GetMapRequest getMapRequest, boolean validateSchema)
143: throws Exception {
144: File temp = null;
145:
146: if (validateSchema) //copy POST to a file
147: {
148: //make tempfile
149: temp = File.createTempFile("getMapPost", "xml");
150: temp.deleteOnExit();
151:
152: FileOutputStream fos = new FileOutputStream(temp);
153: BufferedOutputStream out = new BufferedOutputStream(fos);
154:
155: int c;
156:
157: while (-1 != (c = xml.read())) {
158: out.write(c);
159: }
160:
161: xml.close();
162: out.flush();
163: out.close();
164: xml = new BufferedReader(new FileReader(temp)); // pretend like nothing has happened
165: }
166:
167: try {
168: javax.xml.parsers.DocumentBuilderFactory dbf = javax.xml.parsers.DocumentBuilderFactory
169: .newInstance();
170:
171: dbf.setExpandEntityReferences(false);
172: dbf.setValidating(false);
173: dbf.setNamespaceAware(true);
174:
175: javax.xml.parsers.DocumentBuilder db = dbf
176: .newDocumentBuilder();
177:
178: InputSource input = new InputSource(xml);
179: org.w3c.dom.Document dom = db.parse(input);
180:
181: SLDParser sldParser = new SLDParser(styleFactory);
182:
183: Node rootNode = dom.getDocumentElement();
184:
185: // we have the SLD component, now we get all the GetMAp components
186: // step a -- attribute "version"
187: Node nodeGetMap = rootNode;
188:
189: if (!(nodeNameEqual(nodeGetMap, "getmap"))) {
190: if (nodeNameEqual(nodeGetMap, "StyledLayerDescriptor")) //oopsy!! its a SLD POST with get parameters!
191: {
192: if (validateSchema) {
193: validateSchemaSLD(temp, getMapRequest);
194: }
195:
196: handlePostGet(rootNode, sldParser, getMapRequest);
197:
198: return;
199: }
200:
201: throw new Exception(
202: "GetMap XML parser - start node isnt 'GetMap' or 'StyledLayerDescriptor' tag");
203: }
204:
205: if (validateSchema) {
206: validateSchemaGETMAP(temp, getMapRequest);
207: }
208:
209: NamedNodeMap atts = nodeGetMap.getAttributes();
210: Node wmsVersion = atts.getNamedItem("version");
211:
212: if (wmsVersion == null) {
213: throw new Exception(
214: "GetMap XML parser - couldnt find attribute 'version' in GetMap tag");
215: }
216:
217: getMapRequest.setVersion(wmsVersion.getNodeValue());
218:
219: //ignore the OWSType since we know its supposed to be WMS
220: //step b -bounding box
221: parseBBox(getMapRequest, nodeGetMap);
222:
223: // for SLD we already have it (from above) (which we'll handle as layers later)
224: StyledLayerDescriptor sld = sldParser
225: .parseDescriptor(getNode(rootNode,
226: "StyledLayerDescriptor"));
227: processStyles(getMapRequest, sld);
228:
229: //step c - "Output"
230: parseXMLOutput(nodeGetMap, getMapRequest); //make this function easier to read
231:
232: //step d - "exceptions"
233: getMapRequest.setExceptions(getNodeValue(nodeGetMap,
234: "Exceptions"));
235:
236: //step e - "VendorType
237: // we dont actually do anything with this, so...
238: //step f - rebuild SLD info. Ie. fill in the Layer and Style information, just like SLD post-get
239: } finally {
240: if (temp != null) {
241: temp.delete();
242: }
243: }
244: }
245:
246: /**
247: * This is the hybrid SLD POST way. Normal is the GetMap - with a built in
248: * SLD. The alternate, for stupid people, is the WMS parameters in the
249: * GET, and the SLD in the post. This handles that case.
250: *
251: * @param rootNode
252: * @param sldParser
253: * @param getMapRequest
254: *
255: * @throws Exception DOCUMENT ME!
256: */
257: private void handlePostGet(Node rootNode, SLDParser sldParser,
258: GetMapRequest getMapRequest) throws Exception {
259: //get the GET parmeters
260: HttpServletRequest request = getMapRequest
261: .getHttpServletRequest();
262:
263: String qString = request.getQueryString();
264:
265: if (LOGGER.isLoggable(Level.FINE)) {
266: LOGGER.fine(new StringBuffer("reading request: ").append(
267: qString).toString());
268: }
269:
270: //Map requestParams = KvpRequestReader.parseKvpSet(qString);
271: Map requestParams = new HashMap();
272: String paramName;
273: String paramValue;
274:
275: for (Enumeration pnames = request.getParameterNames(); pnames
276: .hasMoreElements();) {
277: paramName = (String) pnames.nextElement();
278: paramValue = request.getParameter(paramName);
279: requestParams.put(paramName.toUpperCase(), paramValue);
280: }
281:
282: GetMapKvpReader kvpReader = new GetMapKvpReader(requestParams,
283: (WMService) getServiceRef());
284:
285: String version = kvpReader.getRequestVersion();
286: getMapRequest.setVersion(version);
287:
288: kvpReader.parseMandatoryParameters(getMapRequest, false); //false means dont do styles/layers (see below)
289: kvpReader.parseOptionalParameters(getMapRequest);
290:
291: //get styles/layers from the sld.
292: StyledLayerDescriptor sld = sldParser.parseDescriptor(rootNode); //root = <StyledLayerDescriptor>
293: processStyles(getMapRequest, sld);
294: }
295:
296: /**
297: * taken from the kvp reader, with modifications
298: *
299: * @param getMapRequest
300: * @param sld
301: *
302: * @throws Exception DOCUMENT ME!
303: * @throws WmsException DOCUMENT ME!
304: */
305: private void processStyles(GetMapRequest getMapRequest,
306: StyledLayerDescriptor sld) throws Exception {
307: final StyledLayer[] styledLayers = sld.getStyledLayers();
308: final int slCount = styledLayers.length;
309:
310: if (slCount == 0) {
311: throw new WmsException("SLD document contains no layers");
312: }
313:
314: final List layers = new ArrayList();
315: final List styles = new ArrayList();
316: MapLayerInfo currLayer;
317:
318: StyledLayer sl = null;
319:
320: for (int i = 0; i < slCount; i++) {
321: currLayer = new MapLayerInfo();
322: sl = styledLayers[i];
323:
324: String layerName = sl.getName();
325:
326: if (null == layerName) {
327: throw new WmsException(
328: "A UserLayer without layer name was passed");
329: }
330:
331: // TODO: add support for remote WFS here
332: //handle the InLineFeature stuff
333: boolean isBaseMap = false;
334: if ((sl instanceof UserLayer)
335: && ((((UserLayer) sl)).getInlineFeatureDatastore() != null)) {
336: //SPECIAL CASE - we make the temporary version
337: UserLayer ul = ((UserLayer) sl);
338: GetMapKvpReader.initializeInlineFeatureLayer(
339: getMapRequest, ul, currLayer);
340: } else {
341:
342: //look for a base map layer
343: String layerGroup = (String) getMapRequest.getWMS()
344: .getBaseMapLayers().get(layerName);
345: if (layerGroup != null) {
346: isBaseMap = true;
347: List layerGroupExpanded = GetMapKvpReader
348: .parseLayerGroup(layerGroup);
349: for (Iterator it = layerGroupExpanded.iterator(); it
350: .hasNext();) {
351: layerName = (String) it.next();
352: currLayer = new MapLayerInfo();
353: try {
354: currLayer.setFeature(GetMapKvpReader
355: .findFeatureLayer(getMapRequest,
356: layerName));
357: } catch (Exception e) {
358: currLayer.setCoverage(GetMapKvpReader
359: .findCoverageLayer(getMapRequest,
360: layerName));
361: }
362:
363: GetMapKvpReader.addStyles(getMapRequest,
364: currLayer, styledLayers[i], layers,
365: styles);
366: }
367: } else {
368: try {
369: currLayer.setFeature(GetMapKvpReader
370: .findFeatureLayer(getMapRequest,
371: layerName));
372: } catch (Exception e) {
373: currLayer.setCoverage(GetMapKvpReader
374: .findCoverageLayer(getMapRequest,
375: layerName));
376: }
377: }
378: }
379:
380: if (!isBaseMap) {
381: GetMapKvpReader.addStyles(getMapRequest, currLayer,
382: styledLayers[i], layers, styles);
383: }
384: }
385:
386: getMapRequest.setLayers((MapLayerInfo[]) layers
387: .toArray(new MapLayerInfo[layers.size()]));
388: getMapRequest.setStyles(styles);
389: }
390:
391: /**
392: * xs:element name="BoundingBox" type="gml:BoxType"/> dont forget the SRS!
393: *
394: * @param getMapRequest
395: * @param nodeGetMap
396: *
397: * @throws Exception DOCUMENT ME!
398: */
399: private void parseBBox(GetMapRequest getMapRequest, Node nodeGetMap)
400: throws Exception {
401: Node bboxNode = getNode(nodeGetMap, "BoundingBox");
402:
403: if (bboxNode == null) {
404: throw new Exception(
405: "GetMap XML parser - couldnt find node 'BoundingBox' in GetMap tag");
406: }
407:
408: List coordList = ExpressionDOMParser.parseCoords(bboxNode);
409:
410: if (coordList.size() != 2) {
411: throw new Exception(
412: "GetMap XML parser - node 'BoundingBox' in GetMap tag should have 2 coordinates in it");
413: }
414:
415: com.vividsolutions.jts.geom.Envelope env = new com.vividsolutions.jts.geom.Envelope();
416: final int size = coordList.size();
417:
418: for (int i = 0; i < size; i++) {
419: env.expandToInclude((Coordinate) coordList.get(i));
420: }
421:
422: getMapRequest.setBbox(env);
423:
424: // SRS
425: NamedNodeMap atts = bboxNode.getAttributes();
426: Node srsNode = atts.getNamedItem("srsName");
427:
428: if (srsNode != null) {
429: String srs = srsNode.getNodeValue();
430: String epsgCode = srs.substring(srs.indexOf('#') + 1);
431: epsgCode = "EPSG:" + epsgCode;
432:
433: try {
434: CoordinateReferenceSystem mapcrs = CRS.decode(epsgCode);
435: getMapRequest.setCrs(mapcrs);
436: getMapRequest.setSRS(epsgCode);
437: } catch (Exception e) {
438: //couldnt make it - we send off a service exception with the correct info
439: throw new WmsException(e.getLocalizedMessage(),
440: "InvalidSRS");
441: }
442: }
443: }
444:
445: //J--
446: /**
447: *
448: * <xs:element name="Format" type="ogc:FormatType"/>
449: * <xs:element name="Transparent" type="xs:boolean" minOccurs="0"/>
450: * <xs:element name="BGcolor" type="xs:string" minOccurs="0"/>
451: * <xs:element name="Size">
452: * <xs:complexType>
453: * <xs:sequence>
454: * <xs:element name="Width" type="xs:positiveInteger"/>
455: * <xs:element name="Height" type="xs:positiveInteger"/>
456: * </xs:sequence>
457: * </xs:complexType>
458: * <xs:element name="Buffer" type="xs:integer" minOccurs="0"/>
459: * </xs:element><!--Size-->
460: *
461: * @param nodeGetMap
462: * @param getMapRequest
463: */
464:
465: //J+
466: private void parseXMLOutput(Node nodeGetMap,
467: GetMapRequest getMapRequest) throws Exception {
468: Node outputNode = getNode(nodeGetMap, "Output");
469:
470: if (outputNode == null) {
471: throw new Exception(
472: "GetMap XML parser - couldnt find node 'Output' in GetMap tag");
473: }
474:
475: //Format
476: String format = getNodeValue(outputNode, "Format");
477:
478: if (format == null) {
479: throw new Exception(
480: "GetMap XML parser - couldnt find node 'Format' in GetMap/Output tag");
481: }
482:
483: getMapRequest.setFormat(format);
484:
485: // Transparent
486: String trans = getNodeValue(outputNode, "Transparent");
487:
488: if (trans != null) {
489: if (trans.equalsIgnoreCase("false")
490: || trans.equalsIgnoreCase("0")) {
491: getMapRequest.setTransparent(false);
492: } else {
493: getMapRequest.setTransparent(true);
494: }
495: }
496:
497: // Buffer
498: String bufferValue = getNodeValue(outputNode, "Buffer");
499:
500: if (bufferValue != null) {
501: getMapRequest.setBuffer(Integer.parseInt(bufferValue));
502: }
503:
504: //BGColor
505: String bgColor = getNodeValue(outputNode, "BGcolor");
506:
507: if (bgColor != null) {
508: getMapRequest.setBgColor(Color.decode(bgColor));
509: }
510:
511: //SIZE
512: Node sizeNode = getNode(outputNode, "Size");
513:
514: if (sizeNode == null) {
515: throw new Exception(
516: "GetMap XML parser - couldnt find node 'Size' in GetMap/Output tag");
517: }
518:
519: //Size/Width
520: String width = getNodeValue(sizeNode, "Width");
521:
522: if (width == null) {
523: throw new Exception(
524: "GetMap XML parser - couldnt find node 'Width' in GetMap/Output/Size tag");
525: }
526:
527: getMapRequest.setWidth(Integer.parseInt(width));
528:
529: //Size/Height
530: String height = getNodeValue(sizeNode, "Height");
531:
532: if (width == null) {
533: throw new Exception(
534: "GetMap XML parser - couldnt find node 'Height' in GetMap/Output/Size tag");
535: }
536:
537: getMapRequest.setHeight(Integer.parseInt(height));
538: }
539:
540: /**
541: * Give a node and the name of a child of that node, return it. This doesnt
542: * do anything complex.
543: *
544: * @param parentNode
545: * @param wantedChildName
546: *
547: * @return
548: */
549: public Node getNode(Node parentNode, String wantedChildName) {
550: NodeList children = parentNode.getChildNodes();
551:
552: for (int i = 0; i < children.getLength(); i++) {
553: Node child = children.item(i);
554:
555: if ((child == null)
556: || (child.getNodeType() != Node.ELEMENT_NODE)) {
557: continue;
558: }
559:
560: String childName = child.getLocalName();
561:
562: if (childName == null) {
563: childName = child.getNodeName();
564: }
565:
566: if (childName.equalsIgnoreCase(wantedChildName)) {
567: return child;
568: }
569: }
570:
571: return null;
572: }
573:
574: /**
575: * Give a node and the name of a child of that node, find its (string)
576: * value. This doesnt do anything complex.
577: *
578: * @param parentNode
579: * @param wantedChildName
580: *
581: * @return
582: */
583: public String getNodeValue(Node parentNode, String wantedChildName) {
584: NodeList children = parentNode.getChildNodes();
585:
586: for (int i = 0; i < children.getLength(); i++) {
587: Node child = children.item(i);
588:
589: if ((child == null)
590: || (child.getNodeType() != Node.ELEMENT_NODE)) {
591: continue;
592: }
593:
594: String childName = child.getLocalName();
595:
596: if (childName == null) {
597: childName = child.getNodeName();
598: }
599:
600: if (childName.equalsIgnoreCase(wantedChildName)) {
601: return child.getChildNodes().item(0).getNodeValue();
602: }
603: }
604:
605: return null;
606: }
607:
608: /**
609: * returns true if this node is named "name". Ignores case and namespaces.
610: *
611: * @param n
612: * @param name
613: *
614: * @return
615: */
616: public boolean nodeNameEqual(Node n, String name) {
617: if (n.getNodeName().equalsIgnoreCase(name)) {
618: return true;
619: }
620:
621: String nname = n.getNodeName();
622: int idx = nname.indexOf(':');
623:
624: if (idx == -1) {
625: return false;
626: }
627:
628: if (nname.substring(idx + 1).equalsIgnoreCase(name)) {
629: return true;
630: }
631:
632: return false;
633: }
634:
635: /**
636: * This should only be called if the xml starts with StyledLayerDescriptor
637: * Don't use on a GetMap.
638: *
639: * @param f
640: * @param getMapRequest
641: *
642: * @throws Exception
643: * @throws WmsException DOCUMENT ME!
644: */
645: public void validateSchemaSLD(File f, GetMapRequest getMapRequest)
646: throws Exception {
647: SLDValidator validator = new SLDValidator();
648: List errors = null;
649:
650: try {
651: FileInputStream in = null;
652:
653: try {
654: in = new FileInputStream(f);
655: errors = validator.validateSLD(in, getMapRequest
656: .getHttpServletRequest().getSession()
657: .getServletContext());
658: } finally {
659: if (in != null) {
660: in.close();
661: }
662: }
663:
664: if (errors.size() != 0) {
665: in = new FileInputStream(f);
666: throw new WmsException(SLDValidator.getErrorMessage(in,
667: errors));
668: }
669: } catch (IOException e) {
670: String msg = new StringBuffer("Creating remote SLD url: ")
671: .append(e.getMessage()).toString();
672:
673: if (LOGGER.isLoggable(Level.WARNING)) {
674: LOGGER.log(Level.WARNING, msg, e);
675: }
676:
677: throw new WmsException(e, msg, "parseSldParam");
678: }
679: }
680:
681: /**
682: * This should only be called if the xml starts with GetMap Don't use on a
683: * SLD.
684: *
685: * @param f
686: * @param getMapRequest
687: *
688: * @throws Exception
689: * @throws WmsException DOCUMENT ME!
690: */
691: public void validateSchemaGETMAP(File f, GetMapRequest getMapRequest)
692: throws Exception {
693: GETMAPValidator validator = new GETMAPValidator();
694: List errors = null;
695:
696: try {
697: FileInputStream in = null;
698:
699: try {
700: in = new FileInputStream(f);
701: errors = validator.validateGETMAP(in, getMapRequest
702: .getHttpServletRequest().getSession()
703: .getServletContext());
704: } finally {
705: if (in != null) {
706: in.close();
707: }
708: }
709:
710: if (errors.size() != 0) {
711: in = new FileInputStream(f);
712: throw new WmsException(GETMAPValidator.getErrorMessage(
713: in, errors));
714: }
715: } catch (IOException e) {
716: String msg = new StringBuffer(
717: "Creating remote GETMAP url: ").append(
718: e.getMessage()).toString();
719:
720: if (LOGGER.isLoggable(Level.WARNING)) {
721: LOGGER.log(Level.WARNING, msg, e);
722: }
723:
724: throw new WmsException(e, msg, "GETMAP validator");
725: }
726: }
727:
728: /**
729: * DOCUMENT ME!
730: *
731: * @param request
732: *
733: * @return
734: */
735: private boolean wantToValidate(HttpServletRequest request) {
736: String queryString = request.getQueryString(); // ie. FORMAT=image/png&TRANSPARENT=TRUE&HEIGHT=480&REQUEST=GetMap&BBOX=-73.94896388053894,40.77323718492597,-73.94105110168456,40.77796711500081&WIDTH=803&SRS=EPSG:4326&VERSION=1.1.1
737:
738: if (queryString == null) {
739: return false; // pure POST without any query
740: }
741:
742: queryString = queryString.toLowerCase();
743:
744: if (queryString.startsWith("validateschema")
745: || (queryString.indexOf("&validateschema") != -1)) {
746: return true;
747: }
748:
749: return false;
750: }
751: }
|