001    //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_testing/src/org/deegree/tools/wms/MapServer2DeegreeWMS.java $
002    /*----------------------------------------------------------------------------
003     This file is part of deegree, http://deegree.org/
004     Copyright (C) 2001-2009 by:
005       Department of Geography, University of Bonn
006     and
007       lat/lon GmbH
008    
009     This library is free software; you can redistribute it and/or modify it under
010     the terms of the GNU Lesser General Public License as published by the Free
011     Software Foundation; either version 2.1 of the License, or (at your option)
012     any later version.
013     This library is distributed in the hope that it will be useful, but WITHOUT
014     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
015     FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
016     details.
017     You should have received a copy of the GNU Lesser General Public License
018     along with this library; if not, write to the Free Software Foundation, Inc.,
019     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020    
021     Contact information:
022    
023     lat/lon GmbH
024     Aennchenstr. 19, 53177 Bonn
025     Germany
026     http://lat-lon.de/
027    
028     Department of Geography, University of Bonn
029     Prof. Dr. Klaus Greve
030     Postfach 1147, 53001 Bonn
031     Germany
032     http://www.geographie.uni-bonn.de/deegree/
033    
034     e-mail: info@deegree.org
035    ----------------------------------------------------------------------------*/
036    
037    package org.deegree.tools.wms;
038    
039    import static java.lang.Double.MAX_VALUE;
040    import static java.lang.Double.parseDouble;
041    import static org.deegree.framework.log.LoggerFactory.getLogger;
042    import static org.deegree.framework.xml.XMLTools.appendElement;
043    import static org.deegree.framework.xml.XMLTools.getElement;
044    import static org.deegree.model.spatialschema.GeometryFactory.createEnvelope;
045    import static org.deegree.ogcbase.CommonNamespaces.DEEGREEWMS;
046    import static org.deegree.ogcbase.CommonNamespaces.DGJDBC;
047    import static org.deegree.ogcbase.CommonNamespaces.XLNNS;
048    
049    import java.io.BufferedReader;
050    import java.io.File;
051    import java.io.FileReader;
052    import java.io.FileWriter;
053    import java.io.IOException;
054    import java.security.InvalidParameterException;
055    import java.util.LinkedList;
056    
057    import javax.xml.transform.TransformerException;
058    
059    import org.deegree.framework.log.ILogger;
060    import org.deegree.framework.xml.XMLFragment;
061    import org.deegree.framework.xml.XMLParsingException;
062    import org.deegree.model.crs.CRSFactory;
063    import org.deegree.model.crs.CRSTransformationException;
064    import org.deegree.model.crs.GeoTransformer;
065    import org.deegree.model.crs.UnknownCRSException;
066    import org.deegree.model.spatialschema.Envelope;
067    import org.w3c.dom.Element;
068    import org.xml.sax.SAXException;
069    
070    /**
071     * <code>MapServer2DeegreeWMS</code>
072     *
073     * @author <a href="mailto:schmitz@lat-lon.de">Andreas Schmitz</a>
074     * @author last edited by: $Author: rbezema $
075     *
076     * @version $Revision: 20031 $, $Date: 2009-10-07 13:57:33 +0200 (Mi, 07 Okt 2009) $
077     */
078    public class MapServer2DeegreeWMS {
079    
080        private static final ILogger LOG = getLogger( MapServer2DeegreeWMS.class );
081    
082        private File mapFile;
083    
084        private Layer root = new Layer();
085    
086        private boolean featureTypes;
087    
088        private MapServer2DeegreeWMS( String name, boolean featureTypes ) {
089            this.featureTypes = featureTypes;
090            mapFile = new File( name );
091            if ( !mapFile.exists() ) {
092                LOG.logInfo( "The input file does not exist!" );
093                return;
094            }
095        }
096    
097        private String arg( String line, String name ) {
098            if ( line.trim().toLowerCase().startsWith( name.toLowerCase() ) ) {
099                String arg = line.trim().substring( name.length() ).trim();
100                return arg.startsWith( "\"" ) ? arg.substring( 1, arg.length() - 1 ) : arg;
101            }
102            return null;
103        }
104    
105        private void readTree()
106                                throws IOException {
107            BufferedReader in = new BufferedReader( new FileReader( mapFile ) );
108    
109            boolean rootRead = false;
110            Layer current = root;
111            String currentConn = null;
112    
113            String s;
114            while ( ( s = in.readLine() ) != null ) {
115    
116                if ( s.trim().equalsIgnoreCase( "layer" ) ) {
117                    rootRead = true;
118                    current = new Layer();
119                }
120    
121                if ( current.name == null ) {
122                    current.name = arg( s, "name" );
123                }
124                if ( current.title == null ) {
125                    current.title = arg( s, "\"wms_title\"" );
126                }
127    
128                if ( rootRead ) {
129                    String cat = arg( s, "\"wms_layer_group\"" );
130                    if ( cat != null ) {
131                        Layer parent = root;
132                        String[] cats = cat.substring( 1 ).split( "/" );
133                        outer: for ( String c : cats ) {
134                            for ( Layer l : parent.children ) {
135                                if ( l.title.equals( c ) ) {
136                                    parent = l;
137                                    continue outer;
138                                }
139                            }
140                            Layer l = new Layer();
141                            l.title = c;
142                            parent.children.add( l );
143                            parent = l;
144                        }
145    
146                        parent.children.add( current );
147                    }
148    
149                    String conn = arg( s, "connection " );
150                    if ( conn != null ) {
151                        currentConn = conn;
152                    }
153                    String connType = arg( s, "connectiontype" );
154                    if ( connType != null && connType.equalsIgnoreCase( "oraclespatial" ) ) {
155                        current.oracleconn = currentConn;
156                    }
157                    if ( connType != null && connType.equalsIgnoreCase( "wms" ) ) {
158                        current.remotewms = currentConn;
159                    }
160                    // TODO add more connection types
161                    String data = arg( s, "data" );
162                    if ( data != null ) {
163                        current.data = data;
164                    }
165                    String srs = arg( s, "\"wms_srs\"" );
166                    if ( srs != null ) {
167                        current.srs = srs;
168                    }
169                    String minscale = arg( s, "minscale" );
170                    if ( minscale != null ) {
171                        current.minscale = minscale;
172                    }
173                    String maxscale = arg( s, "maxscale" );
174                    if ( maxscale != null ) {
175                        current.maxscale = maxscale;
176                    }
177                    String bbox = arg( s, "\"wms_extent\"" );
178                    if ( bbox != null ) {
179                        current.bbox = bbox;
180                    }
181                    String wmsname = arg( s, "\"wms_name\"" );
182                    if ( wmsname != null ) {
183                        current.wmsname = wmsname;
184                    }
185                    String wmsversion = arg( s, "\"wms_server_version\"" );
186                    if ( wmsversion != null ) {
187                        current.wmsversion = wmsversion;
188                    }
189                    String wmsformat = arg( s, "\"wms_format\"" );
190                    if ( wmsformat != null ) {
191                        current.wmsformat = wmsformat;
192                    }
193                    String type = arg( s, "type" );
194                    if ( type != null ) {
195                        current.raster = type.equalsIgnoreCase( "raster" );
196                    }
197                } else {
198                    String extent = arg( s, "extent" );
199                    if ( extent != null ) {
200                        current.bbox = extent;
201                    }
202                    String proj = arg( s, "\"init=" );
203                    if ( proj != null ) {
204                        current.srs = proj.substring( 0, proj.length() - 1 );
205                    }
206                }
207    
208            }
209            root.print( 0 );
210        }
211    
212        private void appendLayer( Element root, Layer layer )
213                                throws InvalidParameterException, CRSTransformationException {
214            root = appendElement( root, null, layer.raster ? "RasterLayer" : "Layer" );
215    
216            root.setAttribute( "queryable", "1" );
217    
218            if ( layer.name != null ) {
219                appendElement( root, null, "Name", layer.name );
220            }
221            if ( layer.title != null ) {
222                appendElement( root, null, "Title", layer.title );
223            }
224            if ( layer.srs != null && !layer.srs.equalsIgnoreCase( this.root.srs ) ) {
225                appendElement( root, null, "SRS", this.root.srs.toUpperCase() );
226            }
227            if ( layer.srs != null ) {
228                appendElement( root, null, "SRS", layer.srs.toUpperCase() );
229            }
230            if ( layer.bbox != null && layer.srs != null ) {
231                String[] ss = layer.bbox.split( " " );
232                double minx = Double.parseDouble( ss[0] );
233                double miny = Double.parseDouble( ss[1] );
234                double maxx = Double.parseDouble( ss[2] );
235                double maxy = Double.parseDouble( ss[3] );
236                try {
237                    Envelope bbox = createEnvelope( minx, miny, maxx, maxy, CRSFactory.create( layer.srs ) );
238                    Envelope wgs84bbox = new GeoTransformer( "EPSG:4326" ).transform( bbox, layer.srs, true );
239                    Element elem = appendElement( root, null, "LatLonBoundingBox" );
240                    elem.setAttribute( "minx", "" + wgs84bbox.getMin().getX() );
241                    elem.setAttribute( "miny", "" + wgs84bbox.getMin().getY() );
242                    elem.setAttribute( "maxx", "" + wgs84bbox.getMax().getX() );
243                    elem.setAttribute( "maxy", "" + wgs84bbox.getMax().getY() );
244    
245                    elem = appendElement( root, null, "BoundingBox" );
246                    elem.setAttribute( "SRS", layer.srs );
247                    elem.setAttribute( "minx", "" + minx );
248                    elem.setAttribute( "miny", "" + miny );
249                    elem.setAttribute( "maxx", "" + maxx );
250                    elem.setAttribute( "maxy", "" + maxy );
251                } catch ( UnknownCRSException e ) {
252                    LOG.logError( "Unknown error", e );
253                }
254            }
255    
256            Element sh = appendElement( root, null, "ScaleHint" );
257            sh.setAttribute( "min", layer.minscale == null ? "0"
258                                                          : Double.toString( ( parseDouble( layer.minscale ) / 0.00028 ) ) );
259            sh.setAttribute( "max", layer.maxscale == null ? "" + MAX_VALUE
260                                                          : Double.toString( ( parseDouble( layer.maxscale ) / 0.00028 ) ) );
261    
262            if ( layer.remotewms == null && layer != this.root && layer.name != null ) { // no style for remotewms layers
263                Element style = appendElement( root, null, "Style" );
264                appendElement( style, null, "Name", "default" );
265                appendElement( style, null, "Title", "default" );
266                appendElement( style, DEEGREEWMS, "StyleResource", "styles/" + layer.name + ".sld" );
267            }
268    
269            if ( layer.name != null ) {
270                Element ds = appendElement( root, DEEGREEWMS, "DataSource" );
271                ds.setAttribute( "failOnException", "0" );
272                ds.setAttribute( "queryable", "1" );
273                if ( layer.oracleconn != null ) {
274                    String[] data = layer.data.split( " " );
275    
276                    if ( featureTypes ) {
277                        appendElement( ds, DEEGREEWMS, "Name", "app:" + data[2].trim().toUpperCase() );
278                        appendElement( ds, DEEGREEWMS, "GeometryProperty", "app:" + data[0].toLowerCase() );
279                    } else {
280                        appendElement( ds, DEEGREEWMS, "Name", layer.name );
281                        appendElement( ds, DEEGREEWMS, "Type", "DATABASE" );
282                        Element elem = appendElement( ds, DGJDBC, "JDBCConnection" );
283                        appendElement( elem, DGJDBC, "Driver", "oracle.jdbc.driver.OracleDriver" );
284                        String user = layer.oracleconn.substring( 0, layer.oracleconn.indexOf( "/" ) );
285                        String pass = layer.oracleconn.substring( user.length() + 1, layer.oracleconn.indexOf( "@" ) );
286                        String url = layer.oracleconn.substring( user.length() + pass.length() + 1 ); // keep the @
287                        url = "jdbc:oracle:thin:" + url;
288                        appendElement( elem, DGJDBC, "Url", url );
289                        appendElement( elem, DGJDBC, "User", user );
290                        appendElement( elem, DGJDBC, "Password", pass );
291                        appendElement( ds, DEEGREEWMS, "GeometryField", data[0] );
292                        appendElement( ds, DEEGREEWMS, "SQLTemplate", "select * " + layer.data.substring( data[0].length() )
293                                                                      + " where " );
294                        appendElement( ds, DEEGREEWMS, "NativeCRS", layer.srs );
295                    }
296                }
297                if ( layer.remotewms != null ) {
298                    appendElement( ds, DEEGREEWMS, "Name", layer.name );
299                    appendElement( ds, DEEGREEWMS, "Type", "REMOTEWMS" );
300                    Element elem = appendElement( ds, DEEGREEWMS, "OWSCapabilities" );
301                    elem = appendElement( elem, DEEGREEWMS, "OnlineResource" );
302                    elem.setAttributeNS( "http://www.w3.org/1999/xlink", "xlink:type", "simple" );
303                    elem.setAttributeNS( "http://www.w3.org/1999/xlink", "xlink:href",
304                                         layer.remotewms + "?request=GetCapabilities&service=WMS&version="
305                                                                 + layer.wmsversion );
306                    elem = appendElement( ds, DEEGREEWMS, "FilterCondition" );
307                    appendElement( elem, DEEGREEWMS, "WMSRequest", "service=WMS&version=1.1.1&request=GetMap&format="
308                                                                   + layer.wmsformat
309                                                                   + "&transparent=true&exceptions=application/vnd.ogc."
310                                                                   + "se_inimage&styles=&layers=" + layer.wmsname + "&srs="
311                                                                   + layer.srs );
312                }
313                if ( layer.raster ) {
314                    appendElement( ds, DEEGREEWMS, "Name", layer.name );
315                    appendElement( ds, DEEGREEWMS, "Type", "LOCALWCS" );
316                    Element e = appendElement( ds, DEEGREEWMS, "OWSCapabilities" );
317                    e = appendElement( e, DEEGREEWMS, "OnlineResource" );
318                    e.setAttributeNS( XLNNS.toASCIIString(), "xlink:type", "simple" );
319                    e.setAttributeNS( XLNNS.toASCIIString(), "xlink:href", "LOCALWCS_configuration.xml" );
320                    e = appendElement( ds, DEEGREEWMS, "FilterCondition" );
321                    e = appendElement( e, DEEGREEWMS, "WCSRequest",
322                                       "VERSION=1.0.0&TRANSPARENT=TRUE&FORMAT=png&EXCEPTIONS=application/vnd.ogc.se_xml&coverage="
323                                                               + layer.name );
324                }
325            }
326    
327            for ( Layer l : layer.children ) {
328                appendLayer( root, l );
329            }
330        }
331    
332        private void produceWMSConfig()
333                                throws IOException, SAXException, XMLParsingException, InvalidParameterException,
334                                CRSTransformationException, TransformerException {
335            XMLFragment doc = new XMLFragment( MapServer2DeegreeWMS.class.getResource( "wms_configuration_template.xml" ) );
336            Element capability = getElement( doc.getRootElement(), "/WMT_MS_Capabilities/Capability", null );
337            appendLayer( capability, root );
338            doc.prettyPrint( new FileWriter( "wms_configuration.xml" ) );
339        }
340    
341        /**
342         * @param args
343         * @throws IOException
344         * @throws CRSTransformationException
345         * @throws XMLParsingException
346         * @throws SAXException
347         * @throws InvalidParameterException
348         * @throws TransformerException
349         */
350        public static void main( String[] args )
351                                throws IOException, InvalidParameterException, SAXException, XMLParsingException,
352                                CRSTransformationException, TransformerException {
353            if ( args.length < 1 ) {
354                LOG.logInfo( "Usage:" );
355                LOG.logInfo( "java -cp deegree2.jar org.deegree.tools.wms.MapServer2DeegreeWMS [options] <mapfile>" );
356                LOG.logInfo( "Options:" );
357                LOG.logInfo( " -f: generate feature type data sources instead of database data sources" );
358                return;
359            }
360    
361            if ( new File( "wms_configuration.xml" ).exists() ) {
362                LOG.logInfo( "wms_configuration.xml already exists. Please remove it and run the tool again." );
363                return;
364            }
365    
366            String file = args.length > 1 ? args[1] : args[0];
367            MapServer2DeegreeWMS conv;
368            if ( args.length > 1 ) {
369                conv = new MapServer2DeegreeWMS( file, args[0].equals( "-f" ) );
370            } else {
371                conv = new MapServer2DeegreeWMS( file, false );
372            }
373            conv.readTree();
374            conv.produceWMSConfig();
375        }
376    
377        static class Layer {
378            String name, title, oracleconn, remotewms, bbox, srs, wmsname, wmsformat, data, wmsversion, minscale, maxscale;
379    
380            boolean raster;
381    
382            LinkedList<Layer> children = new LinkedList<Layer>();
383    
384            static void maybePrint( int indent, String name, String val ) {
385                if ( val != null ) {
386                    for ( int i = 0; i < indent; ++i ) {
387                        System.out.print( ' ' );
388                    }
389                    System.out.println( name + " " + val );
390                }
391            }
392    
393            void print( int indent ) {
394                maybePrint( indent, "NAME", name );
395                maybePrint( indent, "TITLE", title );
396                maybePrint( indent, "ORACLE CONNECTION", oracleconn );
397                maybePrint( indent, "REMOTEWMS", remotewms );
398                maybePrint( indent, "REMOTEWMS NAME", wmsname );
399                maybePrint( indent, "REMOTEWMS FORMAT", wmsformat );
400                maybePrint( indent, "SRS", srs );
401                maybePrint( indent, "BBOX", bbox );
402                for ( Layer l : children ) {
403                    l.print( indent + 2 );
404                }
405            }
406        }
407    
408    }