0001: /* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
0002: * This code is licensed under the GPL 2.0 license, availible at the root
0003: * application directory.
0004: */
0005: package org.geoserver.wfs;
0006:
0007: import com.vividsolutions.jts.geom.Envelope;
0008:
0009: import net.opengis.wfs.GetCapabilitiesType;
0010:
0011: import org.geoserver.ows.util.RequestUtils;
0012: import org.geoserver.ows.util.ResponseUtils;
0013: import org.geoserver.ows.xml.v1_0.OWS;
0014: import org.geoserver.platform.GeoServerExtensions;
0015: import org.geoserver.platform.ServiceException;
0016: import org.geoserver.wfs.response.GetCapabilitiesResponse;
0017: import org.geotools.factory.FactoryRegistry;
0018: import org.geotools.filter.FunctionExpression;
0019: import org.geotools.filter.v1_0.OGC;
0020: import org.geotools.gml3.bindings.GML;
0021: import org.geotools.xlink.bindings.XLINK;
0022: import org.geotools.xml.transform.TransformerBase;
0023: import org.geotools.xml.transform.Translator;
0024: import org.opengis.filter.expression.Function;
0025: import org.vfny.geoserver.global.Data;
0026: import org.vfny.geoserver.global.FeatureTypeInfo;
0027: import org.vfny.geoserver.global.FeatureTypeInfoTitleComparator;
0028: import org.vfny.geoserver.global.NameSpaceInfo;
0029: import org.xml.sax.ContentHandler;
0030: import org.xml.sax.helpers.AttributesImpl;
0031: import java.io.IOException;
0032: import java.net.URL;
0033: import java.util.ArrayList;
0034: import java.util.Arrays;
0035: import java.util.Collection;
0036: import java.util.Collections;
0037: import java.util.Comparator;
0038: import java.util.HashMap;
0039: import java.util.Iterator;
0040: import java.util.List;
0041: import java.util.Map;
0042: import java.util.SortedSet;
0043: import java.util.TreeSet;
0044: import java.util.logging.Level;
0045: import java.util.logging.Logger;
0046:
0047: /**
0048: * Based on the <code>org.geotools.xml.transform</code> framework, does the job
0049: * of encoding a WFS 1.0 Capabilities document.
0050: *
0051: * @author Gabriel Roldan, Axios Engineering
0052: * @author Chris Holmes
0053: * @author Justin Deoliveira
0054: *
0055: * @version $Id: CapabilitiesTransformer.java 8406 2008-02-14 19:49:39Z saul.farber $
0056: */
0057: public abstract class CapabilitiesTransformer extends TransformerBase {
0058: /** logger */
0059: private static final Logger LOGGER = org.geotools.util.logging.Logging
0060: .getLogger(CapabilitiesTransformer.class.getPackage()
0061: .getName());
0062:
0063: /** identifer of a http get + post request */
0064: private static final String HTTP_GET = "Get";
0065: private static final String HTTP_POST = "Post";
0066:
0067: /** wfs namespace */
0068: protected static final String WFS_URI = "http://www.opengis.net/wfs";
0069:
0070: /** xml schema namespace + prefix */
0071: protected static final String XSI_PREFIX = "xsi";
0072: protected static final String XSI_URI = "http://www.w3.org/2001/XMLSchema-instance";
0073:
0074: /** filter namesapce + prefix */
0075: protected static final String OGC_PREFIX = "ogc";
0076: protected static final String OGC_URI = OGC.NAMESPACE;
0077:
0078: /** wfs service */
0079: protected WFS wfs;
0080:
0081: /** catalog */
0082: protected Data catalog;
0083:
0084: /**
0085: * Creates a new CapabilitiesTransformer object.
0086: */
0087: public CapabilitiesTransformer(WFS wfs, Data catalog) {
0088: super ();
0089: setNamespaceDeclarationEnabled(false);
0090:
0091: this .wfs = wfs;
0092: this .catalog = catalog;
0093: }
0094:
0095: /**
0096: * It turns out that the he WFS 1.0 and 1.1 specifications don't actually support an updatesequence-based
0097: * getcapabilities operation. There's no mention of an updatesequence request parameter in the getcapabilities
0098: * operation, and there's no normative behaviour description for what the updatesequence parameter in the
0099: * capabilities document should *do*.
0100: *
0101: * So this behaviour is not used right now, at all (as of Jan 2007)
0102: * @param request
0103: * @throws ServiceException
0104: */
0105: public void verifyUpdateSequence(GetCapabilitiesType request)
0106: throws ServiceException {
0107: int reqUS = -1;
0108: if (request.getUpdateSequence() != null) {
0109: try {
0110: reqUS = Integer.parseInt(request.getUpdateSequence());
0111: } catch (NumberFormatException nfe) {
0112: throw new ServiceException(
0113: "GeoServer only accepts numbers in the updateSequence parameter");
0114: }
0115: }
0116: int geoUS = wfs.getGeoServer().getUpdateSequence();
0117: if (reqUS > geoUS) {
0118: throw new ServiceException(
0119: "Client supplied an updateSequence that is greater than the current sever updateSequence",
0120: "InvalidUpdateSequence");
0121: }
0122: if (reqUS == geoUS) {
0123: throw new ServiceException(
0124: "WMS capabilities document is current (updateSequence = "
0125: + geoUS + ")", "CurrentUpdateSequence");
0126: }
0127: }
0128:
0129: /**
0130: * Transformer for wfs 1.0 capabilities document.
0131: *
0132: * @author Justin Deoliveira, The Open Planning Project
0133: *
0134: */
0135: public static class WFS1_0 extends CapabilitiesTransformer {
0136: public WFS1_0(WFS wfs, Data catalog) {
0137: super (wfs, catalog);
0138: }
0139:
0140: public Translator createTranslator(ContentHandler handler) {
0141: return new CapabilitiesTranslator1_0(handler);
0142: }
0143:
0144: class CapabilitiesTranslator1_0 extends TranslatorSupport {
0145: GetCapabilitiesType request;
0146:
0147: public CapabilitiesTranslator1_0(ContentHandler handler) {
0148: super (handler, null, null);
0149: }
0150:
0151: public void encode(Object object)
0152: throws IllegalArgumentException {
0153: request = (GetCapabilitiesType) object;
0154: String proxifiedBaseUrl = RequestUtils
0155: .proxifiedBaseURL(request.getBaseUrl(), wfs
0156: .getGeoServer().getProxyBaseUrl());
0157:
0158: //verifyUpdateSequence(request);
0159:
0160: AttributesImpl attributes = new AttributesImpl();
0161: attributes.addAttribute("", "version", "version", "",
0162: "1.0.0");
0163: attributes.addAttribute("", "xmlns", "xmlns", "",
0164: WFS_URI);
0165:
0166: NameSpaceInfo[] namespaces = catalog.getNameSpaces();
0167:
0168: for (int i = 0; i < namespaces.length; i++) {
0169: NameSpaceInfo namespace = namespaces[i];
0170: String prefix = namespace.getPrefix();
0171: String uri = namespace.getURI();
0172:
0173: if ("xml".equals(prefix)) {
0174: continue;
0175: }
0176:
0177: String prefixDef = "xmlns:" + prefix;
0178: attributes.addAttribute("", prefixDef, prefixDef,
0179: "", uri);
0180: }
0181:
0182: //filter
0183: attributes.addAttribute("", "xmlns:" + OGC_PREFIX,
0184: "xmlns:" + OGC_PREFIX, "", OGC_URI);
0185:
0186: //xml schema
0187: attributes.addAttribute("", "xmlns:" + XSI_PREFIX,
0188: "xmlns:" + XSI_PREFIX, "", XSI_URI);
0189:
0190: String locationAtt = XSI_PREFIX + ":schemaLocation";
0191: String locationDef = WFS_URI
0192: + " "
0193: + ResponseUtils
0194: .appendPath(proxifiedBaseUrl,
0195: "schemas/wfs/1.0.0/WFS-capabilities.xsd");
0196: attributes.addAttribute("", locationAtt, locationAtt,
0197: "", locationDef);
0198: //attributes.addAttribute("", "updateSequence", "updateSequence", "", wfs.getGeoServer().getUpdateSequence() + "");
0199:
0200: start("WFS_Capabilities", attributes);
0201:
0202: handleService();
0203: handleCapability();
0204: handleFeatureTypes();
0205: handleFilterCapabilities();
0206:
0207: end("WFS_Capabilities");
0208: }
0209:
0210: /**
0211: * Encodes the wfs:Service element.
0212: *
0213: * <pre>
0214: * <xsd:complexType name="ServiceType">
0215: * <xsd:sequence>
0216: * <xsd:element name="Name" type="xsd:string"/>
0217: * <xsd:element ref="wfs:Title"/>
0218: * <xsd:element ref="wfs:Abstract" minOccurs="0"/>
0219: * <xsd:element ref="wfs:Keywords" minOccurs="0"/>
0220: * <xsd:element ref="wfs:OnlineResource"/>
0221: * <xsd:element ref="wfs:Fees" minOccurs="0"/>
0222: * <xsd:element ref="wfs:AccessConstraints" minOccurs="0"/>
0223: * </xsd:sequence>
0224: * </xsd:complexType>
0225: *
0226: * </pre>
0227: *
0228: */
0229: private void handleService() {
0230: start("Service");
0231: element("Name", wfs.getName());
0232: element("Title", wfs.getTitle());
0233: element("Abstract", wfs.getAbstract());
0234:
0235: handleKeywords(wfs.getKeywords());
0236:
0237: String proxifiedBaseUrl = RequestUtils
0238: .proxifiedBaseURL(request.getBaseUrl(), wfs
0239: .getGeoServer().getProxyBaseUrl());
0240:
0241: element("OnlineResource", ResponseUtils.appendPath(
0242: proxifiedBaseUrl, "wfs"));
0243: element("Fees", wfs.getFees());
0244: element("AccessConstraints", wfs.getAccessConstraints());
0245: end("Service");
0246: }
0247:
0248: /**
0249: * Encodes the wfs:Keywords element.
0250: * <p>
0251: *
0252: * <pre>
0253: * <!-- Short words to help catalog searching.
0254: * Currently, no controlled vocabulary has
0255: * been defined. -->
0256: * <xsd:element name="Keywords" type="xsd:string"/>
0257: * </pre>
0258: *
0259: * </p>
0260: *
0261: */
0262: private void handleKeywords(String[] kwlist) {
0263: if (kwlist == null) {
0264: handleKeywords((List) null);
0265: } else {
0266: handleKeywords(Arrays.asList(kwlist));
0267: }
0268: }
0269:
0270: /**
0271: * Encodes the wfs:Keywords element.
0272: * <p>
0273: *
0274: * <pre>
0275: * <!-- Short words to help catalog searching.
0276: * Currently, no controlled vocabulary has
0277: * been defined. -->
0278: * <xsd:element name="Keywords" type="xsd:string"/>
0279: * </pre>
0280: *
0281: * </p>
0282: *
0283: */
0284: private void handleKeywords(List kwlist) {
0285: StringBuffer kwds = new StringBuffer();
0286:
0287: for (int i = 0; (kwlist != null) && (i < kwlist.size()); i++) {
0288: kwds.append(kwlist.get(i));
0289:
0290: if (i != (kwlist.size() - 1)) {
0291: kwds.append(", ");
0292: }
0293: }
0294:
0295: element("Keywords", kwds.toString());
0296: }
0297:
0298: /**
0299: * Encodes the wfs:Capability element.
0300: * <p>
0301: *
0302: * <pre>
0303: * <xsd:complexType name="CapabilityType">
0304: * <xsd:sequence>
0305: * <xsd:element name="Request" type="wfs:RequestType"/>
0306: * <!-- The optional VendorSpecificCapabilities element lists any
0307: * capabilities unique to a particular server. Because the
0308: * information is not known a priori, it cannot be constrained
0309: * by this particular schema document. A vendor-specific schema
0310: * fragment must be supplied at the start of the XML capabilities
0311: * document, after the reference to the general WFS_Capabilities
0312: * schema. -->
0313: * <xsd:element ref="wfs:VendorSpecificCapabilities" minOccurs="0"/>
0314: * </xsd:sequence>
0315: * </xsd:complexType>
0316: * </pre>
0317: *
0318: * </p>
0319: */
0320: private void handleCapability() {
0321: start("Capability");
0322: start("Request");
0323: handleGetCapabilities();
0324: handleDescribeFT();
0325: handleGetFeature();
0326:
0327: if (wfs.getServiceLevel() >= WFS.TRANSACTIONAL) {
0328: handleTransaction();
0329: }
0330:
0331: if (wfs.getServiceLevel() == WFS.COMPLETE) {
0332: handleLock();
0333: handleFeatureWithLock();
0334: }
0335:
0336: end("Request");
0337: end("Capability");
0338: }
0339:
0340: /**
0341: * Encodes the wfs:GetCapabilities elemnt.
0342: * <p>
0343: *
0344: * <pre>
0345: * <xsd:complexType name="GetCapabilitiesType">
0346: * <xsd:sequence>
0347: * <xsd:element name="DCPType" type="wfs:DCPTypeType" maxOccurs="unbounded"/>
0348: * </xsd:sequence>
0349: * </xsd:complexType>
0350: * </pre>
0351: *
0352: * </p>
0353: */
0354: private void handleGetCapabilities() {
0355: String capName = "GetCapabilities";
0356: start(capName);
0357: handleDcpType(capName, HTTP_GET);
0358: handleDcpType(capName, HTTP_POST);
0359: end(capName);
0360: }
0361:
0362: /**
0363: * Encodes the wfs:DescribeFeatureType element.
0364: * <p>
0365: * <pre>
0366: * <xsd:complexType name="DescribeFeatureTypeType">
0367: * <xsd:sequence>
0368: * <xsd:element name="SchemaDescriptionLanguage"
0369: * type="wfs:SchemaDescriptionLanguageType"/>
0370: * <xsd:element name="DCPType"
0371: * type="wfs:DCPTypeType" maxOccurs="unbounded"/>
0372: * </xsd:sequence>
0373: * </xsd:complexType>
0374: * </pre>
0375: * </p>
0376: */
0377: private void handleDescribeFT() {
0378: String capName = "DescribeFeatureType";
0379: start(capName);
0380: start("SchemaDescriptionLanguage");
0381: element("XMLSCHEMA", null);
0382: end("SchemaDescriptionLanguage");
0383:
0384: handleDcpType(capName, HTTP_GET);
0385: handleDcpType(capName, HTTP_POST);
0386: end(capName);
0387: }
0388:
0389: /**
0390: * Encodes the wfs:GetFeature element.
0391: *
0392: * <xsd:complexType name="GetFeatureTypeType">
0393: * <xsd:sequence>
0394: * <xsd:element name="ResultFormat" type="wfs:ResultFormatType"/>
0395: * <xsd:element name="DCPType" type="wfs:DCPTypeType" maxOccurs="unbounded"/>
0396: * </xsd:sequence>
0397: * </xsd:complexType>
0398: */
0399: private void handleGetFeature() {
0400: String capName = "GetFeature";
0401: start(capName);
0402:
0403: String resultFormat = "ResultFormat";
0404: start(resultFormat);
0405:
0406: //we accept numerous formats, but cite only allows you to have GML2
0407: if (wfs.getCiteConformanceHacks()) {
0408: element("GML2", null);
0409: } else {
0410: //FULL MONTY
0411: Collection featureProducers = GeoServerExtensions
0412: .extensions(WFSGetFeatureOutputFormat.class);
0413:
0414: Map dupes = new HashMap();
0415: for (Iterator i = featureProducers.iterator(); i
0416: .hasNext();) {
0417: WFSGetFeatureOutputFormat format = (WFSGetFeatureOutputFormat) i
0418: .next();
0419: if (!dupes.containsKey(format
0420: .getCapabilitiesElementName())) {
0421: element(
0422: format.getCapabilitiesElementName(),
0423: null);
0424: dupes.put(format
0425: .getCapabilitiesElementName(),
0426: new Object());
0427: }
0428: }
0429: }
0430:
0431: end(resultFormat);
0432:
0433: handleDcpType(capName, HTTP_GET);
0434: handleDcpType(capName, HTTP_POST);
0435: end(capName);
0436: }
0437:
0438: /**
0439: * Encodes the wfs:Transaction element.
0440: * <p>
0441: * <pre>
0442: * <xsd:complexType name="TransactionType">
0443: * <xsd:sequence>
0444: * <xsd:element name="DCPType" type="wfs:DCPTypeType" maxOccurs="unbounded"/>
0445: * </xsd:sequence>
0446: * </xsd:complexType>
0447: * </pre>
0448: * </p>
0449: */
0450: private void handleTransaction() {
0451: String capName = "Transaction";
0452: start(capName);
0453: handleDcpType(capName, HTTP_GET);
0454: handleDcpType(capName, HTTP_POST);
0455: end(capName);
0456: }
0457:
0458: /**
0459: * Encodes the wfs:LockFeature element.
0460: * <p>
0461: * <pre>
0462: * <xsd:complexType name="LockFeatureTypeType">
0463: * <xsd:sequence>
0464: * <xsd:element name="DCPType" type="wfs:DCPTypeType" maxOccurs="unbounded"/>
0465: * </xsd:sequence>
0466: * </xsd:complexType>
0467: * </pre>
0468: * </p>
0469: */
0470: private void handleLock() {
0471: String capName = "LockFeature";
0472: start(capName);
0473: handleDcpType(capName, HTTP_GET);
0474: handleDcpType(capName, HTTP_POST);
0475: end(capName);
0476: }
0477:
0478: /**
0479: * Encodes the wfs:GetFeatureWithLock element.
0480: *
0481: * <xsd:complexType name="GetFeatureTypeType">
0482: * <xsd:sequence>
0483: * <xsd:element name="ResultFormat" type="wfs:ResultFormatType"/>
0484: * <xsd:element name="DCPType" type="wfs:DCPTypeType" maxOccurs="unbounded"/>
0485: * </xsd:sequence>
0486: * </xsd:complexType>
0487: */
0488: private void handleFeatureWithLock() {
0489: String capName = "GetFeatureWithLock";
0490: start(capName);
0491: start("ResultFormat");
0492: //TODO: output format extensions
0493: element("GML2", null);
0494: end("ResultFormat");
0495: handleDcpType(capName, HTTP_GET);
0496: handleDcpType(capName, HTTP_POST);
0497: end(capName);
0498: }
0499:
0500: /**
0501: * Encodes a <code>DCPType</code> element.
0502: * <p>
0503: * <pre>
0504: * <!-- Available Distributed Computing Platforms (DCPs) are
0505: * listed here. At present, only HTTP is defined. -->
0506: * <xsd:complexType name="DCPTypeType">
0507: * <xsd:sequence>
0508: * <xsd:element name="HTTP" type="wfs:HTTPType"/>
0509: * </xsd:sequence>
0510: * </xsd:complexType>
0511: *
0512: * </pre>
0513: * </p>
0514: * @param capabilityName the URL of the onlineresource for HTTP GET
0515: * method requests
0516: * @param httpMethod the URL of the onlineresource for HTTP POST method
0517: * requests
0518: */
0519: private void handleDcpType(String capabilityName,
0520: String httpMethod) {
0521: String proxifiedBaseUrl = RequestUtils
0522: .proxifiedBaseURL(request.getBaseUrl(), wfs
0523: .getGeoServer().getProxyBaseUrl());
0524:
0525: if (proxifiedBaseUrl.endsWith("?")) {
0526: proxifiedBaseUrl = proxifiedBaseUrl.substring(0,
0527: proxifiedBaseUrl.length() - 1);
0528: }
0529:
0530: if (HTTP_GET.equals(httpMethod)) {
0531: proxifiedBaseUrl = ResponseUtils.appendPath(
0532: proxifiedBaseUrl, "wfs?request="
0533: + capabilityName);
0534: } else if (HTTP_POST.equals(httpMethod)) {
0535: proxifiedBaseUrl = ResponseUtils.appendPath(
0536: proxifiedBaseUrl, "wfs?");
0537: }
0538:
0539: start("DCPType");
0540: start("HTTP");
0541:
0542: AttributesImpl atts = new AttributesImpl();
0543: atts.addAttribute("", "onlineResource",
0544: "onlineResource", "", proxifiedBaseUrl);
0545: element(httpMethod, null, atts);
0546:
0547: end("HTTP");
0548: end("DCPType");
0549: }
0550:
0551: /**
0552: * Encodes the wfs:FeatureTYpeList element.
0553: * <p>
0554: * <pre>
0555: * <xsd:complexType name="FeatureTypeListType">
0556: * <xsd:sequence>
0557: * <xsd:element name="Operations"
0558: * type="wfs:OperationsType" minOccurs="0"/>
0559: * <xsd:element name="FeatureType"
0560: * type="wfs:FeatureTypeType" maxOccurs="unbounded"/>
0561: * </xsd:sequence>
0562: * </xsd:complexType>
0563: * </pre>
0564: * </p>
0565: */
0566: private void handleFeatureTypes() {
0567: if (!wfs.isEnabled()) {
0568: // should we return anything if we are disabled?
0569: }
0570:
0571: start("FeatureTypeList");
0572: start("Operations");
0573:
0574: if ((wfs.getServiceLevel() | WFS.SERVICE_BASIC) != 0) {
0575: element("Query", null);
0576: }
0577:
0578: if ((wfs.getServiceLevel() | WFS.SERVICE_INSERT) != 0) {
0579: element("Insert", null);
0580: }
0581:
0582: if ((wfs.getServiceLevel() | WFS.SERVICE_UPDATE) != 0) {
0583: element("Update", null);
0584: }
0585:
0586: if ((wfs.getServiceLevel() | WFS.SERVICE_DELETE) != 0) {
0587: element("Delete", null);
0588: }
0589:
0590: if ((wfs.getServiceLevel() | WFS.SERVICE_LOCKING) != 0) {
0591: element("Lock", null);
0592: }
0593:
0594: end("Operations");
0595:
0596: List featureTypes = new ArrayList(catalog
0597: .getFeatureTypeInfos().values());
0598: Collections.sort(featureTypes,
0599: new FeatureTypeInfoTitleComparator());
0600: for (Iterator it = featureTypes.iterator(); it
0601: .hasNext();) {
0602: FeatureTypeInfo ftype = (FeatureTypeInfo) it.next();
0603:
0604: //can't handle ones that aren't enabled.
0605: //and they shouldn't be handled, as they won't function.
0606: //JD: deal with this
0607: //if (ftype.isEnabled()) {
0608: handleFeatureType(ftype);
0609:
0610: //}
0611: }
0612:
0613: end("FeatureTypeList");
0614: }
0615:
0616: /**
0617: * Default handle of a FeatureTypeInfo content that writes the
0618: * latLongBBox as well as the GlobalBasic's parameters
0619: *
0620: * <p>
0621: * <pre>
0622: * <xsd:complexType name="FeatureTypeType">
0623: * <xsd:sequence>
0624: * <xsd:element name="Name" type="xsd:QName"/>
0625: * <xsd:element ref="wfs:Title" minOccurs="0"/>
0626: * <xsd:element ref="wfs:Abstract" minOccurs="0"/>
0627: * <xsd:element ref="wfs:Keywords" minOccurs="0"/>
0628: * <xsd:element ref="wfs:SRS"/>
0629: * <xsd:element name="Operations"
0630: * type="wfs:OperationsType" minOccurs="0"/>
0631: * <xsd:element name="LatLongBoundingBox"
0632: * type="wfs:LatLongBoundingBoxType"
0633: * minOccurs="0" maxOccurs="unbounded"/>
0634: * <xsd:element name="MetadataURL"
0635: * type="wfs:MetadataURLType"
0636: * minOccurs="0" maxOccurs="unbounded"/>
0637: * </xsd:sequence>
0638: * </xsd:complexType>
0639: * </pre>
0640: * </p>
0641: * @param ftype The FeatureType configuration to report capabilities
0642: * on.
0643: *
0644: * @throws RuntimeException For any errors.
0645: */
0646: private void handleFeatureType(FeatureTypeInfo info) {
0647: Envelope bbox = null;
0648:
0649: try {
0650: bbox = info.getLatLongBoundingBox();
0651: } catch (IOException e) {
0652: String msg = "Could not calculate bbox for: "
0653: + info.getName();
0654: LOGGER.log(Level.SEVERE, msg, e);
0655:
0656: return;
0657: }
0658:
0659: start("FeatureType");
0660: element("Name", info.getName());
0661: element("Title", info.getTitle());
0662: element("Abstract", info.getAbstract());
0663: handleKeywords(info.getKeywords());
0664:
0665: /**
0666: * @task REVISIT: should getSRS() return the full URL?
0667: */
0668: element("SRS", "EPSG:" + info.getSRS());
0669:
0670: String minx = String.valueOf(bbox.getMinX());
0671: String miny = String.valueOf(bbox.getMinY());
0672: String maxx = String.valueOf(bbox.getMaxX());
0673: String maxy = String.valueOf(bbox.getMaxY());
0674:
0675: AttributesImpl bboxAtts = new AttributesImpl();
0676: bboxAtts.addAttribute("", "minx", "minx", "", minx);
0677: bboxAtts.addAttribute("", "miny", "miny", "", miny);
0678: bboxAtts.addAttribute("", "maxx", "maxx", "", maxx);
0679: bboxAtts.addAttribute("", "maxy", "maxy", "", maxy);
0680:
0681: element("LatLongBoundingBox", null, bboxAtts);
0682:
0683: end("FeatureType");
0684: }
0685:
0686: /**
0687: * Encodes the ogc:Filter_Capabilities element.
0688: * <p>
0689: * <pre>
0690: * <xsd:element name="Filter_Capabilities">
0691: * <xsd:complexType>
0692: * <xsd:sequence>
0693: * <xsd:element name="Spatial_Capabilities" type="ogc:Spatial_CapabilitiesType"/>
0694: * <xsd:element name="Scalar_Capabilities" type="ogc:Scalar_CapabilitiesType"/>
0695: * </xsd:sequence>
0696: * </xsd:complexType>
0697: *</xsd:element>
0698: * </pre>
0699: * </p>
0700: */
0701: private void handleFilterCapabilities() {
0702: String ogc = "ogc:";
0703:
0704: //REVISIT: for now I"m just prepending ogc onto the name element.
0705: //Is the proper way to only do that for the qname? I guess it
0706: //would only really matter if we're going to be producing capabilities
0707: //documents that aren't qualified, and I don't see any reason to
0708: //do that.
0709: start(ogc + "Filter_Capabilities");
0710: start(ogc + "Spatial_Capabilities");
0711: start(ogc + "Spatial_Operators");
0712: element(ogc + "Disjoint", null);
0713: element(ogc + "Equals", null);
0714: element(ogc + "DWithin", null);
0715: element(ogc + "Beyond", null);
0716: element(ogc + "Intersect", null);
0717: element(ogc + "Touches", null);
0718: element(ogc + "Crosses", null);
0719: element(ogc + "Within", null);
0720: element(ogc + "Contains", null);
0721: element(ogc + "Overlaps", null);
0722: element(ogc + "BBOX", null);
0723: end(ogc + "Spatial_Operators");
0724: end(ogc + "Spatial_Capabilities");
0725:
0726: start(ogc + "Scalar_Capabilities");
0727: element(ogc + "Logical_Operators", null);
0728: start(ogc + "Comparison_Operators");
0729: element(ogc + "Simple_Comparisons", null);
0730: element(ogc + "Between", null);
0731: element(ogc + "Like", null);
0732: element(ogc + "NullCheck", null);
0733: end(ogc + "Comparison_Operators");
0734: start(ogc + "Arithmetic_Operators");
0735: element(ogc + "Simple_Arithmetic", null);
0736:
0737: handleFunctions(ogc); //djb: list functions
0738:
0739: end(ogc + "Arithmetic_Operators");
0740: end(ogc + "Scalar_Capabilities");
0741: end(ogc + "Filter_Capabilities");
0742: }
0743:
0744: /**
0745: * <xsd:complexType name="FunctionsType">
0746: * <xsd:sequence>
0747: * <xsd:element name="Function_Names" type="ogc:Function_NamesType"/>
0748: * </xsd:sequence>
0749: * </xsd:complexType>
0750: *
0751: */
0752: private void handleFunctions(String prefix) {
0753: start(prefix + "Functions");
0754: start(prefix + "Function_Names");
0755:
0756: Iterator it = FactoryRegistry
0757: .lookupProviders(Function.class);
0758:
0759: //Sort them up for easier visual inspection
0760: SortedSet sortedFunctions = new TreeSet(
0761: new Comparator() {
0762: public int compare(Object o1, Object o2) {
0763: String n1 = ((Function) o1).getName();
0764: String n2 = ((Function) o2).getName();
0765:
0766: return n1.toLowerCase().compareTo(
0767: n2.toLowerCase());
0768: }
0769: });
0770:
0771: while (it.hasNext()) {
0772: sortedFunctions.add(it.next());
0773: }
0774:
0775: //write them now that functions are sorted by name
0776: it = sortedFunctions.iterator();
0777:
0778: while (it.hasNext()) {
0779: Function fe = (Function) it.next();
0780:
0781: //TODO: as of now the geoapi Function interface
0782: // does not allow use to report back properly the number of
0783: // parameters, so we check for instances of FunctionExpression
0784: // for now
0785: if (fe instanceof FunctionExpression) {
0786: String funName = fe.getName();
0787: int funNArgs = ((FunctionExpression) fe)
0788: .getArgCount();
0789:
0790: AttributesImpl atts = new AttributesImpl();
0791: atts.addAttribute("", "nArgs", "nArgs", "",
0792: funNArgs + "");
0793:
0794: element(prefix + "Function_Name", funName, atts);
0795: }
0796: }
0797:
0798: end(prefix + "Function_Names");
0799: end(prefix + "Functions");
0800: }
0801: }
0802: }
0803:
0804: /**
0805: * Transformer for wfs 1.1 capabilities document.
0806: *
0807: * @author Justin Deoliveira, The Open Planning Project
0808: *
0809: */
0810: public static class WFS1_1 extends CapabilitiesTransformer {
0811: public WFS1_1(WFS wfs, Data catalog) {
0812: super (wfs, catalog);
0813: }
0814:
0815: public Translator createTranslator(ContentHandler handler) {
0816: return new CapabilitiesTranslator1_1(handler);
0817: }
0818:
0819: class CapabilitiesTranslator1_1 extends TranslatorSupport {
0820: GetCapabilitiesType request;
0821:
0822: public CapabilitiesTranslator1_1(ContentHandler handler) {
0823: super (handler, null, null);
0824: }
0825:
0826: public void encode(Object object)
0827: throws IllegalArgumentException {
0828: request = (GetCapabilitiesType) object;
0829: String proxifiedBaseUrl = RequestUtils
0830: .proxifiedBaseURL(request.getBaseUrl(), wfs
0831: .getGeoServer().getProxyBaseUrl());
0832:
0833: verifyUpdateSequence(request);
0834:
0835: AttributesImpl attributes = attributes(new String[] {
0836: "version",
0837: "1.1.0",
0838: "xmlns:xsi",
0839: XSI_URI,
0840: "xmlns",
0841: WFS_URI,
0842: "xmlns:wfs",
0843: WFS_URI,
0844: "xmlns:ows",
0845: OWS.NAMESPACE,
0846: "xmlns:gml",
0847: GML.NAMESPACE,
0848: "xmlns:ogc",
0849: OGC.NAMESPACE,
0850: "xmlns:xlink",
0851: XLINK.NAMESPACE,
0852: "xsi:schemaLocation",
0853:
0854: org.geoserver.wfs.xml.v1_1_0.WFS.NAMESPACE
0855: + " "
0856: + ResponseUtils.appendPath(
0857: proxifiedBaseUrl,
0858: "schemas/wfs/1.1.0/wfs.xsd") });
0859:
0860: NameSpaceInfo[] namespaces = catalog.getNameSpaces();
0861:
0862: for (int i = 0; i < namespaces.length; i++) {
0863: NameSpaceInfo namespace = namespaces[i];
0864:
0865: String prefix = namespace.getPrefix();
0866: String uri = namespace.getURI();
0867:
0868: //ignore xml prefix
0869: if ("xml".equals(prefix)) {
0870: continue;
0871: }
0872:
0873: String prefixDef = "xmlns:" + prefix;
0874:
0875: attributes.addAttribute("", prefixDef, prefixDef,
0876: "", uri);
0877: }
0878:
0879: attributes.addAttribute("", "updateSequence",
0880: "updateSequence", "", wfs.getGeoServer()
0881: .getUpdateSequence()
0882: + "");
0883:
0884: start("wfs:WFS_Capabilities", attributes);
0885:
0886: serviceIdentification();
0887: serviceProvider();
0888: operationsMetadata();
0889: featureTypeList();
0890: //supportsGMLObjectTypeList();
0891: filterCapabilities();
0892:
0893: end("wfs:WFS_Capabilities");
0894: }
0895:
0896: /**
0897: * Encodes the ows:ServiceIdentification element.
0898: * <p>
0899: * <pre>
0900: * <complexType>
0901: * <complexContent>
0902: * <extension base="ows:DescriptionType">
0903: * <sequence>
0904: * <element name="ServiceType" type="ows:CodeType">
0905: * <annotation>
0906: * <documentation>A service type name from a registry of services.
0907: * For example, the values of the codeSpace URI and name and code string may
0908: * be "OGC" and "catalogue." This type name is normally used for
0909: * machine-to-machine communication.</documentation>
0910: * </annotation>
0911: * </element>
0912: * <element name="ServiceTypeVersion" type="ows:VersionType" maxOccurs="unbounded">
0913: * <annotation>
0914: * <documentation>Unordered list of one or more versions of this service
0915: * type implemented by this server. This information is not adequate for
0916: * version negotiation, and shall not be used for that purpose. </documentation>
0917: * </annotation>
0918: * </element>
0919: * <element ref="ows:Fees" minOccurs="0">
0920: * <annotation>
0921: * <documentation>If this element is omitted, no meaning is implied. </documentation>
0922: * </annotation>
0923: * </element>
0924: * <element ref="ows:AccessConstraints" minOccurs="0" maxOccurs="unbounded">
0925: * <annotation>
0926: * <documentation>Unordered list of access constraints applied to assure
0927: * the protection of privacy or intellectual property, and any other
0928: * restrictions on retrieving or using data from or otherwise using this
0929: * server. The reserved value NONE (case insensitive) shall be used to
0930: * mean no access constraints are imposed. If this element is omitted,
0931: * no meaning is implied. </documentation>
0932: * </annotation>
0933: * </element>
0934: * </sequence>
0935: * </extension>
0936: * </complexContent>
0937: *</complexType>
0938: * </pre>
0939: * </p>
0940: *
0941: */
0942: void serviceIdentification() {
0943: start("ows:ServiceIdentification");
0944:
0945: element("ows:Title", wfs.getTitle());
0946: element("ows:Abstract", wfs.getAbstract());
0947:
0948: keywords(wfs.getKeywords());
0949:
0950: element("ows:ServiceType", "WFS");
0951: element("ows:ServiceTypeVersion", "1.1.0");
0952:
0953: element("ows:Fees", wfs.getFees());
0954: element("ows:AccessConstraints", wfs
0955: .getAccessConstraints());
0956:
0957: end("ows:ServiceIdentification");
0958: }
0959:
0960: /**
0961: * Encodes the ows:ServiceProvider element.
0962: * <p>
0963: * <pre>
0964: * <complexType>
0965: * <sequence>
0966: * <element name="ProviderName" type="string">
0967: * <annotation>
0968: * <documentation>A unique identifier for the service provider organization. </documentation>
0969: * </annotation>
0970: * </element>
0971: * <element name="ProviderSite" type="ows:OnlineResourceType" minOccurs="0">
0972: * <annotation>
0973: * <documentation>Reference to the most relevant web site of the service provider. </documentation>
0974: * </annotation>
0975: * </element>
0976: * <element name="ServiceContact" type="ows:ResponsiblePartySubsetType">
0977: * <annotation>
0978: * <documentation>Information for contacting the service provider. The
0979: * OnlineResource element within this ServiceContact element should not be used
0980: * to reference a web site of the service provider. </documentation>
0981: * </annotation>
0982: * </element>
0983: * </sequence>
0984: *</complexType>
0985: * </pre>
0986: * </p>
0987: *
0988: */
0989: void serviceProvider() {
0990: start("ows:ServiceProvider");
0991:
0992: element("ows:ProviderName", null);
0993: element("ows:ProviderSite", null);
0994: element("ows:ServiceContact", null);
0995:
0996: end("ows:ServiceProvider");
0997: }
0998:
0999: /**
1000: * Encodes the ows:OperationsMetadata element.
1001: * <p>
1002: * <pre>
1003: * <complexType>
1004: * <sequence>
1005: * <element ref="ows:Operation" minOccurs="2" maxOccurs="unbounded">
1006: * <annotation>
1007: * <documentation>Metadata for unordered list of all the (requests for) operations
1008: * that this server interface implements. The list of required and optional
1009: * operations implemented shall be specified in the Implementation Specification
1010: * for this service. </documentation>
1011: * </annotation>
1012: * </element>
1013: * <element name="Parameter" type="ows:DomainType" minOccurs="0" maxOccurs="unbounded">
1014: * <annotation>
1015: * <documentation>Optional unordered list of parameter valid domains that each
1016: * apply to one or more operations which this server interface implements. The
1017: * list of required and optional parameter domain limitations shall be specified
1018: * in the Implementation Specification for this service. </documentation>
1019: * </annotation>
1020: * </element>
1021: * <element name="Constraint" type="ows:DomainType" minOccurs="0" maxOccurs="unbounded">
1022: * <annotation>
1023: * <documentation>Optional unordered list of valid domain constraints on
1024: * non-parameter quantities that each apply to this server. The list of
1025: * required and optional constraints shall be specified in the Implementation
1026: * Specification for this service. </documentation>
1027: * </annotation>
1028: * </element>
1029: * <element ref="ows:ExtendedCapabilities" minOccurs="0"/>
1030: * </sequence>
1031: *</complexType>
1032: * </pre>
1033: * </p>
1034: *
1035: */
1036: void operationsMetadata() {
1037: start("ows:OperationsMetadata");
1038:
1039: getCapabilities();
1040: describeFeatureType();
1041: getFeature();
1042:
1043: if (wfs.getServiceLevel() == WFS.COMPLETE) {
1044: lockFeature();
1045: getFeatureWithLock();
1046: }
1047:
1048: if (wfs.getServiceLevel() >= WFS.TRANSACTIONAL) {
1049: transaction();
1050: }
1051:
1052: end("ows:OperationsMetadata");
1053: }
1054:
1055: /**
1056: * Encodes the GetCapabilities ows:Operation element.
1057: *
1058: */
1059: void getCapabilities() {
1060: Map.Entry[] parameters = new Map.Entry[] {
1061: parameter("AcceptVersions", new String[] {
1062: "1.0.0", "1.1.0" }),
1063: parameter("AcceptFormats",
1064: new String[] { "text/xml" })
1065: // parameter(
1066: // "Sections",
1067: // new String[]{
1068: // "ServiceIdentification", "ServiceProvider", "OperationsMetadata",
1069: // "FeatureTypeList", "ServesGMLObjectTypeList", "SupportsGMLObjectTypeList",
1070: // "Filter_Capabilities"
1071: // }
1072: // )
1073: };
1074: operation("GetCapabilities", parameters, true, true);
1075: }
1076:
1077: /**
1078: * Encodes the DescribeFeatureType ows:Operation element.
1079: */
1080: void describeFeatureType() {
1081: //TODO: process extension point
1082: Map.Entry[] parameters = new Map.Entry[] { parameter(
1083: "outputFormat",
1084: new String[] { "text/gml; subtype=gml/3.1.1" }) };
1085:
1086: operation("DescribeFeatureType", parameters, true, true);
1087: }
1088:
1089: /**
1090: * Encodes the GetFeature ows:Operation element.
1091: */
1092: void getFeature() {
1093: Map.Entry[] parameters = new Map.Entry[] {
1094: parameter("resultType", new String[] {
1095: "results", "hits" }),
1096: parameter(
1097: "outputFormat",
1098: new String[] { "text/gml; subtype=gml/3.1.1" }) };
1099:
1100: operation("GetFeature", parameters, true, true);
1101: }
1102:
1103: /**
1104: * Encodes the GetFeatureWithLock ows:Operation element.
1105: */
1106: void getFeatureWithLock() {
1107: Map.Entry[] parameters = new Map.Entry[] {
1108: parameter("resultType", new String[] {
1109: "results", "hits" }),
1110: parameter(
1111: "outputFormat",
1112: new String[] { "text/gml; subtype=gml/3.1.1" }) };
1113:
1114: operation("GetFeatureWithLock", parameters, true, true);
1115: }
1116:
1117: /**
1118: * Encodes the LockFeature ows:Operation element.
1119: */
1120: void lockFeature() {
1121: Map.Entry[] parameters = new Map.Entry[] { parameter(
1122: "releaseAction", new String[] { "ALL", "SOME" }) };
1123:
1124: operation("LockFeature", parameters, true, true);
1125: }
1126:
1127: /**
1128: * Encodes the Transaction ows:Operation element.
1129: */
1130: void transaction() {
1131: Map.Entry[] parameters = new Map.Entry[] {
1132: parameter(
1133: "inputFormat",
1134: new String[] { "text/gml; subtype=gml/3.1.1" }),
1135: parameter("idgen", new String[] {
1136: "GenerateNew", "UseExisting",
1137: "ReplaceDuplicate" }),
1138: parameter("releaseAction", new String[] {
1139: "ALL", "SOME" }) };
1140:
1141: operation("Transaction", parameters, true, true);
1142: }
1143:
1144: /**
1145: * Encdoes the wfs:FeatureTypeList element.
1146: *<p>
1147: *<pre>
1148: * <xsd:complexType name="FeatureTypeListType">
1149: * <xsd:annotation>
1150: * <xsd:documentation>
1151: * A list of feature types available from this server.
1152: * </xsd:documentation>
1153: * </xsd:annotation>
1154: * <xsd:sequence>
1155: * <xsd:element name="Operations"
1156: * type="wfs:OperationsType"
1157: * minOccurs="0"/>
1158: * <xsd:element name="FeatureType"
1159: * type="wfs:FeatureTypeType"
1160: * maxOccurs="unbounded"/>
1161: * </xsd:sequence>
1162: * </xsd:complexType>
1163: *</pre>
1164: *</p>
1165: */
1166: void featureTypeList() {
1167: start("FeatureTypeList");
1168:
1169: start("Operations");
1170:
1171: if ((wfs.getServiceLevel() | WFS.SERVICE_BASIC) != 0) {
1172: element("Operation", "Query");
1173: }
1174:
1175: if ((wfs.getServiceLevel() | WFS.SERVICE_INSERT) != 0) {
1176: element("Operation", "Insert");
1177: }
1178:
1179: if ((wfs.getServiceLevel() | WFS.SERVICE_UPDATE) != 0) {
1180: element("Operation", "Update");
1181: }
1182:
1183: if ((wfs.getServiceLevel() | WFS.SERVICE_DELETE) != 0) {
1184: element("Operation", "Delete");
1185: }
1186:
1187: if ((wfs.getServiceLevel() | WFS.SERVICE_LOCKING) != 0) {
1188: element("Operation", "Lock");
1189: }
1190:
1191: end("Operations");
1192:
1193: List featureTypes = new ArrayList(catalog
1194: .getFeatureTypeInfos().values());
1195: Collections.sort(featureTypes,
1196: new FeatureTypeInfoTitleComparator());
1197: for (Iterator i = featureTypes.iterator(); i.hasNext();) {
1198: FeatureTypeInfo featureType = (FeatureTypeInfo) i
1199: .next();
1200: featureType(featureType);
1201: }
1202:
1203: end("FeatureTypeList");
1204: }
1205:
1206: /**
1207: * Encodes the wfs:FeatureType element.
1208: * <p>
1209: * <pre>
1210: * <xsd:complexType name="FeatureTypeType">
1211: * <xsd:annotation>
1212: * <xsd:documentation>
1213: * An element of this type that describes a feature in an application
1214: * namespace shall have an xml xmlns specifier, e.g.
1215: * xmlns:bo="http://www.BlueOx.org/BlueOx"
1216: * </xsd:documentation>
1217: * </xsd:annotation>
1218: * <xsd:sequence>
1219: * <xsd:element name="Name" type="xsd:QName">
1220: * <xsd:annotation>
1221: * <xsd:documentation>
1222: * Name of this feature type, including any namespace prefix
1223: * </xsd:documentation>
1224: * </xsd:annotation>
1225: * </xsd:element>
1226: * <xsd:element name="Title" type="xsd:string">
1227: * <xsd:annotation>
1228: * <xsd:documentation>
1229: * Title of this feature type, normally used for display
1230: * to a human.
1231: * </xsd:documentation>
1232: * </xsd:annotation>
1233: * </xsd:element>
1234: * <xsd:element name="Abstract" type="xsd:string" minOccurs="0">* <xsd:annotation>
1235: * <xsd:documentation>
1236: * Brief narrative description of this feature type, normally* used for display to a human.
1237: * </xsd:documentation>
1238: * </xsd:annotation>
1239: * </xsd:element>
1240: * <xsd:element ref="ows:Keywords" minOccurs="0" maxOccurs="unbounded"/>
1241: * <xsd:choice>
1242: * <xsd:sequence>
1243: * <xsd:element name="DefaultSRS"
1244: * type="xsd:anyURI">
1245: * <xsd:annotation>
1246: * <xsd:documentation>
1247: * The DefaultSRS element indicated which spatial
1248: * reference system shall be used by a WFS to
1249: * express the state of a spatial feature if not
1250: * otherwise explicitly identified within a query
1251: * or transaction request. The SRS may be indicated
1252: * using either the EPSG form (EPSG:posc code) or
1253: * the URL form defined in subclause 4.3.2 of
1254: * refernce[2].
1255: * </xsd:documentation>
1256: * </xsd:annotation>
1257: * </xsd:element>
1258: * <xsd:element name="OtherSRS"
1259: * type="xsd:anyURI"
1260: * minOccurs="0" maxOccurs="unbounded">
1261: * <xsd:annotation>
1262: * <xsd:documentation>
1263: * The OtherSRS element is used to indicate other
1264: * supported SRSs within query and transaction
1265: * operations. A supported SRS means that the
1266: * WFS supports the transformation of spatial
1267: * properties between the OtherSRS and the internal
1268: * storage SRS. The effects of such transformations
1269: * must be considered when determining and declaring
1270: * the guaranteed data accuracy.
1271: * </xsd:documentation>
1272: * </xsd:annotation>
1273: * </xsd:element>
1274: * </xsd:sequence>
1275: * <xsd:element name="NoSRS">
1276: * <xsd:complexType/>
1277: * </xsd:element>
1278: * </xsd:choice>
1279: * <xsd:element name="Operations"
1280: * type="wfs:OperationsType"
1281: * minOccurs="0"/>
1282: * <xsd:element name="OutputFormats"
1283: * type="wfs:OutputFormatListType"
1284: * minOccurs="0"/>
1285: * <xsd:element ref="ows:WGS84BoundingBox"
1286: * minOccurs="1" maxOccurs="unbounded"/>
1287: * <xsd:element name="MetadataURL"
1288: * type="wfs:MetadataURLType"
1289: * minOccurs="0" maxOccurs="unbounded"/>
1290: * </xsd:sequence>
1291: * </xsd:complexType>
1292: * </pre>
1293: * </p>
1294: * @param featureType
1295: */
1296: void featureType(FeatureTypeInfo featureType) {
1297: String prefix = featureType.getNameSpace().getPrefix();
1298: String uri = featureType.getNameSpace().getURI();
1299:
1300: start("FeatureType", attributes(new String[] {
1301: "xmlns:" + prefix, uri }));
1302:
1303: element("Name", featureType.getName());
1304: element("Title", featureType.getTitle());
1305: element("Abstract", featureType.getAbstract());
1306: keywords(featureType.getKeywords());
1307:
1308: //default srs
1309: element("DefaultSRS", "urn:x-ogc:def:crs:EPSG:6.11.2:"
1310: + featureType.getSRS());
1311:
1312: //TODO: other srs's
1313: start("OutputFormats");
1314:
1315: Collection featureProducers = GeoServerExtensions
1316: .extensions(WFSGetFeatureOutputFormat.class);
1317: TreeSet displayed = new TreeSet();
1318:
1319: for (Iterator i = featureProducers.iterator(); i
1320: .hasNext();) {
1321: WFSGetFeatureOutputFormat format = (WFSGetFeatureOutputFormat) i
1322: .next();
1323: for (Iterator f = format.getOutputFormats()
1324: .iterator(); f.hasNext();) {
1325: String formatName = f.next().toString();
1326: if (!displayed.contains(formatName)) {
1327: element("Format", formatName);
1328: displayed.add(formatName);
1329: }
1330: }
1331: }
1332:
1333: end("OutputFormats");
1334:
1335: Envelope bbox = null;
1336:
1337: try {
1338: bbox = featureType.getLatLongBoundingBox();
1339: } catch (IOException e) {
1340: throw new RuntimeException(e);
1341: }
1342:
1343: start("ows:WGS84BoundingBox");
1344:
1345: element("ows:LowerCorner", bbox.getMinX() + " "
1346: + bbox.getMinY());
1347: element("ows:UpperCorner", bbox.getMaxX() + " "
1348: + bbox.getMaxY());
1349:
1350: end("ows:WGS84BoundingBox");
1351:
1352: end("FeatureType");
1353: }
1354:
1355: /**
1356: * Encodes the wfs:SupportsGMLObjectTypeList element.
1357: * <p>
1358: * <pre>
1359: *<xsd:complexType name="GMLObjectTypeListType">
1360: * <xsd:sequence>
1361: * <xsd:element name="GMLObjectType" type="wfs:GMLObjectTypeType"
1362: * maxOccurs="unbounded">
1363: * <xsd:annotation>
1364: * <xsd:documentation>
1365: * Name of this GML object type, including any namespace prefix
1366: * </xsd:documentation>
1367: * </xsd:annotation>
1368: * </xsd:element>
1369: * </xsd:sequence>
1370: * </xsd:complexType>
1371: * </pre>
1372: * </p>
1373: */
1374: void supportsGMLObjectTypeList() {
1375: element("SupportsGMLObjectTypeList", null);
1376: }
1377:
1378: /**
1379: * Encodes the ogc:Filter_Capabilities element.
1380: * <p>
1381: * <pre>
1382: * *<xsd:element name="Filter_Capabilities">
1383: * <xsd:complexType>
1384: * <xsd:sequence>
1385: * <xsd:element name="Spatial_Capabilities"
1386: * type="ogc:Spatial_CapabilitiesType"/>
1387: * <xsd:element name="Scalar_Capabilities"
1388: * type="ogc:Scalar_CapabilitiesType"/>
1389: * <xsd:element name="Id_Capabilities"
1390: * type="ogc:Id_CapabilitiesType"/>
1391: * </xsd:sequence>
1392: * </xsd:complexType>
1393: * </xsd:element>
1394: * </pre>
1395: * </p>
1396: *
1397: */
1398: void filterCapabilities() {
1399: start("ogc:Filter_Capabilities");
1400:
1401: start("ogc:Spatial_Capabilities");
1402:
1403: start("ogc:GeometryOperands");
1404: element("ogc:GeometryOperand", "gml:Envelope");
1405: element("ogc:GeometryOperand", "gml:Point");
1406: element("ogc:GeometryOperand", "gml:LineString");
1407: element("ogc:GeometryOperand", "gml:Polygon");
1408: end("ogc:GeometryOperands");
1409:
1410: start("ogc:SpatialOperators");
1411: element("ogc:SpatialOperator", null,
1412: attributes(new String[] { "name", "Disjoint" }));
1413: element("ogc:SpatialOperator", null,
1414: attributes(new String[] { "name", "Equals" }));
1415: element("ogc:SpatialOperator", null,
1416: attributes(new String[] { "name", "DWithin" }));
1417: element("ogc:SpatialOperator", null,
1418: attributes(new String[] { "name", "Beyond" }));
1419: element(
1420: "ogc:SpatialOperator",
1421: null,
1422: attributes(new String[] { "name", "Intersects" }));
1423: element("ogc:SpatialOperator", null,
1424: attributes(new String[] { "name", "Touches" }));
1425: element("ogc:SpatialOperator", null,
1426: attributes(new String[] { "name", "Crosses" }));
1427: element("ogc:SpatialOperator", null,
1428: attributes(new String[] { "name", "Contains" }));
1429: element("ogc:SpatialOperator", null,
1430: attributes(new String[] { "name", "Overlaps" }));
1431: element("ogc:SpatialOperator", null,
1432: attributes(new String[] { "name", "BBOX" }));
1433: end("ogc:SpatialOperators");
1434:
1435: end("ogc:Spatial_Capabilities");
1436:
1437: start("ogc:Scalar_Capabilities");
1438:
1439: element("ogc:LogicalOperators", null);
1440:
1441: start("ogc:ComparisonOperators");
1442: element("ogc:ComparisonOperator", "LessThan");
1443: element("ogc:ComparisonOperator", "GreaterThan");
1444: element("ogc:ComparisonOperator", "LessThanEqualTo");
1445: element("ogc:ComparisonOperator", "GreaterThanEqualTo");
1446: element("ogc:ComparisonOperator", "EqualTo");
1447: element("ogc:ComparisonOperator", "NotEqualTo");
1448: element("ogc:ComparisonOperator", "Like");
1449: element("ogc:ComparisonOperator", "Between");
1450: element("ogc:ComparisonOperator", "NullCheck");
1451: end("ogc:ComparisonOperators");
1452:
1453: start("ogc:ArithmeticOperators");
1454: element("ogc:SimpleArithmetic", null);
1455:
1456: functions();
1457:
1458: end("ogc:ArithmeticOperators");
1459:
1460: end("ogc:Scalar_Capabilities");
1461:
1462: start("ogc:Id_Capabilities");
1463: element("ogc:FID", null);
1464: element("ogc:EID", null);
1465: end("ogc:Id_Capabilities");
1466:
1467: end("ogc:Filter_Capabilities");
1468: }
1469:
1470: void functions() {
1471: start("ogc:Functions");
1472:
1473: Iterator itr = FactoryRegistry
1474: .lookupProviders(Function.class);
1475:
1476: if (itr.hasNext()) {
1477: start("ogc:FunctionNames");
1478:
1479: SortedSet sortedFunctions = new TreeSet(
1480: new Comparator() {
1481: public int compare(Object o1, Object o2) {
1482: String n1 = ((Function) o1)
1483: .getName();
1484: String n2 = ((Function) o2)
1485: .getName();
1486:
1487: return n1.toLowerCase().compareTo(
1488: n2.toLowerCase());
1489: }
1490: });
1491:
1492: while (itr.hasNext()) {
1493: sortedFunctions.add(itr.next());
1494: }
1495:
1496: //write them now that functions are sorted by name
1497: itr = sortedFunctions.iterator();
1498:
1499: while (itr.hasNext()) {
1500: Function fe = (Function) itr.next();
1501: String name = fe.getName();
1502: int nargs = fe.getParameters().size();
1503:
1504: element("ogc:FunctionName", name,
1505: attributes(new String[] { "nArgs",
1506: "" + nargs }));
1507: }
1508:
1509: end("ogc:FunctionNames");
1510: }
1511:
1512: end("ogc:Functions");
1513: }
1514:
1515: /**
1516: * Encodes the ows:Keywords element.
1517: * <p>
1518: * <pre>
1519: * <complexType name="KeywordsType">
1520: * <annotation>
1521: * <documentation>Unordered list of one or more commonly used or formalised word(s) or phrase(s) used to describe the subject. When needed, the optional "type" can name the type of the associated list of keywords that shall all have the same type. Also when needed, the codeSpace attribute of that "type" can reference the type name authority and/or thesaurus. </documentation>
1522: * <documentation>For OWS use, the optional thesaurusName element was omitted as being complex information that could be referenced by the codeSpace attribute of the Type element. </documentation>
1523: * </annotation>
1524: * <sequence>
1525: * <element name="Keyword" type="string" maxOccurs="unbounded"/>
1526: * <element name="Type" type="ows:CodeType" minOccurs="0"/>
1527: * </sequence>
1528: * </complexType>
1529: * </pre>
1530: * </p>
1531: * @param keywords
1532: */
1533: void keywords(String[] keywords) {
1534: if ((keywords == null) || (keywords.length == 0)) {
1535: return;
1536: }
1537:
1538: start("ows:Keywords");
1539:
1540: for (int i = 0; i < keywords.length; i++) {
1541: element("ows:Keyword", keywords[i]);
1542: }
1543:
1544: end("ows:Keywords");
1545: }
1546:
1547: void keywords(List keywords) {
1548: keywords((String[]) keywords
1549: .toArray(new String[keywords.size()]));
1550: }
1551:
1552: /**
1553: * Encodes the ows:Operation element.
1554: * <p>
1555: * <pre>
1556: * <complexType>
1557: * <sequence>
1558: * <element ref="ows:DCP" maxOccurs="unbounded">
1559: * <annotation>
1560: * <documentation>Unordered list of Distributed Computing Platforms (DCPs) supported for this operation. At present, only the HTTP DCP is defined, so this element will appear only once. </documentation>
1561: * </annotation>
1562: * </element>
1563: * <element name="Parameter" type="ows:DomainType" minOccurs="0" maxOccurs="unbounded">
1564: * <annotation>
1565: * <documentation>Optional unordered list of parameter domains that each apply to this operation which this server implements. If one of these Parameter elements has the same "name" attribute as a Parameter element in the OperationsMetadata element, this Parameter element shall override the other one for this operation. The list of required and optional parameter domain limitations for this operation shall be specified in the Implementation Specification for this service. </documentation>
1566: * </annotation>
1567: * </element>
1568: * <element name="Constraint" type="ows:DomainType" minOccurs="0" maxOccurs="unbounded">
1569: * <annotation>
1570: * <documentation>Optional unordered list of valid domain constraints on non-parameter quantities that each apply to this operation. If one of these Constraint elements has the same "name" attribute as a Constraint element in the OperationsMetadata element, this Constraint element shall override the other one for this operation. The list of required and optional constraints for this operation shall be specified in the Implementation Specification for this service. </documentation>
1571: * </annotation>
1572: * </element>
1573: * <element ref="ows:Metadata" minOccurs="0" maxOccurs="unbounded">
1574: * <annotation>
1575: * <documentation>Optional unordered list of additional metadata about this operation and its' implementation. A list of required and optional metadata elements for this operation should be specified in the Implementation Specification for this service. (Informative: This metadata might specify the operation request parameters or provide the XML Schemas for the operation request.) </documentation>
1576: * </annotation>
1577: * </element>
1578: * </sequence>
1579: * <attribute name="name" type="string" use="required">
1580: * <annotation>
1581: * <documentation>Name or identifier of this operation (request) (for example, GetCapabilities). The list of required and optional operations implemented shall be specified in the Implementation Specification for this service. </documentation>
1582: * </annotation>
1583: * </attribute>
1584: * </complexType>
1585: * </pre>
1586: * </p>
1587: *
1588: * @param name
1589: * @param parameters
1590: * @param get
1591: * @param post
1592: */
1593: void operation(String name, Map.Entry[] parameters,
1594: boolean get, boolean post) {
1595: start("ows:Operation", attributes(new String[] {
1596: "name", name }));
1597:
1598: //dcp
1599: start("ows:DCP");
1600: start("ows:HTTP");
1601:
1602: String proxifiedBaseUrl = RequestUtils
1603: .proxifiedBaseURL(request.getBaseUrl(), wfs
1604: .getGeoServer().getProxyBaseUrl());
1605:
1606: if (proxifiedBaseUrl.endsWith("?")) {
1607: proxifiedBaseUrl = proxifiedBaseUrl.substring(0,
1608: proxifiedBaseUrl.length() - 1);
1609: }
1610:
1611: if (proxifiedBaseUrl.indexOf('?') != -1) {
1612: proxifiedBaseUrl = proxifiedBaseUrl.substring(0,
1613: proxifiedBaseUrl.indexOf('?'));
1614: }
1615:
1616: if (get) {
1617: element("ows:Get", null, attributes(new String[] {
1618: "xlink:href",
1619: ResponseUtils.appendPath(proxifiedBaseUrl,
1620: "wfs?") }));
1621: }
1622:
1623: if (post) {
1624: element("ows:Post", null, attributes(new String[] {
1625: "xlink:href",
1626: ResponseUtils.appendPath(proxifiedBaseUrl,
1627: "wfs?") }));
1628: }
1629:
1630: end("ows:HTTP");
1631: end("ows:DCP");
1632:
1633: //parameters
1634: for (int i = 0; i < parameters.length; i++) {
1635: String pname = (String) parameters[i].getKey();
1636: String[] pvalues = (String[]) parameters[i]
1637: .getValue();
1638:
1639: start("ows:Parameter", attributes(new String[] {
1640: "name", pname }));
1641:
1642: for (int j = 0; j < pvalues.length; j++) {
1643: element("ows:Value", pvalues[j]);
1644: }
1645:
1646: end("ows:Parameter");
1647: }
1648:
1649: end("ows:Operation");
1650: }
1651:
1652: AttributesImpl attributes(String[] nameValues) {
1653: AttributesImpl atts = new AttributesImpl();
1654:
1655: for (int i = 0; i < nameValues.length; i += 2) {
1656: String name = nameValues[i];
1657: String valu = nameValues[i + 1];
1658:
1659: atts.addAttribute(null, null, name, null, valu);
1660: }
1661:
1662: return atts;
1663: }
1664:
1665: Map.Entry parameter(final String name, final String[] values) {
1666: return new Map.Entry() {
1667: public Object getKey() {
1668: return name;
1669: }
1670:
1671: public Object getValue() {
1672: return values;
1673: }
1674:
1675: public Object setValue(Object value) {
1676: return null;
1677: }
1678: };
1679: }
1680: }
1681: }
1682: }
|