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.vfny.geoserver.wms.responses.helpers;
0006:
0007: import java.io.IOException;
0008: import java.util.ArrayList;
0009: import java.util.Arrays;
0010: import java.util.Collection;
0011: import java.util.Iterator;
0012: import java.util.List;
0013: import java.util.Map;
0014: import java.util.Set;
0015: import java.util.logging.Level;
0016: import java.util.logging.Logger;
0017:
0018: import javax.xml.transform.OutputKeys;
0019: import javax.xml.transform.Transformer;
0020: import javax.xml.transform.TransformerException;
0021:
0022: import org.apache.xalan.transformer.TransformerIdentityImpl;
0023: import org.geoserver.ows.util.RequestUtils;
0024: import org.geoserver.platform.GeoServerExtensions;
0025: import org.geotools.geometry.GeneralEnvelope;
0026: import org.geotools.referencing.CRS;
0027: import org.geotools.resources.CRSUtilities;
0028: import org.geotools.styling.Style;
0029: import org.geotools.xml.transform.TransformerBase;
0030: import org.geotools.xml.transform.Translator;
0031: import org.opengis.referencing.FactoryException;
0032: import org.opengis.referencing.crs.CoordinateReferenceSystem;
0033: import org.opengis.referencing.operation.MathTransform;
0034: import org.opengis.referencing.operation.TransformException;
0035: import org.springframework.context.ApplicationContext;
0036: import org.vfny.geoserver.global.CoverageInfo;
0037: import org.vfny.geoserver.global.CoverageInfoLabelComparator;
0038: import org.vfny.geoserver.global.Data;
0039: import org.vfny.geoserver.global.FeatureTypeInfo;
0040: import org.vfny.geoserver.global.FeatureTypeInfoTitleComparator;
0041: import org.vfny.geoserver.global.GeoServer;
0042: import org.vfny.geoserver.global.LegendURL;
0043: import org.vfny.geoserver.global.MapLayerInfo;
0044: import org.vfny.geoserver.global.MetaDataLink;
0045: import org.vfny.geoserver.global.WMS;
0046: import org.vfny.geoserver.util.requests.CapabilitiesRequest;
0047: import org.vfny.geoserver.wms.WmsException;
0048: import org.vfny.geoserver.wms.requests.GetLegendGraphicRequest;
0049: import org.vfny.geoserver.wms.responses.DescribeLayerResponse;
0050: import org.vfny.geoserver.wms.responses.GetFeatureInfoResponse;
0051: import org.vfny.geoserver.wms.responses.GetLegendGraphicResponse;
0052: import org.xml.sax.ContentHandler;
0053: import org.xml.sax.helpers.AttributesImpl;
0054: import java.util.Collections;
0055:
0056: import com.vividsolutions.jts.geom.Envelope;
0057:
0058: /**
0059: * Geotools xml framework based encoder for a Capabilities WMS 1.1.1 document.
0060: *
0061: * @author Gabriel Roldan, Axios Engineering
0062: * @version $Id
0063: */
0064: public class WMSCapsTransformer extends TransformerBase {
0065: /** fixed MIME type for the returned capabilities document */
0066: public static final String WMS_CAPS_MIME = "application/vnd.ogc.wms_xml";
0067:
0068: /** DOCUMENT ME! */
0069: private String baseUrl;
0070: private Set formats;
0071: private ApplicationContext applicationContext;
0072:
0073: /**
0074: * Creates a new WMSCapsTransformer object.
0075: *
0076: * @param baseUrl
0077: * needed to get the schema base URL
0078: * @param formats
0079: * @param applicationContext
0080: *
0081: * @throws NullPointerException
0082: * if <code>schemaBaseUrl</code> is null;
0083: */
0084: public WMSCapsTransformer(String baseUrl, Set formats,
0085: ApplicationContext applicationContext) {
0086: super ();
0087: this .formats = formats;
0088:
0089: if (baseUrl == null) {
0090: throw new NullPointerException();
0091: }
0092:
0093: this .baseUrl = baseUrl;
0094: this .setNamespaceDeclarationEnabled(false);
0095: this .applicationContext = applicationContext;
0096: }
0097:
0098: /**
0099: * DOCUMENT ME!
0100: *
0101: * @param handler
0102: * DOCUMENT ME!
0103: *
0104: * @return DOCUMENT ME!
0105: */
0106: public Translator createTranslator(ContentHandler handler) {
0107: return new CapabilitiesTranslator(handler, formats,
0108: applicationContext);
0109: }
0110:
0111: /**
0112: * Gets the <code>Transformer</code> created by the overriden method in
0113: * the superclass and adds it the system DOCTYPE token pointing to the
0114: * Capabilities DTD on this server instance.
0115: *
0116: * <p>
0117: * The DTD is set at the fixed location given by the
0118: * <code>schemaBaseUrl</code> passed to the constructor <code>+
0119: * "wms/1.1.1/WMS_MS_Capabilities.dtd</code>.
0120: * </p>
0121: *
0122: * @return a Transformer propoerly configured to produce DescribeLayer
0123: * responses.
0124: *
0125: * @throws TransformerException
0126: * if it is thrown by <code>super.createTransformer()</code>
0127: */
0128: public Transformer createTransformer() throws TransformerException {
0129: Transformer transformer = super .createTransformer();
0130: GeoServer gs = (GeoServer) GeoServerExtensions.extensions(
0131: GeoServer.class, applicationContext).get(0);
0132: String dtdUrl = RequestUtils.proxifiedBaseURL(this .baseUrl, gs
0133: .getProxyBaseUrl())
0134: + "schemas/wms/1.1.1/WMS_MS_Capabilities.dtd"; // DJB: fixed this to
0135: // point to correct
0136: // location
0137:
0138: transformer
0139: .setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, dtdUrl);
0140:
0141: return transformer;
0142: }
0143:
0144: /**
0145: * DOCUMENT ME!
0146: *
0147: * @author Gabriel Roldan, Axios Engineering
0148: * @version $Id
0149: */
0150: private static class CapabilitiesTranslator extends
0151: TranslatorSupport {
0152: /** DOCUMENT ME! */
0153: private static final Logger LOGGER = org.geotools.util.logging.Logging
0154: .getLogger(CapabilitiesTranslator.class.getPackage()
0155: .getName());
0156:
0157: /** DOCUMENT ME! */
0158: private static final String EPSG = "EPSG:";
0159:
0160: /** DOCUMENT ME! */
0161: private static AttributesImpl wmsVersion = new AttributesImpl();
0162:
0163: /** DOCUMENT ME! */
0164: private static final String XLINK_NS = "http://www.w3.org/1999/xlink";
0165:
0166: static {
0167: wmsVersion.addAttribute("", "version", "version", "",
0168: "1.1.1");
0169: }
0170:
0171: /**
0172: * The request from wich all the information needed to produce the
0173: * capabilities document can be obtained
0174: */
0175: private CapabilitiesRequest request;
0176: private Set formats;
0177: private ApplicationContext applicationContext;
0178:
0179: /**
0180: * Creates a new CapabilitiesTranslator object.
0181: *
0182: * @param handler
0183: * content handler to send sax events to.
0184: */
0185: public CapabilitiesTranslator(ContentHandler handler,
0186: Set formats, ApplicationContext applicationContext) {
0187: super (handler, null, null);
0188: this .formats = formats;
0189: this .applicationContext = applicationContext;
0190: }
0191:
0192: /**
0193: * DOCUMENT ME!
0194: *
0195: * @param o
0196: * the <code>CapabilitiesRequest</code>
0197: *
0198: * @throws IllegalArgumentException
0199: * DOCUMENT ME!
0200: */
0201: public void encode(Object o) throws IllegalArgumentException {
0202: if (!(o instanceof CapabilitiesRequest)) {
0203: throw new IllegalArgumentException();
0204: }
0205:
0206: this .request = (CapabilitiesRequest) o;
0207:
0208: if (LOGGER.isLoggable(Level.FINE)) {
0209: LOGGER.fine(new StringBuffer(
0210: "producing a capabilities document for ")
0211: .append(request).toString());
0212: }
0213:
0214: WMS wms = (WMS) request.getServiceRef().getServiceRef();
0215: AttributesImpl rootAtts = new AttributesImpl(wmsVersion);
0216: rootAtts.addAttribute("", "updateSequence",
0217: "updateSequence", "", wms.getGeoServer()
0218: .getUpdateSequence()
0219: + "");
0220: start("WMT_MS_Capabilities", rootAtts);
0221: handleService();
0222: handleCapability();
0223: end("WMT_MS_Capabilities");
0224: }
0225:
0226: /**
0227: * Encodes the service metadata section of a WMS capabilities document.
0228: */
0229: private void handleService() {
0230: WMS wms = (WMS) request.getServiceRef().getServiceRef();
0231: start("Service");
0232:
0233: element("Name", "OGC:WMS");
0234: element("Title", wms.getTitle());
0235: element("Abstract", wms.getAbstract());
0236:
0237: handleKeywordList(wms.getKeywords());
0238:
0239: AttributesImpl orAtts = new AttributesImpl();
0240: orAtts.addAttribute("", "xmlns:xlink", "xmlns:xlink", "",
0241: XLINK_NS);
0242: orAtts.addAttribute(XLINK_NS, "xlink:type", "xlink:type",
0243: "", "simple");
0244: orAtts.addAttribute("", "xlink:href", "xlink:href", "",
0245: RequestUtils.proxifiedBaseURL(request.getBaseUrl(),
0246: wms.getGeoServer().getProxyBaseUrl())
0247: + "wms");
0248: element("OnlineResource", null, orAtts);
0249:
0250: handleContactInfo(wms.getGeoServer());
0251:
0252: element("Fees", wms.getFees());
0253: element("AccessConstraints", wms.getAccessConstraints());
0254: end("Service");
0255: }
0256:
0257: /**
0258: * Encodes contact information in the WMS capabilities document
0259: * @param geoServer
0260: */
0261: public void handleContactInfo(GeoServer geoServer) {
0262: start("ContactInformation");
0263:
0264: start("ContactPersonPrimary");
0265: element("ContactPerson", geoServer.getContactPerson());
0266: element("ContactOrganization", geoServer
0267: .getContactOrganization());
0268: end("ContactPersonPrimary");
0269:
0270: element("ContactPosition", geoServer.getContactPosition());
0271:
0272: start("ContactAddress");
0273: element("AddressType", geoServer.getAddressType());
0274: element("Address", geoServer.getAddress());
0275: element("City", geoServer.getAddressCity());
0276: element("StateOrProvince", geoServer.getAddressState());
0277: element("PostCode", geoServer.getAddressPostalCode());
0278: element("Country", geoServer.getAddressCountry());
0279: end("ContactAddress");
0280:
0281: element("ContactVoiceTelephone", geoServer
0282: .getContactVoice());
0283: element("ContactFacsimileTelephone", geoServer
0284: .getContactFacsimile());
0285: element("ContactElectronicMailAddress", geoServer
0286: .getContactEmail());
0287:
0288: end("ContactInformation");
0289: }
0290:
0291: /**
0292: * Turns the keyword list to XML
0293: *
0294: * @param keywords
0295: */
0296: private void handleKeywordList(List keywords) {
0297: start("KeywordList");
0298:
0299: if (keywords != null) {
0300: for (Iterator it = keywords.iterator(); it.hasNext();) {
0301: element("Keyword", String.valueOf(it.next()));
0302: }
0303: }
0304:
0305: end("KeywordList");
0306: }
0307:
0308: /**
0309: * Turns the metadata URL list to XML
0310: *
0311: * @param keywords
0312: */
0313: private void handleMetadataList(List metadataURLs) {
0314: if (metadataURLs == null) {
0315: return;
0316: }
0317:
0318: for (Iterator it = metadataURLs.iterator(); it.hasNext();) {
0319: MetaDataLink link = (MetaDataLink) it.next();
0320:
0321: AttributesImpl lnkAtts = new AttributesImpl();
0322: lnkAtts.addAttribute("", "type", "type", "", link
0323: .getMetadataType());
0324: start("MetadataURL", lnkAtts);
0325:
0326: element("Format", link.getType());
0327:
0328: AttributesImpl orAtts = new AttributesImpl();
0329: orAtts.addAttribute("", "xmlns:xlink", "xmlns:xlink",
0330: "", XLINK_NS);
0331: orAtts.addAttribute(XLINK_NS, "xlink:type",
0332: "xlink:type", "", "simple");
0333: orAtts.addAttribute("", "xlink:href", "xlink:href", "",
0334: link.getContent());
0335: element("OnlineResource", null, orAtts);
0336:
0337: end("MetadataURL");
0338: }
0339: }
0340:
0341: /**
0342: * Encodes the capabilities metadata section of a WMS capabilities
0343: * document
0344: */
0345: private void handleCapability() {
0346: start("Capability");
0347: handleRequest();
0348: handleException();
0349: handleSLD();
0350: handleLayers();
0351: end("Capability");
0352: }
0353:
0354: /**
0355: * DOCUMENT ME!
0356: */
0357: private void handleRequest() {
0358: start("Request");
0359:
0360: start("GetCapabilities");
0361: element("Format", WMS_CAPS_MIME);
0362:
0363: String serviceUrl = RequestUtils.proxifiedBaseURL(request
0364: .getBaseUrl(), request.getServiceRef()
0365: .getGeoServer().getProxyBaseUrl())
0366: + "wms?SERVICE=WMS&";
0367:
0368: handleDcpType(serviceUrl, serviceUrl);
0369: end("GetCapabilities");
0370:
0371: start("GetMap");
0372:
0373: List sortedFormats = new ArrayList(formats);
0374: Collections.sort(sortedFormats);
0375: // this is a hack necessary to make cite tests pass: we need an output format
0376: // that is equal to the mime type as the first one....
0377: if (sortedFormats.contains("image/png")) {
0378: sortedFormats.remove("image/png");
0379: sortedFormats.add(0, "image/png");
0380: }
0381: for (Iterator it = sortedFormats.iterator(); it.hasNext();) {
0382: element("Format", String.valueOf(it.next()));
0383: }
0384:
0385: handleDcpType(serviceUrl, null);
0386: end("GetMap");
0387:
0388: start("GetFeatureInfo");
0389:
0390: for (Iterator it = GetFeatureInfoResponse.getFormats()
0391: .iterator(); it.hasNext();) {
0392: element("Format", String.valueOf(it.next()));
0393: }
0394:
0395: handleDcpType(serviceUrl, serviceUrl);
0396: end("GetFeatureInfo");
0397:
0398: start("DescribeLayer");
0399: element("Format", DescribeLayerResponse.DESCLAYER_MIME_TYPE);
0400: handleDcpType(serviceUrl, null);
0401: end("DescribeLayer");
0402:
0403: start("GetLegendGraphic");
0404:
0405: for (Iterator it = GetLegendGraphicResponse.getFormats(
0406: applicationContext).iterator(); it.hasNext();) {
0407: element("Format", String.valueOf(it.next()));
0408: }
0409:
0410: handleDcpType(serviceUrl, null);
0411: end("GetLegendGraphic");
0412:
0413: end("Request");
0414: }
0415:
0416: /**
0417: * Encodes a <code>DCPType</code> fragment for HTTP GET and POST
0418: * methods.
0419: *
0420: * @param getUrl the URL of the onlineresource for HTTP GET method
0421: * requests
0422: * @param postUrl the URL of the onlineresource for HTTP POST method
0423: * requests
0424: */
0425: private void handleDcpType(String getUrl, String postUrl) {
0426: AttributesImpl orAtts = new AttributesImpl();
0427: orAtts.addAttribute("", "xmlns:xlink", "xmlns:xlink", "",
0428: XLINK_NS);
0429: orAtts.addAttribute("", "xlink:type", "xlink:type", "",
0430: "simple");
0431: orAtts.addAttribute("", "xlink:href", "xlink:href", "",
0432: getUrl);
0433: start("DCPType");
0434: start("HTTP");
0435:
0436: if (getUrl != null) {
0437: start("Get");
0438: element("OnlineResource", null, orAtts);
0439: end("Get");
0440: }
0441:
0442: if (postUrl != null) {
0443: orAtts.setAttribute(2, "", "xlink:href", "xlink:href",
0444: "", postUrl);
0445: start("Post");
0446: element("OnlineResource", null, orAtts);
0447: end("Post");
0448: }
0449:
0450: end("HTTP");
0451: end("DCPType");
0452: }
0453:
0454: /**
0455: * DOCUMENT ME!
0456: */
0457: private void handleException() {
0458: start("Exception");
0459:
0460: WMS wms = (WMS) request.getServiceRef().getServiceRef();
0461: Iterator it = Arrays.asList(wms.getExceptionFormats())
0462: .iterator();
0463:
0464: while (it.hasNext()) {
0465: element("Format", String.valueOf(it.next()));
0466: }
0467:
0468: end("Exception");
0469: }
0470:
0471: /**
0472: * DOCUMENT ME!
0473: */
0474: private void handleSLD() {
0475: AttributesImpl sldAtts = new AttributesImpl();
0476: WMS config = (WMS) request.getServiceRef().getServiceRef();
0477: String supportsSLD = config.supportsSLD() ? "1" : "0";
0478: String supportsUserLayer = config.supportsUserLayer() ? "1"
0479: : "0";
0480: String supportsUserStyle = config.supportsUserStyle() ? "1"
0481: : "0";
0482: String supportsRemoteWFS = config.supportsRemoteWFS() ? "1"
0483: : "0";
0484: sldAtts.addAttribute("", "SupportSLD", "SupportSLD", "",
0485: supportsSLD);
0486: sldAtts.addAttribute("", "UserLayer", "UserLayer", "",
0487: supportsUserLayer);
0488: sldAtts.addAttribute("", "UserStyle", "UserStyle", "",
0489: supportsUserStyle);
0490: sldAtts.addAttribute("", "RemoteWFS", "RemoteWFS", "",
0491: supportsRemoteWFS);
0492:
0493: start("UserDefinedSymbolization", sldAtts);
0494: // djb: this was removed, even though they are correct - the CITE tests have an incorrect DTD
0495: // element("SupportedSLDVersion","1.0.0"); //djb: added that we support this. We support partial 1.1
0496: end("UserDefinedSymbolization");
0497:
0498: //element("UserDefinedSymbolization", null, sldAtts);
0499: }
0500:
0501: /**
0502: * Handles the encoding of the layers elements.
0503: *
0504: * <p>
0505: * This method does a search over the SRS of all the layers to see if
0506: * there are at least a common one, as needed by the spec: "<i>The root
0507: * Layer element shall include a sequence of zero or more <SRS>
0508: * elements listing all SRSes that are common to all subsidiary layers.
0509: * Use a single SRS element with empty content (like so:
0510: * "<SRS></SRS>") if there is no common SRS."</i>
0511: * </p>
0512: *
0513: * <p>
0514: * By the other hand, this search is also used to collecto the whole
0515: * latlon bbox, as stated by the spec: <i>"The bounding box metadata in
0516: * Capabilities XML specify the minimum enclosing rectangle for the
0517: * layer as a whole."</i>
0518: * </p>
0519: *
0520: * @task TODO: manage this differently when we have the layer list of
0521: * the WMS service decoupled from the feature types configured for
0522: * the server instance. (This involves nested layers,
0523: * gridcoverages, etc)
0524: */
0525: private void handleLayers() {
0526: WMS wms = (WMS) request.getServiceRef().getServiceRef();
0527: start("Layer");
0528:
0529: Data catalog = wms.getData();
0530: Collection ftypes = catalog.getFeatureTypeInfos().values();
0531: Collection coverages = catalog.getCoverageInfos().values();
0532:
0533: element("Title", wms.getTitle());
0534: element("Abstract", wms.getAbstract());
0535:
0536: handleRootSRSAndBbox(ftypes, MapLayerInfo.TYPE_VECTOR);
0537:
0538: // now encode each layer individually
0539: LayerTree featuresLayerTree = new LayerTree(ftypes);
0540: handleFeaturesTree(featuresLayerTree);
0541:
0542: LayerTree coveragesLayerTree = new LayerTree(coverages);
0543: handleCoveragesTree(coveragesLayerTree);
0544:
0545: try {
0546: handleLayerGroups(wms.getBaseMapLayers(), wms
0547: .getBaseMapStyles(), wms.getBaseMapEnvelopes());
0548: } catch (FactoryException e) {
0549: throw new RuntimeException(
0550: "Can't obtain Envelope of Layer-Groups: "
0551: + e.getMessage(), e);
0552: } catch (TransformException e) {
0553: throw new RuntimeException(
0554: "Can't obtain Envelope of Layer-Groups: "
0555: + e.getMessage(), e);
0556: }
0557:
0558: end("Layer");
0559: }
0560:
0561: /**
0562: * Called from <code>handleLayers()</code>, does the first
0563: * iteration over the available featuretypes to look for common SRS's
0564: * and summarize their LatLonBBox'es, to state at the root layer.<p>NOTE:
0565: * by now we just have "layer.getSRS()", so the search is done against
0566: * this only SRS.</p>
0567: *
0568: * @param ftypes DOCUMENT ME!
0569: * @param TYPE DOCUMENT ME!
0570: *
0571: * @throws RuntimeException DOCUMENT ME!
0572: *
0573: * @task TODO: figure out how to incorporate multiple SRS using the
0574: * reprojection facilities from gt2
0575: */
0576: private void handleRootSRSAndBbox(Collection ftypes, int TYPE) {
0577: String commonSRS = "";
0578: boolean isCommonSRS = true;
0579: Envelope latlonBbox = new Envelope();
0580: Envelope layerBbox = null;
0581:
0582: if (LOGGER.isLoggable(Level.FINER)) {
0583: LOGGER
0584: .finer("Collecting summarized latlonbbox and common SRS...");
0585: }
0586:
0587: if (TYPE == MapLayerInfo.TYPE_VECTOR) {
0588: FeatureTypeInfo layer;
0589:
0590: for (Iterator it = ftypes.iterator(); it.hasNext();) {
0591: layer = (FeatureTypeInfo) it.next();
0592:
0593: if (layer.isEnabled()) {
0594: try {
0595: layerBbox = layer.getLatLongBoundingBox();
0596: } catch (IOException e) {
0597: throw new RuntimeException(
0598: "Can't obtain latLonBBox of "
0599: + layer.getName() + ": "
0600: + e.getMessage(), e);
0601: }
0602:
0603: latlonBbox.expandToInclude(layerBbox);
0604:
0605: String layerSRS = layer.getSRS();
0606:
0607: if ("".equals(commonSRS)) {
0608: commonSRS = layerSRS;
0609: } else if (!commonSRS.equals(layerSRS)) {
0610: isCommonSRS = false;
0611: }
0612: }
0613: }
0614:
0615: if (isCommonSRS) {
0616: commonSRS = EPSG + commonSRS;
0617: LOGGER.fine("Common SRS is " + commonSRS);
0618: } else {
0619: commonSRS = "";
0620: LOGGER
0621: .fine("No common SRS, don't forget to incorporate reprojection support...");
0622: }
0623:
0624: if (!(commonSRS.equals(""))) {
0625: comment("common SRS:");
0626: element("SRS", commonSRS);
0627: }
0628:
0629: // okay - we've sent out the commonSRS, if it exists.
0630: comment("All supported EPSG projections:");
0631:
0632: try {
0633: Set s = CRS.getSupportedCodes("EPSG");
0634: Iterator it = s.iterator();
0635: String currentSRS;
0636:
0637: while (it.hasNext()) {
0638: // do not output srs if it was output as common srs
0639: // note, if commonSRS is "", this will not match
0640: currentSRS = it.next().toString();
0641:
0642: if (!currentSRS.equals(commonSRS)) {
0643: element("SRS", EPSG + currentSRS);
0644: }
0645: }
0646: } catch (Exception e) {
0647: if (LOGGER.isLoggable(Level.WARNING)) {
0648: LOGGER.log(Level.WARNING, e
0649: .getLocalizedMessage(), e);
0650: }
0651: }
0652:
0653: if (LOGGER.isLoggable(Level.FINE)) {
0654: LOGGER.fine("Summarized LatLonBBox is "
0655: + latlonBbox);
0656: }
0657:
0658: handleLatLonBBox(latlonBbox);
0659: } else if (TYPE == MapLayerInfo.TYPE_RASTER) {
0660: CoverageInfo layer;
0661:
0662: for (Iterator it = ftypes.iterator(); it.hasNext();) {
0663: layer = (CoverageInfo) it.next();
0664:
0665: if (layer.isEnabled()) {
0666: final GeneralEnvelope bbox = layer
0667: .getWGS84LonLatEnvelope();
0668: layerBbox = new Envelope(bbox.getLowerCorner()
0669: .getOrdinate(0), bbox.getUpperCorner()
0670: .getOrdinate(0), bbox.getLowerCorner()
0671: .getOrdinate(1), bbox.getUpperCorner()
0672: .getOrdinate(1));
0673:
0674: latlonBbox.expandToInclude(layerBbox);
0675:
0676: String layerSRS = layer.getSrsName();
0677:
0678: if ("".equals(commonSRS)) {
0679: commonSRS = layerSRS;
0680: } else if (!commonSRS.equals(layerSRS)) {
0681: isCommonSRS = false;
0682: }
0683: }
0684: }
0685:
0686: if (isCommonSRS) {
0687: // commonSRS = EPSG + commonSRS;
0688: if (LOGGER.isLoggable(Level.FINE)) {
0689: LOGGER.fine(new StringBuffer("Common SRS is ")
0690: .append(commonSRS).toString());
0691: }
0692: } else {
0693: commonSRS = "";
0694:
0695: if (LOGGER.isLoggable(Level.FINE)) {
0696: LOGGER
0697: .fine("No common SRS, don't forget to incorporate reprojection support...");
0698: }
0699: }
0700:
0701: if (!(commonSRS.equals(""))) {
0702: comment("common SRS:");
0703: element("SRS", commonSRS);
0704: }
0705:
0706: // okay - we've sent out the commonSRS, if it exists.
0707: comment("All supported EPSG projections:");
0708:
0709: try {
0710: String currentSRS;
0711: ArrayList SRSs = new ArrayList(ftypes.size());
0712:
0713: for (Iterator it = ftypes.iterator(); it.hasNext();) {
0714: layer = (CoverageInfo) it.next();
0715:
0716: if (layer.isEnabled()) {
0717: List s = layer.getRequestCRSs();
0718: Iterator it_1 = s.iterator();
0719:
0720: while (it_1.hasNext()) {
0721: // do not output srs if it was output as common
0722: // srs
0723: // note, if commonSRS is "", this will not match
0724: currentSRS = it_1.next().toString();
0725:
0726: if (!currentSRS.equals(commonSRS)
0727: && !SRSs.contains(currentSRS)) {
0728: SRSs.add(currentSRS);
0729: element("SRS", currentSRS);
0730: }
0731: }
0732: }
0733: }
0734: } catch (Exception e) {
0735: if (LOGGER.isLoggable(Level.WARNING)) {
0736: LOGGER.log(Level.WARNING, e
0737: .getLocalizedMessage(), e);
0738: }
0739: }
0740:
0741: if (LOGGER.isLoggable(Level.FINE)) {
0742: LOGGER.fine("Summarized LatLonBBox is "
0743: + latlonBbox);
0744: }
0745:
0746: handleLatLonBBox(latlonBbox);
0747: }
0748: }
0749:
0750: /**
0751: * @param featuresLayerTree
0752: */
0753: private void handleFeaturesTree(LayerTree featuresLayerTree) {
0754: final List data = new ArrayList(featuresLayerTree.getData());
0755: final Collection childrens = featuresLayerTree
0756: .getChildrens();
0757: FeatureTypeInfo fLayer;
0758:
0759: Collections
0760: .sort(data, new FeatureTypeInfoTitleComparator());
0761: for (Iterator it = data.iterator(); it.hasNext();) {
0762: fLayer = (FeatureTypeInfo) it.next();
0763:
0764: try {
0765: if (fLayer.isEnabled() && !fLayer.isGeometryless()) {
0766: handleFeatureType(fLayer);
0767: }
0768: } catch (Exception e) {
0769: if (LOGGER.isLoggable(Level.WARNING)) {
0770: LOGGER.log(Level.WARNING, e
0771: .getLocalizedMessage(), e);
0772: }
0773: }
0774: }
0775:
0776: LayerTree layerTree;
0777:
0778: for (Iterator it = childrens.iterator(); it.hasNext();) {
0779: layerTree = (LayerTree) it.next();
0780: start("Layer");
0781: element("Name", layerTree.getName());
0782: element("Title", layerTree.getName());
0783: handleFeaturesTree(layerTree);
0784: end("Layer");
0785: }
0786: }
0787:
0788: /**
0789: * Calls super.handleFeatureType to add common FeatureType content such
0790: * as Name, Title and LatLonBoundingBox, and then writes WMS specific
0791: * layer properties as Styles, Scale Hint, etc.
0792: *
0793: * @param ftype
0794: * The featureType to write out.
0795: *
0796: * @throws RuntimeException
0797: * DOCUMENT ME!
0798: *
0799: * @task TODO: write wms specific elements.
0800: */
0801: protected void handleFeatureType(FeatureTypeInfo ftype) {
0802: // HACK: by now all our layers are queryable, since they reference
0803: // only featuretypes managed by this server
0804: AttributesImpl qatts = new AttributesImpl();
0805: qatts.addAttribute("", "queryable", "queryable", "", "1");
0806: start("Layer", qatts);
0807: element("Name", ftype.getName());
0808: element("Title", ftype.getTitle());
0809: element("Abstract", ftype.getAbstract());
0810:
0811: handleKeywordList(ftype.getKeywords());
0812:
0813: /**
0814: * @task REVISIT: should getSRS() return the full URL? no - the spec
0815: * says it should be a set of <SRS>EPSG:#</SRS>...
0816: */
0817: element("SRS", EPSG + ftype.getSRS());
0818:
0819: // DJB: I want to be nice to the people reading the capabilities
0820: // file - I'm going to get the
0821: // human readable name and stick it in the capabilities file
0822: // NOTE: this isnt well done because "comment()" isnt in the
0823: // ContentHandler interface...
0824: try {
0825: CoordinateReferenceSystem crs = CRS.decode(EPSG
0826: + ftype.getSRS());
0827: String desc = "WKT definition of this CRS:\n" + crs;
0828: comment(desc);
0829: } catch (Exception e) {
0830: if (LOGGER.isLoggable(Level.WARNING)) {
0831: LOGGER.log(Level.WARNING, e.getLocalizedMessage(),
0832: e);
0833: }
0834: }
0835:
0836: Envelope bbox = null;
0837: Envelope llbbox = null;
0838:
0839: try {
0840: bbox = ftype.getBoundingBox();
0841: llbbox = ftype.getLatLongBoundingBox();
0842: } catch (IOException ex) {
0843: throw new RuntimeException(
0844: "Can't obtain latLongBBox of "
0845: + ftype.getName() + ": "
0846: + ex.getMessage(), ex);
0847: }
0848:
0849: handleLatLonBBox(llbbox);
0850: handleBBox(bbox, EPSG + ftype.getSRS());
0851: // handle metadata URLs
0852: handleMetadataList(ftype.getMetadataLinks());
0853:
0854: // add the layer style
0855: start("Style");
0856:
0857: Style ftStyle = ftype.getDefaultStyle();
0858: element("Name", ftStyle.getName());
0859: element("Title", ftStyle.getTitle());
0860: element("Abstract", ftStyle.getAbstract());
0861: handleLegendURL(ftype);
0862: end("Style");
0863:
0864: final ArrayList styles = ftype.getStyles();
0865: Iterator s_IT = styles.iterator();
0866:
0867: while (s_IT.hasNext()) {
0868: ftStyle = (Style) s_IT.next();
0869: start("Style");
0870: element("Name", ftStyle.getName());
0871: element("Title", ftStyle.getTitle());
0872: element("Abstract", ftStyle.getAbstract());
0873: handleLegendURL(ftype);
0874: end("Style");
0875: }
0876:
0877: end("Layer");
0878: }
0879:
0880: /**
0881: * @param coveragesLayerTree
0882: */
0883: private void handleCoveragesTree(LayerTree coveragesLayerTree) {
0884: final List data = new ArrayList(coveragesLayerTree
0885: .getData());
0886: final Collection childrens = coveragesLayerTree
0887: .getChildrens();
0888: CoverageInfo cLayer;
0889:
0890: Collections.sort(data, new CoverageInfoLabelComparator());
0891: for (Iterator it = data.iterator(); it.hasNext();) {
0892: cLayer = (CoverageInfo) it.next();
0893:
0894: if (cLayer.isEnabled()) {
0895: handleCoverage(cLayer);
0896: }
0897: }
0898:
0899: LayerTree layerTree;
0900:
0901: for (Iterator it = childrens.iterator(); it.hasNext();) {
0902: layerTree = (LayerTree) it.next();
0903: start("Layer");
0904: element("Name", layerTree.getName());
0905: element("Title", layerTree.getName());
0906: handleCoveragesTree(layerTree);
0907: end("Layer");
0908: }
0909: }
0910:
0911: protected void handleCoverage(CoverageInfo coverage) {
0912: // HACK: by now all our layers are queryable, since they reference
0913: // only featuretypes managed by this server
0914: AttributesImpl qatts = new AttributesImpl();
0915: qatts.addAttribute("", "queryable", "queryable", "", "1");
0916: // qatts.addAttribute("", "opaque", "opaque", "", "1");
0917: // qatts.addAttribute("", "cascaded", "cascaded", "", "1");
0918: start("Layer", qatts);
0919: element("Name", coverage.getName());
0920: element("Title", coverage.getLabel());
0921: element("Abstract", coverage.getDescription());
0922:
0923: handleKeywordList(coverage.getKeywords());
0924:
0925: String desc = "WKT definition of this CRS:\n"
0926: + coverage.getSrsWKT();
0927: comment(desc);
0928:
0929: String authority = coverage.getSrsName();
0930:
0931: /*CoordinateReferenceSystem crs = coverage.getCrs();
0932: if (crs != null && !crs.getIdentifiers().isEmpty()) {
0933: Identifier[] idents = (Identifier[]) crs.getIdentifiers()
0934: .toArray(new Identifier[crs.getIdentifiers().size()]);
0935: authority = idents[0].toString();
0936: } else if (crs != null && crs instanceof DerivedCRS) {
0937: final CoordinateReferenceSystem baseCRS = ((DerivedCRS) crs)
0938: .getBaseCRS();
0939: if (baseCRS != null && !baseCRS.getIdentifiers().isEmpty())
0940: authority = ((Identifier[]) baseCRS.getIdentifiers()
0941: .toArray(
0942: new Identifier[baseCRS.getIdentifiers()
0943: .size()]))[0].toString();
0944: else
0945: authority = coverage.getNativeCRS();
0946: } else if (crs != null && crs instanceof ProjectedCRS) {
0947: final CoordinateReferenceSystem baseCRS = ((ProjectedCRS) crs)
0948: .getBaseCRS();
0949: if (baseCRS != null && !baseCRS.getIdentifiers().isEmpty())
0950: authority = ((Identifier[]) baseCRS.getIdentifiers()
0951: .toArray(
0952: new Identifier[baseCRS.getIdentifiers()
0953: .size()]))[0].toString();
0954: else
0955: authority = coverage.getNativeCRS();
0956: } else
0957: authority = coverage.getNativeCRS();*/
0958: element("SRS", authority);
0959:
0960: GeneralEnvelope bounds = null;
0961: GeneralEnvelope llBounds = null;
0962:
0963: // try {
0964: // We need LON/LAT Envelopes
0965: // TODO check for BBOX, maybe it should be expressed in original
0966: // CRS coords!!
0967: final GeneralEnvelope latLonEnvelope = coverage
0968: .getWGS84LonLatEnvelope();
0969: // final CoordinateReferenceSystem llCRS = latLonEnvelope
0970: // .getCoordinateReferenceSystem();
0971: bounds = coverage.getEnvelope();
0972: llBounds = latLonEnvelope;
0973:
0974: // bounds =
0975: // CoverageStoreUtils.adjustEnvelopeLongitudeFirst(llCRS,
0976: // coverage.getEnvelope());
0977: // llBounds =
0978: // CoverageStoreUtils.adjustEnvelopeLongitudeFirst(llCRS,
0979: // // latLonEnvelope);
0980: // } catch (MismatchedDimensionException e) {
0981: //
0982: // } catch (IndexOutOfBoundsException e) {
0983: //
0984: // }
0985: final Envelope bbox = new Envelope(bounds.getLowerCorner()
0986: .getOrdinate(0), bounds.getUpperCorner()
0987: .getOrdinate(0), bounds.getLowerCorner()
0988: .getOrdinate(1), bounds.getUpperCorner()
0989: .getOrdinate(1));
0990:
0991: final Envelope llBbox = new Envelope(llBounds
0992: .getLowerCorner().getOrdinate(0), llBounds
0993: .getUpperCorner().getOrdinate(0), llBounds
0994: .getLowerCorner().getOrdinate(1), llBounds
0995: .getUpperCorner().getOrdinate(1));
0996:
0997: handleLatLonBBox(llBbox);
0998: handleBBox(bbox, authority);
0999:
1000: // add the layer style
1001: start("Style");
1002:
1003: Style cvStyle = coverage.getDefaultStyle();
1004: element("Name", cvStyle.getName());
1005: element("Title", cvStyle.getTitle());
1006: element("Abstract", cvStyle.getAbstract());
1007: handleLegendURL(coverage);
1008: end("Style");
1009:
1010: final ArrayList styles = coverage.getStyles();
1011: Iterator s_IT = styles.iterator();
1012:
1013: while (s_IT.hasNext()) {
1014: cvStyle = (Style) s_IT.next();
1015: start("Style");
1016: element("Name", cvStyle.getName());
1017: element("Title", cvStyle.getTitle());
1018: element("Abstract", cvStyle.getAbstract());
1019: handleLegendURL(coverage);
1020: end("Style");
1021: }
1022:
1023: end("Layer");
1024: }
1025:
1026: protected void handleLayerGroups(Map baseMapLayers,
1027: Map baseMapStyles, Map baseMapEnvelopes)
1028: throws FactoryException, TransformException {
1029: if (baseMapLayers == null) {
1030: return;
1031: }
1032:
1033: List names = new ArrayList(baseMapLayers.keySet());
1034: Collections.sort(names);
1035:
1036: CoordinateReferenceSystem wgs84 = CRS.decode("EPSG:4326");
1037:
1038: for (Iterator it = names.iterator(); it.hasNext();) {
1039: String layerName = (String) it.next();
1040:
1041: AttributesImpl qatts = new AttributesImpl();
1042: qatts.addAttribute("", "queryable", "queryable", "",
1043: "0");
1044: // qatts.addAttribute("", "opaque", "opaque", "", "1");
1045: // qatts.addAttribute("", "cascaded", "cascaded", "", "1");
1046: start("Layer", qatts);
1047: element("Name", layerName);
1048: element("Title", layerName);
1049: element("Abstract", "Layer-Group type layer: "
1050: + layerName);
1051:
1052: //handleKeywordList(...getKeywords());
1053:
1054: /*String desc = "WKT definition of this CRS:\n" + coverage.getSrsWKT();
1055: comment(desc);*/
1056: GeneralEnvelope bounds = (GeneralEnvelope) baseMapEnvelopes
1057: .get(layerName);
1058: GeneralEnvelope llBounds = null;
1059:
1060: String authority = bounds
1061: .getCoordinateReferenceSystem()
1062: .getIdentifiers().toArray()[0].toString();
1063:
1064: element("SRS", authority);
1065:
1066: if (CRSUtilities.equalsIgnoreMetadata(wgs84, bounds
1067: .getCoordinateReferenceSystem())) {
1068: llBounds = bounds;
1069: } else {
1070: try {
1071: final MathTransform srcCRStoWGS84 = CRS
1072: .findMathTransform(
1073: bounds
1074: .getCoordinateReferenceSystem(),
1075: wgs84, true);
1076: final GeneralEnvelope latLonEnvelope = CRS
1077: .transform(srcCRStoWGS84, bounds);
1078: latLonEnvelope
1079: .setCoordinateReferenceSystem(wgs84);
1080: llBounds = latLonEnvelope;
1081: } catch (TransformException e) {
1082: throw new WmsException(
1083: "Cannot transform envelope to WGS84 for layer group "
1084: + layerName,
1085: "TransformException", e);
1086: }
1087: }
1088:
1089: final Envelope bbox = new Envelope(bounds
1090: .getLowerCorner().getOrdinate(0), bounds
1091: .getUpperCorner().getOrdinate(0), bounds
1092: .getLowerCorner().getOrdinate(1), bounds
1093: .getUpperCorner().getOrdinate(1));
1094:
1095: final Envelope llBbox = new Envelope(llBounds
1096: .getLowerCorner().getOrdinate(0), llBounds
1097: .getUpperCorner().getOrdinate(0), llBounds
1098: .getLowerCorner().getOrdinate(1), llBounds
1099: .getUpperCorner().getOrdinate(1));
1100:
1101: handleLatLonBBox(llBbox);
1102: handleBBox(bbox, authority);
1103:
1104: // add the layer style
1105: start("Style");
1106:
1107: element("Name", layerName);
1108: element("Title", layerName);
1109: element("Abstract", "Layer-Group complex style");
1110: //handleLegendURL(...URL);
1111: end("Style");
1112:
1113: end("Layer");
1114: }
1115: }
1116:
1117: /**
1118: * Writes layer LegendURL pointing to the user supplied icon URL, if
1119: * any, or to the proper GetLegendGraphic operation if an URL was not
1120: * supplied by configuration file.
1121: *
1122: * <p>
1123: * It is common practice to supply a URL to a WMS accesible legend
1124: * graphic when it is difficult to create a dynamic legend for a layer.
1125: * </p>
1126: *
1127: * @param ft
1128: * The FeatureTypeInfo that holds the legendURL to write out,
1129: * or<code>null</code> if dynamically generated.
1130: *
1131: * @task TODO: figure out how to unhack legend parameters such as WIDTH,
1132: * HEIGHT and FORMAT
1133: */
1134: protected void handleLegendURL(Object layer) {
1135: LegendURL legend = null;
1136: String layerName = null;
1137:
1138: if (layer instanceof FeatureTypeInfo) {
1139: legend = ((FeatureTypeInfo) layer).getLegendURL();
1140: layerName = ((FeatureTypeInfo) layer).getName();
1141: } else if (layer instanceof CoverageInfo) {
1142: layerName = ((CoverageInfo) layer).getName();
1143: }
1144:
1145: if (legend != null) {
1146: if (LOGGER.isLoggable(Level.FINE)) {
1147: LOGGER.fine("using user supplied legend URL");
1148: }
1149:
1150: AttributesImpl attrs = new AttributesImpl();
1151: attrs.addAttribute("", "width", "width", "", String
1152: .valueOf(legend.getWidth()));
1153: attrs.addAttribute("", "height", "height", "", String
1154: .valueOf(legend.getHeight()));
1155:
1156: start("LegendURL", attrs);
1157:
1158: element("Format", legend.getFormat());
1159: attrs.clear();
1160: attrs.addAttribute("", "xmlns:xlink", "xmlns:xlink",
1161: "", XLINK_NS);
1162: attrs.addAttribute(XLINK_NS, "type", "xlink:type", "",
1163: "simple");
1164: attrs.addAttribute(XLINK_NS, "href", "xlink:href", "",
1165: legend.getOnlineResource());
1166:
1167: element("OnlineResource", null, attrs);
1168:
1169: end("LegendURL");
1170: } else {
1171: String defaultFormat = GetLegendGraphicRequest.DEFAULT_FORMAT;
1172:
1173: if (!GetLegendGraphicResponse.supportsFormat(
1174: defaultFormat, applicationContext)) {
1175: if (LOGGER.isLoggable(Level.WARNING)) {
1176: LOGGER
1177: .warning(new StringBuffer(
1178: "Default legend format (")
1179: .append(defaultFormat)
1180: .append(
1181: ")is not supported (jai not available?), can't add LegendURL element")
1182: .toString());
1183: }
1184:
1185: return;
1186: }
1187:
1188: if (LOGGER.isLoggable(Level.FINE)) {
1189: LOGGER
1190: .fine("Adding GetLegendGraphic call as LegendURL");
1191: }
1192:
1193: AttributesImpl attrs = new AttributesImpl();
1194: attrs
1195: .addAttribute(
1196: "",
1197: "width",
1198: "width",
1199: "",
1200: String
1201: .valueOf(GetLegendGraphicRequest.DEFAULT_WIDTH));
1202:
1203: // DJB: problem here is that we do not know the size of the
1204: // legend apriori - we need
1205: // to make one and find its height. Not the best way, but it
1206: // would work quite well.
1207: // This was advertising a 20*20 icon, but actually producing
1208: // ones of a different size.
1209: // An alternative is to just scale the resulting icon to what
1210: // the server requested, but this isnt
1211: // the nicest thing since warped images dont look nice. The
1212: // client should do the warping.
1213:
1214: // however, to actually estimate the size is a bit difficult.
1215: // I'm going to do the scaling
1216: // so it obeys the what the request says. For people with a
1217: // problem with that should consider
1218: // changing the default size here so that the request is for the
1219: // correct size.
1220: attrs
1221: .addAttribute(
1222: "",
1223: "height",
1224: "height",
1225: "",
1226: String
1227: .valueOf(GetLegendGraphicRequest.DEFAULT_HEIGHT));
1228:
1229: start("LegendURL", attrs);
1230:
1231: element("Format", defaultFormat);
1232: attrs.clear();
1233:
1234: StringBuffer onlineResource = new StringBuffer(
1235: RequestUtils.proxifiedBaseURL(request
1236: .getBaseUrl(), request.getServiceRef()
1237: .getGeoServer().getProxyBaseUrl()));
1238: onlineResource.append("wms/GetLegendGraphic?VERSION=");
1239: onlineResource
1240: .append(GetLegendGraphicRequest.SLD_VERSION);
1241: onlineResource.append("&FORMAT=");
1242: onlineResource.append(defaultFormat);
1243: onlineResource.append("&WIDTH=");
1244: onlineResource
1245: .append(GetLegendGraphicRequest.DEFAULT_WIDTH);
1246: onlineResource.append("&HEIGHT=");
1247: onlineResource
1248: .append(GetLegendGraphicRequest.DEFAULT_HEIGHT);
1249: onlineResource.append("&LAYER=");
1250: onlineResource.append(layerName);
1251:
1252: attrs.addAttribute("", "xmlns:xlink", "xmlns:xlink",
1253: "", XLINK_NS);
1254: attrs.addAttribute(XLINK_NS, "type", "xlink:type", "",
1255: "simple");
1256: attrs.addAttribute(XLINK_NS, "href", "xlink:href", "",
1257: onlineResource.toString());
1258: element("OnlineResource", null, attrs);
1259:
1260: end("LegendURL");
1261: }
1262: }
1263:
1264: /**
1265: * Encodes a LatLonBoundingBox for the given Envelope.
1266: *
1267: * @param bbox
1268: */
1269: private void handleLatLonBBox(Envelope bbox) {
1270: String minx = String.valueOf(bbox.getMinX());
1271: String miny = String.valueOf(bbox.getMinY());
1272: String maxx = String.valueOf(bbox.getMaxX());
1273: String maxy = String.valueOf(bbox.getMaxY());
1274:
1275: AttributesImpl bboxAtts = new AttributesImpl();
1276: bboxAtts.addAttribute("", "minx", "minx", "", minx);
1277: bboxAtts.addAttribute("", "miny", "miny", "", miny);
1278: bboxAtts.addAttribute("", "maxx", "maxx", "", maxx);
1279: bboxAtts.addAttribute("", "maxy", "maxy", "", maxy);
1280:
1281: element("LatLonBoundingBox", null, bboxAtts);
1282: }
1283:
1284: /**
1285: * adds a comment to the output xml file. THIS IS A BIG HACK. TODO: do
1286: * this in the correct manner!
1287: *
1288: * @param comment
1289: */
1290: public void comment(String comment) {
1291: if (contentHandler instanceof TransformerIdentityImpl) // HACK HACK
1292: // HACK --
1293: // not sure
1294: // of the
1295: // proper
1296: // way to do
1297: // this.
1298: {
1299: try {
1300: TransformerIdentityImpl ch = (TransformerIdentityImpl) contentHandler;
1301: ch.comment(comment.toCharArray(), 0, comment
1302: .length());
1303: } catch (Exception e) {
1304: e.printStackTrace();
1305: }
1306: }
1307: }
1308:
1309: /**
1310: * Encodes a BoundingBox for the given Envelope.
1311: *
1312: * @param bbox
1313: */
1314: private void handleBBox(Envelope bbox, String SRS) {
1315: String minx = String.valueOf(bbox.getMinX());
1316: String miny = String.valueOf(bbox.getMinY());
1317: String maxx = String.valueOf(bbox.getMaxX());
1318: String maxy = String.valueOf(bbox.getMaxY());
1319:
1320: AttributesImpl bboxAtts = new AttributesImpl();
1321: bboxAtts.addAttribute("", "SRS", "SRS", "", SRS);
1322: bboxAtts.addAttribute("", "minx", "minx", "", minx);
1323: bboxAtts.addAttribute("", "miny", "miny", "", miny);
1324: bboxAtts.addAttribute("", "maxx", "maxx", "", maxx);
1325: bboxAtts.addAttribute("", "maxy", "maxy", "", maxy);
1326:
1327: element("BoundingBox", null, bboxAtts);
1328: }
1329: }
1330: }
1331:
1332: /**
1333: * A Class to manage the WMS Layer structure
1334: *
1335: * @author fabiania
1336: *
1337: * TODO To change the template for this generated type comment go to Window -
1338: * Preferences - Java - Code Style - Code Templates
1339: */
1340: class LayerTree {
1341: private String name;
1342: private Collection childrens;
1343: private Collection data;
1344:
1345: /**
1346: * @param name
1347: * String
1348: */
1349: public LayerTree(String name) {
1350: this .name = name;
1351: this .childrens = new ArrayList();
1352: this .data = new ArrayList();
1353: }
1354:
1355: /**
1356: * @param c
1357: * Collection
1358: */
1359: public LayerTree(Collection c) {
1360: this .name = "";
1361: this .childrens = new ArrayList();
1362: this .data = new ArrayList();
1363:
1364: for (Iterator it = c.iterator(); it.hasNext();) {
1365: Object element = it.next();
1366:
1367: if (element instanceof CoverageInfo) {
1368: CoverageInfo cLayer = (CoverageInfo) element;
1369:
1370: if (cLayer.isEnabled()) {
1371: String wmsPath = (((cLayer.getWmsPath() != null) && (cLayer
1372: .getWmsPath().length() > 0)) ? cLayer
1373: .getWmsPath() : "/");
1374:
1375: if (wmsPath.startsWith("/")) {
1376: wmsPath = wmsPath
1377: .substring(1, wmsPath.length());
1378: }
1379:
1380: String[] treeStructure = wmsPath.split("/");
1381: addToNode(this , treeStructure, cLayer);
1382: }
1383: } else if (element instanceof FeatureTypeInfo) {
1384: FeatureTypeInfo fLayer = (FeatureTypeInfo) element;
1385:
1386: if (fLayer.isEnabled()) {
1387: String wmsPath = (((fLayer.getWmsPath() != null) && (fLayer
1388: .getWmsPath().length() > 0)) ? fLayer
1389: .getWmsPath() : "/");
1390:
1391: if (wmsPath.startsWith("/")) {
1392: wmsPath = wmsPath
1393: .substring(1, wmsPath.length());
1394: }
1395:
1396: String[] treeStructure = wmsPath.split("/");
1397: addToNode(this , treeStructure, fLayer);
1398: }
1399: }
1400: }
1401: }
1402:
1403: /**
1404: * @param tree
1405: * @param treeStructure
1406: * @param layer
1407: */
1408: private void addToNode(LayerTree tree, String[] treeStructure,
1409: CoverageInfo layer) {
1410: final int length = treeStructure.length;
1411:
1412: if ((length == 0) || (treeStructure[0].length() == 0)) {
1413: tree.data.add(layer);
1414: } else {
1415: LayerTree node = tree.getNode(treeStructure[0]);
1416:
1417: if (node == null) {
1418: node = new LayerTree(treeStructure[0]);
1419: tree.childrens.add(node);
1420: }
1421:
1422: String[] subTreeStructure = new String[length - 1];
1423: System.arraycopy(treeStructure, 1, subTreeStructure, 0,
1424: length - 1);
1425: addToNode(node, subTreeStructure, layer);
1426: }
1427: }
1428:
1429: private void addToNode(LayerTree tree, String[] treeStructure,
1430: FeatureTypeInfo layer) {
1431: final int length = treeStructure.length;
1432:
1433: if ((length == 0) || (treeStructure[0].length() == 0)) {
1434: tree.data.add(layer);
1435: } else {
1436: LayerTree node = tree.getNode(treeStructure[0]);
1437:
1438: if (node == null) {
1439: node = new LayerTree(treeStructure[0]);
1440: tree.childrens.add(node);
1441: }
1442:
1443: String[] subTreeStructure = new String[length - 1];
1444: System.arraycopy(treeStructure, 1, subTreeStructure, 0,
1445: length - 1);
1446: addToNode(node, subTreeStructure, layer);
1447: }
1448: }
1449:
1450: /**
1451: * @param string
1452: * @return
1453: */
1454: public LayerTree getNode(String name) {
1455: LayerTree node = null;
1456:
1457: for (Iterator it = this .childrens.iterator(); it.hasNext();) {
1458: LayerTree tmpNode = (LayerTree) it.next();
1459:
1460: if (tmpNode.name.equals(name)) {
1461: node = tmpNode;
1462: }
1463: }
1464:
1465: return node;
1466: }
1467:
1468: public Collection getChildrens() {
1469: return childrens;
1470: }
1471:
1472: public Collection getData() {
1473: return data;
1474: }
1475:
1476: public String getName() {
1477: return name;
1478: }
1479: }
|