blob: 7306608ba8689e6e124d896b57870e987b28a7fe [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.axis2.schema.writer;
import org.apache.axiom.om.OMAttribute;
import org.apache.axiom.om.OMElement;
import org.apache.axis2.schema.BeanWriterMetaInfoHolder;
import org.apache.axis2.schema.CompilerOptions;
import org.apache.axis2.schema.SchemaCompilationException;
import org.apache.axis2.schema.SchemaConstants;
import org.apache.axis2.schema.i18n.SchemaCompilerMessages;
import org.apache.axis2.schema.typemap.JavaTypeMap;
import org.apache.axis2.schema.util.PrimitiveTypeFinder;
import org.apache.axis2.schema.util.PrimitiveTypeWrapper;
import org.apache.axis2.schema.util.SchemaPropertyLoader;
import org.apache.axis2.util.JavaUtils;
import org.apache.axis2.util.PrettyPrinter;
import org.apache.axis2.util.URLProcessor;
import org.apache.axis2.util.XSLTTemplateProcessor;
import org.apache.axis2.util.XSLTUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ws.commons.schema.XmlSchemaElement;
import org.apache.ws.commons.schema.XmlSchemaSimpleType;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import javax.xml.namespace.QName;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamSource;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* Java Bean writer for the schema compiler.
*/
public class JavaBeanWriter implements BeanWriter {
private static final Log log = LogFactory.getLog(JavaBeanWriter.class);
public static final String WRAPPED_DATABINDING_CLASS_NAME = "WrappedDatabinder";
private String javaBeanTemplateName = null;
private boolean templateLoaded = false;
private Templates templateCache;
private List nameList;
private Map packageNameToClassNamesMap;
private static int count = 0;
private boolean wrapClasses = false;
private boolean writeClasses = false;
private boolean isUseWrapperClasses = false;
private String packageName = null;
private File rootDir;
private Document globalWrappedDocument;
private Map modelMap = new HashMap();
private static final String DEFAULT_PACKAGE = "adb";
private Map baseTypeMap = new JavaTypeMap().getTypeMap();
private Map ns2packageNameMap = new HashMap();
private boolean isHelperMode = false;
private boolean isSuppressPrefixesMode = false;
/**
* package for the mapping class
*/
private String mappingClassPackage = null;
public static final String EXTENSION_MAPPER_CLASSNAME = "ExtensionMapper";
// a list of externally identified QNames to be processed. This becomes
// useful when only a list of external elements need to be processed
public static final String DEFAULT_CLASS_NAME = OMElement.class.getName();
public static final String DEFAULT_CLASS_ARRAY_NAME = "org.apache.axiom.om.OMElement[]";
public static final String DEFAULT_ATTRIB_CLASS_NAME = OMAttribute.class.getName();
public static final String DEFAULT_ATTRIB_ARRAY_CLASS_NAME = "org.apache.axiom.om.OMAttribute[]";
/**
* Default constructor
*/
public JavaBeanWriter() {
}
/**
* This returns a map of Qnames vs DOMDocument models. One can use this
* method to obtain the raw DOMmodels used to write the classes. This has no
* meaning when the classes are supposed to be wrapped so the
*
* @return Returns Map.
* @see BeanWriter#getModelMap()
*/
public Map getModelMap() {
return modelMap;
}
public String getDefaultClassName() {
return DEFAULT_CLASS_NAME;
}
public String getDefaultClassArrayName() {
return DEFAULT_CLASS_ARRAY_NAME;
}
public String getDefaultAttribClassName() {
return DEFAULT_ATTRIB_CLASS_NAME;
}
public String getDefaultAttribArrayClassName() {
return DEFAULT_ATTRIB_ARRAY_CLASS_NAME;
}
public void init(CompilerOptions options) throws SchemaCompilationException {
try {
// set all state variables to default values
modelMap = new HashMap();
ns2packageNameMap = new HashMap();
mappingClassPackage = null;
initWithFile(options.getOutputLocation());
packageName = options.getPackageName();
writeClasses = options.isWriteOutput();
isUseWrapperClasses = options.isUseWrapperClasses();
if (!writeClasses) {
wrapClasses = false;
} else {
wrapClasses = options.isWrapClasses();
}
// if the wrap mode is set then create a global document to keep the
// wrapped
// element models
if (options.isWrapClasses()) {
globalWrappedDocument = XSLTUtils.getDocument();
Element rootElement = XSLTUtils.getElement(
globalWrappedDocument, "beans");
globalWrappedDocument.appendChild(rootElement);
XSLTUtils.addAttribute(globalWrappedDocument, "name",
WRAPPED_DATABINDING_CLASS_NAME, rootElement);
String tempPackageName;
if (packageName != null && packageName.endsWith(".")) {
tempPackageName = this.packageName.substring(0,
this.packageName.lastIndexOf("."));
} else {
tempPackageName = DEFAULT_PACKAGE;
}
XSLTUtils.addAttribute(globalWrappedDocument, "package",
tempPackageName, rootElement);
}
// add the ns mappings
this.ns2packageNameMap = options.getNs2PackageMap();
//set helper mode
this.isHelperMode = options.isHelperMode();
// set suppress prefixes mode
this.isSuppressPrefixesMode = options.isSuppressPrefixesMode();
//set mapper class package if present
if (options.isMapperClassPackagePresent()) {
this.mappingClassPackage = options.getMapperClassPackage();
}
} catch (IOException e) {
throw new SchemaCompilationException(e);
} catch (ParserConfigurationException e) {
throw new SchemaCompilationException(e); // todo need to put
// correct error
// messages
}
}
/**
* @param element
* @param typeMap
* @param metainf
* @return Returns String.
* @throws SchemaCompilationException
*/
public String write(XmlSchemaElement element,
Map typeMap,
Map groupTypeMap,
BeanWriterMetaInfoHolder metainf) throws SchemaCompilationException {
try {
QName qName = element.getQName();
return process(qName, metainf, typeMap, groupTypeMap, true, false);
} catch (Exception e) {
e.printStackTrace();
throw new SchemaCompilationException(e);
}
}
/**
* `
* @param qName
* @param typeMap
* @param metainf
* @param isAbstract
* @return
* @throws SchemaCompilationException
*/
public String write(QName qName,
Map typeMap,
Map groupTypeMap,
BeanWriterMetaInfoHolder metainf,
boolean isAbstract)
throws SchemaCompilationException {
try {
// determine the package for this type.
return process(qName, metainf, typeMap, groupTypeMap, false,isAbstract);
} catch (SchemaCompilationException e) {
throw e;
} catch (Exception e) {
throw new SchemaCompilationException(e);
}
}
/**
* @throws Exception
* @see BeanWriter#writeBatch()
*/
public void writeBatch() throws SchemaCompilationException {
try {
if (wrapClasses) {
String tempPackage;
if (packageName == null) {
tempPackage = DEFAULT_PACKAGE;
} else {
tempPackage = packageName;
}
File out = createOutFile(tempPackage,
WRAPPED_DATABINDING_CLASS_NAME);
// parse with the template and create the files
parse(globalWrappedDocument, out);
}
} catch (Exception e) {
throw new SchemaCompilationException(e);
}
}
/**
* @param simpleType
* @param typeMap
* @param metainf
* @return Returns String.
* @throws SchemaCompilationException
*/
public String write(XmlSchemaSimpleType simpleType,
Map typeMap,
Map groupTypeMap,
BeanWriterMetaInfoHolder metainf) throws SchemaCompilationException {
try {
QName qName = simpleType.getQName();
if (qName == null) {
qName = (QName) simpleType.getMetaInfoMap().get(SchemaConstants.SchemaCompilerInfoHolder.FAKE_QNAME);
}
metainf.addtStatus(qName, SchemaConstants.SIMPLE_TYPE_OR_CONTENT);
return process(qName, metainf, typeMap, groupTypeMap, true, false);
} catch (Exception e) {
throw new SchemaCompilationException(e);
}
}
/**
* @param rootDir
* @throws IOException
* @see BeanWriter#init(java.io.File)
*/
private void initWithFile(File rootDir) throws IOException {
if (rootDir == null) {
this.rootDir = new File(".");
} else if (!rootDir.isDirectory()) {
throw new IOException(SchemaCompilerMessages
.getMessage("schema.rootnotfolderexception"));
} else {
this.rootDir = rootDir;
}
this.nameList = new ArrayList();
this.packageNameToClassNamesMap = new HashMap();
javaBeanTemplateName = SchemaPropertyLoader.getBeanTemplate();
}
/**
* Make the fully qualified class name for an element or named type
*
* @param qName the qualified Name for this element or type in the schema
* @return the appropriate fully qualified class name to use in generated
* code
*/
public String makeFullyQualifiedClassName(QName qName) {
String namespaceURI = qName.getNamespaceURI();
String basePackageName;
String packageName = getPackage(namespaceURI);
String originalName = qName.getLocalPart();
String className = null;
// when wrapping classes all the data binding and exception class should have
// a unique name since package name is not being applied.
// otherewise we can make unique with the package name
if (!wrapClasses){
className = makeUniqueJavaClassName(this.nameList, originalName);
} else {
if (!this.packageNameToClassNamesMap.containsKey(packageName)) {
this.packageNameToClassNamesMap.put(packageName, new ArrayList());
}
className = makeUniqueJavaClassName((List) this.packageNameToClassNamesMap.get(packageName), originalName);
}
String packagePrefix = null;
String fullyqualifiedClassName;
if (wrapClasses)
packagePrefix = (this.packageName == null ? DEFAULT_PACKAGE + "."
: this.packageName)
+ WRAPPED_DATABINDING_CLASS_NAME;
else if (writeClasses)
packagePrefix = packageName;
if (packagePrefix != null)
fullyqualifiedClassName = packagePrefix
+ (packagePrefix.endsWith(".") ? "" : ".") + className;
else
fullyqualifiedClassName = className;
// return the fully qualified class name
return fullyqualifiedClassName;
}
private String getPackage(String namespaceURI) {
String basePackageName;
if ((ns2packageNameMap != null) && ns2packageNameMap.containsKey(namespaceURI)) {
basePackageName = (String) ns2packageNameMap.get(namespaceURI);
} else {
basePackageName = URLProcessor.makePackageName(namespaceURI);
}
return this.packageName == null ? basePackageName
: this.packageName + basePackageName;
}
/**
* A util method that holds common code for the complete schema that the
* generated XML complies to look under other/beanGenerationSchema.xsd
*
* @param qName
* @param metainf
* @param typeMap
* @param isElement
* @param fullyQualifiedClassName the name returned by makeFullyQualifiedClassName() or null if
* it wasn't called
* @return Returns String.
* @throws Exception
*/
private String process(QName qName,
BeanWriterMetaInfoHolder metainf,
Map typeMap,
Map groupTypeMap,
boolean isElement,
boolean isAbstract)
throws Exception {
String fullyQualifiedClassName = metainf.getOwnClassName();
if (fullyQualifiedClassName == null)
fullyQualifiedClassName = makeFullyQualifiedClassName(qName);
String className = fullyQualifiedClassName
.substring(1 + fullyQualifiedClassName.lastIndexOf('.'));
String basePackageName;
if (fullyQualifiedClassName.lastIndexOf('.') == -1) {// no 'dots' so
// the package
// is not there
basePackageName = "";
} else {
basePackageName = fullyQualifiedClassName.substring(0,
fullyQualifiedClassName.lastIndexOf('.'));
}
String originalName = qName == null ? "" : qName.getLocalPart();
ArrayList propertyNames = new ArrayList();
if (!templateLoaded) {
loadTemplate();
}
// if wrapped then do not write the classes now but add the models to a
// global document. However in order to write the
// global class that is generated, one needs to call the writeBatch()
// method
if (wrapClasses) {
globalWrappedDocument.getDocumentElement().appendChild(
getBeanElement(globalWrappedDocument, className,
originalName, basePackageName, qName, isElement,isAbstract,
metainf, propertyNames, typeMap, groupTypeMap));
} else {
// create the model
Document model = XSLTUtils.getDocument();
// make the XML
model.appendChild(getBeanElement(model, className, originalName,
basePackageName, qName, isElement,isAbstract, metainf, propertyNames,
typeMap, groupTypeMap));
if (writeClasses) {
// create the file
File out = createOutFile(basePackageName, className);
// parse with the template and create the files
if (isHelperMode) {
XSLTUtils.addAttribute(model, "helperMode", "yes", model.getDocumentElement());
// Generate bean classes
parse(model, out);
// Generating the helper classes
out = createOutFile(basePackageName, className + "Helper");
XSLTUtils.addAttribute(model, "helper", "yes", model
.getDocumentElement());
parse(model, out);
} else {
//No helper mode - just generate the classes
parse(model, out);
}
}
// add the model to the model map
modelMap.put(new QName(qName.getNamespaceURI(), className), model);
}
// return the fully qualified class name
return fullyQualifiedClassName;
}
/**
* @param model
* @param className
* @param originalName
* @param packageName
* @param qName
* @param isElement
* @param metainf
* @param propertyNames
* @param typeMap
* @return Returns Element.
* @throws SchemaCompilationException
*/
private Element getBeanElement(Document model,
String className,
String originalName,
String packageName,
QName qName,
boolean isElement,
boolean isAbstract,
BeanWriterMetaInfoHolder metainf,
ArrayList propertyNames,
Map typeMap,
Map groupTypeMap)
throws SchemaCompilationException {
Element rootElt = XSLTUtils.getElement(model, "bean");
XSLTUtils.addAttribute(model, "name", className, rootElt);
XSLTUtils.addAttribute(model, "originalName", originalName, rootElt);
XSLTUtils.addAttribute(model, "package", packageName, rootElt);
XSLTUtils.addAttribute(model, "nsuri", qName.getNamespaceURI(), rootElt);
XSLTUtils.addAttribute(model, "nsprefix", isSuppressPrefixesMode ? "" : getPrefixForURI(qName
.getNamespaceURI(), qName.getPrefix()), rootElt);
if (!wrapClasses) {
XSLTUtils.addAttribute(model, "unwrapped", "yes", rootElt);
}
if (isAbstract){
XSLTUtils.addAttribute(model, "isAbstract", "yes", rootElt);
}
if (!writeClasses) {
XSLTUtils.addAttribute(model, "skip-write", "yes", rootElt);
}
if (!isElement) {
XSLTUtils.addAttribute(model, "type", "yes", rootElt);
}
if (metainf.isAnonymous()) {
XSLTUtils.addAttribute(model, "anon", "yes", rootElt);
}
if (isUseWrapperClasses){
XSLTUtils.addAttribute(model, "usewrapperclasses", "yes", rootElt);
}
if (metainf.isExtension()) {
XSLTUtils.addAttribute(model, "extension", metainf
.getExtensionClassName(), rootElt);
}
if (metainf.isRestriction()) {
XSLTUtils.addAttribute(model, "restriction", metainf
.getRestrictionClassName(), rootElt);
}
//add the mapper class name
XSLTUtils.addAttribute(model, "mapperClass", getFullyQualifiedMapperClassName(), rootElt);
if (metainf.isChoice()) {
XSLTUtils.addAttribute(model, "choice", "yes", rootElt);
}
if (metainf.isSimple()) {
XSLTUtils.addAttribute(model, "simple", "yes", rootElt);
}
if (metainf.isUnion()) {
XSLTUtils.addAttribute(model, "union", "yes", rootElt);
}
if (metainf.isList()) {
XSLTUtils.addAttribute(model, "list", "yes", rootElt);
}
if (metainf.isOrdered()) {
XSLTUtils.addAttribute(model, "ordered", "yes", rootElt);
}
if (isElement && metainf.isNillable(qName)) {
XSLTUtils.addAttribute(model, "nillable", "yes", rootElt);
}
if (metainf.isParticleClass()) {
XSLTUtils.addAttribute(model, "particleClass", "yes", rootElt);
}
if (metainf.isHasParticleType()){
XSLTUtils.addAttribute(model, "hasParticleType", "yes", rootElt);
}
// populate all the information
populateInfo(metainf, model, rootElt, propertyNames, typeMap, groupTypeMap, false);
if (metainf.isSimple() && metainf.isUnion()) {
populateMemberInfo(metainf, model, rootElt, typeMap);
}
if (metainf.isSimple() && metainf.isList()) {
populateListInfo(metainf, model, rootElt, typeMap, groupTypeMap);
}
//////////////////////////////////////////////////////////
// System.out.println(DOM2Writer.nodeToString(rootElt));
////////////////////////////////////////////////////////////
return rootElt;
}
protected void populateListInfo(BeanWriterMetaInfoHolder metainf,
Document model,
Element rootElement,
Map typeMap,
Map groupTypeMap) {
String javaName = makeUniqueJavaClassName(new ArrayList(), metainf.getItemTypeQName().getLocalPart());
Element itemType = XSLTUtils.addChildElement(model, "itemtype", rootElement);
XSLTUtils.addAttribute(model, "type", metainf.getItemTypeClassName(), itemType);
XSLTUtils.addAttribute(model, "nsuri", metainf.getItemTypeQName().getNamespaceURI(), itemType);
XSLTUtils.addAttribute(model, "originalName", metainf.getItemTypeQName().getLocalPart(), itemType);
XSLTUtils.addAttribute(model, "javaname", javaName, itemType);
if (typeMap.containsKey(metainf.getItemTypeQName()) ||
groupTypeMap.containsKey(metainf.getItemTypeClassName())) {
XSLTUtils.addAttribute(model, "ours", "true", itemType);
}
if (PrimitiveTypeFinder.isPrimitive(metainf.getItemTypeClassName())) {
XSLTUtils.addAttribute(model, "primitive", "yes", itemType);
}
String shortTypeName = getShortTypeName(metainf.getItemTypeClassName());
XSLTUtils.addAttribute(model, "shorttypename", shortTypeName, itemType);
}
protected void populateMemberInfo(BeanWriterMetaInfoHolder metainf,
Document model,
Element rootElement,
Map typeMap) {
Map memberTypes = metainf.getMemberTypes();
QName memberQName;
for (Iterator iter = metainf.getMemberTypesKeys().iterator(); iter.hasNext();) {
memberQName = (QName) iter.next();
String memberClass = (String) memberTypes.get(memberQName);
if (PrimitiveTypeFinder.isPrimitive(memberClass)) {
memberClass = PrimitiveTypeWrapper.getWrapper(memberClass);
}
// add member type element
Element memberType = XSLTUtils.addChildElement(model, "memberType", rootElement);
XSLTUtils.addAttribute(model, "type", memberClass, memberType);
XSLTUtils.addAttribute(model, "nsuri", memberQName.getNamespaceURI(), memberType);
XSLTUtils.addAttribute(model, "originalName", memberQName.getLocalPart(), memberType);
if (typeMap.containsKey(memberQName)) {
XSLTUtils.addAttribute(model, "ours", "true", memberType);
}
String shortTypeName = getShortTypeName(memberClass);
XSLTUtils.addAttribute(model, "shorttypename", shortTypeName, memberType);
}
}
/**
* @param metainf
* @param model
* @param rootElt
* @param propertyNames
* @param typeMap
* @throws SchemaCompilationException
*/
private void populateInfo(BeanWriterMetaInfoHolder metainf,
Document model,
Element rootElt,
ArrayList propertyNames,
Map typeMap,
Map groupTypeMap,
boolean isInherited) throws SchemaCompilationException {
// we should add parent class details only if it is
// an extension or simple restriction
// should not in complex restrictions
if (metainf.getParent() != null && (!metainf.isRestriction() || (metainf.isRestriction() && metainf.isSimple())))
{
populateInfo(metainf.getParent(), model, rootElt, propertyNames,
typeMap, groupTypeMap, true);
}
addPropertyEntries(metainf, model, rootElt, propertyNames, typeMap, groupTypeMap,
isInherited);
}
/**
* @param metainf
* @param model
* @param rootElt
* @param propertyNames
* @param typeMap
* @throws SchemaCompilationException
*/
private void addPropertyEntries(BeanWriterMetaInfoHolder metainf,
Document model, Element rootElt,
ArrayList propertyNames,
Map typeMap,
Map groupTypeMap,
boolean isInherited) throws SchemaCompilationException {
// go in the loop and add the part elements
QName[] qName;
String javaClassNameForElement;
ArrayList missingQNames = new ArrayList();
ArrayList qNames = new ArrayList();
BeanWriterMetaInfoHolder parentMetaInf = metainf.getParent();
if (metainf.isOrdered()) {
qName = metainf.getOrderedQNameArray();
} else {
qName = metainf.getQNameArray();
}
for (int i = 0; i < qName.length; i++) {
qNames.add(qName[i]);
}
//adding missing QNames to the end, including elements & attributes.
// for the simple types we have already add the parent elements
// it is almost consider as an extension
if (metainf.isRestriction() && !metainf.isSimple()) {
addMissingQNames(metainf, qNames, missingQNames);
}
QName name;
for (int i = 0; i < qNames.size(); i++) {
name = (QName) qNames.get(i);
Element property = XSLTUtils.addChildElement(model, "property", rootElt);
String xmlName = name.getLocalPart();
XSLTUtils.addAttribute(model, "name", xmlName, property);
XSLTUtils.addAttribute(model, "nsuri", name.getNamespaceURI(), property);
String javaName;
if (metainf.isJavaNameMappingAvailable(xmlName)) {
javaName = metainf.getJavaName(xmlName);
} else {
javaName = makeUniqueJavaClassName(propertyNames, xmlName);
// in a restriction if this element already there and array status have changed
// then we have to generate a new name for this
if (parentMetaInf != null && metainf.isRestriction() && !missingQNames.contains(name) &&
(parentMetaInf.getArrayStatusForQName(name) && !metainf.getArrayStatusForQName(name))) {
javaName = makeUniqueJavaClassName(propertyNames, xmlName);
}
metainf.addXmlNameJavaNameMapping(xmlName,javaName);
}
XSLTUtils.addAttribute(model, "javaname", javaName, property);
if (parentMetaInf != null && metainf.isRestriction() && missingQNames.contains(name)) {
javaClassNameForElement = parentMetaInf.getClassNameForQName(name);
} else {
javaClassNameForElement = metainf.getClassNameForQName(name);
}
if (javaClassNameForElement == null) {
javaClassNameForElement = getDefaultClassName();
log.warn(SchemaCompilerMessages
.getMessage("schema.typeMissing", name.toString()));
}
if (metainf.isRestriction() && typeChanged(name, missingQNames, metainf)) {
XSLTUtils.addAttribute(model, "typeChanged", "yes", property);
//XSLTUtils.addAttribute(model, "restricted", "yes", property);
}
long minOccurs = metainf.getMinOccurs(name);
if (PrimitiveTypeFinder.isPrimitive(javaClassNameForElement)
&& isUseWrapperClasses && ((minOccurs == 0) || metainf.isNillable(name))) {
// if this is an primitive class and user wants to use the
// wrapper type we change the type to wrapper type.
javaClassNameForElement = PrimitiveTypeWrapper.getWrapper(javaClassNameForElement);
}
XSLTUtils.addAttribute(model, "type", javaClassNameForElement, property);
if (PrimitiveTypeFinder.isPrimitive(javaClassNameForElement)) {
XSLTUtils.addAttribute(model, "primitive", "yes", property);
}
// add the default value
if (metainf.isDefaultValueAvailable(name)){
QName schemaQName = metainf.getSchemaQNameForQName(name);
if (baseTypeMap.containsKey(schemaQName)){
XSLTUtils.addAttribute(model, "defaultValue",
metainf.getDefaultValueForQName(name), property);
}
}
//in the case the original element is an array but the derived one is not.
if (parentMetaInf != null && metainf.isRestriction() && !missingQNames.contains(name) &&
(parentMetaInf.getArrayStatusForQName(name) && !metainf.getArrayStatusForQName(name))) {
XSLTUtils.addAttribute(model, "rewrite", "yes", property);
XSLTUtils.addAttribute(model, "occuranceChanged", "yes", property);
} else if (metainf.isRestriction() && !missingQNames.contains(name) &&
(minOccursChanged(name, missingQNames, metainf) || maxOccursChanged(name, missingQNames, metainf)))
{
XSLTUtils.addAttribute(model, "restricted", "yes", property);
XSLTUtils.addAttribute(model, "occuranceChanged", "yes", property);
}
// set the is particle class
if (metainf.getParticleTypeStatusForQName(name)){
XSLTUtils.addAttribute(model, "particleClassType", "yes", property);
}
// if we have an particle class in a extension class then we have
// to consider the whole class has a particle type.
if (metainf.isHasParticleType()) {
XSLTUtils.addAttribute(model, "hasParticleType", "yes", rootElt);
}
// what happed if this contain attributes
// TODO: check the meaning of this removed property
if (metainf.isRestriction() && missingQNames.contains(name) && !metainf.isSimple()) {
//XSLTUtils.addAttribute(model, "restricted", "yes", property);
XSLTUtils.addAttribute(model, "removed", "yes", property);
}
if (isInherited) {
XSLTUtils.addAttribute(model, "inherited", "yes", property);
}
if (metainf.getInnerChoiceStatusForQName(name)){
XSLTUtils.addAttribute(model, "innerchoice", "yes", property);
}
if ((parentMetaInf != null) && metainf.isRestriction() && missingQNames.contains(name)) {
// this element details should be there with the parent meta Inf
addAttributesToProperty(
parentMetaInf,
name,
model,
property,
typeMap,
groupTypeMap,
javaClassNameForElement);
} else {
addAttributesToProperty(
metainf,
name,
model,
property,
typeMap,
groupTypeMap,
javaClassNameForElement);
}
} // end of foo
}
private void addAttributesToProperty(BeanWriterMetaInfoHolder metainf,
QName name,
Document model,
Element property,
Map typeMap,
Map groupTypeMap,
String javaClassNameForElement) {
// add an attribute that says the type is default
if (metainf.getDefaultStatusForQName(name)) {
XSLTUtils.addAttribute(model, "default", "yes", property);
}
if (typeMap.containsKey(metainf.getSchemaQNameForQName(name)) ||
groupTypeMap.containsKey(metainf.getSchemaQNameForQName(name))) {
XSLTUtils.addAttribute(model, "ours", "yes", property);
}
if (metainf.getAttributeStatusForQName(name)) {
XSLTUtils.addAttribute(model, "attribute", "yes", property);
}
if (metainf.isNillable(name)) {
XSLTUtils.addAttribute(model, "nillable", "yes", property);
}
if (metainf.getOptionalAttributeStatusForQName(name)) {
XSLTUtils.addAttribute(model, "optional", "yes", property);
}
String shortTypeName;
if (metainf.getSchemaQNameForQName(name) != null) {
// see whether the QName is a basetype
if (baseTypeMap.containsKey(metainf.getSchemaQNameForQName(name))) {
shortTypeName = metainf.getSchemaQNameForQName(name).getLocalPart();
} else {
shortTypeName = getShortTypeName(javaClassNameForElement);
}
} else {
shortTypeName = getShortTypeName(javaClassNameForElement);
}
XSLTUtils.addAttribute(model, "shorttypename", shortTypeName, property);
if (metainf.getAnyStatusForQName(name)) {
XSLTUtils.addAttribute(model, "any", "yes", property);
}
if (metainf.getBinaryStatusForQName(name)) {
XSLTUtils.addAttribute(model, "binary", "yes", property);
}
if (metainf.isSimple() || metainf.getSimpleStatusForQName(name)) {
XSLTUtils.addAttribute(model, "simple", "yes", property);
}
// put the min occurs count irrespective of whether it's an array or
// not
long minOccurs = metainf.getMinOccurs(name);
XSLTUtils.addAttribute(model, "minOccurs", minOccurs + "", property);
if (metainf.getArrayStatusForQName(name)) {
XSLTUtils.addAttribute(model, "array", "yes", property);
int endIndex = javaClassNameForElement.indexOf("[");
if (endIndex >= 0) {
XSLTUtils.addAttribute(model, "arrayBaseType",
javaClassNameForElement.substring(0, endIndex), property);
} else {
XSLTUtils.addAttribute(model, "arrayBaseType",
javaClassNameForElement, property);
}
long maxOccurs = metainf.getMaxOccurs(name);
if (maxOccurs == Long.MAX_VALUE) {
XSLTUtils.addAttribute(model, "unbound", "yes", property);
} else {
XSLTUtils.addAttribute(model, "maxOccurs", maxOccurs + "", property);
}
}
if (metainf.isRestrictionBaseType(name)) {
XSLTUtils.addAttribute(model, "restrictionBaseType", "yes", property);
}
if (metainf.isExtensionBaseType(name)) {
XSLTUtils.addAttribute(model, "extensionBaseType", "yes", property);
}
if (metainf.isRestrictionBaseType(name) && metainf.getLengthFacet() != -1) {
XSLTUtils.addAttribute(model, "lenFacet", metainf.getLengthFacet() + "", property);
}
if (metainf.isRestrictionBaseType(name) && metainf.getMaxLengthFacet() != -1) {
XSLTUtils.addAttribute(model, "maxLenFacet", metainf.getMaxLengthFacet() + "", property);
}
if (metainf.isRestrictionBaseType(name) && metainf.getMinLengthFacet() != -1) {
XSLTUtils.addAttribute(model, "minLenFacet", metainf.getMinLengthFacet() + "", property);
}
if (metainf.isRestrictionBaseType(name) && metainf.getMaxExclusiveFacet() != null) {
XSLTUtils.addAttribute(model, "maxExFacet", metainf.getMaxExclusiveFacet() + "", property);
}
if (metainf.isRestrictionBaseType(name) && metainf.getMinExclusiveFacet() != null) {
XSLTUtils.addAttribute(model, "minExFacet", metainf.getMinExclusiveFacet() + "", property);
}
if (metainf.isRestrictionBaseType(name) && metainf.getMaxInclusiveFacet() != null) {
XSLTUtils.addAttribute(model, "maxInFacet", metainf.getMaxInclusiveFacet() + "", property);
}
if (metainf.isRestrictionBaseType(name) && metainf.getMinInclusiveFacet() != null) {
XSLTUtils.addAttribute(model, "minInFacet", metainf.getMinInclusiveFacet() + "", property);
}
if (!metainf.getEnumFacet().isEmpty()) {
boolean validJava = true; // Assume all enum values are valid ids
Iterator iterator = metainf.getEnumFacet().iterator();
// Walk the values looking for invalid ids
while (iterator.hasNext()) {
String value = (String) iterator.next();
if (!JavaUtils.isJavaId(value)) {
validJava = false;
}
}
int id = 0;
iterator = metainf.getEnumFacet().iterator();
while (iterator.hasNext()) {
Element enumFacet = XSLTUtils.addChildElement(model, "enumFacet", property);
String attribValue = (String) iterator.next();
XSLTUtils.addAttribute(model, "value", attribValue, enumFacet);
if (validJava) {
XSLTUtils.addAttribute(model, "id", attribValue, enumFacet);
} else {
id++;
XSLTUtils.addAttribute(model, "id", "value" + id, enumFacet);
}
}
}
if (metainf.isRestrictionBaseType(name) && metainf.getPatternFacet() != null) {
XSLTUtils.addAttribute(model, "patternFacet", metainf.getPatternFacet(), property);
}
}
private void addMissingQNames(BeanWriterMetaInfoHolder metainf, ArrayList qName, ArrayList missingQNames) {
QName[] qNames = null;
QName[] pQNames = null;
BeanWriterMetaInfoHolder parentMetaInf = metainf.getParent();
if (metainf.isOrdered()) {
qNames = metainf.getOrderedQNameArray();
} else {
qNames = metainf.getQNameArray();
}
if (parentMetaInf != null) {
if (parentMetaInf.isOrdered()) {
pQNames = parentMetaInf.getOrderedQNameArray();
} else {
pQNames = parentMetaInf.getQNameArray();
}
}
for (int i = 0; pQNames != null && i < pQNames.length; i++) {
if (qNameNotFound(pQNames[i], metainf)) {
missingQNames.add(pQNames[i]);
}
}
//adding missing QNames to the end of list.
if (!missingQNames.isEmpty()) {
for (int i = 0; i < missingQNames.size(); i++) {
qName.add(missingQNames.get(i));
}
}
}
private boolean qNameNotFound(QName qname, BeanWriterMetaInfoHolder metainf) {
boolean found = false;
QName[] qNames;
if (metainf.isOrdered()) {
qNames = metainf.getOrderedQNameArray();
} else {
qNames = metainf.getQNameArray();
}
for (int j = 0; j < qNames.length; j++) {
if (qname.getLocalPart().equals(qNames[j].getLocalPart())) {
found = true;
}
}
return !found;
}
private boolean typeChanged(QName qname, ArrayList missingQNames, BeanWriterMetaInfoHolder metainf) {
boolean typeChanged = false;
QName[] pQNames;
BeanWriterMetaInfoHolder parentMetainf = metainf.getParent();
if (parentMetainf != null && !missingQNames.contains(qname)) {
if (parentMetainf.isOrdered()) {
pQNames = parentMetainf.getOrderedQNameArray();
} else {
pQNames = parentMetainf.getQNameArray();
}
for (int j = 0; j < pQNames.length; j++) {
if (qname.getLocalPart().equals(pQNames[j].getLocalPart())) {
String javaClassForParentElement = parentMetainf.getClassNameForQName(pQNames[j]);
String javaClassForElement = metainf.getClassNameForQName(qname);
if (!javaClassForParentElement.equals(javaClassForElement)) {
if (javaClassForParentElement.endsWith("[]")) {
if ((javaClassForParentElement.substring(0, javaClassForParentElement.indexOf('['))).equals(javaClassForElement))
{
continue;
}
} else if (javaClassForElement.endsWith("[]")) {
if ((javaClassForElement.substring(0, javaClassForElement.indexOf('['))).equals(javaClassForParentElement))
{
continue;
}
} else {
typeChanged = true;
}
}
}
}
}
return typeChanged;
}
private boolean minOccursChanged(QName qname, ArrayList missingQNames, BeanWriterMetaInfoHolder metainf) throws SchemaCompilationException {
boolean minChanged = false;
QName[] pQNames;
BeanWriterMetaInfoHolder parentMetainf = metainf.getParent();
if (parentMetainf != null && !missingQNames.contains(qname)) {
if (parentMetainf.isOrdered()) {
pQNames = parentMetainf.getOrderedQNameArray();
} else {
pQNames = parentMetainf.getQNameArray();
}
for (int j = 0; j < pQNames.length; j++) {
if (qname.getLocalPart().equals(pQNames[j].getLocalPart())) {
if (metainf.getMinOccurs(qname) > parentMetainf.getMinOccurs(pQNames[j])) {
minChanged = true;
} else if (metainf.getMinOccurs(qname) < parentMetainf.getMinOccurs(pQNames[j])) {
throw new SchemaCompilationException(SchemaCompilerMessages.getMessage("minOccurs Wrong!"));
}
}
}
}
return minChanged;
}
private boolean maxOccursChanged(QName qname, ArrayList missingQNames, BeanWriterMetaInfoHolder metainf) throws SchemaCompilationException {
boolean maxChanged = false;
QName[] pQNames;
BeanWriterMetaInfoHolder parentMetainf = metainf.getParent();
if (parentMetainf != null && !missingQNames.contains(qname)) {
if (parentMetainf.isOrdered()) {
pQNames = parentMetainf.getOrderedQNameArray();
} else {
pQNames = parentMetainf.getQNameArray();
}
for (int j = 0; j < pQNames.length; j++) {
if (qname.getLocalPart().equals(pQNames[j].getLocalPart())) {
if (metainf.getMaxOccurs(qname) < parentMetainf.getMaxOccurs(pQNames[j])) {
maxChanged = true;
} else if (metainf.getMaxOccurs(qname) > parentMetainf.getMaxOccurs(pQNames[j])) {
throw new SchemaCompilationException(SchemaCompilerMessages.getMessage("maxOccurs Wrong!"));
}
}
}
}
return maxChanged;
}
/**
* Test whether the given class name matches the default
*
* @param javaClassNameForElement
*/
private boolean isDefault(String javaClassNameForElement) {
return getDefaultClassName()
.equals(javaClassNameForElement)
|| getDefaultClassArrayName()
.equals(javaClassNameForElement);
}
/**
* Given the xml name, make a unique class name taking into account that
* some file systems are case sensitive and some are not. -Consider the
* Jax-WS spec for this
*
* @param listOfNames
* @param xmlName
* @return Returns String.
*/
private String makeUniqueJavaClassName(List listOfNames, String xmlName) {
String javaName;
if (JavaUtils.isJavaKeyword(xmlName)) {
javaName = JavaUtils.makeNonJavaKeyword(xmlName);
} else {
javaName = JavaUtils.capitalizeFirstChar(JavaUtils
.xmlNameToJava(xmlName));
}
while (listOfNames.contains(javaName.toLowerCase())) {
if (!listOfNames.contains((javaName + "E").toLowerCase())){
javaName = javaName + "E";
} else {
javaName = javaName + count++;
}
}
listOfNames.add(javaName.toLowerCase());
return javaName;
}
/**
* A bit of code from the old code generator. We are better off using the
* template engines and such stuff that's already there. But the class
* writers are hard to be reused so some code needs to be repeated (atleast
* a bit)
*/
private void loadTemplate() throws SchemaCompilationException {
// first get the language specific property map
Class clazz = this.getClass();
InputStream xslStream;
String templateName = javaBeanTemplateName;
if (templateName != null) {
try {
xslStream = clazz.getResourceAsStream(templateName);
templateCache = TransformerFactory.newInstance().newTemplates(
new StreamSource(xslStream));
templateLoaded = true;
} catch (TransformerConfigurationException e) {
throw new SchemaCompilationException(SchemaCompilerMessages
.getMessage("schema.templateLoadException"), e);
}
} else {
throw new SchemaCompilationException(SchemaCompilerMessages
.getMessage("schema.templateNotFoundException"));
}
}
/**
* Creates the output file
*
* @param packageName
* @param fileName
* @throws Exception
*/
private File createOutFile(String packageName, String fileName)
throws Exception {
return org.apache.axis2.util.FileWriter.createClassFile(this.rootDir,
packageName, fileName, ".java");
}
/**
* Writes the output file
*
* @param doc
* @param outputFile
* @throws Exception
*/
private void parse(Document doc, File outputFile) throws Exception {
OutputStream outStream = new FileOutputStream(outputFile);
XSLTTemplateProcessor.parse(outStream, doc, getTransformer());
outStream.flush();
outStream.close();
PrettyPrinter.prettify(outputFile);
}
private Transformer getTransformer() throws TransformerConfigurationException, SchemaCompilationException {
try {
return this.templateCache
.newTransformer();
} catch (Exception e){
// Under some peculiar conditions (classloader issues), just scrap the old templateCache,
// create a new one and try again.
loadTemplate();
return this.templateCache
.newTransformer();
}
}
/**
* Get a prefix for a namespace URI. This method will ALWAYS return a valid
* prefix - if the given URI is already mapped in this serialization, we
* return the previous prefix. If it is not mapped, we will add a new
* mapping and return a generated prefix of the form "ns<num>".
*
* @param uri is the namespace uri
* @return Returns prefix.
*/
public String getPrefixForURI(String uri) {
return getPrefixForURI(uri, null);
}
/**
* Last used index suffix for "ns"
*/
private int lastPrefixIndex = 1;
/**
* Map of namespaces URI to prefix(es)
*/
HashMap mapURItoPrefix = new HashMap();
HashMap mapPrefixtoURI = new HashMap();
/**
* Get a prefix for the given namespace URI. If one has already been defined
* in this serialization, use that. Otherwise, map the passed default prefix
* to the URI, and return that. If a null default prefix is passed, use one
* of the form "ns<num>"
*/
public String getPrefixForURI(String uri, String defaultPrefix) {
if ((uri == null) || (uri.length() == 0))
return null;
String prefix = (String) mapURItoPrefix.get(uri);
if (prefix == null) {
if (defaultPrefix == null || defaultPrefix.length() == 0) {
prefix = "ns" + lastPrefixIndex++;
while (mapPrefixtoURI.get(prefix) != null) {
prefix = "ns" + lastPrefixIndex++;
}
} else {
prefix = defaultPrefix;
}
mapPrefixtoURI.put(prefix, uri);
mapURItoPrefix.put(uri, prefix);
}
return prefix;
}
private String getShortTypeName(String typeClassName) {
if (typeClassName.endsWith("[]")) {
typeClassName = typeClassName.substring(0, typeClassName
.lastIndexOf("["));
}
return typeClassName.substring(typeClassName.lastIndexOf(".") + 1,
typeClassName.length());
}
/**
* Get the mapper class name - there is going to be only one
* mapper class for the whole
*/
private String getFullyQualifiedMapperClassName() {
if (wrapClasses || !writeClasses) {
return EXTENSION_MAPPER_CLASSNAME;
} else {
return mappingClassPackage + "." + EXTENSION_MAPPER_CLASSNAME;
}
}
/**
* get the mapper class package name
* May be ignored by the implementer
*/
public String getExtensionMapperPackageName() {
return mappingClassPackage;
}
/**
* Sets the mapping class name of this writer. A mapping class
* package set by the options may be overridden at the this point
*
* @param mapperPackageName
*/
public void registerExtensionMapperPackageName(String mapperPackageName) {
this.mappingClassPackage = mapperPackageName;
}
/**
* Write the extension classes - this is needed to process
* the hierarchy of classes
*
* @param metainfArray
*/
public void writeExtensionMapper(BeanWriterMetaInfoHolder[] metainfArray) throws SchemaCompilationException {
//generate the element
try {
String mapperClassName = getFullyQualifiedMapperClassName();
Document model = XSLTUtils.getDocument();
Element rootElt = XSLTUtils.getElement(model, "mapper");
String mapperName = mapperClassName.substring(mapperClassName.lastIndexOf(".") + 1);
XSLTUtils.addAttribute(model, "name", mapperName, rootElt);
String basePackageName = "";
if (mapperClassName.indexOf(".") != -1) {
basePackageName = mapperClassName.substring(0, mapperClassName.lastIndexOf("."));
XSLTUtils.addAttribute(model, "package", basePackageName, rootElt);
} else {
XSLTUtils.addAttribute(model, "package", "", rootElt);
}
if (!wrapClasses) {
XSLTUtils.addAttribute(model, "unwrapped", "yes", rootElt);
}
if (!writeClasses) {
XSLTUtils.addAttribute(model, "skip-write", "yes", rootElt);
}
if (isHelperMode) {
XSLTUtils.addAttribute(model, "helpermode", "yes", rootElt);
}
for (int i = 0; i < metainfArray.length; i++) {
QName ownQname = metainfArray[i].getOwnQname();
String className = metainfArray[i].getOwnClassName();
//do not add when the qname is not availble
if (ownQname != null) {
Element typeChild = XSLTUtils.addChildElement(model, "type", rootElt);
XSLTUtils.addAttribute(model, "nsuri", ownQname.getNamespaceURI(), typeChild);
XSLTUtils.addAttribute(model, "classname", className == null ? "" : className, typeChild);
XSLTUtils.addAttribute(model, "shortname", ownQname == null ? "" :
ownQname.getLocalPart(), typeChild);
}
}
model.appendChild(rootElt);
if (!templateLoaded) {
loadTemplate();
}
if (wrapClasses) {
rootElt = (Element) globalWrappedDocument.importNode(rootElt, true);
//add to the global wrapped document
globalWrappedDocument.getDocumentElement().appendChild(rootElt);
} else {
if (writeClasses) {
// create the file
File out = createOutFile(basePackageName, mapperName);
// parse with the template and create the files
parse(model, out);
}
// add the model to the model map
modelMap.put(new QName(mapperName), model);
}
} catch (ParserConfigurationException e) {
throw new SchemaCompilationException(SchemaCompilerMessages.getMessage("schema.docuement.error"), e);
} catch (Exception e) {
e.printStackTrace();
throw new SchemaCompilationException(e);
}
}
}