/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2002-2008, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.xml.impl; import org.apache.commons.collections.MultiHashMap; import org.eclipse.xsd.XSDElementDeclaration; import org.eclipse.xsd.XSDFactory; import org.eclipse.xsd.XSDParticle; import org.picocontainer.MutablePicoContainer; import org.w3c.dom.Element; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.xml.namespace.QName; import org.geotools.xml.Encoder; import org.geotools.xml.PropertyExtractor; import org.geotools.xml.Schemas; /** * Uses {@link org.geotools.xml.ComplexBinding#getProperty(Object, QName)} to obtain * properties from the objecet being encoded. * * @author Justin Deoliveira, The Open Planning Project * * * @source $URL$ */ public class BindingPropertyExtractor implements PropertyExtractor { Encoder encoder; MutablePicoContainer context; public BindingPropertyExtractor(Encoder encoder, MutablePicoContainer context) { this.encoder = encoder; this.context = context; } public boolean canHandle(Object object) { return true; } public void setContext(MutablePicoContainer context) { this.context = context; } public List properties(Object object, XSDElementDeclaration element) { List properties = new ArrayList(); //first get all the properties that can be infered from teh schema List children = encoder.getSchemaIndex().getChildElementParticles(element); O: for (Iterator itr = children.iterator(); itr.hasNext();) { XSDParticle particle = (XSDParticle) itr.next(); XSDElementDeclaration child = (XSDElementDeclaration) particle.getContent(); if (child.isElementDeclarationReference()) { child = child.getResolvedElementDeclaration(); } //get the object(s) for this element GetPropertyExecutor executor = new GetPropertyExecutor(object, child); BindingVisitorDispatch.walk(object, encoder.getBindingWalker(), element, executor, context); if (executor.getChildObject() != null) { properties.add(new Object[] { particle, executor.getChildObject() }); } } //second, get the properties which cannot be infereed from the schema GetPropertiesExecutor executor = new GetPropertiesExecutor(object,element); BindingVisitorDispatch.walk(object, encoder.getBindingWalker(), element, executor, context); if (!executor.getProperties().isEmpty()) { //group into a map of name, list MultiHashMap map = new MultiHashMap(); for (Iterator p = executor.getProperties().iterator(); p.hasNext();) { Object[] property = (Object[]) p.next(); map.put(property[0], property[1]); } //turn each map entry into a particle HashMap particles = new HashMap(); for (Iterator e = map.entrySet().iterator(); e.hasNext();) { Map.Entry entry = (Map.Entry) e.next(); //key could be a name or a particle if ( entry.getKey() instanceof XSDParticle ) { XSDParticle particle = (XSDParticle) entry.getKey(); particles.put( Schemas.getParticleName( particle), particle ); continue; } QName name = (QName) entry.getKey(); Collection values = (Collection) entry.getValue(); //check for comment if (Encoder.COMMENT.equals(name)) { //create a dom element which text nodes for the comments Element comment = encoder.getDocument() .createElement(Encoder.COMMENT.getLocalPart()); for (Iterator v = values.iterator(); v.hasNext();) { comment.appendChild(encoder.getDocument().createTextNode(v.next().toString())); } XSDParticle particle = XSDFactory.eINSTANCE.createXSDParticle(); XSDElementDeclaration elementDecl = XSDFactory.eINSTANCE .createXSDElementDeclaration(); elementDecl.setTargetNamespace(Encoder.COMMENT.getNamespaceURI()); elementDecl.setName(Encoder.COMMENT.getLocalPart()); elementDecl.setElement(comment); particle.setContent(elementDecl); particles.put(name, particle); continue; } //find hte element XSDElementDeclaration elementDecl = encoder.getSchemaIndex() .getElementDeclaration(name); if (elementDecl == null) { //TODO: resolving like this will return an element no // matter what, modifying the underlying schema, this might // be dangerous. What we shold do is force the schema to // resolve all of it simports when the encoder starts elementDecl = encoder.getSchema() .resolveElementDeclaration(name.getNamespaceURI(), name.getLocalPart()); } //look for a particle in the containing type which is either // a) a base type of the element // b) in the same subsittuion group // if found use the particle to dervice multiplicity XSDParticle reference = null; for ( Iterator p = Schemas.getChildElementParticles(element.getType(), true).iterator(); p.hasNext(); ) { XSDParticle particle = (XSDParticle) p.next(); XSDElementDeclaration el = (XSDElementDeclaration) particle.getContent(); if ( el.isElementDeclarationReference() ) { el = el.getResolvedElementDeclaration(); } if ( Schemas.isBaseType(elementDecl, el) ) { reference = particle; break; } } //wrap the property in a particle XSDParticle particle = XSDFactory.eINSTANCE.createXSDParticle(); XSDElementDeclaration wrapper = XSDFactory.eINSTANCE.createXSDElementDeclaration(); wrapper.setResolvedElementDeclaration( elementDecl ); particle.setContent(wrapper); //particle.setContent(elementDecl); //if there is a reference, derive multiplicity if ( reference != null ) { particle.setMaxOccurs( reference.getMaxOccurs() ); } else { //dervice from collection if ( values.size() > 1) { //make a multi property particle.setMaxOccurs(-1); } else { //single property particle.setMaxOccurs(1); } } particles.put(name, particle); } //process the particles in order in which we got the properties for (Iterator p = executor.getProperties().iterator(); p.hasNext();) { Object[] property = (Object[]) p.next(); Collection values = (Collection) map.get( property[0] ); QName name; if ( property[0] instanceof XSDParticle ) { name = Schemas.getParticleName( (XSDParticle) property[0] ); } else { name = (QName) property[0]; } XSDParticle particle = (XSDParticle) particles.get(name); if (particle == null) { continue; //already processed, must be a multi property } if (values.size() > 1) { //add as is, the encoder will unwrap properties.add(new Object[] { particle, values }); } else { //unwrap it properties.add(new Object[] { particle, values.iterator().next() }); } //done with this particle particles.remove(name); } } return properties; } }