/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 1997-2013 Oracle and/or its affiliates. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development * and Distribution License("CDDL") (collectively, the "License"). You * may not use this file except in compliance with the License. You can * obtain a copy of the License at * http://glassfish.java.net/public/CDDL+GPL_1_1.html * or packager/legal/LICENSE.txt. See the License for the specific * language governing permissions and limitations under the License. * * When distributing the software, include this License Header Notice in each * file and include the License file at packager/legal/LICENSE.txt. * * GPL Classpath Exception: * Oracle designates this particular file as subject to the "Classpath" * exception as provided by Oracle in the GPL Version 2 section of the License * file that accompanied this code. * * Modifications: * If applicable, add the following below the License Header, with the fields * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyright [year] [name of copyright owner]" * * Contributor(s): * If you wish your version of this file to be governed by only the CDDL or * only the GPL Version 2, indicate your decision by adding "[Contributor] * elects to include this software in this distribution under the [CDDL or GPL * Version 2] license." If you don't indicate a single choice of license, a * recipient has the option to distribute your version of this file under * either the CDDL, the GPL Version 2 or to extend the choice of license to * its licensees as provided above. However, if you add GPL Version 2 code * and therefore, elected the GPL Version 2 license, then the option applies * only if the new code is made subject to such option by the copyright * holder. */ package com.sun.xml.xsom.impl.scd; import com.sun.xml.xsom.XSAttContainer; import com.sun.xml.xsom.XSAttGroupDecl; import com.sun.xml.xsom.XSAttributeDecl; import com.sun.xml.xsom.XSAttributeUse; import com.sun.xml.xsom.XSComplexType; import com.sun.xml.xsom.XSComponent; import com.sun.xml.xsom.XSElementDecl; import com.sun.xml.xsom.XSFacet; import com.sun.xml.xsom.XSIdentityConstraint; import com.sun.xml.xsom.XSListSimpleType; import com.sun.xml.xsom.XSModelGroup; import com.sun.xml.xsom.XSModelGroup.Compositor; import com.sun.xml.xsom.XSModelGroupDecl; import com.sun.xml.xsom.XSNotation; import com.sun.xml.xsom.XSParticle; import com.sun.xml.xsom.XSRestrictionSimpleType; import com.sun.xml.xsom.XSSchema; import com.sun.xml.xsom.XSSimpleType; import com.sun.xml.xsom.XSType; import com.sun.xml.xsom.XSUnionSimpleType; import com.sun.xml.xsom.XSWildcard; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; /** * Axis of traversal. * * @param <T> * The kind of components that this axis may return. * * @author Kohsuke Kawaguchi */ public interface Axis<T extends XSComponent> { Iterator<T> iterator(XSComponent contextNode); Iterator<T> iterator(Iterator<? extends XSComponent> contextNodes); /** * Returns true if this is one of the model group axis. */ boolean isModelGroup(); /** * Pseudo-axis that selects all the {@link XSSchema}s in the current set. * Used to implement the absolute path expression */ public static final Axis<XSSchema> ROOT = new Axis<XSSchema>() { public Iterator<XSSchema> iterator(XSComponent contextNode) { return contextNode.getRoot().iterateSchema(); } public Iterator<XSSchema> iterator(Iterator<? extends XSComponent> contextNodes) { if(!contextNodes.hasNext()) return Iterators.empty(); else // this assumes that all current nodes belong to the same owner. return iterator(contextNodes.next()); } public boolean isModelGroup() { return false; } public String toString() { return "root::"; } }; /** * Pseudo-axis that visits all skipped intermediate steps. * Those are: * <ol> * <li>complex type reachable from element * <li>model groups * <li>combination of above. * </ol> */ public static final Axis<XSComponent> INTERMEDIATE_SKIP = new AbstractAxisImpl<XSComponent>() { public Iterator<XSComponent> elementDecl(XSElementDecl decl) { XSComplexType ct = decl.getType().asComplexType(); if(ct==null) return empty(); else { // also pick up model groups inside this complex type return new Iterators.Union<XSComponent>(singleton(ct),complexType(ct)); } } public Iterator<XSComponent> modelGroupDecl(XSModelGroupDecl decl) { return descendants(decl.getModelGroup()); } public Iterator<XSComponent> particle(XSParticle particle) { return descendants(particle.getTerm().asModelGroup()); } /** * Iterate all descendant model groups of the given model group, including itself. */ private Iterator<XSComponent> descendants(XSModelGroup mg) { // TODO: write a tree iterator // for now, we do it eagerly because I'm lazy List<XSComponent> r = new ArrayList<XSComponent>(); visit(mg,r); return r.iterator(); } private void visit(XSModelGroup mg, List<XSComponent> r) { // since model groups never form a cycle, no cycle check is needed r.add(mg); for (XSParticle p : mg) { XSModelGroup child = p.getTerm().asModelGroup(); if(child!=null) visit(child,r); } } public String toString() { return "(intermediateSkip)"; } }; /** * All descendants reachable via default axes. Used to implement the "//" semantics. * * So far the default axes together are guaranteed not to cause any cycle, so * no cycle check is needed (if it's needed, the life would be much harder!) */ public static final Axis<XSComponent> DESCENDANTS = new Axis<XSComponent>() { public Iterator<XSComponent> iterator(XSComponent contextNode) { return new Visitor().iterator(contextNode); } public Iterator<XSComponent> iterator(Iterator<? extends XSComponent> contextNodes) { return new Visitor().iterator(contextNodes); } public boolean isModelGroup() { return false; } /** * Stateful visitor that remembers what's already traversed, to reduce the search space. */ final class Visitor extends AbstractAxisImpl<XSComponent> { private final Set<XSComponent> visited = new HashSet<XSComponent>(); /** * Recursively apply the {@link Axis#DESCENDANTS} axis. */ final class Recursion extends Iterators.Map<XSComponent,XSComponent> { public Recursion(Iterator<? extends XSComponent> core) { super(core); } protected Iterator<XSComponent> apply(XSComponent u) { return DESCENDANTS.iterator(u); } } public Iterator<XSComponent> schema(XSSchema schema) { if(visited.add(schema)) return ret( schema, new Recursion(schema.iterateElementDecls())); else return empty(); } public Iterator<XSComponent> elementDecl(XSElementDecl decl) { if(visited.add(decl)) return ret(decl, iterator(decl.getType()) ); else return empty(); } public Iterator<XSComponent> simpleType(XSSimpleType type) { if(visited.add(type)) return ret(type, FACET.iterator(type)); else return empty(); } public Iterator<XSComponent> complexType(XSComplexType type) { if(visited.add(type)) return ret(type, iterator(type.getContentType())); else return empty(); } public Iterator<XSComponent> particle(XSParticle particle) { if(visited.add(particle)) return ret(particle, iterator(particle.getTerm())); else return empty(); } public Iterator<XSComponent> modelGroupDecl(XSModelGroupDecl decl) { if(visited.add(decl)) return ret(decl, iterator(decl.getModelGroup())); else return empty(); } public Iterator<XSComponent> modelGroup(XSModelGroup group) { if(visited.add(group)) return ret(group, new Recursion(group.iterator())); else return empty(); } public Iterator<XSComponent> attGroupDecl(XSAttGroupDecl decl) { if(visited.add(decl)) return ret(decl, new Recursion(decl.iterateAttributeUses())); else return empty(); } public Iterator<XSComponent> attributeUse(XSAttributeUse use) { if(visited.add(use)) return ret(use, iterator(use.getDecl())); else return empty(); } public Iterator<XSComponent> attributeDecl(XSAttributeDecl decl) { if(visited.add(decl)) return ret(decl, iterator(decl.getType())); else return empty(); } private Iterator<XSComponent> ret( XSComponent one, Iterator<? extends XSComponent> rest ) { return union(singleton(one),rest); } } public String toString() { return "/"; } }; public static final Axis<XSSchema> X_SCHEMA = new Axis<XSSchema>() { public Iterator<XSSchema> iterator(XSComponent contextNode) { return Iterators.singleton(contextNode.getOwnerSchema()); } public Iterator<XSSchema> iterator(Iterator<? extends XSComponent> contextNodes) { return new Iterators.Adapter<XSSchema,XSComponent>(contextNodes) { protected XSSchema filter(XSComponent u) { return u.getOwnerSchema(); } }; } public boolean isModelGroup() { return false; } public String toString() { return "x-schema::"; } }; public static final Axis<XSElementDecl> SUBSTITUTION_GROUP = new AbstractAxisImpl<XSElementDecl>() { public Iterator<XSElementDecl> elementDecl(XSElementDecl decl) { return singleton(decl.getSubstAffiliation()); } public String toString() { return "substitutionGroup::"; } }; public static final Axis<XSAttributeDecl> ATTRIBUTE = new AbstractAxisImpl<XSAttributeDecl>() { public Iterator<XSAttributeDecl> complexType(XSComplexType type) { return attributeHolder(type); } public Iterator<XSAttributeDecl> attGroupDecl(XSAttGroupDecl decl) { return attributeHolder(decl); } private Iterator<XSAttributeDecl> attributeHolder(final XSAttContainer atts) { // TODO: check spec. is this correct? return new Iterators.Adapter<XSAttributeDecl,XSAttributeUse>(atts.iterateAttributeUses()) { protected XSAttributeDecl filter(XSAttributeUse u) { return u.getDecl(); } }; } public Iterator<XSAttributeDecl> schema(XSSchema schema) { return schema.iterateAttributeDecls(); } public String toString() { return "@"; } }; public static final Axis<XSElementDecl> ELEMENT = new AbstractAxisImpl<XSElementDecl>() { public Iterator<XSElementDecl> particle(XSParticle particle) { return singleton(particle.getTerm().asElementDecl()); } public Iterator<XSElementDecl> schema(XSSchema schema) { return schema.iterateElementDecls(); } public Iterator<XSElementDecl> modelGroupDecl(XSModelGroupDecl decl) { return modelGroup(decl.getModelGroup()); } //public Iterator<XSElementDecl> modelGroup(XSModelGroup group) { // return new Iterators.Map<XSElementDecl,XSParticle>(group.iterator()) { // protected Iterator<XSElementDecl> apply(XSParticle p) { // return particle(p); // } // }; //} @Override public String getName() { return ""; } public String toString() { return "element::"; } }; public static final Axis<XSType> TYPE_DEFINITION = new AbstractAxisImpl<XSType>() { public Iterator<XSType> schema(XSSchema schema) { return schema.iterateTypes(); } public Iterator<XSType> attributeDecl(XSAttributeDecl decl) { return singleton(decl.getType()); } public Iterator<XSType> elementDecl(XSElementDecl decl) { return singleton(decl.getType()); } public String toString() { return "~"; } }; public static final Axis<XSType> BASETYPE = new AbstractAxisImpl<XSType>() { public Iterator<XSType> simpleType(XSSimpleType type) { return singleton(type.getBaseType()); } public Iterator<XSType> complexType(XSComplexType type) { return singleton(type.getBaseType()); } public String toString() { return "baseType::"; } }; public static final Axis<XSSimpleType> PRIMITIVE_TYPE = new AbstractAxisImpl<XSSimpleType>() { public Iterator<XSSimpleType> simpleType(XSSimpleType type) { return singleton(type.getPrimitiveType()); } public String toString() { return "primitiveType::"; } }; public static final Axis<XSSimpleType> ITEM_TYPE = new AbstractAxisImpl<XSSimpleType>() { public Iterator<XSSimpleType> simpleType(XSSimpleType type) { XSListSimpleType baseList = type.getBaseListType(); if(baseList==null) return empty(); return singleton(baseList.getItemType()); } public String toString() { return "itemType::"; } }; public static final Axis<XSSimpleType> MEMBER_TYPE = new AbstractAxisImpl<XSSimpleType>() { public Iterator<XSSimpleType> simpleType(XSSimpleType type) { XSUnionSimpleType baseUnion = type.getBaseUnionType(); if(baseUnion ==null) return empty(); return baseUnion.iterator(); } public String toString() { return "memberType::"; } }; public static final Axis<XSComponent> SCOPE = new AbstractAxisImpl<XSComponent>() { public Iterator<XSComponent> complexType(XSComplexType type) { return singleton(type.getScope()); } // TODO: attribute declaration has a scope, too. // TODO: element declaration has a scope public String toString() { return "scope::"; } }; public static final Axis<XSAttGroupDecl> ATTRIBUTE_GROUP = new AbstractAxisImpl<XSAttGroupDecl>() { public Iterator<XSAttGroupDecl> schema(XSSchema schema) { return schema.iterateAttGroupDecls(); } public String toString() { return "attributeGroup::"; } }; public static final Axis<XSModelGroupDecl> MODEL_GROUP_DECL = new AbstractAxisImpl<XSModelGroupDecl>() { public Iterator<XSModelGroupDecl> schema(XSSchema schema) { return schema.iterateModelGroupDecls(); } public Iterator<XSModelGroupDecl> particle(XSParticle particle) { return singleton(particle.getTerm().asModelGroupDecl()); } public String toString() { return "group::"; } }; public static final Axis<XSIdentityConstraint> IDENTITY_CONSTRAINT = new AbstractAxisImpl<XSIdentityConstraint>() { public Iterator<XSIdentityConstraint> elementDecl(XSElementDecl decl) { return decl.getIdentityConstraints().iterator(); } public Iterator<XSIdentityConstraint> schema(XSSchema schema) { // TODO: iterate all elements in this schema (local or global!) and its identity constraints return super.schema(schema); } public String toString() { return "identityConstraint::"; } }; public static final Axis<XSIdentityConstraint> REFERENCED_KEY = new AbstractAxisImpl<XSIdentityConstraint>() { public Iterator<XSIdentityConstraint> identityConstraint(XSIdentityConstraint decl) { return singleton(decl.getReferencedKey()); } public String toString() { return "key::"; } }; public static final Axis<XSNotation> NOTATION = new AbstractAxisImpl<XSNotation>() { public Iterator<XSNotation> schema(XSSchema schema) { return schema.iterateNotations(); } public String toString() { return "notation::"; } }; public static final Axis<XSWildcard> WILDCARD = new AbstractAxisImpl<XSWildcard>() { public Iterator<XSWildcard> particle(XSParticle particle) { return singleton(particle.getTerm().asWildcard()); } public String toString() { return "any::"; } }; public static final Axis<XSWildcard> ATTRIBUTE_WILDCARD = new AbstractAxisImpl<XSWildcard>() { public Iterator<XSWildcard> complexType(XSComplexType type) { return singleton(type.getAttributeWildcard()); } public Iterator<XSWildcard> attGroupDecl(XSAttGroupDecl decl) { return singleton(decl.getAttributeWildcard()); } public String toString() { return "anyAttribute::"; } }; public static final Axis<XSFacet> FACET = new AbstractAxisImpl<XSFacet>() { public Iterator<XSFacet> simpleType(XSSimpleType type) { // TODO: it's not clear if "facets" mean all inherited facets or just declared facets XSRestrictionSimpleType r = type.asRestriction(); if(r!=null) return r.iterateDeclaredFacets(); else return empty(); } public String toString() { return "facet::"; } }; public static final Axis<XSModelGroup> MODELGROUP_ALL = new ModelGroupAxis(Compositor.ALL); public static final Axis<XSModelGroup> MODELGROUP_CHOICE = new ModelGroupAxis(Compositor.CHOICE); public static final Axis<XSModelGroup> MODELGROUP_SEQUENCE = new ModelGroupAxis(Compositor.SEQUENCE); public static final Axis<XSModelGroup> MODELGROUP_ANY = new ModelGroupAxis(null); static final class ModelGroupAxis extends AbstractAxisImpl<XSModelGroup> { private final XSModelGroup.Compositor compositor; ModelGroupAxis(Compositor compositor) { this.compositor = compositor; } @Override public boolean isModelGroup() { return true; } public Iterator<XSModelGroup> particle(XSParticle particle) { return filter(particle.getTerm().asModelGroup()); } public Iterator<XSModelGroup> modelGroupDecl(XSModelGroupDecl decl) { return filter(decl.getModelGroup()); } private Iterator<XSModelGroup> filter(XSModelGroup mg) { if(mg==null) return empty(); if(mg.getCompositor() == compositor || compositor == null) return singleton(mg); else return empty(); } public String toString() { if(compositor==null) return "model::*"; else return "model::"+compositor; } } }