001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2002-2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.xml.impl;
017:
018: import java.util.ArrayList;
019: import java.util.HashMap;
020: import java.util.Iterator;
021: import java.util.List;
022: import java.util.Stack;
023:
024: import javax.xml.namespace.QName;
025:
026: import org.eclipse.xsd.XSDComplexTypeDefinition;
027: import org.eclipse.xsd.XSDElementDeclaration;
028: import org.eclipse.xsd.XSDFeature;
029: import org.eclipse.xsd.XSDParticle;
030: import org.eclipse.xsd.XSDSimpleTypeDefinition;
031: import org.eclipse.xsd.XSDTypeDefinition;
032: import org.geotools.xml.Binding;
033: import org.geotools.xml.Schemas;
034: import org.geotools.xs.bindings.XS;
035: import org.picocontainer.MutablePicoContainer;
036:
037: public class BindingWalker implements TypeWalker.Visitor {
038: BindingLoader loader;
039: HashMap/*<XSDFeature,BindingExecutionChain>*/chains;
040: TypeWalker typeWalker;
041:
042: MutablePicoContainer context;
043: ArrayList bindings;
044: XSDFeature component;
045: XSDTypeDefinition container;
046:
047: public BindingWalker(BindingLoader factory) {
048: this .loader = factory;
049:
050: chains = new HashMap();
051: typeWalker = new TypeWalker();
052: }
053:
054: public boolean visit(XSDTypeDefinition type) {
055: //look up the associated binding object for this type
056:
057: QName bindingName = null;
058: if (type.getName() != null) {
059: bindingName = new QName(type.getTargetNamespace(), type
060: .getName());
061: } else {
062: //anonymous type, does it belong to a global element
063: for (Iterator e = type.getSchema().getElementDeclarations()
064: .iterator(); e.hasNext();) {
065: XSDElementDeclaration element = (XSDElementDeclaration) e
066: .next();
067: if (type.equals(element.getAnonymousTypeDefinition())) {
068: //TODO: this naming convention for anonymous types could conflict with
069: // other types in the schema
070: bindingName = new QName(type.getTargetNamespace(),
071: "_" + element.getName());
072: break;
073: }
074: }
075:
076: if (bindingName == null) {
077: //do we have a containing type?
078: if (container != null) {
079: //get the anonymous element, and look it up in the container type
080: if (type.getContainer() instanceof XSDElementDeclaration) {
081: XSDElementDeclaration anonymous = (XSDElementDeclaration) type
082: .getContainer();
083: XSDParticle particle = Schemas
084: .getChildElementParticle(container,
085: anonymous.getName(), true);
086: if (particle != null) {
087: bindingName = new QName(container
088: .getTargetNamespace(), container
089: .getName()
090: + "_" + anonymous.getName());
091: }
092: }
093: }
094: }
095:
096: if (bindingName == null
097: || loader.getBinding(bindingName) == null) {
098: //special case check, look for an anonymous complex type
099: // with simple content
100: if (type instanceof XSDComplexTypeDefinition
101: && type.getBaseType() instanceof XSDSimpleTypeDefinition) {
102: //we assign the default complex binding instread of
103: // delegating to parent, because if we dont, any attributes
104: // defined by the type will not be parsed because simple
105: // types cannot have attributes.
106: //TODO: put this somewhere else, perahps in teh factories
107: // that create the bindings
108: bindingName = XS.ANYTYPE;
109: }
110: }
111: }
112:
113: //load the binding into the current context
114: Binding binding = loader.loadBinding(bindingName, context);
115: if (binding != null) {
116: //add the binding
117: bindings.add(binding);
118:
119: //check execution mode, if override break out
120: if (binding.getExecutionMode() == Binding.OVERRIDE) {
121: return false;
122: }
123: }
124:
125: return true;
126: }
127:
128: public void walk(XSDFeature component, Visitor visitor,
129: XSDTypeDefinition container, MutablePicoContainer context) {
130:
131: BindingExecutionChain chain = (BindingExecutionChain) chains
132: .get(component);
133: if (chain == null) {
134:
135: this .container = container;
136: this .component = component;
137: this .context = context;
138: this .bindings = new ArrayList();
139:
140: //first walk the type hierarchy to get the binding objects
141: typeWalker.walk(component.getType(), this );
142:
143: //also look up a binding to teh instance itself, if found it will go
144: // at the bottom of the binding hierarchy
145: if (component.getName() != null) {
146: QName qName = new QName(component.getTargetNamespace(),
147: component.getName());
148: Binding binding = loader.loadBinding(qName, context);
149:
150: if (binding != null) {
151: //check for override
152: if (binding.getExecutionMode() == Binding.OVERRIDE) {
153: //override, clear the binding list
154: bindings.clear();
155: bindings.add(binding);
156: } else {
157: //not override, add as first
158: bindings.add(0, binding);
159: }
160:
161: }
162: }
163:
164: chain = new BindingExecutionChain(bindings);
165: chains.put(component, chain);
166: }
167:
168: chain.execute(visitor);
169: }
170:
171: public void walk(XSDFeature component, Visitor visitor,
172: MutablePicoContainer context) {
173: walk(component, visitor, null, context);
174: }
175:
176: public static interface Visitor {
177: void visit(Binding binding);
178: }
179:
180: public static class BindingExecutionChain {
181: List bindings;
182:
183: public BindingExecutionChain(List bindings) {
184: this .bindings = bindings;
185: }
186:
187: public void execute(Visitor visitor) {
188: //simulated call stack
189: Stack stack = new Stack();
190:
191: //visit from bottom to top
192: for (int i = 0; i < bindings.size(); i++) {
193: Binding binding = (Binding) bindings.get(i);
194:
195: if (binding.getExecutionMode() == Binding.AFTER) {
196: //put on stack to execute after parent
197: stack.push(binding);
198:
199: continue;
200: }
201:
202: //execute the strategy
203: visitor.visit(binding);
204: }
205:
206: //unwind the call stack
207: while (!stack.isEmpty()) {
208: Binding binding = (Binding) stack.pop();
209:
210: visitor.visit(binding);
211: }
212: }
213: }
214: }
|