001: /* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
002: * This code is licensed under the GPL 2.0 license, availible at the root
003: * application directory.
004: */
005: package org.geoserver.wfs.xml;
006:
007: import net.opengis.wfs.FeatureCollectionType;
008: import net.opengis.wfs.GetFeatureType;
009: import net.opengis.wfs.QueryType;
010:
011: import org.geoserver.ows.util.OwsUtils;
012: import org.geoserver.ows.util.RequestUtils;
013: import org.geoserver.ows.util.ResponseUtils;
014: import org.geoserver.platform.Operation;
015: import org.geoserver.platform.ServiceException;
016: import org.geoserver.wfs.WFS;
017: import org.geoserver.wfs.WFSGetFeatureOutputFormat;
018: import org.geotools.feature.FeatureCollection;
019: import org.geotools.feature.FeatureType;
020: import org.geotools.gml.producer.FeatureTransformer;
021: import org.geotools.gml.producer.FeatureTransformer.FeatureTypeNamespaces;
022: import org.geotools.gml2.bindings.GML2EncodingUtils;
023: import org.geotools.referencing.CRS;
024: import org.opengis.referencing.crs.CoordinateReferenceSystem;
025: import org.vfny.geoserver.global.Data;
026: import org.vfny.geoserver.global.FeatureTypeInfo;
027: import org.vfny.geoserver.global.GeoServer;
028: import java.io.IOException;
029: import java.io.OutputStream;
030: import java.util.Arrays;
031: import java.util.HashMap;
032: import java.util.HashSet;
033: import java.util.Iterator;
034: import java.util.List;
035: import java.util.Map;
036: import java.util.Set;
037: import java.util.logging.Level;
038: import java.util.zip.GZIPOutputStream;
039: import javax.xml.transform.TransformerException;
040:
041: /**
042: * Encodes features in Geographic Markup Language (GML) version 2.
043: *
044: * <p>
045: * GML2-GZIP format is just GML2 with gzip compression. If GML2-GZIP format was
046: * requested, <code>getContentEncoding()</code> will retutn
047: * <code>"gzip"</code>, otherwise will return <code>null</code>
048: * </p>
049: *
050: * @author Gabriel Rold?n
051: * @version $Id: GML2OutputFormat.java 7680 2007-10-29 18:16:31Z aaime $
052: */
053: public class GML2OutputFormat extends WFSGetFeatureOutputFormat {
054: private static final int NO_FORMATTING = -1;
055: private static final int INDENT_SIZE = 2;
056: public static final String formatName = "GML2";
057: public static final String formatNameCompressed = "GML2-GZIP";
058:
059: /**
060: * This is a "magic" class provided by Geotools that writes out GML for an
061: * array of FeatureResults.
062: *
063: * <p>
064: * This class seems to do all the work, if you have a problem with GML you
065: * will need to hunt it down. We supply all of the header information in
066: * the execute method, and work through the featureList in the writeTo
067: * method.
068: * </p>
069: *
070: * <p>
071: * This value will be <code>null</code> until execute is called.
072: * </p>
073: */
074: private FeatureTransformer transformer;
075:
076: /** will be true if GML2-GZIP output format was requested */
077: private boolean compressOutput = false;
078:
079: /**
080: * WFS configuration
081: */
082: private WFS wfs;
083:
084: /**
085: * GeoServer configuration
086: */
087: private GeoServer geoServer;
088:
089: /**
090: * The catalog
091: */
092: protected Data catalog;
093:
094: /**
095: * Creates the producer with a reference to the GetFeature operation
096: * using it.
097: */
098: public GML2OutputFormat(WFS wfs, GeoServer geoServer, Data catalog) {
099: super (new HashSet(Arrays.asList(new String[] { "GML2",
100: "text/xml; subtype=gml/2.1.2", "GML2-GZIP" })));
101:
102: this .wfs = wfs;
103: this .geoServer = geoServer;
104: this .catalog = catalog;
105: }
106:
107: public String getCapabilitiesElementName() {
108: return "GML2";
109: }
110:
111: /**
112: * prepares for encoding into GML2 format, optionally compressing its
113: * output in gzip, if outputFormat is equal to GML2-GZIP
114: *
115: * @param outputFormat DOCUMENT ME!
116: * @param results DOCUMENT ME!
117: *
118: * @throws IOException DOCUMENT ME!
119: */
120: public void prepare(String outputFormat,
121: FeatureCollectionType results, GetFeatureType request)
122: throws IOException {
123: this .compressOutput = formatNameCompressed
124: .equalsIgnoreCase(outputFormat);
125:
126: transformer = createTransformer();
127:
128: FeatureTypeNamespaces ftNames = transformer
129: .getFeatureTypeNamespaces();
130: Map ftNamespaces = new HashMap();
131:
132: //TODO: the srs is a back, it only will work property when there is
133: // one type, we really need to set it on the feature level
134: int srs = -1;
135: for (int i = 0; i < results.getFeature().size(); i++) {
136: //FeatureResults features = (FeatureResults) f.next();
137: FeatureCollection features = (FeatureCollection) results
138: .getFeature().get(i);
139: FeatureType featureType = features.getSchema();
140:
141: FeatureTypeInfo meta = catalog.getFeatureTypeInfo(
142: featureType.getTypeName(), featureType
143: .getNamespace().toString());
144:
145: String prefix = meta.getNameSpace().getPrefix();
146: String uri = meta.getNameSpace().getURI();
147:
148: ftNames.declareNamespace(features.getSchema(), prefix, uri);
149:
150: if (ftNamespaces.containsKey(uri)) {
151: String location = (String) ftNamespaces.get(uri);
152: ftNamespaces.put(uri, location + "," + meta.getName());
153: } else {
154: String location = typeSchemaLocation(wfs, meta, request
155: .getBaseUrl());
156: ftNamespaces.put(uri, location);
157: }
158:
159: //JD: wfs reprojection: should not set srs form metadata but from
160: // the request
161: //srs = Integer.parseInt(meta.getSRS());
162: QueryType query = (QueryType) request.getQuery().get(i);
163: try {
164: if (query.getSrsName() != null) {
165: CoordinateReferenceSystem crs = CRS.decode(query
166: .getSrsName().toString());
167: String epsgCode = GML2EncodingUtils.epsgCode(crs);
168: srs = Integer.parseInt(epsgCode);
169: } else {
170: //no SRS in query...asking for the default?
171: srs = Integer.parseInt(meta.getSRS());
172: }
173: } catch (Exception e) {
174: LOGGER.log(Level.WARNING, "Problem encoding:"
175: + query.getSrsName(), e);
176:
177: }
178: }
179:
180: System.setProperty("javax.xml.transform.TransformerFactory",
181: "org.apache.xalan.processor.TransformerFactoryImpl");
182:
183: transformer.setIndentation(wfs.isVerbose() ? INDENT_SIZE
184: : (NO_FORMATTING));
185: transformer.setNumDecimals(geoServer.getNumDecimals());
186: transformer.setFeatureBounding(wfs.isFeatureBounding());
187: transformer.setEncoding(wfs.getCharSet());
188:
189: String wfsSchemaloc = wfsSchemaLocation(wfs, request
190: .getBaseUrl());
191: transformer.addSchemaLocation("http://www.opengis.net/wfs",
192: wfsSchemaloc);
193:
194: for (Iterator it = ftNamespaces.keySet().iterator(); it
195: .hasNext();) {
196: String uri = (String) it.next();
197: transformer.addSchemaLocation(uri, (String) ftNamespaces
198: .get(uri));
199: }
200:
201: transformer.setGmlPrefixing(wfs.getCiteConformanceHacks());
202:
203: if (results.getLockId() != null) {
204: transformer.setLockId(results.getLockId());
205: }
206:
207: if (srs != -1) {
208: transformer.setSrsName(wfs.getSrsPrefix() + srs);
209: }
210: }
211:
212: /**
213: * DOCUMENT ME!
214: *
215: * @return DOCUMENT ME!
216: */
217: public String getContentEncoding() {
218: return compressOutput ? "gzip" : null;
219: }
220:
221: /**
222: * DOCUMENT ME!
223: *
224: * @param output DOCUMENT ME!
225: *
226: * @throws ServiceException DOCUMENT ME!
227: * @throws IOException DOCUMENT ME!
228: * @throws IllegalStateException DOCUMENT ME!
229: */
230: public void encode(OutputStream output,
231: FeatureCollectionType results, GetFeatureType request)
232: throws ServiceException, IOException {
233: if (results == null) {
234: throw new IllegalStateException(
235: "It seems prepare() has not been called"
236: + " or has not succeed");
237: }
238:
239: GZIPOutputStream gzipOut = null;
240:
241: if (compressOutput) {
242: gzipOut = new GZIPOutputStream(output);
243: output = gzipOut;
244: }
245:
246: // execute should of set all the header information
247: // including the lockID
248: //
249: // execute should also fail if all of the locks could not be aquired
250: List resultsList = results.getFeature();
251: FeatureCollection[] featureResults = (FeatureCollection[]) resultsList
252: .toArray(new FeatureCollection[resultsList.size()]);
253:
254: try {
255: transformer.transform(featureResults, output);
256:
257: //we need to "finish" here because if not,it is possible that the gzipped
258: //content do not gets completely written
259: if (gzipOut != null) {
260: gzipOut.finish();
261: gzipOut.flush();
262: }
263: } catch (TransformerException gmlException) {
264: String msg = " error:" + gmlException.getMessage();
265: throw new ServiceException(msg, gmlException);
266: }
267: }
268:
269: protected void write(FeatureCollectionType featureCollection,
270: OutputStream output, Operation getFeature)
271: throws IOException, ServiceException {
272: GetFeatureType request = (GetFeatureType) getFeature
273: .getParameters()[0];
274:
275: prepare(request.getOutputFormat(), featureCollection, request);
276: encode(output, featureCollection, request);
277: }
278:
279: protected FeatureTransformer createTransformer() {
280: return new FeatureTransformer();
281: }
282:
283: protected String wfsSchemaLocation(WFS wfs, String baseUrl) {
284: return ResponseUtils.appendPath(RequestUtils.proxifiedBaseURL(
285: baseUrl, wfs.getGeoServer().getProxyBaseUrl()),
286: "schemas/wfs/1.0.0/WFS-basic.xsd");
287: }
288:
289: protected String typeSchemaLocation(WFS wfs, FeatureTypeInfo meta,
290: String baseUrl) {
291: final String proxifiedBase = RequestUtils.proxifiedBaseURL(
292: baseUrl, wfs.getGeoServer().getProxyBaseUrl());
293: return ResponseUtils.appendQueryString(proxifiedBase + "wfs",
294: "service=WFS&version=1.0.0&request=DescribeFeatureType&typeName="
295: + meta.getName());
296: }
297: }
|