    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    }