001 // $HeadURL: /cvsroot/deegree/src/org/deegree/ogcwebservices/wms/WMPService.java,v
002 // 1.3 2004/07/12 06:12:11 ap Exp $
003 /*----------------------------------------------------------------------------
004 This file is part of deegree, http://deegree.org/
005 Copyright (C) 2001-2009 by:
006 Department of Geography, University of Bonn
007 and
008 lat/lon GmbH
009
010 This library is free software; you can redistribute it and/or modify it under
011 the terms of the GNU Lesser General Public License as published by the Free
012 Software Foundation; either version 2.1 of the License, or (at your option)
013 any later version.
014 This library is distributed in the hope that it will be useful, but WITHOUT
015 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
016 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
017 details.
018 You should have received a copy of the GNU Lesser General Public License
019 along with this library; if not, write to the Free Software Foundation, Inc.,
020 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
021
022 Contact information:
023
024 lat/lon GmbH
025 Aennchenstr. 19, 53177 Bonn
026 Germany
027 http://lat-lon.de/
028
029 Department of Geography, University of Bonn
030 Prof. Dr. Klaus Greve
031 Postfach 1147, 53001 Bonn
032 Germany
033 http://www.geographie.uni-bonn.de/deegree/
034
035 e-mail: info@deegree.org
036 ----------------------------------------------------------------------------*/
037 package org.deegree.ogcwebservices.wmps;
038
039 import java.awt.Dimension;
040 import java.io.File;
041 import java.io.FileFilter;
042 import java.lang.reflect.Constructor;
043 import java.net.URI;
044 import java.util.ArrayList;
045 import java.util.List;
046
047 import org.deegree.enterprise.Proxy;
048 import org.deegree.framework.log.ILogger;
049 import org.deegree.framework.log.LoggerFactory;
050 import org.deegree.framework.trigger.TriggerProvider;
051 import org.deegree.framework.util.Pair;
052 import org.deegree.framework.xml.NamespaceContext;
053 import org.deegree.framework.xml.XMLFragment;
054 import org.deegree.framework.xml.XMLParsingException;
055 import org.deegree.framework.xml.XMLTools;
056 import org.deegree.i18n.Messages;
057 import org.deegree.ogcbase.CommonNamespaces;
058 import org.deegree.ogcwebservices.CurrentUpdateSequenceException;
059 import org.deegree.ogcwebservices.InvalidUpdateSequenceException;
060 import org.deegree.ogcwebservices.OGCWebService;
061 import org.deegree.ogcwebservices.OGCWebServiceException;
062 import org.deegree.ogcwebservices.OGCWebServiceRequest;
063 import org.deegree.ogcwebservices.getcapabilities.OGCCapabilities;
064 import org.deegree.ogcwebservices.wmps.configuration.WMPSConfiguration;
065 import org.deegree.ogcwebservices.wmps.configuration.WMPSDeegreeParams;
066 import org.deegree.ogcwebservices.wmps.operation.DescribeTemplate;
067 import org.deegree.ogcwebservices.wmps.operation.DescribeTemplateResponse;
068 import org.deegree.ogcwebservices.wmps.operation.GetAvailableTemplates;
069 import org.deegree.ogcwebservices.wmps.operation.GetAvailableTemplatesResponse;
070 import org.deegree.ogcwebservices.wmps.operation.PrintMap;
071 import org.deegree.ogcwebservices.wmps.operation.WMPSGetCapabilities;
072 import org.deegree.ogcwebservices.wmps.operation.WMPSGetCapabilitiesResult;
073 import org.deegree.ogcwebservices.wmps.operation.WMPSProtocolFactory;
074 import org.w3c.dom.Element;
075 import org.w3c.dom.Node;
076
077 /**
078 * Handles saving the PrintMap request to the databank and generating the initial response to be sent to the user.
079 *
080 * @author <a href="mailto:deshmukh@lat-lon.de">Anup Deshmukh</a>
081 * @version 2.0
082 */
083 public class WMPService implements OGCWebService {
084
085 private static final ILogger LOG = LoggerFactory.getLogger( WMPService.class );
086
087 private static final TriggerProvider TP = TriggerProvider.create( WMPService.class );
088
089 private PrintMapHandler printMapHandler;
090
091 private WMPSConfiguration configuration;
092
093 /**
094 * Creates a new WMPService object.
095 *
096 * @param configuration
097 */
098 public WMPService( WMPSConfiguration configuration ) {
099 this.configuration = configuration;
100 this.printMapHandler = new PrintMapHandler( configuration );
101 Proxy proxy = this.configuration.getDeegreeParams().getProxy();
102 if ( proxy != null ) {
103 proxy.setProxy( true );
104 }
105 }
106
107 /**
108 * Return the OGCCapabilities.
109 *
110 * @return OGCCapabilities
111 */
112 public OGCCapabilities getCapabilities() {
113 return this.configuration;
114 }
115
116 /**
117 * the method performs the handling of the passed OGCWebServiceEvent directly and returns the result to the calling
118 * class/method
119 *
120 * @param request
121 * request to perform
122 * @return Object
123 * @throws OGCWebServiceException
124 */
125 public Object doService( OGCWebServiceRequest request )
126 throws OGCWebServiceException {
127
128 request = (OGCWebServiceRequest) TP.doPreTrigger( this, request )[0];
129
130 Object result = null;
131 if ( request instanceof PrintMap ) {
132 result = handlePrintMap( request );
133 } else if ( request instanceof GetAvailableTemplates ) {
134 result = handleGetAvailableTemplates();
135 } else if ( request instanceof WMPSGetCapabilities ) {
136 result = handleGetCapabilities( (WMPSGetCapabilities) request );
137 } else if ( request instanceof DescribeTemplate ) {
138 result = handleDescribeTemplate( (DescribeTemplate) request );
139 }
140
141 return TP.doPostTrigger( this, result )[0];
142 }
143
144 /**
145 * @param request
146 * @return
147 * @throws OGCWebServiceException
148 */
149 private Object handleDescribeTemplate( DescribeTemplate request )
150 throws OGCWebServiceException {
151
152 String template = request.getTemplate();
153 String dir = configuration.getDeegreeParams().getPrintMapParam().getTemplateDirectory();
154 dir = dir.substring( 5 );
155 DescribeTemplateResponse response = null;
156 try {
157 File file = new File( dir + "/" + template + ".jrxml" );
158 XMLFragment doc = new XMLFragment( file );
159 NamespaceContext nsc = CommonNamespaces.getNamespaceContext();
160 nsc.addNamespace( "jasper", URI.create( "http://jasperreports.sourceforge.net/jasperreports" ) );
161 // old jasper format
162 List<Element> tmp = XMLTools.getElements( doc.getRootElement(), "//parameter", null );
163 // current jasper format
164 List<Element> params = XMLTools.getElements( doc.getRootElement(), "//jasper:parameter", nsc );
165 for ( Element element : tmp ) {
166 params.add( element );
167 }
168 List<Pair<String, String>> parameter = new ArrayList<Pair<String, String>>();
169 for ( Element element : params ) {
170 String name = element.getAttribute( "name" );
171 String type = element.getAttribute( "class" );
172 if ( name.equals( "MAP" ) ) {
173 Dimension dim = parseImageNodes( doc.getRootElement() );
174 parameter.add( new Pair<String, String>( "$MAPWIDTH", Integer.toString( dim.width ) ) );
175 parameter.add( new Pair<String, String>( "$MAPHEIGHT", Integer.toString( dim.height ) ) );
176 continue;
177 } else if (name.equals( "LEGEND" ) ) {
178 continue;
179 }
180 parameter.add( new Pair<String, String>( name, type ) );
181 }
182 response = new DescribeTemplateResponse( parameter );
183 } catch ( Exception e ) {
184 throw new OGCWebServiceException( WMPService.class.getName(),
185 "can not perform DescribeTemplate operation for template: " + template
186 + "\n" + e.getMessage() );
187 }
188 try {
189 return XMLFactory.export( response );
190 } catch ( Exception e ) {
191 throw new OGCWebServiceException( "Error handling the GetAvailableTemplates request. " + e.getMessage() );
192 }
193 }
194
195 /**
196 *
197 * @param root
198 * @return map dimension in template
199 * @throws PrintMapServiceException
200 */
201 private Dimension parseImageNodes( Element root )
202 throws PrintMapServiceException {
203
204 Dimension dimension = null;
205 try {
206 NamespaceContext nsc = CommonNamespaces.getNamespaceContext();
207 nsc.addNamespace( "jasper", URI.create( "http://jasperreports.sourceforge.net/jasperreports" ) );
208 List<Node> images = XMLTools.getNodes( root, "detail/band/image", null );
209 if ( images == null || images.size() == 0 ) {
210 images = XMLTools.getNodes( root, "jasper:detail/jasper:band/jasper:image", nsc );
211 }
212 for ( int i = 0; i < images.size(); i++ ) {
213 Node image = images.get( i );
214 // e.g. $P{MAP}
215 String value = XMLTools.getNodeAsString( image, "imageExpression", null, null );
216 if ( value == null ) {
217 value = XMLTools.getRequiredNodeAsString( image, "jasper:imageExpression", nsc );
218 }
219 int idx = value.indexOf( "{" );
220 if ( idx != -1 ) {
221
222 String tmp = value.substring( idx + 1, value.length() - 1 );
223 Element reportElement = (Element) XMLTools.getNode( image, "reportElement", null );
224 if ( reportElement == null ) {
225 reportElement = (Element) XMLTools.getRequiredNode( image, "jasper:reportElement", nsc );
226 }
227
228 // Templates created by iReport assumes a resolution of 72 dpi
229 if ( tmp.startsWith( "MAP" ) ) {
230 String width = reportElement.getAttribute( "width" );
231 String height = reportElement.getAttribute( "height" );
232 dimension = new Dimension( Integer.parseInt( width ), Integer.parseInt( height ) );
233 }
234 }
235 }
236 } catch ( XMLParsingException e ) {
237 LOG.logError( e.getMessage(), e );
238 throw new PrintMapServiceException( Messages.getMessage( "WMPS_INVALID_JASPER_TEMPLATE" ) );
239 }
240
241 return dimension;
242 }
243
244 /**
245 * @return
246 * @throws OGCWebServiceException
247 */
248 private Object handleGetAvailableTemplates()
249 throws OGCWebServiceException {
250 String templateDir = configuration.getDeegreeParams().getPrintMapParam().getTemplateDirectory();
251 templateDir = templateDir.substring( 5 );
252 File dir = new File( templateDir );
253 File[] files = dir.listFiles( new FileFilter() {
254 public boolean accept( File pathname ) {
255 String s = pathname.getName().toLowerCase();
256 return s.endsWith( ".xml" ) || s.endsWith( ".jrxml" );
257 }
258 } );
259
260 List<String> list = new ArrayList<String>();
261 for ( File file : files ) {
262 String s = file.getName();
263 int pos = s.lastIndexOf( '.' );
264 list.add( s.substring( 0, pos ) );
265 }
266 GetAvailableTemplatesResponse resp = new GetAvailableTemplatesResponse( list );
267 try {
268 return XMLFactory.export( resp );
269 } catch ( Exception e ) {
270 throw new OGCWebServiceException( "Error handling the GetAvailableTemplates request. " + e.getMessage() );
271 }
272 }
273
274 private Object handlePrintMap( OGCWebServiceRequest request )
275 throws OGCWebServiceException {
276 Object result;
277 String template = ( (PrintMap) request ).getTemplate();
278 WMPSDeegreeParams params = this.configuration.getDeegreeParams();
279 boolean isSynchronous = params.getSynchronousTemplates().contains( template );
280
281 String handler = HandlerMapping.getString( "WMPService.PRINTMAP" );
282 RequestManager rqManager = (RequestManager) createHandler( request, PrintMap.class, handler );
283
284 try {
285 rqManager.saveRequestToDB();
286
287 result = rqManager.createInitialResponse( Messages.getMessage( "WMPS_INIT_RESPONSE" ) );
288 } catch ( OGCWebServiceException e ) {
289
290 throw new OGCWebServiceException( "Error saving the PrintMap request " + "to the DB. " + e.getMessage() );
291 }
292
293 try {
294 if ( isSynchronous ) {
295 result = this.printMapHandler.runSynchronous( (PrintMap) request );
296 } else {
297 Thread printMap = new Thread( this.printMapHandler );
298 printMap.start();
299 }
300 } catch ( Exception e ) {
301 LOG.logError( e.getMessage(), e );
302 throw new OGCWebServiceException( "Error performing the PrintMap request. " + e.getMessage() );
303 }
304 return result;
305 }
306
307 /**
308 * creates a handler class for performing the incomming request. The instance that will be created depends on the
309 * responsible class the for the submitted request in the WMPS capabilities/configuration.
310 *
311 * @param request
312 * request to be performed
313 * @param requestClass
314 * of the request (GetStyles, WMSFeatureInfoRequest etc.)
315 * @param className
316 * type of the operation to perform by the handler
317 * @return Object
318 * @throws OGCWebServiceException
319 */
320 private Object createHandler( OGCWebServiceRequest request, Class<?> requestClass, String className )
321 throws OGCWebServiceException {
322
323 // describes the signature of the required constructor
324 Class<?>[] cl = new Class[2];
325 cl[0] = WMPSConfiguration.class;
326 cl[1] = requestClass;
327
328 // set parameter to submitt to the constructor
329 Object[] o = new Object[2];
330 o[0] = this.configuration;
331 o[1] = request;
332
333 Object handler = null;
334
335 try {
336 // get constructor
337 Class<?> creator = Class.forName( className );
338 Constructor<?> con = creator.getConstructor( cl );
339 // call constructor and instantiate a new DataStore
340 handler = con.newInstance( o );
341 } catch ( Exception e ) {
342 LOG.logError( e.getMessage(), e );
343 throw new OGCWebServiceException( "Couldn't instantiate " + className + '!' );
344 }
345
346 return handler;
347 }
348
349 /**
350 * reads/creates the capabilities of the WMPS.
351 *
352 * @param request
353 * capabilities request
354 * @return WMPSGetCapabilitiesResult
355 * @throws CurrentUpdateSequenceException
356 * @throws InvalidUpdateSequenceException
357 */
358 private WMPSGetCapabilitiesResult handleGetCapabilities( WMPSGetCapabilities request )
359 throws CurrentUpdateSequenceException, InvalidUpdateSequenceException {
360
361 String rUp = request.getUpdateSequence();
362 String cUp = this.configuration.getUpdateSequence();
363
364 if ( ( rUp != null ) && ( cUp != null ) && ( rUp.compareTo( cUp ) == 0 ) ) {
365 throw new CurrentUpdateSequenceException( "request update sequence: " + rUp + "is equal to capabilities"
366 + " update sequence " + cUp );
367 }
368
369 if ( ( rUp != null ) && ( cUp != null ) && ( rUp.compareTo( cUp ) > 0 ) ) {
370 throw new InvalidUpdateSequenceException( "request update sequence: " + rUp + " is higher then the "
371 + "capabilities update sequence " + cUp );
372 }
373 return WMPSProtocolFactory.createGetCapabilitiesResult( request, null, this.configuration );
374 }
375
376 }