001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/tools/datastore/ModifyFTProperties.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.File;
039    import java.io.FileOutputStream;
040    import java.net.URI;
041    import java.net.URL;
042    import java.util.Properties;
043    
044    import org.deegree.datatypes.Types;
045    import org.deegree.datatypes.parameter.InvalidParameterNameException;
046    import org.deegree.framework.util.StringTools;
047    import org.deegree.framework.xml.NamespaceContext;
048    import org.deegree.framework.xml.XMLFragment;
049    import org.deegree.framework.xml.XMLParsingException;
050    import org.deegree.framework.xml.XMLTools;
051    import org.deegree.ogcbase.CommonNamespaces;
052    import org.w3c.dom.Element;
053    import org.w3c.dom.Node;
054    
055    /**
056     * This class enables a user to add a new property to a deegree WFS feature type definition. It is
057     * possible to add a simple property from the feature types major table, a simple property from
058     * another table and a complex property from another already available feature type.
059     *
060     *
061     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
062     * @author last edited by: $Author: mschneider $
063     *
064     * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
065     */
066    public class ModifyFTProperties {
067    
068        private static NamespaceContext nsCntxt = CommonNamespaces.getNamespaceContext();
069    
070        private static URI xsd = CommonNamespaces.XSNS;
071    
072        private static URI dgwfs = CommonNamespaces.DEEGREEWFS;
073    
074        private URL ftDefFile;
075    
076        private String featureType;
077    
078        private String propertyName;
079    
080        private String source;
081    
082        private String from;
083    
084        private String to;
085    
086        private int relType = 0;
087    
088        private String databaseFieldName;
089    
090        private int type = 0;
091    
092        /**
093         *
094         * @param ftDefFile
095         *            schema file containing feature type defintion
096         * @param featureType
097         *            qualified name of the feature to enhance
098         * @param propertyName
099         *            name of the new property
100         * @param databaseFieldName
101         * @param type
102         *            type code of the ne2 property (@see org.deegree.datatypes.Types)
103         */
104        public ModifyFTProperties( URL ftDefFile, String featureType, String propertyName, String databaseFieldName,
105                                   int type ) {
106            this.ftDefFile = ftDefFile;
107            this.featureType = featureType;
108            this.propertyName = propertyName;
109            this.type = type;
110            this.databaseFieldName = databaseFieldName;
111        }
112    
113        /**
114         *
115         * @param ftDefFile
116         *            schema file containing feature type defintion
117         * @param featureType
118         *            qualified name of the feature to enhance
119         * @param propertyName
120         *            name of the new property
121         * @param databaseFieldName
122         * @param table
123         * @param from
124         * @param to
125         * @param type
126         *            type code of the new property (@see org.deegree.datatypes.Types)
127         * @param relType
128         */
129        public ModifyFTProperties( URL ftDefFile, String featureType, String propertyName, String databaseFieldName,
130                                   String table, String from, String to, int type, int relType ) {
131            this.ftDefFile = ftDefFile;
132            this.featureType = featureType;
133            this.propertyName = propertyName;
134            this.type = type;
135            this.source = table;
136            this.from = from;
137            this.to = to;
138            this.relType = relType;
139            this.databaseFieldName = databaseFieldName;
140        }
141    
142        /**
143         * adds a property from the feature types major table
144         *
145         * @throws Exception
146         */
147        public void addSimplePropertyFromMainTable()
148                                throws Exception {
149    
150            XMLFragment xml = new XMLFragment();
151            xml.load( ftDefFile );
152    
153            if ( doesPropertyAlreadyExist( xml, propertyName ) ) {
154                throw new InvalidParameterNameException( "Property already exits", "propertyName" );
155            }
156    
157            Element cType = getPropertyParent( xml );
158    
159            Element elem = XMLTools.appendElement( cType, xsd, "element" );
160            elem.setAttribute( "name", propertyName );
161            elem.setAttribute( "type", "xsd:" + Types.getXSDTypeForSQLType( type, 0 ) );
162            Element el = XMLTools.appendElement( elem, xsd, "annotation" );
163            el = XMLTools.appendElement( el, xsd, "appinfo" );
164            el = XMLTools.appendElement( el, dgwfs, "deegreewfs:Content" );
165            el = XMLTools.appendElement( el, dgwfs, "deegreewfs:MappingField" );
166            el.setAttribute( "field", databaseFieldName );
167            el.setAttribute( "type", Types.getTypeNameForSQLTypeCode( type ) );
168    
169            File file = new File( ftDefFile.getFile() );
170            FileOutputStream fos = new FileOutputStream( file );
171            xml.write( fos );
172            fos.close();
173        }
174    
175        /**
176         * returns the parent node where to add the additional property
177         *
178         * @param xml
179         * @return the parent node where to add the additional property
180         * @throws XMLParsingException
181         */
182        private Element getPropertyParent( XMLFragment xml )
183                                throws XMLParsingException {
184            String xpath = StringTools.concat( 100, "xs:complexType[./@name = '", featureType, "Type']/xs:complexContent/",
185                                               "xs:extension/xs:sequence" );
186            return (Element) XMLTools.getNode( xml.getRootElement(), xpath, nsCntxt );
187        }
188    
189        /**
190         * returns true if a property with the same name as the one to add already exists for a feature
191         * type
192         *
193         * @param xml
194         * @param propertyName
195         * @return true if property already exists
196         * @throws XMLParsingException
197         */
198        private boolean doesPropertyAlreadyExist( XMLFragment xml, String propertyName )
199                                throws XMLParsingException {
200            String xPath = ".//xsd:element[./@name = '" + propertyName + "']";
201            nsCntxt.addNamespace( "xsd", xsd );
202            Node node = XMLTools.getNode( xml.getRootElement(), xPath, nsCntxt );
203            return node != null;
204        }
205    
206        /**
207         * @throws Exception
208         */
209        public void addSimplePropertyFromOtherTable()
210                                throws Exception {
211            XMLFragment xml = new XMLFragment();
212            xml.load( ftDefFile );
213    
214            if ( doesPropertyAlreadyExist( xml, propertyName ) ) {
215                throw new InvalidParameterNameException( "Property already exits", "propertyName" );
216            }
217    
218            Element cType = getPropertyParent( xml );
219    
220            Element elem = XMLTools.appendElement( cType, xsd, "element" );
221            elem.setAttribute( "name", propertyName );
222            elem.setAttribute( "type", "xsd:" + Types.getXSDTypeForSQLType( type, 0 ) );
223            Element el = XMLTools.appendElement( elem, xsd, "annotation" );
224            el = XMLTools.appendElement( el, xsd, "appinfo" );
225            el = XMLTools.appendElement( el, dgwfs, "deegreewfs:Content" );
226            Element mfElem = XMLTools.appendElement( el, dgwfs, "deegreewfs:MappingField" );
227            mfElem.setAttribute( "field", databaseFieldName );
228            mfElem.setAttribute( "type", Types.getTypeNameForSQLTypeCode( type ) );
229    
230            // append relation informations
231            Element relElem = XMLTools.appendElement( el, dgwfs, "deegreewfs:Relation" );
232            el = XMLTools.appendElement( relElem, dgwfs, "deegreewfs:From" );
233            el = XMLTools.appendElement( el, dgwfs, "deegreewfs:MappingField" );
234            el.setAttribute( "field", from );
235            el.setAttribute( "type", Types.getTypeNameForSQLTypeCode( relType ) );
236            el = XMLTools.appendElement( relElem, dgwfs, "deegreewfs:To" );
237            el = XMLTools.appendElement( el, dgwfs, "deegreewfs:MappingField" );
238            el.setAttribute( "field", to );
239            el.setAttribute( "type", Types.getTypeNameForSQLTypeCode( relType ) );
240            el.setAttribute( "table", source );
241    
242            File file = new File( ftDefFile.getFile() );
243            FileOutputStream fos = new FileOutputStream( file );
244            xml.write( fos );
245            fos.close();
246        }
247    
248        /**
249         *
250         */
251        public void addComplexProperty() {
252            // TODO
253        }
254    
255        private static boolean validate( Properties map ) {
256            if ( map.getProperty( "-action" ) == null ) {
257                return false;
258            }
259            if ( map.getProperty( "-xsd" ) == null ) {
260                return false;
261            }
262            if ( map.getProperty( "-featureType" ) == null ) {
263                return false;
264            }
265            if ( map.getProperty( "-propertyName" ) == null ) {
266                return false;
267            }
268            return true;
269        }
270    
271        private static void printHelp() {
272            System.out.println( "properties:" );
273            System.out.println( "-action (addProperty|removeProperty)" );
274            System.out.println( "-xsd" );
275            System.out.println( "-featureType" );
276            System.out.println( "-propertyName" );
277            System.out.println( "-type (simple|complex)" );
278            System.out.println( "must be set!" );
279            System.out.println( "If -source is set " );
280            System.out.println( "-fkSource" );
281            System.out.println( "-fkTarget" );
282            System.out.println( "-fkType" );
283            System.out.println( "must be set too!" );
284        }
285    
286        /**
287         * @param args
288         * @throws Exception
289         */
290        public static void main( String[] args )
291                                throws Exception {
292    
293            Properties map = new Properties();
294            for ( int i = 0; i < args.length; i += 2 ) {
295                System.out.println( args[i + 1] );
296                map.put( args[i], args[i + 1] );
297            }
298            if ( !validate( map ) ) {
299                printHelp();
300                return;
301            }
302    
303            String action = map.getProperty( "-action" );
304            URL url = new URL( map.getProperty( "-xsd" ) );
305            String ft = map.getProperty( "-featureType" );
306            String prop = map.getProperty( "-propertyName" );
307            if ( "addProperty".equals( action ) ) {
308                String field = map.getProperty( "-fieldName" );
309                int type = Types.getTypeCodeForSQLType( map.getProperty( "-propertyType" ) );
310                if ( "simple".equals( map.getProperty( "-type" ) ) && map.getProperty( "-source" ) == null ) {
311                    ModifyFTProperties add = new ModifyFTProperties( url, ft, prop, field, type );
312                    add.addSimplePropertyFromMainTable();
313                }
314                if ( "simple".equals( map.getProperty( "-type" ) ) && map.getProperty( "-source" ) != null ) {
315                    String table = map.getProperty( "-source" );
316                    String from = map.getProperty( "-fkSource" );
317                    String to = map.getProperty( "-fkTarget" );
318                    int fkType = Types.getTypeCodeForSQLType( map.getProperty( "-fkType" ) );
319                    ModifyFTProperties add = new ModifyFTProperties( url, ft, prop, field, table, from, to, fkType, type );
320                    add.addSimplePropertyFromOtherTable();
321                } else if ( "complex".equals( map.getProperty( "-type" ) ) ) {
322                    // TODO
323                    throw new Exception( "not supported yet" );
324                } else {
325                    throw new Exception( "not supported operation" );
326                }
327    
328            } else if ( "removeProperty".equals( action ) ) {
329                // TODO
330                throw new Exception( "not supported yet" );
331            } else {
332                throw new Exception( "not supported operation" );
333            }
334    
335        }
336    
337    }