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