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    }