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 }