blob: b3e25e0dbaf610ef8a3659a74355d414df503f64 [file] [log] [blame]
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* XSD/DTD Model generator tool
*
* By Gregory Shrago
* 2002 - 2006
*/
package org.jetbrains.idea.devkit.dom.generator;
import org.apache.xerces.xs.*;
import org.apache.xerces.impl.xs.XSComplexTypeDecl;
import org.apache.xerces.impl.xs.XSParticleDecl;
import org.apache.xerces.impl.xs.XSAttributeGroupDecl;
import org.apache.xerces.impl.xs.XSElementDecl;
import org.apache.xerces.impl.xs.util.XSObjectListImpl;
import org.apache.xerces.impl.dv.XSSimpleType;
import org.apache.xerces.impl.dv.xs.XSSimpleTypeDecl;
import org.apache.xerces.xni.parser.XMLEntityResolver;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.DOMConfiguration;
import org.w3c.dom.DOMErrorHandler;
import org.w3c.dom.DOMError;
import org.w3c.dom.TypeInfo;
import javax.xml.namespace.QName;
import java.io.File;
import java.util.*;
/**
* @author Gregory.Shrago
* @author Konstantin Bulenkov
*/
public class XSDModelLoader implements ModelLoader {
private static final boolean TEXT_ELEMENTS_ARE_COMPLEX = false;
private ModelDesc model;
public void loadModel(ModelDesc model, Collection<File> files, XMLEntityResolver resolver) throws Exception {
this.model = model;
processSchemas(files, resolver);
}
public static boolean checkComplexType(XSTypeDefinition td) {
if (td.getTypeCategory() != XSTypeDefinition.COMPLEX_TYPE) return false;
XSComplexTypeDefinition ctd = (XSComplexTypeDefinition) td;
if (ctd.getContentType() == XSComplexTypeDefinition.CONTENTTYPE_ELEMENT) {
return true;
}
if ((td instanceof XSComplexTypeDecl) && ((XSComplexTypeDecl) td).getAbstract()) return true;
if (TEXT_ELEMENTS_ARE_COMPLEX) return true;
if (ctd.getAttributeUses() != null) {
for (int i = 0; i < ctd.getAttributeUses().getLength(); i++) {
XSSimpleTypeDefinition xsstd = ((XSAttributeUse) ctd.getAttributeUses().item(i)).getAttrDeclaration().getTypeDefinition();
if ("ID".equals(xsstd.getName())) continue;
return true;
}
}
return false;
}
public static boolean checkEnumType(XSTypeDefinition td) {
final XSSimpleTypeDefinition st;
if (td.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
XSComplexTypeDefinition ctd = (XSComplexTypeDefinition) td;
if (ctd.getContentType() != XSComplexTypeDefinition.CONTENTTYPE_SIMPLE) return false;
if (ctd.getAttributeUses() != null) {
for (int i = 0; i < ctd.getAttributeUses().getLength(); i++) {
XSSimpleTypeDefinition xsstd = ((XSAttributeUse) ctd.getAttributeUses().item(i)).getAttrDeclaration().getTypeDefinition();
if ("ID".equals(xsstd.getName())) continue;
return false;
}
}
st = ctd.getSimpleType();
} else if (td.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) {
st = (XSSimpleTypeDefinition) td;
} else {
return false;
}
return st.getLexicalEnumeration() != null && st.getLexicalEnumeration().getLength() != 0;
}
private static boolean checkBooleanType(XSTypeDefinition td) {
if (td.getTypeCategory() != XSTypeDefinition.SIMPLE_TYPE) return false;
final XSSimpleTypeDefinition st = ((XSSimpleTypeDefinition) td);
final XSObjectList facets = st.getFacets();
for (int i = 0; i < facets.getLength(); i++) {
final XSFacet facet = (XSFacet) facets.item(i);
if (facet.getFacetKind() == XSSimpleTypeDefinition.FACET_LENGTH) {
if ("0".equals(facet.getLexicalFacetValue())) {
return true;
}
}
}
return false;
}
private XSModel loadSchema(File schemaFile, XMLEntityResolver resolver) throws Exception {
// get DOM Implementation using DOM Registry
System.setProperty(
DOMImplementationRegistry.PROPERTY,
"org.apache.xerces.dom.DOMXSImplementationSourceImpl");
DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
XSImplementation impl = (XSImplementation) registry.getDOMImplementation("XS-Loader");
XSLoader schemaLoader = impl.createXSLoader(null);
DOMConfiguration config = schemaLoader.getConfig();
// create Error Handler
DOMErrorHandler errorHandler = new DOMErrorHandler() {
public boolean handleError(DOMError domError) {
Util.log("DOMError: " + domError.getMessage());
Object relatedException = domError.getRelatedException();
if (relatedException != null) {
Util.log("DOMError: " + relatedException);
if (relatedException instanceof Throwable) {
((Throwable) relatedException).printStackTrace(System.out);
}
}
return false;
}
};
// set error handler
config.setParameter("error-handler", errorHandler);
// set validation feature
config.setParameter("validate", Boolean.TRUE);
// parse document
config.setParameter("error-handler", errorHandler);
config.setParameter("http://apache.org/xml/properties/internal/entity-resolver", resolver);
XSModel model = schemaLoader.loadURI(schemaFile.getAbsolutePath());
if (model == null) return null;
XSNamedMap components = model.getComponents(XSConstants.ELEMENT_DECLARATION);
for (int i = 0; i < components.getLength(); i++) {
XSObject obj = components.item(i);
QName qname = new QName(obj.getNamespace(), obj.getName());
String file = this.model.qname2FileMap.get(qname);
this.model.qname2FileMap.put(qname, (file == null ? "" : file + ";") + schemaFile.getName());
}
components = model.getComponents(XSConstants.TYPE_DEFINITION);
for (int i = 0; i < components.getLength(); i++) {
XSObject obj = components.item(i);
QName qname = new QName(obj.getNamespace(), obj.getName());
String file = this.model.qname2FileMap.get(qname);
this.model.qname2FileMap.put(qname, (file == null ? "" : file) + ":" + schemaFile.getName() + ":");
}
return model;
}
public void processSchemas(Collection<File> schemas, XMLEntityResolver resolver) throws Exception {
Map<String, NamespaceDesc> nsdMap = model.nsdMap;
Map<String, TypeDesc> jtMap = model.jtMap;
final NamespaceDesc nsdDef = nsdMap.get("");
final ArrayList<XSModel> models = new ArrayList<XSModel>();
final HashMap<String, XSTypeDefinition> types = new HashMap<String, XSTypeDefinition>();
for (File schemaFile : schemas) {
String fileName = schemaFile.getPath();
if (schemaFile.isDirectory() || !fileName.endsWith(".xsd")) {
Util.log("skipping " + fileName);
continue;
}
Util.log("loading " + fileName + "..");
final XSModel model = loadSchema(schemaFile, resolver);
if (model == null) continue;
final StringList namespaceList = model.getNamespaces();
for (int i = 0; i < namespaceList.getLength(); i++) {
String ns = namespaceList.item(i);
if (!nsdMap.containsKey(ns)) {
Util.log("Adding default namespace desc for: " + ns);
NamespaceDesc nsd = new NamespaceDesc(ns, nsdDef);
nsdMap.put(ns, nsd);
}
}
models.add(model);
final XSNamedMap typeDefMap = model.getComponents(XSConstants.TYPE_DEFINITION);
for (int i = 0; i < typeDefMap.getLength(); i++) {
XSTypeDefinition o = (XSTypeDefinition) typeDefMap.item(i);
NamespaceDesc nsd = nsdMap.get(o.getNamespace());
if (nsd != null && nsd.skip) continue;
final String key = o.getName() + "," + o.getNamespace();
types.put(key, o);
}
final XSNamedMap elementDeclMap = model.getComponents(XSConstants.ELEMENT_DECLARATION);
for (int i = 0; i < elementDeclMap.getLength(); i++) {
XSElementDeclaration o = (XSElementDeclaration) elementDeclMap.item(i);
if (o.getTypeDefinition().getAnonymous() && (o.getTypeDefinition() instanceof XSComplexTypeDefinition)) {
//types.put(o.getName() + "," + o.getNamespace(), o);
XSComplexTypeDefinition ctd = makeTypeFromAnonymous(o);
NamespaceDesc nsd = nsdMap.get(o.getNamespace());
if (nsd != null && nsd.skip) continue;
final String key = ctd.getName() + "," + ctd.getNamespace();
types.put(key, ctd);
}
}
}
Util.log(types.size() + " elements loaded, processing..");
ArrayList<XSTypeDefinition> toProcess = new ArrayList<XSTypeDefinition>(types.values());
ArrayList<XSComplexTypeDefinition> toAdd = new ArrayList<XSComplexTypeDefinition>();
for (ListIterator<XSTypeDefinition> it = toProcess.listIterator(); it.hasNext();) {
XSTypeDefinition td = it.next();
Util.log("processing " + td.getName() + "," + td.getNamespace() + "..");
if (checkComplexType(td)) {
processType((XSComplexTypeDefinition) td, models, jtMap, nsdMap, toAdd);
} else if (checkEnumType(td)) {
processEnumType(td, jtMap, nsdMap);
}
if (toAdd.size() != 0) {
for (XSComplexTypeDefinition o : toAdd) {
final String key = o.getName() + "," + o.getNamespace();
if (!types.containsKey(key)) {
Util.log(" adding " + o.getName() + "," + o.getNamespace());
types.put(key, o);
it.add(o);
it.previous();
} else {
Util.logwarn(key + " already exists");
}
}
toAdd.clear();
}
}
}
private XSComplexTypeDefinition makeTypeFromAnonymous(XSObject o) {
final XSComplexTypeDecl ctd = new XSComplexTypeDecl();
if (o instanceof XSElementDeclaration && ((XSElementDeclaration) o).getTypeDefinition() instanceof XSComplexTypeDecl) {
final XSComplexTypeDecl ctd1 = (XSComplexTypeDecl) ((XSElementDeclaration) o).getTypeDefinition();
final XSObjectListImpl annotations = ctd1.getAnnotations() instanceof XSObjectListImpl ? (XSObjectListImpl) ctd1.getAnnotations() : new XSObjectListImpl();
ctd.setValues(o.getName(), ctd1.getNamespace(), ctd1.getBaseType(), ctd1.getDerivationMethod(),
ctd1.getFinal(), ctd1.getProhibitedSubstitutions(), ctd1.getContentType(),
ctd1.getAbstract(), ctd1.getAttrGrp(), (XSSimpleType) ctd1.getSimpleType(),
(XSParticleDecl) ctd1.getParticle(), annotations);
ctd.setName(o.getName() + Util.ANONYMOUS_ELEM_TYPE_SUFFIX);
} else if (o instanceof XSAttributeDeclaration) {
final XSSimpleTypeDecl ctd1 = (XSSimpleTypeDecl) ((XSAttributeDeclaration) o).getTypeDefinition();
final XSObjectListImpl annotations = ctd1.getAnnotations() instanceof XSObjectListImpl ? (XSObjectListImpl) ctd1.getAnnotations() : new XSObjectListImpl();
ctd.setValues(o.getName(), ctd1.getNamespace(), ctd1.getBaseType(), XSConstants.DERIVATION_RESTRICTION,
ctd1.getFinal(), (short) 0, XSComplexTypeDefinition.CONTENTTYPE_SIMPLE,
false, new XSAttributeGroupDecl(), ctd1,
null, annotations);
ctd.setName(o.getName() + Util.ANONYMOUS_ATTR_TYPE_SUFFIX);
}
model.qname2FileMap.put(new QName(ctd.getNamespace(), ctd.getName()), model.qname2FileMap.get(new QName(o.getNamespace(), o.getName())));
return ctd;
}
public void processEnumType(XSTypeDefinition def, Map<String, TypeDesc> jtMap, Map<String, NamespaceDesc> nsdMap) throws Exception {
boolean complexType = def instanceof XSComplexTypeDefinition;
if (!nsdMap.containsKey(def.getNamespace())) {
Util.log("Namespace desc not found for: " + def);
}
final String typeName = toJavaTypeName(def, nsdMap);
final TypeDesc td = new TypeDesc(def.getName(), def.getNamespace(), typeName, TypeDesc.TypeEnum.ENUM);
final XSComplexTypeDefinition ct = complexType ? (XSComplexTypeDefinition) def : null;
final XSSimpleTypeDefinition st = (XSSimpleTypeDefinition) (complexType ? ((XSComplexTypeDefinition) def).getSimpleType() : def);
for (int i = 0; i < st.getLexicalEnumeration().getLength(); i++) {
final String s = st.getLexicalEnumeration().item(i);
td.fdMap.put(s, new FieldDesc(Util.computeEnumConstantName(s, td.name), s));
}
final XSObjectList anns = complexType ? ct.getAnnotations() : st.getAnnotations();
td.documentation = parseAnnotationString("Enumeration " + def.getNamespace() + ":" + def.getName() + " documentation", anns != null && anns.getLength() > 0 ? ((XSAnnotation) anns.item(0)).getAnnotationString() : null);
jtMap.put(model.toJavaQualifiedTypeName(def, nsdMap, true), td);
}
public void processType(XSComplexTypeDefinition def, List<XSModel> models, Map<String, TypeDesc> jtMap, Map<String, NamespaceDesc> nsdMap, ArrayList<XSComplexTypeDefinition> toAdd) throws Exception {
if (!nsdMap.containsKey(def.getNamespace())) {
Util.log("Namespace desc not found for: " + def);
}
String typeName = toJavaTypeName(def, nsdMap);
TypeDesc td = jtMap.get(model.toJavaQualifiedTypeName(def, nsdMap, false));
if (td != null) {
if (td.fdMap.size() == 0) {
// Util.log("Reusing forward decl: "+typeName);
} else {
Util.logerr("merging: type names collision: " + typeName);
}
} else {
td = new TypeDesc(def.getName(), def.getNamespace(), typeName, TypeDesc.TypeEnum.CLASS);
}
XSObjectList anns = def.getAnnotations();
td.documentation = parseAnnotationString("Type " + def.getNamespace() + ":" + def.getName() + " documentation",
anns != null && anns.getLength() > 0 ? ((XSAnnotation) anns.item(0)).getAnnotationString() : null);
TypeDesc tdBase = null;
if (checkComplexType(def.getBaseType())) {
XSComplexTypeDefinition base = (XSComplexTypeDefinition) def.getBaseType();
String typeNameBase = toJavaTypeName(base, nsdMap);
if ((tdBase = jtMap.get(model.toJavaQualifiedTypeName(base, nsdMap, false))) == null) {
// logwarn("forward decl: "+et);
tdBase = new TypeDesc(base.getName(), base.getNamespace(), typeNameBase, TypeDesc.TypeEnum.CLASS);
jtMap.put(model.toJavaQualifiedTypeName(base, nsdMap, false), tdBase);
}
}
if (def.getSimpleType() != null || def.getContentType() == XSComplexTypeDefinition.CONTENTTYPE_MIXED) {
FieldDesc fd = new FieldDesc(FieldDesc.SIMPLE, "value", "String", null, "null", true);
fd.realIndex = td.fdMap.size();
td.fdMap.put(fd.name, fd);
}
XSObjectList attrs = def.getAttributeUses();
for (int i = 0; i < attrs.getLength(); i++) {
XSAttributeUse au = (XSAttributeUse) attrs.item(i);
XSAttributeDeclaration ad = au.getAttrDeclaration();
XSSimpleTypeDefinition atd = ad.getTypeDefinition();
XSAnnotation ann = ad.getAnnotation();
String documentation = parseAnnotationString("Attribute " + ad.getNamespace() + ":" + ad.getName() + " documentation", ann != null ? ann.getAnnotationString() : null);
// skip "ID" and "FIXED"
if ("ID".equals(atd.getName())) continue;
// "language", "dewey-versionType", "boolean"
if (ad.getConstraintType() == XSConstants.VC_FIXED) continue;
FieldDesc fd1 = new FieldDesc(FieldDesc.ATTR, Util.toJavaFieldName(ad.getName()), "String", null, "null", au.getRequired());
fd1.tagName = ad.getName();
fd1.documentation = documentation;
fd1.realIndex = td.fdMap.size();
td.duplicates = Util.addToNameMap(td.fdMap, fd1, false) || td.duplicates;
if (checkEnumType(ad.getTypeDefinition())) {
XSTypeDefinition etRoot = ad.getTypeDefinition();
if (etRoot.getAnonymous()) {
etRoot = makeTypeFromAnonymous(ad);
if (toAdd != null) toAdd.add((XSComplexTypeDefinition) etRoot);
}
fd1.type = toJavaTypeName(etRoot, nsdMap);
fd1.contentQualifiedName = model.toJavaQualifiedTypeName(etRoot, nsdMap, true);
// forward decl
if (jtMap.get(fd1.contentQualifiedName) == null) {
// logwarn("forward decl: "+et);
TypeDesc ftd = new TypeDesc(etRoot.getName(), etRoot.getNamespace(), fd1.type, TypeDesc.TypeEnum.ENUM);
jtMap.put(fd1.contentQualifiedName, ftd);
// // anonymous (simple type) enum
// if (ad.getTypeDefinition().getAnonymous()) {
// processEnumType(ad.getTypeDefinition(), jtMap, nsdMap);
// }
}
} else {
fd1.simpleTypesString = getSimpleTypesString(ad.getTypeDefinition());
}
}
LinkedList<PEntry> plist = new LinkedList<PEntry>();
if (def.getParticle() != null) {
plist.add(new PEntry(def.getParticle(), false));
}
processParticles(def, plist, nsdMap, jtMap, td, models, toAdd, tdBase);
jtMap.put(model.toJavaQualifiedTypeName(def, nsdMap, false), td);
if (td.fdMap.size() == 1 && def.getSimpleType() != null) {
// calc type hierarchy for simple content
FieldDesc fd = td.fdMap.get("value");
fd.simpleTypesString = getSimpleTypesString(def);
}
}
private static String getSimpleTypesString(XSTypeDefinition et) {
StringBuffer typesHierarchy = new StringBuffer();
while (et != null && !"anySimpleType".equals(et.getName()) && !"anyType".equals(et.getName()) && et.getNamespace() != null) {
typesHierarchy.append(et.getNamespace().substring(et.getNamespace().lastIndexOf("/") + 1)).append(":").append(et.getName()).append(";");
if (et instanceof XSSimpleType) {
XSSimpleType simpleType = (XSSimpleType) et;
if (simpleType.getVariety() == XSSimpleTypeDefinition.VARIETY_LIST
|| simpleType.getVariety() == XSSimpleTypeDefinition.VARIETY_UNION) {
XSObjectList list = simpleType.getMemberTypes();
if (list.getLength() > 0) {
typesHierarchy.append("{");
for (int i = 0; i < list.getLength(); i++) {
typesHierarchy.append(getSimpleTypesString((XSTypeDefinition) list.item(i)));
}
typesHierarchy.append("}");
}
}
}
et = et.getBaseType();
}
return typesHierarchy.toString();
}
private TypeDesc processGroup(XSModelGroup modelGroup, List<XSModel> models, Map<String, TypeDesc> jtMap, Map<String, NamespaceDesc> nsdMap) {
XSModelGroupDefinition def = null;
for (XSModel xsModel : models) {
XSNamedMap map = xsModel.getComponents(XSConstants.MODEL_GROUP_DEFINITION);
for (int i = 0; i < map.getLength(); i++) {
XSModelGroupDefinition mg = (XSModelGroupDefinition) map.item(i);
final XSModelGroup xsModelGroup = mg.getModelGroup();
if (xsModelGroup == modelGroup || xsModelGroup.toString().equals(modelGroup.toString())) {
def = mg;
break;
}
}
}
if (def == null) return null;
if (!nsdMap.containsKey(def.getNamespace())) {
Util.log("Namespace desc not found for: " + def);
}
String typeName = toJavaTypeName(def, nsdMap);
final String typeQName = model.toJavaQualifiedTypeName(def, nsdMap, false);
TypeDesc td = jtMap.get(typeQName);
if (td != null) {
if (td.type == TypeDesc.TypeEnum.GROUP_INTERFACE) {
return td;
} else {
Util.logerr("type-group conflict: " + typeName);
return null;
}
} else {
td = new TypeDesc(def.getName(), def.getNamespace(), typeName, TypeDesc.TypeEnum.GROUP_INTERFACE);
}
XSAnnotation ann = def.getAnnotation();
td.documentation = parseAnnotationString("Type " + def.getNamespace() + ":" + def.getName() + " documentation",
ann == null ? null : ann.getAnnotationString());
td.type = TypeDesc.TypeEnum.GROUP_INTERFACE;
LinkedList<PEntry> plist = new LinkedList<PEntry>();
for (int i = 0; i < def.getModelGroup().getParticles().getLength(); i++) {
XSParticle p = (XSParticle) def.getModelGroup().getParticles().item(i);
plist.add(new PEntry(p, false));
}
processParticles(def, plist, nsdMap, jtMap, td, models, null, null);
jtMap.put(typeQName, td);
return td;
}
private void processParticles(XSObject def, LinkedList<PEntry> plist, Map<String, NamespaceDesc> nsdMap, Map<String, TypeDesc> jtMap, TypeDesc td, List<XSModel> models, ArrayList<XSComplexTypeDefinition> toAdd, TypeDesc baseClass) {
final boolean globalMerge = jtMap.containsKey(model.toJavaQualifiedTypeName(def, nsdMap, td.type == TypeDesc.TypeEnum.ENUM));
final HashMap<XSParticle, String> globalChoice = new HashMap<XSParticle, String>();
final ArrayList<XSObjectList> choiceList = new ArrayList<XSObjectList>();
final ArrayList<TypeDesc> supers = new ArrayList<TypeDesc>();
if (baseClass != null) {
supers.add(baseClass);
}
while (!plist.isEmpty()) {
final PEntry pentry = plist.removeFirst();
final XSParticle p = pentry.p;
if (p.getTerm() instanceof XSElementDecl) {
final XSElementDecl el = (XSElementDecl) p.getTerm();
if (el.getConstraintType() == XSConstants.VC_FIXED) continue;
XSTypeDefinition etRoot = el.getTypeDefinition();
XSTypeDefinition et = etRoot;
XSAnnotation ann = el.getAnnotation();
String documentation = parseAnnotationString("Element " + el.getNamespace() + ":" + el.getName() + " documentation", ann != null ? ann.getAnnotationString() : null);
final FieldDesc fd1 = new FieldDesc(FieldDesc.STR, Util.toJavaFieldName(el.getName()), et.getName(), null, "null", !pentry.many && p.getMinOccurs() > 0);
fd1.documentation = documentation;
fd1.tagName = el.getName();
while (et.getBaseType() != null && !"anySimpleType".equals(et.getBaseType().getName()) && !"anyType".equals(et.getBaseType().getName())) {
et = et.getBaseType();
}
if (checkEnumType(etRoot)) {
if (etRoot.getAnonymous()) {
etRoot = makeTypeFromAnonymous(el);
if (toAdd != null) toAdd.add((XSComplexTypeDefinition) etRoot);
}
fd1.type = toJavaTypeName(etRoot, nsdMap);
fd1.clType = FieldDesc.OBJ;
fd1.contentQualifiedName = model.toJavaQualifiedTypeName(etRoot, nsdMap, true);
// forward decl
if (!jtMap.containsKey(fd1.contentQualifiedName)) {
// logwarn("forward decl: "+et);
TypeDesc ftd = new TypeDesc(etRoot.getName(), etRoot.getNamespace(), fd1.type, TypeDesc.TypeEnum.ENUM);
jtMap.put(fd1.contentQualifiedName, ftd);
}
} else if (checkComplexType(etRoot)) {
if (etRoot.getAnonymous()) {
etRoot = makeTypeFromAnonymous(el);
if (toAdd != null) toAdd.add((XSComplexTypeDefinition) etRoot);
}
fd1.type = toJavaTypeName(etRoot, nsdMap);
fd1.clType = FieldDesc.OBJ;
fd1.contentQualifiedName = model.toJavaQualifiedTypeName(etRoot, nsdMap, false);
// forward decl
if (jtMap.get(fd1.contentQualifiedName) == null) {
//logwarn("forward decl: "+etRoot);
jtMap.put(fd1.contentQualifiedName, new TypeDesc(etRoot.getName(), etRoot.getNamespace(), fd1.type, TypeDesc.TypeEnum.CLASS));
}
} else if (checkBooleanType(etRoot)) {
fd1.type = "boolean";
fd1.clType = FieldDesc.BOOL;
} else {
if (etRoot instanceof XSComplexTypeDefinition) {
final XSComplexTypeDefinition ct = (XSComplexTypeDefinition) etRoot;
// XXX xerces2.7.1 wierd annotation inheritance bug fix
//ann = (XSAnnotation) (ct.getAnnotations()!=null && ct.getAnnotations().getLength()>0?ct.getAnnotations().item(0):null);
ann = (XSAnnotation) (ct.getAnnotations() != null && ct.getAnnotations().getLength() > 0 ? ct.getAnnotations().item(ct.getAnnotations().getLength() - 1) : null);
documentation = parseAnnotationString("Type " + ct.getNamespace() + ":" + ct.getName() + " documentation", ann != null ? ann.getAnnotationString() : null);
if (documentation != null) {
fd1.documentation = fd1.documentation != null ? fd1.documentation + "\n" + documentation : documentation;
}
}
fd1.simpleTypesString = getSimpleTypesString(etRoot);
// "fully-qualified-classType", "jndi-nameType", "transaction-typeType"
// "java-identifierType", "pathType"
fd1.type = et.getName();
if (fd1.type == null) {
fd1.type = "String";
fd1.def = "null";
fd1.clType = FieldDesc.STR;
// fd1.type = "boolean";
// fd1.def = "false";
// fd1.clType = FieldDesc.BOOL;
} else if (fd1.type.equals("string") || fd1.type.equals("anyURI")) {
fd1.type = "String";
} else if (fd1.type.equals("boolean")) {
fd1.type = "String";
} else if (fd1.type.equals("emptyType")) {
fd1.type = "boolean";
fd1.def = "false";
fd1.clType = FieldDesc.BOOL;
} else if (fd1.type.equals("decimal")) {
fd1.type = "String";
fd1.def = "\"0.0\"";
} else if (fd1.type.equals("QName")) {
fd1.type = "String";
} else if (fd1.type.equals("extensibleType")) {
fd1.type = "Object";
} else {
if (et.getBaseType() != null &&
("anySimpleType".equals(et.getBaseType().getName())
|| "anyType".equals(et.getBaseType().getName()))) {
fd1.type = "String";
fd1.def = "null";
fd1.clType = FieldDesc.STR;
} else {
fd1.type = "boolean";
fd1.def = "false";
fd1.clType = FieldDesc.BOOL;
}
Util.logwarn("using '" + fd1.type + "' for unknown base type: " + et.getName() + " for " + el);
}
}
if ((pentry.many || p.getMaxOccursUnbounded() || p.getMaxOccurs() > 1) && fd1.clType != FieldDesc.BOOL) {
fd1.elementType = fd1.type;
fd1.elementName = fd1.name;
fd1.type = "List<" + fd1.elementType + ">";
fd1.name = Util.pluralize(fd1.name);
fd1.def = "new ArrayList(0)";
fd1.clType = -fd1.clType;
fd1.comment = "array of " + fd1.elementType;
}
fd1.realIndex = td.fdMap.size();
boolean merge = globalMerge || globalChoice.containsKey(p) && globalChoice.values().contains(fd1.name);
td.duplicates = Util.addToNameMap(td.fdMap, fd1, merge) || td.duplicates;
globalChoice.put(p, fd1.name);
} else if (p.getTerm() instanceof XSModelGroup) {
boolean addToGlobalChoice = false;
boolean many = p.getMaxOccursUnbounded() || p.getMaxOccurs() > 1;
XSObjectList l = ((XSModelGroup) p.getTerm()).getParticles();
if (!many) {
if (((XSModelGroup) p.getTerm()).getCompositor() == XSModelGroup.COMPOSITOR_CHOICE) {
addToGlobalChoice = true;
choiceList.add(l);
} else {
// generate group interface???
XSModelGroup groupDef = (XSModelGroup) p.getTerm();
TypeDesc gtd = processGroup(groupDef, models, jtMap, nsdMap);
if (gtd != null) supers.add(gtd);
}
}
if (globalChoice.containsKey(p)) {
addToGlobalChoice = true;
}
for (int i = 0; i < l.getLength(); i++) {
final PEntry o = new PEntry((XSParticle) l.item(i), many);
plist.add(o);
if (addToGlobalChoice && !globalChoice.containsKey(o.p)) {
globalChoice.put(o.p, null);
}
}
}
}
int i = 0;
for (Iterator<FieldDesc> it = td.fdMap.values().iterator(); it.hasNext(); i++) {
FieldDesc fd = it.next();
fd.idx = i;
}
for (XSObjectList l : choiceList) {
final ArrayList<XSParticle> clist = new ArrayList<XSParticle>();
final LinkedList<XSParticle> elist = new LinkedList<XSParticle>();
for (i = 0; i < l.getLength(); i++) {
elist.add((XSParticle) l.item(i));
}
while (!elist.isEmpty()) {
final XSParticle p = elist.removeFirst();
if (p.getTerm() instanceof XSModelGroup) {
XSObjectList l2 = ((XSModelGroup) p.getTerm()).getParticles();
for (int i2 = 0; i2 < l2.getLength(); i2++) {
elist.addFirst((XSParticle) l2.item(i2));
}
} else if (p.getTerm() instanceof XSElementDecl) {
clist.add(p);
}
}
boolean choiceOpt = true;
FieldDesc[] choice = new FieldDesc[clist.size()];
for (i = 0; i < choice.length; i++) {
XSParticle p = clist.get(i);
XSElementDecl el = (XSElementDecl) p.getTerm();
String s = Util.toJavaFieldName(el.getName());
if (p.getMaxOccursUnbounded() || p.getMaxOccurs() > 1) {
s = Util.pluralize(s);
}
FieldDesc fd = td.fdMap.get(s);
if (fd == null) {
fd = td.fdMap.get(Util.pluralize(s));
if (fd == null) {
Util.logerr("uknown choice element: " + s);
}
}
if (fd != null) {
choice[i] = fd;
choice[i].choice = choice;
if (fd.required) choiceOpt = false;
}
}
for (i = 0; i < choice.length; i++) {
if (choice[i] != null) {
choice[i].choiceOpt = choiceOpt;
}
}
}
td.supers = supers.toArray(new TypeDesc[supers.size()]);
}
public static String parseAnnotationString(String title, String str) {
if (str == null) return null;
int idx = str.indexOf(":documentation");
if (idx == -1) idx = str.indexOf("<documentation");
if (idx == -1) return null;
idx = str.indexOf(">", idx + 1);
if (idx == -1) return null;
int idx2 = str.indexOf(":documentation", idx + 1);
if (idx2 == -1) idx2 = str.indexOf("</documentation", idx + 1);
idx2 = str.lastIndexOf("<", idx2 + 1);
str = str.substring(idx + 1, idx2).trim();
idx = str.indexOf("<![CDATA[");
if (idx > -1) {
idx = str.indexOf("[", idx + 3);
idx2 = str.indexOf("]]>", idx + 1);
str = str.substring(idx + 1, idx2);
}
return "<pre>\n<h3>" + title + "</h3>\n" + str + "\n</pre>";
}
public String toJavaTypeName(XSObject xs, Map<String, NamespaceDesc> nsdMap) {
String name = xs.getName();
if (name == null) {
if (xs instanceof TypeInfo) {
name = ((TypeInfo) xs).getTypeName();
if (name != null && name.startsWith("#")) {
name = name.substring(1);
}
}
}
return model.toJavaTypeName(name, xs.getNamespace());
}
public static class PEntry {
public PEntry(XSParticle p, boolean many) {
this.p = p;
this.many = many;
}
XSParticle p;
boolean many;
}
}