001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/model/feature/GMLFeatureCollectionDocument.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 Aennchenstraße 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.model.feature;
044
045 import java.util.ArrayList;
046 import java.util.Collection;
047 import java.util.Iterator;
048 import java.util.List;
049
050 import org.deegree.framework.util.IDGenerator;
051 import org.deegree.framework.xml.ElementList;
052 import org.deegree.framework.xml.XMLParsingException;
053 import org.deegree.framework.xml.XMLTools;
054 import org.w3c.dom.Element;
055 import org.w3c.dom.Text;
056
057 /**
058 * Parser and wrapper class for GML feature collections.
059 * <p>
060 * Extends {@link GMLFeatureDocument}, as a feature collection is a feature in the GML type
061 * hierarchy.
062 * <p>
063 *
064 * TODO Remove hack for xlinked feature members (should be easy after fixing model package).
065 *
066 * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider </a>
067 * @author last edited by: $Author: apoth $
068 *
069 * @version $Revision: 9343 $, $Date: 2007-12-27 14:30:32 +0100 (Do, 27 Dez 2007) $
070 *
071 * @see GMLFeatureDocument
072 */
073 public class GMLFeatureCollectionDocument extends GMLFeatureDocument {
074
075 private static final long serialVersionUID = -6923435144671685710L;
076
077 private Collection<String> xlinkedMembers = new ArrayList<String>();
078
079 /**
080 * Creates a new instance of <code>GMLFeatureCollectionDocument</code>.
081 * <p>
082 * Simple types encountered during parsing are "guessed", i.e. the parser tries to convert the
083 * values to double, integer, calendar, etc. However, this may lead to unwanted results, e.g. a
084 * property value of "054604" is converted to "54604".
085 */
086 public GMLFeatureCollectionDocument() {
087 super();
088 }
089
090 /**
091 * Creates a new instance of <code>GMLFeatureCollectionDocument</code>.
092 * <p>
093 *
094 * @param guessSimpleTypes
095 * set to true, if simple types should be "guessed" during parsing
096 */
097 public GMLFeatureCollectionDocument( boolean guessSimpleTypes ) {
098 super( guessSimpleTypes );
099 }
100
101 /**
102 * Returns the object representation of the underlying feature collection document.
103 *
104 * @return object representation of the underlying feature collection document.
105 * @throws XMLParsingException
106 */
107 public FeatureCollection parse()
108 throws XMLParsingException {
109 FeatureCollection fc = parse( this.getRootElement() );
110 resolveXLinkReferences();
111 addXLinkedMembers( fc );
112 return fc;
113 }
114
115 /**
116 * Ugly hack that adds the "xlinked" feature members to the feature collection.
117 *
118 * TODO remove this
119 *
120 * @param fc
121 * @throws XMLParsingException
122 */
123 private void addXLinkedMembers( FeatureCollection fc )
124 throws XMLParsingException {
125 Iterator<String> iter = this.xlinkedMembers.iterator();
126 while ( iter.hasNext() ) {
127 String fid = iter.next();
128 Feature feature = this.featureMap.get( fid );
129 if ( feature == null ) {
130 String msg = Messages.format( "ERROR_XLINK_NOT_RESOLVABLE", fid );
131 throw new XMLParsingException( msg );
132 }
133 fc.add( feature );
134 }
135 }
136
137 /**
138 * Returns the object representation for the given feature collection element.
139 *
140 * @return object representation for the given feature collection element.
141 * @throws XMLParsingException
142 */
143 private FeatureCollection parse( Element element )
144 throws XMLParsingException {
145
146 String fcId = parseFeatureId( element );
147 // generate id if necessary (use feature type name + a unique number as id)
148 if ( "".equals( fcId ) ) {
149 fcId = element.getLocalName();
150 fcId += IDGenerator.getInstance().generateUniqueID();
151 }
152
153 String srsName = XMLTools.getNodeAsString( element, "gml:boundedBy/*[1]/@srsName", nsContext, null );
154
155 ElementList el = XMLTools.getChildElements( element );
156 List<Feature> list = new ArrayList<Feature>( el.getLength() );
157
158 for ( int i = 0; i < el.getLength(); i++ ) {
159 Feature member = null;
160 Element propertyElement = el.item( i );
161 String propertyName = propertyElement.getNodeName();
162
163 if ( !propertyName.endsWith( "boundedBy" ) && !propertyName.endsWith( "name" )
164 && !propertyName.endsWith( "description" ) ) {
165 // the first child of a feature member must always be a feature
166 Element featureElement = XMLTools.getChildElements( el.item( i ) ).item( 0 );
167 if ( featureElement == null ) {
168 // check if feature content is xlinked
169 // TODO remove this ugly hack
170 Text xlinkHref = (Text) XMLTools.getNode( propertyElement, "@xlink:href/text()", nsContext );
171 if ( xlinkHref == null ) {
172 String msg = Messages.format( "ERROR_INVALID_FEATURE_PROPERTY", propertyName );
173 throw new XMLParsingException( msg );
174 }
175 String href = xlinkHref.getData();
176 if ( !href.startsWith( "#" ) ) {
177 String msg = Messages.format( "ERROR_EXTERNAL_XLINK_NOT_SUPPORTED", href );
178 throw new XMLParsingException( msg );
179 }
180 String fid = href.substring( 1 );
181 this.xlinkedMembers.add( fid );
182 } else {
183 try {
184 member = parseFeature( featureElement, srsName );
185 list.add( member );
186 } catch ( Exception e ) {
187 throw new XMLParsingException( "Error creating feature instance from element '"
188 + featureElement.getLocalName() + "': " + e.getMessage(), e );
189 }
190 }
191 }
192 }
193
194 Feature[] features = list.toArray( new Feature[list.size()] );
195 FeatureCollection fc = FeatureFactory.createFeatureCollection( fcId, features );
196 String nof = element.getAttribute( "numberOfFeatures" );
197 if ( nof == null ) {
198 nof = "" + features.length;
199 }
200 fc.setAttribute( "numberOfFeatures", nof );
201 return fc;
202 }
203 }