| /* Copyright 2004 The Apache Software Foundation |
| * |
| * 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. |
| */ |
| |
| package org.apache.xmlbeans.impl.schema; |
| |
| import org.apache.xmlbeans.*; |
| import org.apache.xmlbeans.impl.common.NameUtil; |
| |
| import javax.xml.namespace.QName; |
| import java.math.BigInteger; |
| import java.util.*; |
| |
| public class StscJavaizer { |
| |
| /** |
| * XMLBEANS-307 |
| * if enumeration count is greater than 3668, |
| * xmlbeans scomp will fail with a code too large error |
| */ |
| private static final int MAX_ENUM_COUNT = 3668; |
| |
| /** |
| * Does a topo walk of all the types to resolve them. |
| */ |
| public static void javaizeAllTypes(boolean javaize) { |
| StscState state = StscState.get(); |
| |
| List<SchemaType> allSeenTypes = new ArrayList<>(); |
| allSeenTypes.addAll(Arrays.asList(state.documentTypes())); |
| allSeenTypes.addAll(Arrays.asList(state.attributeTypes())); |
| allSeenTypes.addAll(Arrays.asList(state.globalTypes())); |
| |
| // First distribute the global names among the top entities. |
| if (javaize) { |
| assignGlobalJavaNames(allSeenTypes); |
| } |
| |
| // now fully javaize everything deeply. |
| for (int i = 0; i < allSeenTypes.size(); i++) { |
| SchemaType gType = allSeenTypes.get(i); |
| if (javaize) { |
| javaizeType((SchemaTypeImpl) gType); |
| String className = gType.getFullJavaName(); |
| if (className != null) { |
| state.addClassname(className.replace('$', '.'), gType); |
| } |
| } else { |
| skipJavaizingType((SchemaTypeImpl) gType); |
| } |
| allSeenTypes.addAll(Arrays.asList(gType.getAnonymousTypes())); |
| // We need to javaize the anonymous types defined inside redefined types |
| // since redefined type do not get a Java class of their own. |
| // The exception is complex types derived by restriction, since in this case |
| // anonymous types are not inherited |
| addAnonymousTypesFromRedefinition(gType, allSeenTypes); |
| } |
| } |
| |
| static void assignGlobalJavaNames(Collection<SchemaType> schemaTypes) { |
| HashSet<String> usedNames = new HashSet<>(); |
| StscState state = StscState.get(); |
| |
| for (SchemaType schemaType : schemaTypes) { |
| SchemaTypeImpl sImpl = (SchemaTypeImpl) schemaType; |
| QName topName = findTopName(sImpl); |
| String pickedName = state.getJavaname(topName, sImpl.isDocumentType() ? |
| BindingConfig.QNAME_DOCUMENT_TYPE : BindingConfig.QNAME_TYPE); |
| if (sImpl.isUnjavaized()) { |
| sImpl.setFullJavaName(pickFullJavaClassName(usedNames, findTopName(sImpl), pickedName, sImpl.isDocumentType(), sImpl.isAttributeType())); |
| sImpl.setFullJavaImplName(pickFullJavaImplName(usedNames, sImpl.getFullJavaName())); |
| |
| setUserTypes(sImpl, state); |
| |
| setExtensions(sImpl, state); |
| } |
| } |
| |
| verifyInterfaceNameCollisions(usedNames, state); |
| } |
| |
| private static void verifyInterfaceNameCollisions(Set<String> usedNames, StscState state) { |
| BindingConfig config = state.getBindingConfig(); |
| if (config == null) { |
| return; |
| } |
| |
| InterfaceExtension[] exts = config.getInterfaceExtensions(); |
| for (InterfaceExtension ext : exts) { |
| if (usedNames.contains(ext.getInterface().toLowerCase())) { |
| state.error("InterfaceExtension interface '" + ext.getInterface() + "' creates a name collision with one of the generated interfaces or classes.", XmlError.SEVERITY_ERROR, null); |
| } |
| |
| String handler = ext.getStaticHandler(); |
| if (handler != null && usedNames.contains(handler.toLowerCase())) { |
| state.error("InterfaceExtension handler class '" + handler + "' creates a name collision with one of the generated interfaces or classes.", XmlError.SEVERITY_ERROR, null); |
| } |
| } |
| |
| PrePostExtension[] prepost = config.getPrePostExtensions(); |
| for (PrePostExtension prePostExtension : prepost) { |
| String handler = prePostExtension.getStaticHandler(); |
| if (handler != null && usedNames.contains(handler.toLowerCase())) { |
| state.error("PrePostExtension handler class '" + handler + "' creates a name collision with one of the generated interfaces or classes.", XmlError.SEVERITY_ERROR, null); |
| } |
| } |
| } |
| |
| private static void setUserTypes(SchemaTypeImpl sImpl, StscState state) { |
| BindingConfig config = state.getBindingConfig(); |
| |
| if (config != null) { |
| UserType utype = config.lookupUserTypeForQName(sImpl.getName()); |
| if (utype != null) { |
| sImpl.setUserTypeName(utype.getJavaName()); |
| sImpl.setUserTypeHandlerName(utype.getStaticHandler()); |
| } |
| } |
| } |
| |
| private static void setExtensions(SchemaTypeImpl sImpl, StscState state) { |
| String javaName = sImpl.getFullJavaName(); |
| BindingConfig config = state.getBindingConfig(); |
| |
| if (javaName != null && config != null) { |
| sImpl.setInterfaceExtensions(config.getInterfaceExtensions(javaName)); |
| sImpl.setPrePostExtension(config.getPrePostExtension(javaName)); |
| } |
| } |
| |
| private static boolean isStringType(SchemaType type) { |
| if (type == null || type.getSimpleVariety() != SchemaType.ATOMIC) { |
| return false; |
| } |
| return (type.getPrimitiveType().getBuiltinTypeCode() == SchemaType.BTC_STRING); |
| } |
| |
| static String pickConstantName(Set<String> usedNames, String words) { |
| String base = NameUtil.upperCaseUnderbar(words); |
| |
| if (base.length() == 0) { |
| base = "X"; |
| } |
| |
| if (base.startsWith("INT_")) { |
| // reserved for int codes |
| base = "X_" + base; |
| } |
| |
| String uniqName; |
| int index = 1; |
| for (uniqName = base; usedNames.contains(uniqName); ) { |
| index++; |
| uniqName = base + "_" + index; |
| } |
| |
| usedNames.add(uniqName); |
| |
| return uniqName; |
| } |
| |
| static void skipJavaizingType(SchemaTypeImpl sImpl) { |
| if (sImpl.isJavaized()) { |
| return; |
| } |
| |
| SchemaTypeImpl baseType = (SchemaTypeImpl) sImpl.getBaseType(); |
| if (baseType != null) { |
| skipJavaizingType(baseType); |
| } |
| |
| sImpl.startJavaizing(); |
| secondPassProcessType(sImpl); |
| sImpl.finishJavaizing(); |
| } |
| |
| static void secondPassProcessType(SchemaTypeImpl sImpl) { |
| if (!isStringType(sImpl)) { |
| return; |
| } |
| |
| XmlAnySimpleType[] enumVals = sImpl.getEnumerationValues(); |
| |
| // if this is an enumerated string type, values are to be |
| // javaized as constants. |
| if (enumVals == null) { |
| return; |
| } |
| |
| // ERROR is found at > 3668 |
| if (enumVals.length > MAX_ENUM_COUNT) { |
| StscState.get().warning("SchemaType Enumeration found with too many enumeration values to create a Java " + |
| "enumeration. The base SchemaType \"" + sImpl.getBaseEnumType() + "\" will be used instead", XmlError.SEVERITY_WARNING, null); |
| return; |
| } |
| SchemaType basedOn = sImpl.getBaseEnumType(); |
| if (basedOn == null) { |
| return; |
| } |
| |
| SchemaStringEnumEntry[] entryArray = new SchemaStringEnumEntry[enumVals.length]; |
| if (basedOn == sImpl) { |
| Set<String> usedNames = new HashSet<>(); |
| for (int i = 0; i < enumVals.length; i++) { |
| String val = enumVals[i].getStringValue(); |
| entryArray[i] = new SchemaStringEnumEntryImpl(val, i + 1, pickConstantName(usedNames, val)); |
| } |
| } else { |
| for (int i = 0; i < enumVals.length; i++) { |
| String val = enumVals[i].getStringValue(); |
| entryArray[i] = basedOn.enumEntryForString(val); |
| } |
| } |
| sImpl.setStringEnumEntries(entryArray); |
| } |
| |
| static void javaizeType(SchemaTypeImpl sImpl) { |
| if (sImpl.isJavaized()) { |
| return; |
| } |
| |
| SchemaTypeImpl baseType = (SchemaTypeImpl) sImpl.getBaseType(); |
| if (baseType != null) { |
| javaizeType(baseType); |
| } |
| if (sImpl.getContentBasedOnType() != null && sImpl.getContentBasedOnType() != baseType) { |
| javaizeType((SchemaTypeImpl) sImpl.getContentBasedOnType()); |
| } |
| |
| sImpl.startJavaizing(); |
| |
| sImpl.setCompiled(true); |
| |
| secondPassProcessType(sImpl); |
| |
| if (!sImpl.isSimpleType()) { |
| SchemaProperty[] eltProps = sImpl.getElementProperties(); |
| SchemaProperty[] attrProps = sImpl.getAttributeProperties(); |
| |
| // Handing out java names - this permits us to avoid collisions. |
| Set<String> usedPropNames = new HashSet<>(); |
| |
| // First, copy all used property names from base, since these |
| // cannnot be changed at this point and they may be arbitrary |
| // because of derivation by restriction and the "nopvr" switch |
| SchemaProperty[] baseProps = baseType.getProperties(); |
| for (SchemaProperty baseProp : baseProps) { |
| String name = baseProp.getJavaPropertyName(); |
| assert !usedPropNames.contains(name); |
| usedPropNames.add(name); |
| } |
| |
| // count in the methods from extension interfaces |
| avoidExtensionMethods(usedPropNames, sImpl); |
| |
| // Assign names in two passes: first inherited names, then others. |
| for (boolean doInherited = true; ; doInherited = false) { |
| if (eltProps.length > 0) { |
| assignJavaPropertyNames(usedPropNames, eltProps, baseType, doInherited); |
| } |
| |
| assignJavaPropertyNames(usedPropNames, attrProps, baseType, doInherited); |
| |
| if (!doInherited) { |
| break; |
| } |
| } |
| |
| SchemaProperty[] allprops = sImpl.getProperties(); |
| |
| // determine whether order insensitive |
| boolean insensitive = isPropertyModelOrderInsensitive(allprops); |
| |
| // Fill in the java type codes now. |
| // This depends on recursive type information, so it's done in typechecking |
| assignJavaTypeCodes(allprops); |
| |
| sImpl.setOrderSensitive(!insensitive); |
| } |
| |
| // assign java type names to anonymous types |
| // for redefined types, this step was performed when javaizing the redefinition |
| if (sImpl.getFullJavaName() != null || sImpl.getOuterType() != null) { |
| assignJavaAnonymousTypeNames(sImpl); |
| } |
| |
| sImpl.finishJavaizing(); |
| } |
| |
| private static final String[] PREFIXES = new String[]{"get", "xget", "isNil", "isSet", "sizeOf", "set", |
| "xset", "addNew", "setNil", "unset", "insert", "add", "insertNew", "addNew", "remove"}; |
| |
| private static void avoidExtensionMethods(Set<String> usedPropNames, SchemaTypeImpl sImpl) { |
| InterfaceExtension[] exts = sImpl.getInterfaceExtensions(); |
| if (exts != null) { |
| for (InterfaceExtension ext : exts) { |
| InterfaceExtension.MethodSignature[] methods = ext.getMethods(); |
| for (InterfaceExtension.MethodSignature method : methods) { |
| String methodName = method.getName(); |
| for (String prefix : PREFIXES) { |
| if (methodName.startsWith(prefix)) { |
| usedPropNames.add(methodName.substring(prefix.length())); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| static void assignJavaAnonymousTypeNames(SchemaTypeImpl outerType) { |
| Set<String> usedTypeNames = new HashSet<>(); |
| SchemaType[] anonymousTypes = outerType.getAnonymousTypes(); |
| StscState state = StscState.get(); |
| |
| int nrOfAnonTypes = anonymousTypes.length; |
| if (outerType.isRedefinition()) { |
| // We have to add the anonymous types for redefinitions to the list |
| // since they don't have another outer class |
| ArrayList<SchemaType> list = new ArrayList<>(); |
| addAnonymousTypesFromRedefinition(outerType, list); |
| if (list.size() > 0) { |
| SchemaType[] temp = new SchemaType[nrOfAnonTypes + list.size()]; |
| list.toArray(temp); |
| System.arraycopy(anonymousTypes, 0, temp, list.size(), nrOfAnonTypes); |
| anonymousTypes = temp; |
| } |
| } |
| |
| // Because we generate nested java interfaces, and nested |
| // interface names must not be the same as an ancestor, use up |
| // the ancestors |
| |
| for (SchemaType scanOuterType = outerType; |
| scanOuterType != null; |
| scanOuterType = scanOuterType.getOuterType()) { |
| usedTypeNames.add(scanOuterType.getShortJavaName()); |
| } |
| |
| for (SchemaType scanOuterType = outerType; |
| scanOuterType != null; |
| scanOuterType = scanOuterType.getOuterType()) { |
| usedTypeNames.add(scanOuterType.getShortJavaImplName()); |
| } |
| |
| // and because things are problematic if an inner type name |
| // is the same as a top-level package name, also get rid of that |
| // collision |
| usedTypeNames.add(getOutermostPackage(outerType.getFullJavaName())); |
| |
| // assign names |
| for (int i = 0; i < anonymousTypes.length; i++) { |
| SchemaTypeImpl sImpl = (SchemaTypeImpl) anonymousTypes[i]; |
| if (sImpl == null) // already handled in first pass |
| { |
| continue; |
| } |
| if (sImpl.isSkippedAnonymousType()) { |
| continue; |
| } |
| String localname = null; |
| String javaname; |
| |
| SchemaField containerField = sImpl.getContainerField(); |
| if (containerField != null) { |
| QName qname = sImpl.getContainerField().getName(); |
| localname = qname.getLocalPart(); |
| javaname = state.getJavaname(sImpl.getContainerField().getName(), BindingConfig.QNAME_TYPE); |
| } else { |
| // not defined inside an Elt or Attr: must be a nested simple type |
| switch (sImpl.getOuterType().getSimpleVariety()) { |
| case SchemaType.UNION: |
| javaname = "Member"; |
| break; |
| case SchemaType.LIST: |
| javaname = "Item"; |
| break; |
| case SchemaType.ATOMIC: |
| default: |
| assert (false) : "Weird type " + sImpl.toString(); |
| javaname = "Base"; |
| break; |
| } |
| } |
| |
| if (i < nrOfAnonTypes) { |
| sImpl.setShortJavaName( |
| pickInnerJavaClassName(usedTypeNames, localname, javaname)); |
| sImpl.setShortJavaImplName( |
| pickInnerJavaImplName(usedTypeNames, localname, javaname == null ? null : javaname + "Impl")); |
| } else { |
| // This comes from redefined types, so we have to compute the |
| // full name here |
| sImpl.setFullJavaName(outerType.getFullJavaName() + "$" + |
| pickInnerJavaClassName(usedTypeNames, localname, javaname)); |
| sImpl.setFullJavaImplName(outerType.getFullJavaImplName() + "$" + |
| pickInnerJavaImplName(usedTypeNames, localname, javaname == null ? null : javaname + "Impl")); |
| } |
| |
| // TODO(radup) why is this inside this loop here? |
| setExtensions(sImpl, state); |
| } |
| } |
| |
| static void assignJavaPropertyNames(Set<String> usedNames, SchemaProperty[] props, SchemaType baseType, boolean doInherited) { |
| StscState state = StscState.get(); |
| |
| // two passes: first deal with inherited properties, then with new ones. |
| // this ensures that we match up with base class definitions cleanly |
| // BUGBUG(radup) We have to look for particles that have been removed |
| // in the derivation tree for this type using derivation by restriction, |
| // because they have not been removed in Java and may collide with |
| // this type's properties. |
| |
| for (SchemaProperty prop : props) { |
| SchemaPropertyImpl sImpl = (SchemaPropertyImpl) prop; |
| |
| SchemaProperty baseProp = |
| (sImpl.isAttribute() ? |
| baseType.getAttributeProperty(sImpl.getName()) : |
| baseType.getElementProperty(sImpl.getName())); |
| |
| if ((baseProp == null) == doInherited) { |
| continue; |
| } |
| |
| QName propQName = sImpl.getName(); |
| |
| String theName; |
| |
| if (baseProp == null) { |
| theName = pickJavaPropertyName(usedNames, propQName.getLocalPart(), |
| state.getJavaname(propQName, sImpl.isAttribute() ? BindingConfig.QNAME_ACCESSOR_ATTRIBUTE : |
| BindingConfig.QNAME_ACCESSOR_ELEMENT)); |
| } else { |
| theName = baseProp.getJavaPropertyName(); |
| } |
| |
| sImpl.setJavaPropertyName(theName); |
| |
| boolean isArray = (sImpl.getMaxOccurs() == null || |
| sImpl.getMaxOccurs().compareTo(BigInteger.ONE) > 0); |
| boolean isSingleton = !isArray && (sImpl.getMaxOccurs().signum() > 0); |
| boolean isOption = isSingleton && (sImpl.getMinOccurs().signum() == 0); |
| SchemaType javaBasedOnType = sImpl.getType(); |
| |
| if (baseProp != null) { |
| if (baseProp.extendsJavaArray()) { |
| isSingleton = false; |
| isOption = false; |
| isArray = true; |
| } |
| if (baseProp.extendsJavaSingleton()) { |
| isSingleton = true; |
| } |
| if (baseProp.extendsJavaOption()) { |
| isOption = true; |
| } |
| javaBasedOnType = baseProp.javaBasedOnType(); |
| } |
| |
| sImpl.setExtendsJava(javaBasedOnType.getRef(), isSingleton, isOption, isArray); |
| } |
| |
| } |
| |
| static void assignJavaTypeCodes(SchemaProperty[] properties) { |
| for (SchemaProperty property : properties) { |
| SchemaPropertyImpl sImpl = (SchemaPropertyImpl) property; |
| SchemaType sType = sImpl.javaBasedOnType(); |
| sImpl.setJavaTypeCode(javaTypeCodeForType(sType)); |
| } |
| } |
| |
| static int javaTypeCodeInCommon(SchemaType[] types) { |
| if (types == null || types.length == 0) { |
| return SchemaProperty.XML_OBJECT; |
| } |
| |
| int code = javaTypeCodeForType(types[0]); |
| if (code == SchemaProperty.JAVA_OBJECT) { |
| return code; |
| } |
| for (int i = 1; i < types.length; i++) { |
| // if any two are different, the answer is java.lang.Object |
| if (code != javaTypeCodeForType(types[i])) { |
| return SchemaProperty.JAVA_OBJECT; |
| } |
| } |
| return code; |
| } |
| |
| static int javaTypeCodeForType(SchemaType sType) { |
| if (!sType.isSimpleType()) { |
| return SchemaProperty.XML_OBJECT; |
| } |
| |
| if (((SchemaTypeImpl) sType).getUserTypeHandlerName() != null) { |
| return SchemaProperty.JAVA_USER; |
| } |
| |
| if (sType.getSimpleVariety() == SchemaType.UNION) { |
| // see if we can find an interesting common base type, e.g., for string enums |
| SchemaType baseType = sType.getUnionCommonBaseType(); |
| if (baseType != null && !baseType.isURType()) { |
| sType = baseType; |
| } else { |
| return javaTypeCodeInCommon(sType.getUnionConstituentTypes()); |
| } |
| } |
| |
| if (sType.getSimpleVariety() == SchemaType.LIST) { |
| return SchemaProperty.JAVA_LIST; |
| } |
| |
| if (sType.isURType()) { |
| return SchemaProperty.XML_OBJECT; |
| } |
| |
| switch (sType.getPrimitiveType().getBuiltinTypeCode()) { |
| case SchemaType.BTC_ANY_SIMPLE: |
| // return SchemaProperty.XML_OBJECT; |
| return SchemaProperty.JAVA_STRING; |
| |
| case SchemaType.BTC_BOOLEAN: |
| return SchemaProperty.JAVA_BOOLEAN; |
| |
| case SchemaType.BTC_BASE_64_BINARY: |
| return SchemaProperty.JAVA_BYTE_ARRAY; |
| |
| case SchemaType.BTC_HEX_BINARY: |
| return SchemaProperty.JAVA_BYTE_ARRAY; |
| |
| case SchemaType.BTC_ANY_URI: |
| return SchemaProperty.JAVA_STRING; |
| |
| case SchemaType.BTC_QNAME: |
| return SchemaProperty.JAVA_QNAME; |
| |
| case SchemaType.BTC_NOTATION: |
| return SchemaProperty.XML_OBJECT; |
| |
| case SchemaType.BTC_FLOAT: |
| return SchemaProperty.JAVA_FLOAT; |
| |
| case SchemaType.BTC_DOUBLE: |
| return SchemaProperty.JAVA_DOUBLE; |
| |
| case SchemaType.BTC_DECIMAL: |
| switch (sType.getDecimalSize()) { |
| case SchemaType.SIZE_BYTE: |
| return SchemaProperty.JAVA_BYTE; |
| case SchemaType.SIZE_SHORT: |
| return SchemaProperty.JAVA_SHORT; |
| case SchemaType.SIZE_INT: |
| return SchemaProperty.JAVA_INT; |
| case SchemaType.SIZE_LONG: |
| return SchemaProperty.JAVA_LONG; |
| case SchemaType.SIZE_BIG_INTEGER: |
| return SchemaProperty.JAVA_BIG_INTEGER; |
| case SchemaType.SIZE_BIG_DECIMAL: |
| default: |
| return SchemaProperty.JAVA_BIG_DECIMAL; |
| } |
| |
| case SchemaType.BTC_STRING: |
| if (isStringType(sType.getBaseEnumType())) { |
| // This is necessary for local types, etc. |
| // schema enums with > ~3668 cause a Java Src file to be created |
| // that cannot be compiled due to JVM restrictions |
| // FIXFIX: http://issues.apache.org/jira/browse/XMLBEANS-307 |
| // FIXFIX: XMLBeans scomp throws error "code too large" |
| if (sType.getEnumerationValues() != null && |
| sType.getEnumerationValues().length > MAX_ENUM_COUNT) { |
| return SchemaProperty.JAVA_STRING; |
| } else { |
| return SchemaProperty.JAVA_ENUM; |
| } |
| } |
| return SchemaProperty.JAVA_STRING; |
| |
| case SchemaType.BTC_DURATION: |
| return SchemaProperty.JAVA_GDURATION; |
| |
| case SchemaType.BTC_DATE_TIME: |
| case SchemaType.BTC_DATE: |
| // return SchemaProperty.JAVA_DATE; // converted to calendar |
| |
| case SchemaType.BTC_TIME: |
| case SchemaType.BTC_G_YEAR_MONTH: |
| case SchemaType.BTC_G_YEAR: |
| case SchemaType.BTC_G_MONTH_DAY: |
| case SchemaType.BTC_G_DAY: |
| case SchemaType.BTC_G_MONTH: |
| // return SchemaProperty.JAVA_GDATE; // converted to calendar (JAX-B) |
| return SchemaProperty.JAVA_CALENDAR; |
| |
| default: |
| assert (false) : "unrecognized code " + sType.getPrimitiveType().getBuiltinTypeCode(); |
| throw new IllegalStateException("unrecognized code " + sType.getPrimitiveType().getBuiltinTypeCode() + " of " + sType.getPrimitiveType().getName()); |
| } |
| } |
| |
| static boolean isPropertyModelOrderInsensitive(SchemaProperty[] properties) { |
| for (SchemaProperty prop : properties) { |
| if (prop.hasNillable() == SchemaProperty.VARIABLE) { |
| return false; |
| } |
| if (prop.hasDefault() == SchemaProperty.VARIABLE) { |
| return false; |
| } |
| if (prop.hasFixed() == SchemaProperty.VARIABLE) { |
| return false; |
| } |
| if (prop.hasDefault() != SchemaProperty.NEVER && |
| prop.getDefaultText() == null) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| static boolean protectReservedGlobalClassNames(String name) { |
| int i = name.lastIndexOf('.'); |
| String lastSegment = name.substring(i + 1); |
| return lastSegment.endsWith("Document") && !lastSegment.equals("Document"); |
| } |
| |
| static boolean protectReservedInnerClassNames(String name) { |
| return (name.equals("Enum") || name.equals("Factory")); |
| } |
| |
| static String[] PROTECTED_PROPERTIES = { |
| "StringValue", |
| "BooleanValue", |
| "ByteValue", |
| "ShortValue", |
| "IntValue", |
| "LongValue", |
| "BigIntegerValue", |
| "BigDecimalValue", |
| "FloatValue", |
| "DoubleValue", |
| "ByteArrayValue", |
| "EnumValue", |
| "CalendarValue", |
| "DateValue", |
| "GDateValue", |
| "GDurationValue", |
| "QNameValue", |
| "ListValue", |
| "ObjectValue", |
| "Class", |
| }; |
| static Set<String> PROTECTED_PROPERTIES_SET = new HashSet<>(Arrays.asList(PROTECTED_PROPERTIES)); |
| |
| static boolean protectReservedPropertyNames(String name) { |
| return PROTECTED_PROPERTIES_SET.contains(name) || |
| (name.endsWith("Array") && !name.equals("Array")); |
| } |
| |
| static String pickFullJavaClassName(Set<String> usedNames, QName qName, String configname, boolean isDocument, boolean isAttrType) { |
| String base; |
| boolean protect; |
| |
| if (configname != null && configname.indexOf('.') >= 0) { |
| // a configname with dots defines the fully qualified java class name |
| base = configname; |
| protect = protectReservedGlobalClassNames(base); |
| } else { |
| StscState state = StscState.get(); |
| String uri = qName.getNamespaceURI(); |
| |
| base = NameUtil.getClassNameFromQName(qName); |
| |
| // Check to see if we have a mapping from namespace URI to Java package |
| // name. If so, apply the mapped package prefix at the beginning of |
| // the base name |
| |
| String pkgPrefix = state.getPackageOverride(uri); |
| |
| if (pkgPrefix != null) { |
| // Form the new qualified class name from the new package name |
| // and the old class name |
| base = pkgPrefix + "." + base.substring(base.lastIndexOf('.') + 1); |
| } |
| |
| // See if there is a prefix... |
| String javaPrefix = state.getJavaPrefix(uri); |
| if (javaPrefix != null) { |
| base = base.substring(0, base.lastIndexOf('.') + 1) + javaPrefix + base.substring(base.lastIndexOf('.') + 1); |
| } |
| |
| // a configname without dots may override the shortname part. |
| if (configname != null) { |
| base = base.substring(0, base.lastIndexOf('.') + 1) + configname; |
| } |
| |
| protect = protectReservedGlobalClassNames(base); |
| if (configname == null) { |
| // add special suffix |
| if (isDocument) { |
| base = base + "Document"; |
| } else if (isAttrType) { |
| base = base + "Attribute"; |
| } |
| |
| // add configured suffix |
| String javaSuffix = state.getJavaSuffix(uri); |
| if (javaSuffix != null) { |
| base = base + javaSuffix; |
| } |
| } |
| } |
| |
| String outermostPkg = getOutermostPackage(base); |
| |
| int index = 1; |
| String uniqName; |
| if (protect) { |
| uniqName = base + index; |
| } else { |
| uniqName = base; |
| } |
| while (usedNames.contains(uniqName.toLowerCase()) || uniqName.equals(outermostPkg)) { |
| index++; |
| uniqName = base + index; |
| } |
| |
| usedNames.add(uniqName.toLowerCase()); |
| |
| return uniqName; |
| } |
| |
| static String getOutermostPackage(String fqcn) { |
| if (fqcn == null) { |
| return ""; |
| } |
| |
| // remove class name |
| int lastdot = fqcn.indexOf('.'); |
| if (lastdot < 0) { |
| return ""; |
| } |
| |
| // remove outer package names |
| return fqcn.substring(0, lastdot); |
| } |
| |
| static String pickFullJavaImplName(Set<String> usedNames, String intfName) { |
| // Strip off the package from the class name so we can replace it |
| String className = intfName; |
| String pkgName = null; |
| int index = intfName.lastIndexOf('.'); |
| if (index >= 0) { |
| className = intfName.substring(index + 1); |
| pkgName = intfName.substring(0, index); |
| } |
| |
| // Form the new qualified class name from the new package name |
| // and the old class name |
| String base = pkgName + ".impl." + className + "Impl"; |
| |
| index = 1; |
| String uniqName = base; |
| while (usedNames.contains(uniqName.toLowerCase())) { |
| index++; |
| uniqName = base + index; |
| } |
| |
| usedNames.add(uniqName.toLowerCase()); |
| |
| return uniqName; |
| } |
| |
| static String pickJavaPropertyName(Set<String> usedNames, String localName, String javaName) { |
| if (javaName == null) { |
| javaName = NameUtil.upperCamelCase(localName); |
| } |
| boolean protect = protectReservedPropertyNames(javaName); |
| String uniqName; |
| int index = 1; |
| if (protect) { |
| uniqName = javaName + index; |
| } else { |
| uniqName = javaName; |
| } |
| while (usedNames.contains(uniqName)) { |
| index++; |
| uniqName = javaName + index; |
| } |
| |
| usedNames.add(uniqName); |
| |
| return uniqName; |
| } |
| |
| static String pickInnerJavaClassName(Set<String> usedNames, String localName, String javaName) { |
| if (javaName == null) { |
| javaName = NameUtil.upperCamelCase(localName); |
| } |
| boolean protect = protectReservedInnerClassNames(javaName); |
| String uniqName; |
| int index = 1; |
| if (protect) { |
| uniqName = javaName + index; |
| } else { |
| uniqName = javaName; |
| } |
| while (usedNames.contains(uniqName)) { |
| index++; |
| uniqName = javaName + index; |
| } |
| |
| usedNames.add(uniqName); |
| |
| return uniqName; |
| } |
| |
| static String pickInnerJavaImplName(Set<String> usedNames, String localName, String javaName) { |
| if (javaName == null) { |
| javaName = NameUtil.upperCamelCase(localName) + "Impl"; |
| } |
| String uniqName = javaName; |
| int index = 1; |
| while (usedNames.contains(uniqName)) { |
| index++; |
| uniqName = javaName + index; |
| } |
| |
| usedNames.add(uniqName); |
| |
| return uniqName; |
| } |
| |
| static QName findTopName(SchemaType sType) { |
| if (sType.getName() != null) { |
| return sType.getName(); |
| } |
| |
| if (sType.isDocumentType()) { |
| // A document type must have a content model consisting of a single elt |
| if (sType.getContentModel() == null || sType.getContentModel().getParticleType() != SchemaParticle.ELEMENT) { |
| throw new IllegalStateException(); |
| } |
| return (sType.getDocumentElementName()); |
| } |
| |
| if (sType.isAttributeType()) { |
| if (sType.getAttributeModel() == null || sType.getAttributeModel().getAttributes().length != 1) { |
| throw new IllegalStateException(); |
| } |
| return sType.getAttributeTypeAttributeName(); |
| } |
| |
| SchemaField sElt = sType.getContainerField(); |
| assert (sElt != null); |
| assert (sType.getOuterType() == null); |
| return sElt.getName(); |
| } |
| |
| static void addAnonymousTypesFromRedefinition(SchemaType sType, List<SchemaType> result) { |
| while (((SchemaTypeImpl) sType).isRedefinition() && |
| (sType.getDerivationType() == SchemaType.DT_EXTENSION || |
| sType.isSimpleType())) { |
| sType = sType.getBaseType(); |
| SchemaType[] newAnonTypes = sType.getAnonymousTypes(); |
| if (newAnonTypes.length > 0) { |
| result.addAll(Arrays.asList(newAnonTypes)); |
| } |
| } |
| } |
| } |