325N/A/*
325N/A * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
325N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
325N/A *
325N/A * This code is free software; you can redistribute it and/or modify it
325N/A * under the terms of the GNU General Public License version 2 only, as
325N/A * published by the Free Software Foundation. Oracle designates this
325N/A * particular file as subject to the "Classpath" exception as provided
325N/A * by Oracle in the LICENSE file that accompanied this code.
325N/A *
325N/A * This code is distributed in the hope that it will be useful, but WITHOUT
325N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
325N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
325N/A * version 2 for more details (a copy is included in the LICENSE file that
325N/A * accompanied this code).
325N/A *
325N/A * You should have received a copy of the GNU General Public License version
325N/A * 2 along with this work; if not, write to the Free Software Foundation,
325N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
325N/A *
325N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
325N/A * or visit www.oracle.com if you need additional information or have any
325N/A * questions.
325N/A */
325N/A
325N/Apackage com.sun.tools.internal.xjc.model;
325N/A
325N/Aimport java.util.Collections;
325N/Aimport java.util.HashMap;
325N/Aimport java.util.HashSet;
325N/Aimport java.util.Iterator;
325N/Aimport java.util.LinkedHashMap;
325N/Aimport java.util.Map;
325N/Aimport java.util.Set;
325N/A
325N/Aimport javax.xml.bind.annotation.XmlAttribute;
325N/Aimport javax.xml.bind.annotation.XmlNsForm;
325N/Aimport javax.xml.bind.annotation.XmlTransient;
325N/Aimport javax.xml.namespace.QName;
325N/Aimport javax.xml.transform.Result;
325N/A
325N/Aimport com.sun.codemodel.internal.JClass;
325N/Aimport com.sun.codemodel.internal.JCodeModel;
325N/Aimport com.sun.codemodel.internal.JPackage;
325N/Aimport com.sun.tools.internal.xjc.ErrorReceiver;
325N/Aimport com.sun.tools.internal.xjc.Options;
325N/Aimport com.sun.tools.internal.xjc.Plugin;
325N/Aimport com.sun.tools.internal.xjc.api.ClassNameAllocator;
325N/Aimport com.sun.tools.internal.xjc.generator.bean.BeanGenerator;
325N/Aimport com.sun.tools.internal.xjc.generator.bean.ImplStructureStrategy;
325N/Aimport com.sun.tools.internal.xjc.model.nav.NClass;
325N/Aimport com.sun.tools.internal.xjc.model.nav.NType;
325N/Aimport com.sun.tools.internal.xjc.model.nav.NavigatorImpl;
325N/Aimport com.sun.tools.internal.xjc.outline.Outline;
325N/Aimport com.sun.tools.internal.xjc.reader.xmlschema.Messages;
325N/Aimport com.sun.tools.internal.xjc.util.ErrorReceiverFilter;
325N/Aimport com.sun.xml.internal.bind.api.impl.NameConverter;
325N/Aimport com.sun.xml.internal.bind.v2.model.core.Ref;
325N/Aimport com.sun.xml.internal.bind.v2.model.core.TypeInfoSet;
325N/Aimport com.sun.xml.internal.bind.v2.model.nav.Navigator;
325N/Aimport com.sun.xml.internal.bind.v2.util.FlattenIterator;
325N/Aimport com.sun.xml.internal.xsom.XSComponent;
325N/Aimport com.sun.xml.internal.xsom.XSSchemaSet;
325N/A
325N/Aimport org.xml.sax.Locator;
325N/Aimport org.xml.sax.SAXException;
325N/Aimport org.xml.sax.helpers.LocatorImpl;
325N/A
325N/A/**
325N/A * Root of the object model that represents the code that needs to be generated.
325N/A *
325N/A * <p>
325N/A * A {@link Model} is a schema language neutral representation of the
325N/A * result of a schema parsing. The back-end then works against this model
325N/A * to turn this into a series of Java source code.
325N/A *
325N/A * @author Kohsuke Kawaguchi
325N/A */
325N/Apublic final class Model implements TypeInfoSet<NType,NClass,Void,Void>, CCustomizable {
325N/A
325N/A /**
325N/A * Generated beans.
325N/A */
325N/A private final Map<NClass,CClassInfo> beans = new LinkedHashMap<NClass,CClassInfo>();
325N/A
325N/A /**
325N/A * Generated enums.
325N/A */
325N/A private final Map<NClass,CEnumLeafInfo> enums = new LinkedHashMap<NClass,CEnumLeafInfo>();
325N/A
325N/A /**
325N/A * The element mappings.
325N/A */
325N/A private final Map<NClass/*scope*/,Map<QName,CElementInfo>> elementMappings =
325N/A new HashMap<NClass,Map<QName,CElementInfo>>();
325N/A
325N/A private final Iterable<? extends CElementInfo> allElements =
325N/A new Iterable<CElementInfo>() {
325N/A public Iterator<CElementInfo> iterator() {
325N/A return new FlattenIterator<CElementInfo>(elementMappings.values());
325N/A }
325N/A };
325N/A
325N/A /**
325N/A * {@link TypeUse}s for all named types.
325N/A * <p>
325N/A * I really don't want to promote the notion of a 'type' in any place except in the XML Schema code,
325N/A * but this needs to be exposed for JAX-RPC. A reference to a named XML type will be converted into
325N/A * a reference to a Java type with annotations.
325N/A */
325N/A private final Map<QName,TypeUse> typeUses = new LinkedHashMap<QName, TypeUse>();
325N/A
325N/A /**
325N/A * {@link NameConverter} to be used.
325N/A */
325N/A private NameConverter nameConverter;
325N/A
325N/A /**
325N/A * Single linked list that connects all {@link CCustomizations} that belong to this model.
325N/A *
325N/A * @see CCustomizations#next
325N/A */
325N/A /*package*/ CCustomizations customizations;
325N/A
325N/A /**
325N/A * This field controls the generation of package level annotations for s2j
325N/A */
325N/A private boolean packageLevelAnnotations = true;
325N/A
325N/A /**
325N/A * If this model was built from XML Schema, this field
325N/A * stores the root object of the parse schema model.
325N/A * Otherwise null.
325N/A *
325N/A * @sine 2.1.1
325N/A */
325N/A public final XSSchemaSet schemaComponent;
325N/A
325N/A private CCustomizations gloablCustomizations = new CCustomizations();
325N/A
325N/A /**
325N/A * @param nc
325N/A * Usually this should be set in the constructor, but we do allow this parameter
325N/A * to be initially null, and then set later.
325N/A * @param schemaComponent
325N/A * The source schema model, if this is built from XSD.
325N/A */
325N/A public Model( Options opts, JCodeModel cm, NameConverter nc, ClassNameAllocator allocator, XSSchemaSet schemaComponent ) {
325N/A this.options = opts;
325N/A this.codeModel = cm;
325N/A this.nameConverter = nc;
325N/A this.defaultSymbolSpace = new SymbolSpace(codeModel);
325N/A defaultSymbolSpace.setType(codeModel.ref(Object.class));
325N/A
325N/A elementMappings.put(null,new HashMap<QName,CElementInfo>());
325N/A
325N/A if(opts.automaticNameConflictResolution)
325N/A allocator = new AutoClassNameAllocator(allocator);
325N/A this.allocator = new ClassNameAllocatorWrapper(allocator);
325N/A this.schemaComponent = schemaComponent;
325N/A this.gloablCustomizations.setParent(this,this);
325N/A }
325N/A
325N/A public void setNameConverter(NameConverter nameConverter) {
325N/A assert this.nameConverter==null;
325N/A assert nameConverter!=null;
325N/A this.nameConverter = nameConverter;
325N/A }
325N/A
325N/A /**
325N/A * Gets the name converter that shall be used to parse XML names into Java names.
325N/A */
325N/A public final NameConverter getNameConverter() {
325N/A return nameConverter;
325N/A }
325N/A
325N/A public boolean isPackageLevelAnnotations() {
325N/A return packageLevelAnnotations;
325N/A }
325N/A
325N/A public void setPackageLevelAnnotations(boolean packageLevelAnnotations) {
325N/A this.packageLevelAnnotations = packageLevelAnnotations;
325N/A }
325N/A
325N/A /**
325N/A * This model uses this code model exclusively.
325N/A */
325N/A @XmlTransient
325N/A public final JCodeModel codeModel;
325N/A
325N/A /**
325N/A * Command-line options used for building this model.
325N/A */
325N/A public final Options options;
325N/A
325N/A /**
325N/A * True to generate serializable classes.
325N/A */
325N/A @XmlAttribute
325N/A public boolean serializable;
325N/A
325N/A /**
325N/A * serial version UID to be generated.
325N/A *
325N/A * null if not to generate serialVersionUID field.
325N/A */
325N/A @XmlAttribute
325N/A public Long serialVersionUID;
325N/A
325N/A /**
325N/A * If non-null, all the generated classes should eventually derive from this class.
325N/A */
325N/A @XmlTransient
325N/A public JClass rootClass;
325N/A
325N/A /**
325N/A * If non-null, all the generated interfaces should eventually derive from this interface.
325N/A */
325N/A @XmlTransient
325N/A public JClass rootInterface;
325N/A
325N/A /**
325N/A * Specifies the code generation strategy.
325N/A * Must not be null.
325N/A */
325N/A public ImplStructureStrategy strategy = ImplStructureStrategy.BEAN_ONLY;
325N/A
325N/A /**
325N/A * This allocator has the final say on deciding the class name.
325N/A * Must not be null.
325N/A *
325N/A * <p>
325N/A * Model classes are responsible for using the allocator.
325N/A * This allocator interaction should be transparent to the user/builder
325N/A * of the model.
325N/A */
325N/A /*package*/ final ClassNameAllocatorWrapper allocator;
325N/A
325N/A /**
325N/A * Default ID/IDREF symbol space. Any ID/IDREF without explicit
325N/A * reference to a symbol space is assumed to use this default
325N/A * symbol space.
325N/A */
325N/A @XmlTransient
325N/A public final SymbolSpace defaultSymbolSpace;
325N/A
325N/A /** All the defined {@link SymbolSpace}s keyed by their name. */
325N/A private final Map<String,SymbolSpace> symbolSpaces = new HashMap<String,SymbolSpace>();
325N/A
325N/A public SymbolSpace getSymbolSpace( String name ) {
325N/A SymbolSpace ss = symbolSpaces.get(name);
325N/A if(ss==null)
325N/A symbolSpaces.put(name,ss=new SymbolSpace(codeModel));
325N/A return ss;
325N/A }
325N/A
325N/A /**
325N/A * Fully-generate the source code into the given model.
325N/A *
325N/A * @return
325N/A * null if there was any errors. Otherwise it returns a valid
325N/A * {@link Outline} object, which captures how the model objects
325N/A * are mapped to the generated source code.
325N/A * <p>
325N/A * Add-ons can use those information to further augment the generated
325N/A * source code.
325N/A */
325N/A public Outline generateCode(Options opt,ErrorReceiver receiver) {
325N/A ErrorReceiverFilter ehf = new ErrorReceiverFilter(receiver);
325N/A
325N/A // run extensions // moved to BGMBuilder._build() - issue with hyperjaxb3
325N/A// for( Plugin ma : opt.activePlugins )
325N/A// ma.postProcessModel(this,ehf);
325N/A
325N/A Outline o = BeanGenerator.generate(this, ehf);
325N/A
325N/A try {// run extensions
325N/A for( Plugin ma : opt.activePlugins )
325N/A ma.run(o,opt,ehf);
325N/A } catch (SAXException e) {
325N/A // fatal error. error should have been reported
325N/A return null;
325N/A }
325N/A
325N/A // check for unused plug-in customizations.
325N/A // these can be only checked after the plug-ins run, so it's here.
325N/A // the JAXB bindings are checked by XMLSchema's builder.
325N/A Set<CCustomizations> check = new HashSet<CCustomizations>();
325N/A for( CCustomizations c=customizations; c!=null; c=c.next ) {
325N/A if(!check.add(c)) {
325N/A throw new AssertionError(); // detect a loop
325N/A }
325N/A for (CPluginCustomization p : c) {
325N/A if(!p.isAcknowledged()) {
325N/A ehf.error(
325N/A p.locator,
325N/A Messages.format(
325N/A Messages.ERR_UNACKNOWLEDGED_CUSTOMIZATION,
325N/A p.element.getNodeName()
325N/A ));
325N/A ehf.error(
325N/A c.getOwner().getLocator(),
325N/A Messages.format(
325N/A Messages.ERR_UNACKNOWLEDGED_CUSTOMIZATION_LOCATION));
325N/A }
325N/A }
325N/A }
325N/A
325N/A if(ehf.hadError())
325N/A o = null;
325N/A return o;
325N/A }
325N/A
325N/A /**
325N/A * Represents the "top-level binding".
325N/A *
325N/A * <p>
325N/A * This is used to support the use of a schema inside WSDL.
325N/A * For XML Schema, the top-level binding is a map from
325N/A * global element declarations to its representation class.
325N/A *
325N/A * <p>
325N/A * For other schema languages, it should follow the appendicies in
325N/A * WSDL (but in practice no one would use WSDL with a schema language
325N/A * other than XML Schema, so it doesn't really matter.)
325N/A *
325N/A * <p>
325N/A * This needs to be filled by the front-end.
325N/A */
325N/A public final Map<QName,CClassInfo> createTopLevelBindings() {
325N/A Map<QName,CClassInfo> r = new HashMap<QName,CClassInfo>();
325N/A for( CClassInfo b : beans().values() ) {
325N/A if(b.isElement())
325N/A r.put(b.getElementName(),b);
325N/A }
325N/A return r;
325N/A }
325N/A
325N/A public Navigator<NType,NClass,Void,Void> getNavigator() {
325N/A return NavigatorImpl.theInstance;
325N/A }
325N/A
325N/A public CNonElement getTypeInfo(NType type) {
325N/A CBuiltinLeafInfo leaf = CBuiltinLeafInfo.LEAVES.get(type);
325N/A if(leaf!=null) return leaf;
325N/A
325N/A return getClassInfo(getNavigator().asDecl(type));
325N/A }
325N/A
325N/A public CBuiltinLeafInfo getAnyTypeInfo() {
325N/A return CBuiltinLeafInfo.ANYTYPE;
325N/A }
325N/A
325N/A public CNonElement getTypeInfo(Ref<NType,NClass> ref) {
325N/A // TODO: handle XmlValueList
325N/A assert !ref.valueList;
325N/A return getTypeInfo(ref.type);
325N/A }
325N/A
325N/A public Map<NClass,CClassInfo> beans() {
325N/A return beans;
325N/A }
325N/A
325N/A public Map<NClass,CEnumLeafInfo> enums() {
325N/A return enums;
325N/A }
325N/A
325N/A public Map<QName,TypeUse> typeUses() {
325N/A return typeUses;
325N/A }
325N/A
325N/A /**
325N/A * No array mapping generation for XJC.
325N/A */
325N/A public Map<NType, ? extends CArrayInfo> arrays() {
325N/A return Collections.emptyMap();
325N/A }
325N/A
325N/A public Map<NType, ? extends CBuiltinLeafInfo> builtins() {
325N/A return CBuiltinLeafInfo.LEAVES;
325N/A }
325N/A
325N/A public CClassInfo getClassInfo(NClass t) {
325N/A return beans.get(t);
325N/A }
325N/A
325N/A public CElementInfo getElementInfo(NClass scope,QName name) {
325N/A Map<QName,CElementInfo> m = elementMappings.get(scope);
325N/A if(m!=null) {
325N/A CElementInfo r = m.get(name);
325N/A if(r!=null) return r;
325N/A }
325N/A return elementMappings.get(null).get(name);
325N/A }
325N/A
325N/A public Map<QName,CElementInfo> getElementMappings(NClass scope) {
325N/A return elementMappings.get(scope);
325N/A }
325N/A
325N/A public Iterable<? extends CElementInfo> getAllElements() {
325N/A return allElements;
325N/A }
325N/A
325N/A /**
325N/A * @deprecated
325N/A * Always return null. Perhaps you are interested in {@link #schemaComponent}?
325N/A */
325N/A public XSComponent getSchemaComponent() {
325N/A return null;
325N/A }
325N/A
325N/A /**
325N/A * @deprecated
325N/A * No line number available for the "root" component.
325N/A */
325N/A public Locator getLocator() {
325N/A LocatorImpl r = new LocatorImpl();
325N/A r.setLineNumber(-1);
325N/A r.setColumnNumber(-1);
325N/A return r;
325N/A }
325N/A
325N/A /**
325N/A * Gets the global customizations.
325N/A */
325N/A public CCustomizations getCustomizations() {
325N/A return gloablCustomizations;
325N/A }
325N/A
325N/A /**
325N/A * Not implemented in the compile-time model.
325N/A */
325N/A public Map<String, String> getXmlNs(String namespaceUri) {
325N/A return Collections.emptyMap();
325N/A }
325N/A
325N/A public Map<String, String> getSchemaLocations() {
325N/A return Collections.emptyMap();
325N/A }
325N/A
325N/A public XmlNsForm getElementFormDefault(String nsUri) {
325N/A throw new UnsupportedOperationException();
325N/A }
325N/A
325N/A public XmlNsForm getAttributeFormDefault(String nsUri) {
325N/A throw new UnsupportedOperationException();
325N/A }
325N/A
325N/A public void dump(Result out) {
325N/A // TODO
325N/A throw new UnsupportedOperationException();
325N/A }
325N/A
325N/A /*package*/ void add( CEnumLeafInfo e ) {
325N/A enums.put( e.getClazz(), e );
325N/A }
325N/A
325N/A /*package*/ void add( CClassInfo ci ) {
325N/A beans.put( ci.getClazz(), ci );
325N/A }
325N/A
325N/A /*package*/ void add( CElementInfo ei ) {
325N/A NClass clazz = null;
325N/A if(ei.getScope()!=null)
325N/A clazz = ei.getScope().getClazz();
325N/A
325N/A Map<QName,CElementInfo> m = elementMappings.get(clazz);
325N/A if(m==null)
325N/A elementMappings.put(clazz,m=new HashMap<QName,CElementInfo>());
325N/A m.put(ei.getElementName(),ei);
325N/A }
325N/A
325N/A
325N/A private final Map<JPackage,CClassInfoParent.Package> cache = new HashMap<JPackage,CClassInfoParent.Package>();
325N/A
325N/A public CClassInfoParent.Package getPackage(JPackage pkg) {
325N/A CClassInfoParent.Package r = cache.get(pkg);
325N/A if(r==null)
325N/A cache.put(pkg,r=new CClassInfoParent.Package(pkg));
325N/A return r;
325N/A }
325N/A
325N/A /*package*/ static final Locator EMPTY_LOCATOR;
325N/A
325N/A static {
325N/A LocatorImpl l = new LocatorImpl();
325N/A l.setColumnNumber(-1);
325N/A l.setLineNumber(-1);
325N/A EMPTY_LOCATOR = l;
325N/A }
325N/A}