001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/tools/wms/WFS2WMS.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001-2008 by:
006     EXSE, Department of Geography, University of Bonn
007     http://www.giub.uni-bonn.de/deegree/
008     lat/lon GmbH
009     http://www.lat-lon.de
010    
011     This library is free software; you can redistribute it and/or
012     modify it under the terms of the GNU Lesser General Public
013     License as published by the Free Software Foundation; either
014     version 2.1 of the License, or (at your option) any later version.
015    
016     This library is distributed in the hope that it will be useful,
017     but WITHOUT ANY WARRANTY; without even the implied warranty of
018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
019     Lesser General Public License for more details.
020    
021     You should have received a copy of the GNU Lesser General Public
022     License along with this library; if not, write to the Free Software
023     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
024    
025     Contact:
026    
027     Andreas Poth
028     lat/lon GmbH
029     Aennchenstr. 19
030     53177 Bonn
031     Germany
032     E-Mail: poth@lat-lon.de
033    
034     Prof. Dr. Klaus Greve
035     Department of Geography
036     University of Bonn
037     Meckenheimer Allee 166
038     53115 Bonn
039     Germany
040     E-Mail: greve@giub.uni-bonn.de
041    
042     ---------------------------------------------------------------------------*/
043    package org.deegree.tools.wms;
044    
045    import java.io.File;
046    import java.io.FileOutputStream;
047    import java.net.URL;
048    import java.util.ArrayList;
049    import java.util.HashMap;
050    import java.util.List;
051    import java.util.Map;
052    import java.util.Properties;
053    
054    import org.deegree.datatypes.QualifiedName;
055    import org.deegree.framework.log.ILogger;
056    import org.deegree.framework.log.LoggerFactory;
057    import org.deegree.framework.util.ColorUtils;
058    import org.deegree.framework.xml.NamespaceContext;
059    import org.deegree.framework.xml.XMLFragment;
060    import org.deegree.framework.xml.XMLParsingException;
061    import org.deegree.framework.xml.XMLTools;
062    import org.deegree.framework.xml.XSLTDocument;
063    import org.deegree.graphics.sld.AbstractLayer;
064    import org.deegree.graphics.sld.NamedLayer;
065    import org.deegree.graphics.sld.StyleFactory;
066    import org.deegree.graphics.sld.StyledLayerDescriptor;
067    import org.deegree.graphics.sld.UserStyle;
068    import org.deegree.ogcbase.CommonNamespaces;
069    import org.deegree.ogcwebservices.getcapabilities.InvalidCapabilitiesException;
070    import org.deegree.ogcwebservices.wfs.capabilities.WFSCapabilities;
071    import org.deegree.ogcwebservices.wfs.capabilities.WFSCapabilitiesDocument;
072    import org.deegree.ogcwebservices.wfs.capabilities.WFSFeatureType;
073    import org.w3c.dom.Node;
074    
075    /**
076     * creates a deegree WMS configuration document or a Layer section from a WFS capabilities document.
077     * The datasource type for each layer will be LOCALWFS. Also a style with random color(s) will be
078     * created, assigned to the layers and stored in a xml document named $OUTFILE_BASE$_styles.xml.
079     * TODO support for usage of an already existing WMS configuration document TODO determine geometry
080     * types of the feature types registered within the wfs capabilities document
081     * 
082     * 
083     * @version $Revision: 9346 $
084     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
085     * @author last edited by: $Author: apoth $
086     * 
087     * @version 1.0. $Revision: 9346 $, $Date: 2007-12-27 17:39:07 +0100 (Do, 27 Dez 2007) $
088     * 
089     * @since 2.0
090     */
091    public class WFS2WMS {
092    
093        private static NamespaceContext nsc = CommonNamespaces.getNamespaceContext();
094    
095        private ILogger LOG = LoggerFactory.getLogger( WFS2WMS.class );
096    
097        private URL xsl = WFS2WMS.class.getResource( "wfs2wms.xsl" );
098    
099        private Properties prop = null;
100    
101        public WFS2WMS( Properties prop ) {
102            this.prop = prop;
103        }
104    
105        public static double getMinX( Node node ) {
106            double v = -180;
107            try {
108                String s = XMLTools.getNodeAsString( node, ".", nsc, "-180 -90" );
109                String[] t = s.split( " " );
110                v = Double.parseDouble( t[0] );
111            } catch ( XMLParsingException e ) {
112                e.printStackTrace();
113            }
114            return v;
115        }
116    
117        public static double getMinY( Node node ) {
118            double v = -90;
119            try {
120                String s = XMLTools.getNodeAsString( node, ".", nsc, "-180 -90" );
121                String[] t = s.split( " " );
122                v = Double.parseDouble( t[1] );
123            } catch ( XMLParsingException e ) {
124                e.printStackTrace();
125            }
126            return v;
127        }
128    
129        public static double getMaxX( Node node ) {
130            double v = 180;
131            try {
132                String s = XMLTools.getNodeAsString( node, ".", nsc, "180 90" );
133                String[] t = s.split( " " );
134                v = Double.parseDouble( t[0] );
135            } catch ( XMLParsingException e ) {
136                e.printStackTrace();
137            }
138            return v;
139        }
140    
141        public static double getMaxY( Node node ) {
142            double v = 90;
143            try {
144                String s = XMLTools.getNodeAsString( node, ".", nsc, "180 90" );
145                String[] t = s.split( " " );
146                v = Double.parseDouble( t[1] );
147            } catch ( XMLParsingException e ) {
148                e.printStackTrace();
149            }
150            return v;
151        }
152    
153        /**
154         * append all required namespace definition to the root element
155         * 
156         * @param xml
157         * @return
158         * @throws InvalidCapabilitiesException
159         */
160        private XMLFragment addNamespaces( XMLFragment wms, WFSCapabilities capa ) {
161            WFSFeatureType[] fts = capa.getFeatureTypeList().getFeatureTypes();
162            for ( int i = 0; i < fts.length; i++ ) {
163                QualifiedName qn = fts[i].getName();
164                XMLTools.appendNSBinding( wms.getRootElement(), qn.getPrefix(), qn.getNamespace() );
165            }
166            return wms;
167        }
168    
169        /**
170         * creates a style for each feature type registered in a WFS capabilities document
171         * 
172         * @param wfs
173         * @return
174         */
175        private List<UserStyle> createStyles( WFSCapabilities capa ) {
176            List<UserStyle> styles = new ArrayList<UserStyle>();
177            Map<QualifiedName, Integer> types = determineGeometryType( capa );
178    
179            WFSFeatureType[] fts = capa.getFeatureTypeList().getFeatureTypes();
180    
181            UserStyle st = null;
182            for ( int i = 0; i < fts.length; i++ ) {
183                QualifiedName qn = fts[i].getName();
184                int type = types.get( qn );
185                switch ( type ) {
186                case 1: {
187                    st = (UserStyle) StyleFactory.createPointStyle( "square", ColorUtils.getRandomColor( false ),
188                                                                    ColorUtils.getRandomColor( false ), 1, 1, 10, 10, 0,
189                                                                    Double.MAX_VALUE );
190                    break;
191                }
192                case 2: {
193                    st = (UserStyle) StyleFactory.createLineStyle( ColorUtils.getRandomColor( false ), 4, 1, 0,
194                                                                   Double.MAX_VALUE );
195                    break;
196                }
197    
198                case 3: {
199                    st = (UserStyle) StyleFactory.createPolygonStyle( ColorUtils.getRandomColor( false ), 1,
200                                                                      ColorUtils.getRandomColor( false ), 1, 1, 0,
201                                                                      Double.MAX_VALUE );
202                    break;
203                }
204                }
205                st.setName( "default:" + qn.getPrefixedName() );
206                styles.add( st );
207            }
208    
209            return styles;
210        }
211    
212        /**
213         * 
214         * @param styles
215         * @return
216         */
217        private StyledLayerDescriptor createSLD( List<UserStyle> styles ) {
218    
219            UserStyle[] us = styles.toArray( new UserStyle[styles.size()] );
220            NamedLayer nl = new NamedLayer( "defaultstyle", null, us );
221            return new StyledLayerDescriptor( new AbstractLayer[] { nl }, "1.0.0" );
222    
223        }
224    
225        /**
226         * returns the geometrytype of each feature type registered within the passed WFS capabilities
227         * document<br>
228         * <ul>
229         * <li>1 = point or multi point
230         * <li>2 = curve or multi curve
231         * <li>3 = surface or multi surface
232         * </ul>
233         * 
234         * @param capa
235         * @return
236         */
237        private Map<QualifiedName, Integer> determineGeometryType( WFSCapabilities capa ) {
238    
239            Map<QualifiedName, Integer> types = new HashMap<QualifiedName, Integer>();
240    
241            WFSFeatureType[] fts = capa.getFeatureTypeList().getFeatureTypes();
242            for ( int i = 0; i < fts.length; i++ ) {
243                QualifiedName qn = fts[i].getName();
244                // TODO
245                // get real geometry type
246                types.put( qn, 3 );
247            }
248    
249            return types;
250        }
251    
252        /**
253         * method the starts running the conversation
254         * 
255         * @throws Exception
256         */
257        public void run()
258                                throws Exception {
259    
260            String out = prop.getProperty( "-outFile" );
261            File file = new File( out );
262            int pos = file.getName().lastIndexOf( '.' );
263            String styleDoc = file.getName().substring( 0, pos ) + "_styles.xml";
264    
265            HashMap<String, String> param = new HashMap<String, String>();
266            param.put( "PARENTLAYER", prop.getProperty( "-parentLayer" ) );
267            param.put( "MINX", prop.getProperty( "-minx" ) );
268            param.put( "MINY", prop.getProperty( "-miny" ) );
269            param.put( "MAXX", prop.getProperty( "-maxx" ) );
270            param.put( "MAXY", prop.getProperty( "-maxy" ) );
271            param.put( "SRS", prop.getProperty( "-srs" ) );
272            if ( "true".equals( prop.getProperty( "-full" ) ) ) {
273                param.put( "WMSCAPS", "1" );
274            }
275            param.put( "STYLEDOC", styleDoc );
276    
277            LOG.logInfo( "XSLT-parameter: ", param );
278    
279            XSLTDocument outXSLSheet = new XSLTDocument();
280            outXSLSheet.load( xsl );
281    
282            file = new File( prop.getProperty( "-wfsCaps" ) );
283            param.put( "WFSCAPS", file.toURL().toExternalForm() );
284            XMLFragment doc = new XMLFragment();
285            doc.load( file.toURL() );
286    
287            XMLFragment resultDocument = outXSLSheet.transform( doc, null, null, param );
288    
289            WFSCapabilitiesDocument wfsdoc = new WFSCapabilitiesDocument();
290            wfsdoc.setRootElement( doc.getRootElement() );
291            WFSCapabilities capa = (WFSCapabilities) wfsdoc.parseCapabilities();
292    
293            resultDocument = addNamespaces( resultDocument, capa );
294    
295            List<UserStyle> styles = createStyles( capa );
296            StyledLayerDescriptor sld = createSLD( styles );
297    
298            String s = prop.getProperty( "-outFile" ).replace( ".xml", "_styles.xml" );
299            file = new File( s );
300            FileOutputStream fos = new FileOutputStream( file );
301            fos.write( sld.exportAsXML().getBytes() );
302            fos.close();
303    
304            file = new File( prop.getProperty( "-outFile" ) );
305            fos = new FileOutputStream( file );
306            resultDocument.write( fos );
307            fos.close();
308        }
309    
310        private static void validate( Properties map )
311                                throws Exception {
312            if ( map.get( "-parentLayer" ) == null ) {
313                throw new Exception( Messages.getString( "WFS2WMS.validate_2" ) );
314            }
315            if ( map.get( "-minx" ) != null ) {
316                Double.parseDouble( map.getProperty( "-minx" ) );
317            } else {
318                map.put( "-minx", "-180" );
319            }
320            if ( map.get( "-miny" ) != null ) {
321                Double.parseDouble( map.getProperty( "-miny" ) );
322            } else {
323                map.put( "-miny", "-90" );
324            }
325            if ( map.get( "-maxx" ) != null ) {
326                Double.parseDouble( map.getProperty( "-maxx" ) );
327            } else {
328                map.put( "-maxx", "180" );
329            }
330            if ( map.get( "-maxy" ) != null ) {
331                Double.parseDouble( map.getProperty( "-maxy" ) );
332            } else {
333                map.put( "-maxy", "90" );
334            }
335            if ( map.get( "-srs" ) == null ) {
336                map.put( "-srs", "EPSG:4326" );
337            }
338            if ( map.get( "-wfsCaps" ) == null ) {
339                throw new Exception( Messages.getString( "WFS2WMS.validate_0" ) );
340            }
341            if ( map.get( "-outFile" ) == null ) {
342                throw new Exception( Messages.getString( "WFS2WMS.validate_1" ) );
343            }
344        }
345    
346        /**
347         * @param args
348         */
349        public static void main( String[] args )
350                                throws Exception {
351    
352            Properties map = new Properties();
353            for ( int i = 0; i < args.length; i += 2 ) {
354                System.out.println( args[i + 1] );
355                map.put( args[i], args[i + 1] );
356            }
357    
358            try {
359                validate( map );
360            } catch ( Exception e ) {
361                System.out.println( "!!! E R R O R !!!" );
362                System.out.println( e.getMessage() );
363                System.out.println( "----------------------------------------------------" );
364                System.out.println( Messages.getString( "WFS2WMS.parentLayer" ) );
365                System.out.println( Messages.getString( "WFS2WMS.wfsCaps" ) );
366                System.out.println( Messages.getString( "WFS2WMS.outFile" ) );
367                return;
368            }
369    
370            WFS2WMS wfs2wms = new WFS2WMS( map );
371            wfs2wms.run();
372    
373        }
374    
375    }