001    //$HeadURL: svn+ssh://developername@svn.wald.intevation.org/deegree/base/trunk/src/org/deegree/tools/datastore/DBSchemaToDatastoreConf.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    package org.deegree.tools.datastore;
037    
038    import java.io.BufferedReader;
039    import java.io.File;
040    import java.io.FileOutputStream;
041    import java.io.IOException;
042    import java.io.InputStreamReader;
043    import java.io.StringReader;
044    import java.net.URL;
045    import java.security.InvalidParameterException;
046    import java.sql.Connection;
047    import java.sql.ResultSet;
048    import java.sql.ResultSetMetaData;
049    import java.sql.SQLException;
050    import java.sql.Statement;
051    import java.util.HashMap;
052    import java.util.Map;
053    
054    import javax.xml.transform.TransformerException;
055    
056    import org.deegree.datatypes.Types;
057    import org.deegree.datatypes.UnknownTypeException;
058    import org.deegree.framework.log.ILogger;
059    import org.deegree.framework.log.LoggerFactory;
060    import org.deegree.framework.util.FileUtils;
061    import org.deegree.framework.util.StringTools;
062    import org.deegree.framework.xml.XMLFragment;
063    import org.deegree.io.DBConnectionPool;
064    import org.deegree.io.DBPoolException;
065    import org.deegree.io.dbaseapi.DBaseException;
066    import org.deegree.io.shpapi.HasNoDBaseFileException;
067    import org.deegree.io.shpapi.ShapeFile;
068    import org.xml.sax.SAXException;
069    
070    /**
071     * Example: java -classpath .;deegree.jar;$databasedriver.jar
072     * org.deegree.tools.datastore.DBSchemaToDatastoreConf -tables mytable,myothertable -user dev
073     * -password dev -driver oracle.jdbc.OracleDriver -url jdbc:oracle:thin:@localhost:1521:devs -output
074     * e:/temp/schema.xsd<br>
075     * or for shapefile:<br>
076     * java -classpath .;deegree.jar org.deegree.tools.datastore.DBSchemaToDatastoreConf -url
077     * c:/data/myshape -driver SHAPE -output e:/temp/schema.xsd<br>
078     * 
079     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
080     * @author last edited by: $Author: apoth $
081     * 
082     * @version $Revision: 8049 $, $Date: 2007-08-23 10:19:28 +0200 (Do, 23 Aug 2007) $
083     */
084    public class DBSchemaToDatastoreConf {
085    
086        private static final ILogger LOG = LoggerFactory.getLogger( DBSchemaToDatastoreConf.class );
087    
088        private String[] tables;
089    
090        private String user;
091    
092        private String pw;
093    
094        private String driver;
095    
096        private String logon;
097    
098        private String backend;
099    
100        private String vendor;
101    
102        private String srs;
103    
104        private String defaultPKey;
105    
106        private String insert;
107    
108        private String update;
109    
110        private String delete;
111    
112        private String idGenerator;
113    
114        private String sequence;
115    
116        private Integer defaultSRID;
117    
118        private String omitFidAsProperty;
119    
120        /**
121         * 
122         * @param tables
123         *            list of table names used for one featuretype
124         * @param user
125         *            database user
126         * @param pw
127         *            users password
128         * @param driver
129         *            database driver
130         * @param logon
131         *            database URL/logon
132         * @param srs
133         * @throws IOException
134         */
135        public DBSchemaToDatastoreConf( String[] tables, String user, String pw, String driver, String logon, String srs,
136                                        String pkey, Integer srid, String insert, String update, String delete,
137                                        String idGenerator, String sequence, String omitFidAsProperty ) throws IOException {
138            this.driver = driver;
139            this.logon = logon;
140            this.pw = pw;
141            this.user = user;
142            this.tables = tables;
143            if ( srs != null ) {
144                this.srs = srs;
145            } else {
146                this.srs = readUserInput( DBSchemaToDatastoreConfSQLMSGAccess.getMessage( "ENTERSRS" ), false );
147            }
148    
149            if ( driver.toUpperCase().indexOf( "ORACLE" ) > -1 ) {
150                backend = "ORACLE";
151                vendor = backend;
152            } else if ( driver.toUpperCase().indexOf( "POSTGRES" ) > -1 ) {
153                backend = "POSTGIS";
154                vendor = backend;
155            } else if ( driver.toUpperCase().contains( "SHAPE" ) ) {
156                backend = "SHAPE";
157                vendor = backend;
158            } else {
159                backend = "GENERICSQL";
160                vendor = getVendor( driver );
161            }
162            this.defaultPKey = pkey;
163            this.defaultSRID = srid;
164            this.insert = insert;
165            this.delete = delete;
166            this.update = update;
167            this.idGenerator = idGenerator;
168            this.sequence = sequence;
169            this.omitFidAsProperty = omitFidAsProperty;
170        }
171    
172        private String getVendor( String driver ) {
173            // find out which database is used
174            String vendor = null;
175            if ( driver.toUpperCase().contains( "POSTGRES" ) ) {
176                backend = "POSTGRES";
177            } else if ( driver.toUpperCase().contains( "SQLSERVER" ) ) {
178                backend = "SQLSERVER";
179            } else if ( driver.toUpperCase().contains( "INGRES" ) || driver.equals( "ca.edbc.jdbc.EdbcDriver" ) ) {
180                backend = "INGRES";
181            } else if ( driver.toUpperCase().contains( "HSQLDB" ) ) {
182                backend = "HSQLDB";
183            } else {
184                backend = "SHAPE";
185            }
186            return vendor;
187        }
188    
189        /**
190         * creates a schema/datastore configuration for accessin database table through deegree WFS
191         * 
192         * @return a schema/datastore configuration for accessin database table through deegree WFS
193         * @throws Exception
194         */
195        public String run()
196                                throws Exception {
197            StringBuffer sb = new StringBuffer( 5000 );
198    
199            if ( backend.equals( "SHAPE" ) ) {
200                handleShape( sb );
201            } else {
202                handleDatabase( sb );
203            }
204            printFooter( sb );
205    
206            return sb.toString();
207        }
208    
209        /**
210         * creates a datastore configuration for a database backend
211         * 
212         * @param sb
213         * @throws DBPoolException
214         * @throws SQLException
215         * @throws Exception
216         * @throws UnknownTypeException
217         * @throws IOException
218         */
219        private void handleDatabase( StringBuffer sb )
220                                throws DBPoolException, SQLException, Exception, UnknownTypeException, IOException {
221            printHeader( sb );
222    
223            for ( int k = 0; k < tables.length; k++ ) {
224                LOG.logInfo( "Opening JDBC connection with driver: " + driver );
225                LOG.logInfo( "Opening JDBC connection to database : " + logon );
226    
227                Connection con = DBConnectionPool.getInstance().acquireConnection( driver, logon, user, pw );
228                Statement stmt = con.createStatement();
229                // ensure that we do not get a filled resultset because we just
230                // need the metainformation
231                LOG.logDebug( "read table: ", tables[k] );
232                ResultSet rs = stmt.executeQuery( "select * from " + tables[k] + " where 1 = 2" );
233    
234                ResultSetMetaData rsmd = rs.getMetaData();
235                int cols = rsmd.getColumnCount();
236    
237                printComplexHeader( sb, tables[k] );
238                for ( int i = 0; i < cols; i++ ) {
239                    if ( rsmd.getColumnType( i + 1 ) != 2004 ) {
240                        int tp = rsmd.getColumnType( i + 1 );
241                        String tpn = Types.getTypeNameForSQLTypeCode( tp );
242                        LOG.logDebug( tables[k] + '.' + rsmd.getColumnName( i + 1 ) + ": " + tpn );
243                        // add property just if type != BLOB
244                        if ( !"true".equals( omitFidAsProperty )
245                             || !getPKeyName( tables[k] ).equalsIgnoreCase( rsmd.getColumnName( i + 1 ) ) ) {
246                            printProperty( tables[k], rsmd.getColumnName( i + 1 ), rsmd.getColumnType( i + 1 ), tpn,
247                                           rsmd.getPrecision( i + 1 ), sb );
248                        }
249                    } else {
250                        String msg = StringTools.concat( 200, "skiped: ", tables[k], '.', rsmd.getColumnName( i + 1 ),
251                                                         ": ", rsmd.getColumnTypeName( i + 1 ) );
252                        LOG.logDebug( msg );
253                    }
254                }
255    
256                DBConnectionPool.getInstance().releaseConnection( con, driver, logon, user, pw );
257                printComplexFooter( sb );
258            }
259        }
260    
261        /**
262         * creates a datastore configuration for a shapefile backend
263         * 
264         * @param sb
265         * @throws IOException
266         * @throws Exception
267         * @throws HasNoDBaseFileException
268         * @throws DBaseException
269         * @throws DBPoolException
270         * @throws SQLException
271         * @throws UnknownTypeException
272         */
273        private void handleShape( StringBuffer sb )
274                                throws IOException, Exception, HasNoDBaseFileException, DBaseException, DBPoolException,
275                                SQLException, UnknownTypeException {
276            // TODO throw RE if tbl.len != 1
277    
278            printShapeHeader( sb, tables[0] );
279    
280            File f = new File( tables[0] );
281            ShapeFile shp = new ShapeFile( f.getAbsolutePath() );
282    
283            printComplexHeader( sb, f.getName() );
284    
285            String[] dataTypes = shp.getDataTypes();
286    
287            printProperty( f.getName(), "GEOM", 2002, "GEOM", -9999, sb );
288    
289            String[] props = shp.getProperties();
290            for ( int i = 0; i < props.length; i++ ) {
291                int sqlCode = toSQLCode( dataTypes[i] );
292                printProperty( tables[0], props[i], sqlCode, Types.getTypeNameForSQLTypeCode( sqlCode ),
293                               toPrecision( dataTypes[i] ), sb );
294            }
295    
296            printComplexFooter( sb );
297    
298            shp.close();
299        }
300    
301        /**
302         * @return precision for a dBase numerical type
303         * 
304         * @param dbfType
305         */
306        private int toPrecision( String dbfType ) {
307            int precision = 0;
308    
309            if ( dbfType.equalsIgnoreCase( "N" ) ) {
310                precision = 1;
311            } else if ( dbfType.equalsIgnoreCase( "F" ) ) {
312                precision = 2;
313            }
314    
315            return precision;
316        }
317    
318        /**
319         * @return the SQL type code for a dBase type char
320         * 
321         * @param dbfType
322         */
323        private int toSQLCode( String dbfType ) {
324    
325            int type = -9999;
326    
327            if ( dbfType.equalsIgnoreCase( "C" ) ) {
328                type = Types.VARCHAR;
329            } else if ( dbfType.equalsIgnoreCase( "F" ) || dbfType.equalsIgnoreCase( "N" ) ) {
330                type = Types.NUMERIC;
331            } else if ( dbfType.equalsIgnoreCase( "D" ) || dbfType.equalsIgnoreCase( "M" ) ) {
332                type = Types.DATE;
333            } else if ( dbfType.equalsIgnoreCase( "L" ) ) {
334                type = Types.BOOLEAN;
335            } else if ( dbfType.equalsIgnoreCase( "B" ) ) {
336                type = Types.BLOB;
337            }
338    
339            if ( type == -9999 ) {
340                throw new RuntimeException( "Type '" + dbfType + "' is not suported." );
341            }
342    
343            return type;
344        }
345    
346        /**
347         * adds the header of the configuration/schema for a database datastore
348         * 
349         * @param sb
350         */
351        private void printHeader( StringBuffer sb ) {
352    
353            String s = DBSchemaToDatastoreConfSQLXSDAccess.getXSDFragment( "HEADER", backend, srs, driver, logon, user, pw );
354            sb.append( s );
355    
356        }
357    
358        /**
359         * adds the header of the configuration/schema for a shapefile datastore
360         * 
361         * @param sb
362         * @param filename
363         *            path to the shapefile
364         */
365        private void printShapeHeader( StringBuffer sb, String filename ) {
366    
367            String s = DBSchemaToDatastoreConfSQLXSDAccess.getXSDFragment( "SHAPEHEADER", filename, srs );
368            sb.append( s );
369    
370        }
371    
372        /**
373         * adds a header for a feature type to the schema
374         * 
375         * @param sb
376         * @param table
377         *            name of the table the feature type is assigned to
378         * @throws Exception
379         */
380        private void printComplexHeader( StringBuffer sb, String table )
381                                throws Exception {
382            String idField = getPKeyName( table );
383            String tp = "INTEGER";
384            if ( backend.equals( "GENERICSQL" ) ) {
385                tp = "VARCHAR";
386            }
387            String idg = "";
388            if ( "DB_MAX".equalsIgnoreCase( idGenerator ) ) {
389                idg = DBSchemaToDatastoreConfSQLXSDAccess.getXSDFragment( "DB_MAX_IDGENERATOR", table, idField );
390            } else if ( "DB_SEQ".equalsIgnoreCase( idGenerator ) && sequence != null ) {
391                idg = DBSchemaToDatastoreConfSQLXSDAccess.getXSDFragment( "DB_SEQ_IDGENERATOR", sequence );
392            }
393            String s = DBSchemaToDatastoreConfSQLXSDAccess.getXSDFragment( "COMPLEXHEADER", table, table, table, idField,
394                                                                           tp, table, update, delete, insert, idg );
395            sb.append( s );
396    
397        }
398    
399        /**
400         * adds the footer of a feature type definition
401         * 
402         * @param sb
403         */
404        private void printComplexFooter( StringBuffer sb ) {
405            sb.append( DBSchemaToDatastoreConfSQLXSDAccess.getXSDFragment( "COMPLEXFOOTER" ) );
406        }
407    
408        /**
409         * prints XSD footer
410         * 
411         * @param sb
412         */
413        private void printFooter( StringBuffer sb ) {
414            sb.append( DBSchemaToDatastoreConfSQLXSDAccess.getXSDFragment( "FOOTER" ) );
415        }
416    
417        /**
418         * adds a property assigned to a database table field to the schema
419         * 
420         * @param tableName
421         *            table name
422         * @param name
423         *            property name
424         * @param type
425         *            xsd type name
426         * @param typeName
427         *            SQL type name
428         * @param precision
429         *            number precision if type is a number
430         * @param sb
431         * @throws SQLException
432         * @throws DBPoolException
433         * @throws IOException
434         */
435        private void printProperty( String tableName, String name, int type, String typeName, int precision, StringBuffer sb )
436                                throws DBPoolException, SQLException, IOException {
437    
438            String tp = Types.getXSDTypeForSQLType( type, precision );
439            if ( !tp.startsWith( "gml:" ) ) {
440                tp = "xsd:" + tp;
441            }
442    
443            if ( tp.equals( "gml:GeometryPropertyType" ) ) {
444                int srid = getSRID( tableName, name );
445                String s = DBSchemaToDatastoreConfSQLXSDAccess.getXSDFragment( "GEOMPROPERTY", name.toLowerCase(), tp,
446                                                                               name, "" + srid );
447                sb.append( s );
448            } else {
449                String s = DBSchemaToDatastoreConfSQLXSDAccess.getXSDFragment( "PROPERTY", name.toLowerCase(), tp, name,
450                                                                               typeName.toUpperCase() );
451                sb.append( s );
452            }
453        }
454    
455        private int getSRID( String tableName, String columnName )
456                                throws SQLException, DBPoolException, IOException {
457    
458            if ( defaultSRID != null ) {
459                return defaultSRID;
460            }
461    
462            int srid = -1;
463            String query = DBSchemaToDatastoreConfSQLSQLAccess.getSQLStatement( vendor + "_SRID", tableName.toUpperCase(),
464                                                                                columnName.toUpperCase() );
465            LOG.logInfo( query );
466            Connection con = null;
467            Statement stmt = null;
468            ResultSet rs = null;
469            if ( query != null && query.indexOf( "not found$" ) < 0 ) {
470                try {
471                    con = DBConnectionPool.getInstance().acquireConnection( driver, logon, user, pw );
472                    stmt = con.createStatement();
473                    rs = stmt.executeQuery( query );
474    
475                    while ( rs.next() ) {
476                        srid = rs.getInt( 1 );
477                    }
478    
479                    if ( srid == 0 ) {
480                        srid = -1;
481                    }
482    
483                } catch ( SQLException e ) {
484                    System.out.println( DBSchemaToDatastoreConfSQLMSGAccess.getMessage( "ERRORSRID" ) + e.getMessage() );
485                    System.out.println( DBSchemaToDatastoreConfSQLMSGAccess.getMessage( "ENTERFIELD" ) );
486                } finally {
487                    rs.close();
488                    stmt.close();
489                    DBConnectionPool.getInstance().releaseConnection( con, driver, logon, user, pw );
490                }
491            } else {
492                System.out.println( DBSchemaToDatastoreConfSQLMSGAccess.getMessage( "NOSRIDQUERY" ) );
493            }
494            if ( srid == -1 ) {
495                String tmp = DBSchemaToDatastoreConfSQLMSGAccess.getMessage( "ENTERSRID" );
496                srid = Integer.parseInt( readUserInput( tmp, false ) );
497            }
498            return srid;
499        }
500    
501        /**
502         * returns the name of the primary key of the passed table
503         * 
504         * @param table
505         * @return the name of the primary key of the passed table
506         * @throws DBPoolException
507         * @throws SQLException
508         * @throws IOException
509         */
510        private String getPKeyName( String table )
511                                throws DBPoolException, SQLException, IOException {
512    
513            if ( defaultPKey != null ) {
514                return defaultPKey;
515            }
516    
517            String query = DBSchemaToDatastoreConfSQLSQLAccess.getSQLStatement( vendor + "_ID", table.toUpperCase() );
518            LOG.logInfo( query );
519            Object id = null;
520            Statement stmt = null;
521            ResultSet rs = null;
522            if ( query != null && query.indexOf( "not found$" ) < 0 ) {
523                Connection con = DBConnectionPool.getInstance().acquireConnection( driver, logon, user, pw );
524                try {
525                    stmt = con.createStatement();
526                    rs = stmt.executeQuery( query );
527    
528                    if ( rs.next() ) {
529                        id = rs.getObject( 1 );
530                    }
531                } catch ( Exception e ) {
532                    System.out.println( DBSchemaToDatastoreConfSQLMSGAccess.getMessage( "ERRORPK" ) + e.getMessage() );
533                    System.out.println( DBSchemaToDatastoreConfSQLMSGAccess.getMessage( "ENTERFIELD" ) );
534                } finally {
535                    rs.close();
536                    stmt.close();
537                    DBConnectionPool.getInstance().releaseConnection( con, driver, logon, user, pw );
538                }
539            } else {
540                System.out.println( DBSchemaToDatastoreConfSQLMSGAccess.getMessage( "NOPKQUERY" ) );
541            }
542            if ( id == null ) {
543                id = readUserInput( DBSchemaToDatastoreConfSQLMSGAccess.getMessage( "ENTERPK" ), false );
544            }
545            return id.toString();
546        }
547    
548        private static void validate( Map<String, String> map )
549                                throws InvalidParameterException, IOException {
550            if ( map.get( "-?" ) != null || map.get( "-h" ) != null || map.get( "-help" ) != null ) {
551                printHelp();
552                System.exit( 1 );
553            }
554            if ( map.get( "-tables" ) == null ) {
555                String s = readUserInput( DBSchemaToDatastoreConfSQLMSGAccess.getMessage( "ENTERTABLES" ), false );
556                map.put( "-tables", s );
557            }
558    
559            if ( map.get( "-driver" ) == null ) {
560                String s = readUserInput( DBSchemaToDatastoreConfSQLMSGAccess.getMessage( "ENTERDRIVER" ), false );
561                map.put( "-driver", s );
562            }
563    
564            if ( map.get( "-user" ) == null ) {
565                if ( !"SHAPE".equals( map.get( "-driver" ) ) ) {
566                    String s = readUserInput( DBSchemaToDatastoreConfSQLMSGAccess.getMessage( "ENTERUSER" ), false );
567                    map.put( "-user", s );
568                }
569            }
570    
571            if ( map.get( "-password" ) == null ) {
572                if ( !"SHAPE".equals( map.get( "-driver" ) ) ) {
573                    String s = readUserInput( DBSchemaToDatastoreConfSQLMSGAccess.getMessage( "ENTERPASSWORD" ), false );
574                    map.put( "-password", s );
575                } else {
576                    map.put( "-password", " " );
577                }
578            }
579    
580            if ( map.get( "-url" ) == null && !"SHAPE".equalsIgnoreCase( (String) map.get( "-driver" ) ) ) {
581                String s = readUserInput( DBSchemaToDatastoreConfSQLMSGAccess.getMessage( "ENTERURL" ), false );
582                map.put( "-url", s );
583            }
584            if ( map.get( "-output" ) == null ) {
585                String s = readUserInput( DBSchemaToDatastoreConfSQLMSGAccess.getMessage( "ENTEROUTPUT" ), false );
586                map.put( "-output", s );
587            }
588        }
589    
590        private static void printHelp()
591                                throws IOException {
592            URL url = DBSchemaToDatastoreConf.class.getResource( "DBSchemaToDatastoreConfHelp.txt" );
593            System.out.println( FileUtils.readTextFile( url ) );
594        }
595    
596        /**
597         * @param args
598         * @throws IOException
599         * @throws SAXException
600         * @throws TransformerException
601         * @throws Exception
602         */
603        public static void main( String[] args )
604                                throws Exception {
605    
606            Map<String, String> map = new HashMap<String, String>();
607            for ( int i = 0; i < args.length; ) {
608                String first = args[i++];
609                if ( "?".equals( first ) || "-h".equals( first ) || "-help".equals( first ) ) {
610                    printHelp();
611                    System.exit( 0 );
612                }
613                map.put( first, args[i++] );
614            }
615    
616            try {
617                validate( map );
618            } catch ( InvalidParameterException ipe ) {
619                LOG.logError( ipe.getMessage() );
620                printHelp();
621                System.exit( 1 );
622            }
623            LOG.logDebug( "Resulting commandline arguments and their values {argument=value, ...}: " + map );
624            String tmp = (String) map.get( "-tables" );
625            String[] tables = StringTools.toArray( tmp, ",;|", true );
626            String user = (String) map.get( "-user" );
627            String pw = (String) map.get( "-password" );
628            String driver = (String) map.get( "-driver" );
629            String url = (String) map.get( "-url" );
630            String output = (String) map.get( "-output" );
631            String srs = (String) map.get( "-srs" );
632            String insert = "false";
633            if ( "true".equalsIgnoreCase( map.get( "-insert" ) ) ) {
634                insert = "true";
635            }
636            String delete = "false";
637            if ( "true".equalsIgnoreCase( map.get( "-delete" ) ) ) {
638                delete = "true";
639            }
640            String update = "false";
641            if ( "true".equalsIgnoreCase( map.get( "-update" ) ) ) {
642                update = "true";
643            }
644            String idGenerator = (String) map.get( "-idGenerator" );
645            String sequence = (String) map.get( "-sequence" );
646    
647            String omitFidAsProperty = "false";
648            if ( "true".equalsIgnoreCase( map.get( "-omitFidAsProperty" ) ) ) {
649                omitFidAsProperty = "true";
650            }
651    
652            // hidden parameters to ease bulk processing, if provided, these values determine
653            // primary key column name and srid for all tables
654            String pkey = (String) map.get( "-pkey" );
655            String sridString = (String) map.get( "-srid" );
656            Integer srid = null;
657            if ( sridString != null ) {
658                srid = Integer.parseInt( sridString );
659            }
660    
661            DBSchemaToDatastoreConf stc = new DBSchemaToDatastoreConf( tables, user, pw, driver, url, srs, pkey, srid,
662                                                                       insert, update, delete, idGenerator, sequence,
663                                                                       omitFidAsProperty );
664            String conf = null;
665            try {
666                conf = stc.run();
667            } catch ( Exception e ) {
668                LOG.logError( e.getMessage(), e );
669                System.exit( 1 );
670            }
671            storeSchema( output, conf );
672            System.exit( 0 );
673        }
674    
675        /**
676         * 
677         * @param output
678         * @param conf
679         * @throws IOException
680         * @throws SAXException
681         * @throws TransformerException
682         */
683        private static void storeSchema( String output, String conf )
684                                throws SAXException, IOException, TransformerException {
685            if ( conf != null ) {
686                XMLFragment xml = new XMLFragment();
687                xml.load( new StringReader( conf ), XMLFragment.DEFAULT_URL );
688                FileOutputStream fos = new FileOutputStream( output );
689                xml.prettyPrint( fos );
690                fos.close();
691            }
692        }
693    
694        /**
695         * This function prints a message on the command line and asks the user for an input, returns
696         * the text the User has typed, null otherwise
697         * 
698         * @param describtion
699         *            The message to be displayed to the user asking for a certain text to type
700         * @return the read text, or null if nothing was read
701         * @throws IOException
702         */
703        private static String readUserInput( String describtion, boolean acceptNull )
704                                throws IOException {
705    
706            String result = null;
707            do {
708                System.out.print( describtion );
709                System.out.println( ':' );
710                BufferedReader reader = new BufferedReader( new InputStreamReader( System.in ) );
711                result = reader.readLine();
712            } while ( !acceptNull && ( result == null || result.trim().length() == 0 ) );
713            return result;
714    
715        }
716    }