blob: d41141afb6703b45fc7ebd4224f7f0b378789dd3 [file] [log] [blame]
package org.apache.axis2.schema;
import org.apache.axis2.description.AxisMessage;
import org.apache.axis2.description.AxisOperation;
import org.apache.axis2.description.AxisService;
import org.apache.axis2.wsdl.WSDLConstants;
import org.apache.axis2.wsdl.WSDLUtil;
import org.apache.axis2.wsdl.codegen.CodeGenConfiguration;
import org.apache.axis2.wsdl.databinding.DefaultTypeMapper;
import org.apache.axis2.wsdl.databinding.JavaTypeMapper;
import org.apache.axis2.wsdl.databinding.TypeMapper;
import org.apache.axis2.wsdl.util.Constants;
import org.apache.ws.commons.schema.*;
import javax.xml.namespace.QName;
import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/*
* Copyright 2004,2005 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.
*/
/**
* This is the utility for the extension to call by reflection.
*/
public class ExtensionUtility {
public static void invoke(CodeGenConfiguration configuration) throws Exception {
List schemaList = configuration.getAxisService().getSchema();
//hashmap that keeps the targetnamespace and the xmlSchema object
//this is a convenience to locate the relevant schema quickly
//by looking at the target namespace
Map schemaMap = new HashMap();
populateSchemaMap(schemaMap, schemaList);
if (schemaList == null || schemaList.isEmpty()) {
//there are no types to be code generated
//However if the type mapper is left empty it will be a problem for the other
//processes. Hence the default type mapper is set to the configuration
configuration.setTypeMapper(new DefaultTypeMapper());
return;
}
//call the schema compiler
CompilerOptions options = new CompilerOptions();
//set the default options
populateDefaultOptions(options, configuration);
//set the user parameters. the user parameters get the preference over
//the default ones. But the user better know what he's doing if he
//used module specific parameters
populateUserparameters(options, configuration);
SchemaCompiler schemaCompiler = new SchemaCompiler(options);
// run the schema compiler
schemaCompiler.compile(schemaList);
//create the type mapper
//First try to take the one that is already there
TypeMapper mapper = configuration.getTypeMapper();
if (mapper == null) {
mapper = new JavaTypeMapper();
}
if (options.isWriteOutput()) {
//get the processed element map and transfer it to the type mapper
Map processedMap = schemaCompiler.getProcessedElementMap();
Iterator processedkeys = processedMap.keySet().iterator();
QName qNameKey;
while (processedkeys.hasNext()) {
qNameKey = (QName) processedkeys.next();
mapper.addTypeMappingName(qNameKey, processedMap.get(qNameKey).toString());
}
} else {
//get the processed model map and transfer it to the type mapper
//since the options mentiond that its not writable, it should have
//populated the model map
Map processedModelMap = schemaCompiler.getProcessedModelMap();
Iterator processedkeys = processedModelMap.keySet().iterator();
QName qNameKey;
while (processedkeys.hasNext()) {
qNameKey = (QName) processedkeys.next();
mapper.addTypeMappingObject(qNameKey, processedModelMap.get(qNameKey));
}
Map processedMap = schemaCompiler.getProcessedElementMap();
processedkeys = processedMap.keySet().iterator();
while (processedkeys.hasNext()) {
qNameKey = (QName) processedkeys.next();
mapper.addTypeMappingName(qNameKey, processedMap.get(qNameKey).toString());
}
//get the ADB template from the schema compilers property bag and set the
//template
configuration.putProperty(Constants.EXTERNAL_TEMPLATE_PROPERTY_KEY,
schemaCompiler.getCompilerProperties().getProperty(
SchemaConstants.SchemaPropertyNames.BEAN_WRITER_TEMPLATE_KEY));
}
//process the unwrapped parameters
if (!configuration.isParametersWrapped()) {
//figure out the unwrapped operations
AxisService axisService = configuration.getAxisService();
for (Iterator operations = axisService.getOperations();
operations.hasNext();) {
AxisOperation op = (AxisOperation) operations.next();
if (WSDLUtil.isInputPresentForMEP(op.getMessageExchangePattern())) {
walkSchema(op.getMessage(
WSDLConstants.MESSAGE_LABEL_IN_VALUE),
mapper,
schemaMap,
op.getName().getLocalPart());
}
}
}
//set the type mapper to the config
configuration.setTypeMapper(mapper);
}
/**
* Populate the schema objects into the
*
* @param schemaMap
* @param schemaList
*/
private static void populateSchemaMap(Map schemaMap, List schemaList) {
for (int i = 0; i < schemaList.size(); i++) {
XmlSchema xmlSchema = (XmlSchema) schemaList.get(i);
schemaMap.put(xmlSchema.getTargetNamespace(), xmlSchema);
}
}
/**
* @param message
* @param mapper
*/
private static void walkSchema(AxisMessage message,
TypeMapper mapper,
Map schemaMap,
String opName) {
if (message.getParameter(Constants.UNWRAPPED_KEY) != null) {
XmlSchemaType schemaType = message.getSchemaElement().getSchemaType();
//create a type mapper
processXMLSchemaComplexType(schemaType, mapper, opName, schemaMap);
}
}
private static void processXMLSchemaComplexType(XmlSchemaType schemaType, TypeMapper mapper, String opName, Map schemaMap) {
if (schemaType instanceof XmlSchemaComplexType) {
XmlSchemaComplexType cmplxType = (XmlSchemaComplexType) schemaType;
if (cmplxType.getContentModel() == null) {
processSchemaSequence(cmplxType.getParticle(), mapper, opName, schemaMap);
} else {
processComplexContentModel(cmplxType, mapper, opName, schemaMap);
}
}
}
private static void processComplexContentModel(XmlSchemaComplexType cmplxType, TypeMapper mapper, String opName, Map schemaMap) {
XmlSchemaContentModel contentModel = cmplxType.getContentModel();
if (contentModel instanceof XmlSchemaComplexContent) {
XmlSchemaComplexContent xmlSchemaComplexContent = (XmlSchemaComplexContent) contentModel;
XmlSchemaContent content = xmlSchemaComplexContent.getContent();
if (content instanceof XmlSchemaComplexContentExtension) {
XmlSchemaComplexContentExtension schemaExtension = (XmlSchemaComplexContentExtension) content;
// process particles inside this extension, if any
processSchemaSequence(schemaExtension.getParticle(), mapper, opName, schemaMap);
// now we need to get the schema of the extension type from the parent schema. For that let's first retrieve
// the parent schema
XmlSchema parentSchema = (XmlSchema) schemaMap.get(schemaExtension.getBaseTypeName().getNamespaceURI());
// ok now we got the parent schema. Now let's get the extension's schema type
XmlSchemaType extensionSchemaType = parentSchema.getTypeByName(schemaExtension.getBaseTypeName());
processXMLSchemaComplexType(extensionSchemaType, mapper, opName, schemaMap);
}
}
}
private static void processSchemaSequence(XmlSchemaParticle particle, TypeMapper mapper, String opName, Map schemaMap) {
if (particle instanceof XmlSchemaSequence) {
XmlSchemaObjectCollection items =
((XmlSchemaSequence) particle).getItems();
for (Iterator i = items.getIterator(); i.hasNext();) {
Object item = i.next();
// get each and every element in the sequence and
// traverse through them
if (item instanceof XmlSchemaElement) {
//populate the map with the partname - class name
//attached to the schema element
XmlSchemaElement xmlSchemaElement = (XmlSchemaElement) item;
XmlSchemaType eltSchemaType = xmlSchemaElement.getSchemaType();
if (eltSchemaType != null) {
//there is a schema type object.We can utilize that
populateClassName(eltSchemaType, mapper, opName, xmlSchemaElement);
} else if (xmlSchemaElement.getSchemaTypeName() != null) {
//there is no schema type object but there is a
//schema type QName. Use that Qname to look up the
//schematype in other schema objects
eltSchemaType = findSchemaType(schemaMap,
xmlSchemaElement.getSchemaTypeName());
if (eltSchemaType != null) {
populateClassName(eltSchemaType, mapper, opName, xmlSchemaElement);
} else if (xmlSchemaElement.getSchemaTypeName().equals(SchemaConstants.XSD_ANYTYPE)) {
QName partQName = WSDLUtil.getPartQName(opName,
WSDLConstants.INPUT_PART_QNAME_SUFFIX,
xmlSchemaElement.getName());
if (xmlSchemaElement.getMaxOccurs() > 1) {
mapper.addTypeMappingName(partQName, "org.apache.axiom.om.OMElement[]");
} else {
mapper.addTypeMappingName(partQName, "org.apache.axiom.om.OMElement");
}
}
}
} else if (item instanceof XmlSchemaAny) {
// if this is an instance of xs:any, then there is no part name for it. Using ANY_ELEMENT_FIELD_NAME
// for it for now
//we have to handle both maxoccurs 1 and maxoccurs > 1 situation
XmlSchemaAny xmlSchemaAny = (XmlSchemaAny) item;
QName partQName = WSDLUtil.getPartQName(opName,
WSDLConstants.INPUT_PART_QNAME_SUFFIX,
Constants.ANY_ELEMENT_FIELD_NAME);
if (((XmlSchemaAny) item).getMaxOccurs() > 1) {
mapper.addTypeMappingName(partQName, "org.apache.axiom.om.OMElement[]");
} else {
mapper.addTypeMappingName(partQName, "org.apache.axiom.om.OMElement");
}
}
}
}
}
// private static void
/**
* Util method to populate the class name into the typeMap
*
* @param eltSchemaType
*/
private static void populateClassName(XmlSchemaType eltSchemaType,
TypeMapper typeMap,
String opName,
XmlSchemaElement xmlSchemaElement) {
boolean isArray = xmlSchemaElement.getMaxOccurs() > 1;
Map metaInfoMap = eltSchemaType.getMetaInfoMap();
if (metaInfoMap != null) {
String className = (String) metaInfoMap.
get(SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_KEY);
// this is a temporary patch
// the acual problem is keeping the class name details on the schemaType in
// XmlSchema compiler.
// we have to store them in XmlElement
if (isArray && !className.endsWith("[]")) {
className += "[]";
} else if (!isArray && className.endsWith("[]")) {
className = className.substring(0, className.length() - 2);
}
QName partQName = WSDLUtil.getPartQName(opName,
WSDLConstants.INPUT_PART_QNAME_SUFFIX,
xmlSchemaElement.getName());
typeMap.addTypeMappingName(partQName, className);
if (Boolean.TRUE.equals(
metaInfoMap.get(SchemaConstants.
SchemaCompilerInfoHolder.CLASSNAME_PRIMITVE_KEY))) {
//this type is primitive - add that to the type mapper status
//for now lets add a boolean
typeMap.addTypeMappingStatus(partQName, Boolean.TRUE);
}
}
}
/**
* Look for a given schema type given the schema type Qname
*
* @param schemaMap
* @return null if the schema is not found
*/
private static XmlSchemaType findSchemaType(Map schemaMap, QName schemaTypeName) {
//find the schema
XmlSchema schema = (XmlSchema) schemaMap.get(schemaTypeName.getNamespaceURI());
if (schema != null) {
return schema.getTypeByName(schemaTypeName);
}
return null;
}
/**
* populate parameters from the user
*
* @param options
*/
private static void populateUserparameters(CompilerOptions options, CodeGenConfiguration configuration) {
Map propertyMap = configuration.getProperties();
if (propertyMap.containsKey(SchemaConstants.SchemaCompilerArguments.WRAP_SCHEMA_CLASSES)) {
if (Boolean.valueOf(
propertyMap.get(SchemaConstants.SchemaCompilerArguments.WRAP_SCHEMA_CLASSES).toString()).
booleanValue()) {
options.setWrapClasses(true);
} else {
options.setWrapClasses(false);
}
}
if (propertyMap.containsKey(SchemaConstants.SchemaCompilerArguments.WRITE_SCHEMA_CLASSES)) {
if (Boolean.valueOf(
propertyMap.get(SchemaConstants.SchemaCompilerArguments.WRITE_SCHEMA_CLASSES).toString()).
booleanValue()) {
options.setWriteOutput(true);
} else {
options.setWriteOutput(false);
}
}
// add the custom package name
if (propertyMap.containsKey(SchemaConstants.SchemaCompilerArguments.PACKAGE)) {
String packageName = (String) propertyMap.get(SchemaConstants.SchemaCompilerArguments.PACKAGE);
if (packageName != null || !"".equals(packageName)) {
options.setPackageName(packageName);
}
}
//add custom mapper package name
if (propertyMap.containsKey(SchemaConstants.SchemaCompilerArguments.MAPPER_PACKAGE)) {
String packageName = (String) propertyMap.get(SchemaConstants.SchemaCompilerArguments.MAPPER_PACKAGE);
if (packageName != null || !"".equals(packageName)) {
options.setMapperClassPackage(packageName);
}
}
//set helper mode
//this becomes effective only if the classes are unpacked
if (!options.isWrapClasses()) {
if (propertyMap.containsKey(SchemaConstants.SchemaCompilerArguments.HELPER_MODE)) {
options.setHelperMode(true);
}
}
}
/**
* populate the default options - called before the applying of user parameters
*
* @param options
*/
private static void populateDefaultOptions(CompilerOptions options,
CodeGenConfiguration configuration) {
//create the output directory
File outputDir = configuration.isFlattenFiles() ?
configuration.getOutputLocation() :
new File(configuration.getOutputLocation(), configuration.getSourceLocation());
if (!outputDir.exists()) {
outputDir.mkdirs();
}
/// these options need to be taken from the command line
options.setOutputLocation(outputDir);
options.setNs2PackageMap(configuration.getUri2PackageNameMap() == null ?
new HashMap() :
configuration.getUri2PackageNameMap());
//default setting is to set the wrap status depending on whether it's
//the server side or the client side
if (configuration.isServerSide()) {
//for the serverside we generate unwrapped by default
options.setWrapClasses(false);
//for the serverside we write the output by default
options.setWriteOutput(true);
} else {
// for the client let the users preference be the word here
options.setWrapClasses(configuration.isPackClasses());
//for the client side the default setting is not to write the
//output
options.setWriteOutput(!configuration.isPackClasses());
}
if (configuration.isGenerateAll()) {
options.setGenerateAll(true);
}
if (configuration.isBackwordCompatibilityMode()) {
options.setBackwordCompatibilityMode(true);
}
if (configuration.isSuppressPrefixesMode()) {
options.setSuppressPrefixesMode(true);
}
}
}