blob: 8b67fa6d04a00345e71140719ca753001e7eb1cd [file] [log] [blame]
/*
* Copyright 2001-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.axis.wsdl.toJava;
import org.apache.axis.components.logger.LogFactory;
import org.apache.axis.utils.JavaUtils;
import org.apache.axis.utils.Messages;
import org.apache.axis.wsdl.gen.Generator;
import org.apache.axis.wsdl.gen.GeneratorFactory;
import org.apache.axis.wsdl.gen.NoopGenerator;
import org.apache.axis.wsdl.symbolTable.BaseTypeMapping;
import org.apache.axis.wsdl.symbolTable.BindingEntry;
import org.apache.axis.wsdl.symbolTable.ContainedAttribute;
import org.apache.axis.wsdl.symbolTable.Element;
import org.apache.axis.wsdl.symbolTable.ElementDecl;
import org.apache.axis.wsdl.symbolTable.FaultInfo;
import org.apache.axis.wsdl.symbolTable.MessageEntry;
import org.apache.axis.wsdl.symbolTable.Parameter;
import org.apache.axis.wsdl.symbolTable.Parameters;
import org.apache.axis.wsdl.symbolTable.PortTypeEntry;
import org.apache.axis.wsdl.symbolTable.SchemaUtils;
import org.apache.axis.wsdl.symbolTable.ServiceEntry;
import org.apache.axis.wsdl.symbolTable.SymTabEntry;
import org.apache.axis.wsdl.symbolTable.SymbolTable;
import org.apache.axis.wsdl.symbolTable.Type;
import org.apache.axis.wsdl.symbolTable.TypeEntry;
import org.apache.commons.logging.Log;
import javax.wsdl.Binding;
import javax.wsdl.Definition;
import javax.wsdl.Fault;
import javax.wsdl.Message;
import javax.wsdl.Operation;
import javax.wsdl.OperationType;
import javax.wsdl.Port;
import javax.wsdl.PortType;
import javax.wsdl.Service;
import javax.xml.namespace.QName;
import javax.xml.rpc.holders.BooleanHolder;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Vector;
/**
* This is Wsdl2java's implementation of the GeneratorFactory
*/
public class JavaGeneratorFactory implements GeneratorFactory {
private static final Log log =
LogFactory.getLog(JavaGeneratorFactory.class.getName());
/** Field emitter */
protected Emitter emitter;
/** Field symbolTable */
protected SymbolTable symbolTable;
/** Field COMPLEX_TYPE_FAULT */
public static String COMPLEX_TYPE_FAULT = "ComplexTypeFault";
/** Field EXCEPTION_CLASS_NAME */
public static String EXCEPTION_CLASS_NAME = "ExceptionClassName";
/** Field EXCEPTION_DATA_TYPE */
public static String EXCEPTION_DATA_TYPE = "ExceptionDataType";
/* Name suffixes for collision */
private static final String SERVICE_SUFFIX = "_Service";
private static final String PORT_TYPE_SUFFIX = "_PortType"; // "_Port" (Axis classic) --> "_PortType" (JAX-RPC 1.1)
private static final String TYPE_SUFFIX = "_Type";
private static final String ELEMENT_SUFFIX = "_Element"; // "_ElemType (Axis classic) --> "_Element" (JAX-RPC 1.1)
private static final String EXCEPTION_SUFFIX = "_Exception";
private static final String BINDING_SUFFIX = "_Binding";
/**
* Default constructor. Note that this class is unusable until setEmitter
* is called.
*/
public JavaGeneratorFactory() {
addGenerators();
} // ctor
/**
* Constructor JavaGeneratorFactory
*
* @param emitter
*/
public JavaGeneratorFactory(Emitter emitter) {
this.emitter = emitter;
addGenerators();
} // ctor
/**
* Method setEmitter
*
* @param emitter
*/
public void setEmitter(Emitter emitter) {
this.emitter = emitter;
} // setEmitter
/**
* Method addGenerators
*/
private void addGenerators() {
addMessageGenerators();
addPortTypeGenerators();
addBindingGenerators();
addServiceGenerators();
addTypeGenerators();
addDefinitionGenerators();
} // addGenerators
/**
* These addXXXGenerators are called by the constructor.
* If an extender of this factory wants to CHANGE the set
* of generators that are called per WSDL construct, they
* should override these addXXXGenerators methods. If all
* an extender wants to do is ADD a generator, then the
* extension should simply call addGenerator.
* (NOTE: It doesn't quite work this way, yet. Only the
* Definition generators fit this model at this point in
* time.)
*/
protected void addMessageGenerators() {
} // addMessageGenerators
/**
* Method addPortTypeGenerators
*/
protected void addPortTypeGenerators() {
} // addPortTypeGenerators
/**
* Method addBindingGenerators
*/
protected void addBindingGenerators() {
} // addBindingGenerators
/**
* Method addServiceGenerators
*/
protected void addServiceGenerators() {
} // addServiceGenerators
/**
* Method addTypeGenerators
*/
protected void addTypeGenerators() {
} // addTypeGenerators
/**
* Method addDefinitionGenerators
*/
protected void addDefinitionGenerators() {
addGenerator(Definition.class, JavaDefinitionWriter.class); // for faults
addGenerator(Definition.class,
JavaDeployWriter.class); // for deploy.wsdd
addGenerator(Definition.class,
JavaUndeployWriter.class); // for undeploy.wsdd
addGenerator(Definition.class,
JavaBuildFileWriter.class); //add a build file writer
} // addDefinitionGenerators
/**
* Do the Wsdl2java generator pass:
* - resolve name clashes
* - construct signatures
*
* @param def
* @param symbolTable
*/
public void generatorPass(Definition def, SymbolTable symbolTable) {
this.symbolTable = symbolTable;
javifyNames(symbolTable);
setFaultContext(symbolTable);
resolveNameClashes(symbolTable);
determineInterfaceNames(symbolTable);
if (emitter.isAllWanted()) {
setAllReferencesToTrue();
} else {
ignoreNonSOAPBindings(symbolTable);
}
constructSignatures(symbolTable);
determineIfHoldersNeeded(symbolTable);
} // generatorPass
/** Since Wsdl2java doesn't emit anything for Messages, return the No-op generator. */
private Writers messageWriters = new Writers();
/**
* Method getGenerator
*
* @param message
* @param symbolTable
* @return
*/
public Generator getGenerator(Message message, SymbolTable symbolTable) {
if (include(message.getQName())) {
MessageEntry mEntry = symbolTable.getMessageEntry(message.getQName());
messageWriters.addStuff(new NoopGenerator(), mEntry, symbolTable);
return messageWriters;
}
else {
return new NoopGenerator();
}
} // getGenerator
/** Return Wsdl2java's JavaPortTypeWriter object. */
private Writers portTypeWriters = new Writers();
/**
* Method getGenerator
*
* @param portType
* @param symbolTable
* @return
*/
public Generator getGenerator(PortType portType, SymbolTable symbolTable) {
if (include(portType.getQName())) {
PortTypeEntry ptEntry =
symbolTable.getPortTypeEntry(portType.getQName());
portTypeWriters.addStuff(new NoopGenerator(), ptEntry, symbolTable);
return portTypeWriters;
}
else {
return new NoopGenerator();
}
} // getGenerator
/** Return Wsdl2java's JavaBindingWriter object. */
protected Writers bindingWriters = new Writers();
/**
* Method getGenerator
*
* @param binding
* @param symbolTable
* @return
*/
public Generator getGenerator(Binding binding, SymbolTable symbolTable) {
if (include(binding.getQName())) {
Generator writer = new JavaBindingWriter(emitter, binding,
symbolTable);
BindingEntry bEntry = symbolTable.getBindingEntry(binding.getQName());
bindingWriters.addStuff(writer, bEntry, symbolTable);
return bindingWriters;
}
else {
return new NoopGenerator();
}
} // getGenerator
/** Return Wsdl2java's JavaServiceWriter object. */
protected Writers serviceWriters = new Writers();
/**
* Method getGenerator
*
* @param service
* @param symbolTable
* @return
*/
public Generator getGenerator(Service service, SymbolTable symbolTable) {
if (include(service.getQName())) {
Generator writer = new JavaServiceWriter(emitter, service,
symbolTable);
ServiceEntry sEntry = symbolTable.getServiceEntry(service.getQName());
serviceWriters.addStuff(writer, sEntry, symbolTable);
return serviceWriters;
}
else {
return new NoopGenerator();
}
} // getGenerator
/** Return Wsdl2java's JavaTypeWriter object. */
private Writers typeWriters = new Writers();
/**
* Method getGenerator
*
* @param type
* @param symbolTable
* @return
*/
public Generator getGenerator(TypeEntry type, SymbolTable symbolTable) {
if (include(type.getQName())) {
Generator writer = new JavaTypeWriter(emitter, type, symbolTable);
typeWriters.addStuff(writer, type, symbolTable);
return typeWriters;
}
else {
return new NoopGenerator();
}
} // getGenerator
/** Return Wsdl2java's JavaDefinitionWriter object. */
private Writers defWriters = new Writers();
/**
* Method getGenerator
*
* @param definition
* @param symbolTable
* @return
*/
public Generator getGenerator(Definition definition,
SymbolTable symbolTable) {
if (include(definition.getQName())) {
defWriters.addStuff(null, definition, symbolTable);
return defWriters;
}
else {
return new NoopGenerator();
}
} // getGenerator
// Hack class just to play with the idea of adding writers
/**
* Class Writers
*
* @version %I%, %G%
*/
protected class Writers implements Generator {
/** Field writers */
Vector writers = new Vector();
/** Field symbolTable */
SymbolTable symbolTable = null;
/** Field baseWriter */
Generator baseWriter = null;
// entry or def, but not both, will be a parameter.
/** Field entry */
SymTabEntry entry = null;
/** Field def */
Definition def = null;
/**
* Method addGenerator
*
* @param writer
*/
public void addGenerator(Class writer) {
writers.add(writer);
} // addWriter
/**
* Method addStuff
*
* @param baseWriter
* @param entry
* @param symbolTable
*/
public void addStuff(Generator baseWriter, SymTabEntry entry,
SymbolTable symbolTable) {
this.baseWriter = baseWriter;
this.entry = entry;
this.symbolTable = symbolTable;
} // addStuff
/**
* Method addStuff
*
* @param baseWriter
* @param def
* @param symbolTable
*/
public void addStuff(Generator baseWriter, Definition def,
SymbolTable symbolTable) {
this.baseWriter = baseWriter;
this.def = def;
this.symbolTable = symbolTable;
} // addStuff
/**
* Method generate
*
* @throws IOException
*/
public void generate() throws IOException {
if (baseWriter != null) {
baseWriter.generate();
}
Class[] formalArgs;
Object[] actualArgs;
if (entry != null) {
formalArgs = new Class[]{Emitter.class, entry.getClass(),
SymbolTable.class};
actualArgs = new Object[]{emitter, entry, symbolTable};
} else {
formalArgs = new Class[]{Emitter.class, Definition.class,
SymbolTable.class};
actualArgs = new Object[]{emitter, def, symbolTable};
}
for (int i = 0; i < writers.size(); ++i) {
Class wClass = (Class) writers.get(i);
Generator gen;
try {
Constructor ctor = wClass.getConstructor(formalArgs);
gen = (Generator) ctor.newInstance(actualArgs);
} catch (Throwable t) {
throw new IOException(Messages.getMessage("exception01",
t.getMessage()));
}
gen.generate();
}
} // generate
public String toString() {
return "Writers[baseWriter=" + baseWriter + ",writers=" + writers + ",entry.name=" + (entry == null ? "N/A" : entry.getName()) + "]";
}
} // class Writers
/**
* Method addGenerator
*
* @param wsdlClass
* @param generator
*/
public void addGenerator(Class wsdlClass, Class generator) {
if (log.isDebugEnabled()) {
log.debug("Adding generator for " + wsdlClass.getName() + ": " + generator.getName());
}
// This is just a hack right now... it just works with Service
if (Message.class.isAssignableFrom(wsdlClass)) {
messageWriters.addGenerator(generator);
} else if (PortType.class.isAssignableFrom(wsdlClass)) {
portTypeWriters.addGenerator(generator);
} else if (Binding.class.isAssignableFrom(wsdlClass)) {
bindingWriters.addGenerator(generator);
} else if (Service.class.isAssignableFrom(wsdlClass)) {
serviceWriters.addGenerator(generator);
} else if (TypeEntry.class.isAssignableFrom(wsdlClass)) {
typeWriters.addGenerator(generator);
} else if (Definition.class.isAssignableFrom(wsdlClass)) {
defWriters.addGenerator(generator);
}
} // addGenerator
/**
* Fill in the names of each SymTabEntry with the javaified name.
* Note: This method also ensures that anonymous types are
* given unique java type names.
*
* @param symbolTable
*/
protected void javifyNames(SymbolTable symbolTable) {
int uniqueNum = 0;
HashMap anonQNames = new HashMap();
Iterator it = symbolTable.getHashMap().values().iterator();
while (it.hasNext()) {
Vector v = (Vector) it.next();
for (int i = 0; i < v.size(); ++i) {
SymTabEntry entry = (SymTabEntry) v.elementAt(i);
if (entry.getName() != null) {
continue;
}
// Use the type or the referenced type's QName to generate the java name.
if (entry instanceof TypeEntry) {
uniqueNum = javifyTypeEntryName(symbolTable, (TypeEntry) entry, anonQNames, uniqueNum);
}
// If it is not a type, then use this entry's QName to
// generate its name.
else {
entry.setName(emitter.getJavaName(entry.getQName()));
}
}
}
} // javifyNames
/** Refactored to call recursively for JAX-RPC 1.1 spec 4.2.5. */
protected int javifyTypeEntryName(SymbolTable symbolTable, TypeEntry entry, HashMap anonQNames, int uniqueNum) {
TypeEntry tEntry = entry;
String dims = tEntry.getDimensions();
TypeEntry refType = tEntry.getRefType();
while (refType != null) {
tEntry = refType;
dims += tEntry.getDimensions();
refType = tEntry.getRefType();
}
TypeEntry te = tEntry;
while (te != null) {
TypeEntry base = SchemaUtils.getBaseType(te, symbolTable);
if (base == null)
break;
uniqueNum = javifyTypeEntryName(symbolTable, base, anonQNames, uniqueNum);
if (Utils.getEnumerationBaseAndValues(te.getNode(), symbolTable) == null
&&SchemaUtils.getComplexElementExtensionBase(te.getNode(), symbolTable) == null
&& te.getContainedAttributes() == null) {
if(!SchemaUtils.isSimpleTypeWithUnion(te.getNode())) {
if (base.isSimpleType()) {
// Case 1:
// <simpleType name="mySimpleStringType">
// <restriction base="xs:string">
// </restriction>
// </simpleType>
te.setSimpleType(true);
te.setName(base.getName());
te.setRefType(base);
}
if (base.isBaseType()) {
// Case 2:
// <simpleType name="FooString">
// <restriction base="foo:mySimpleStringType">
// </restriction>
// </simpleType>
te.setBaseType(true);
te.setName(base.getName());
te.setRefType(base);
}
}
}
if (!te.isSimpleType())
break;
te = base;
}
// Need to javify the ref'd TypeEntry if it was not
// already processed
if (tEntry.getName() == null) {
boolean processed = false; // true if the java name is already determined
// Get the QName of the ref'd TypeEntry, which
// is will be used to javify the name
QName typeQName = tEntry.getQName();
// In case of <xsd:list itemType="...">,
// set typeQName to the value of the itemType attribute.
QName itemType = SchemaUtils.getListItemType(tEntry.getNode());
if (itemType != null) {
// Get the typeEntry so we know the absolute base type
TypeEntry itemEntry = symbolTable.getTypeEntry(itemType, false);
// TODO - If the itemEntry is not found, we need to throw
// an exception. "Item is referenced, but not defined"
javifyTypeEntryName(symbolTable, itemEntry, anonQNames, uniqueNum);
// Grab the referenced type, If it's there.
TypeEntry refedEntry = itemEntry.getRefType();
QName baseName = refedEntry == null ? itemEntry.getQName() :
refedEntry.getQName();
typeQName = new QName(baseName.getNamespaceURI(),
baseName.getLocalPart() + "[]");
}
if (emitter.isDeploy()) {
Class class1 = (Class) emitter.getQName2ClassMap().get(typeQName);
if (class1 != null && !class1.isArray()) {
tEntry.setName(getJavaClassName(class1));
processed = true;
}
}
if (!processed) {
if ((typeQName.getLocalPart().
indexOf(SymbolTable.ANON_TOKEN) < 0)) {
// Normal Case: The ref'd type is not anonymous
// Simply construct the java name from
// the qName
tEntry.setName(emitter.getJavaName(typeQName));
} else {
// This is an anonymous type name.
// Axis uses '>' as a nesting token to generate
// unique qnames for anonymous types.
// Only consider the localName after the last '>'
// when generating the java name
// String localName = typeQName.getLocalPart();
// localName =
// localName.substring(
// localName.lastIndexOf(
// SymbolTable.ANON_TOKEN)+1);
// typeQName = new QName(typeQName.getNamespaceURI(),
// localName);
String localName = typeQName.getLocalPart();
// Check to see if this is an anonymous type,
// if it is, replace Axis' ANON_TOKEN with
// an underscore to make sure we don't run
// into name collisions with similarly named
// non-anonymous types
StringBuffer sb = new StringBuffer(localName);
int aidx;
while ((aidx = sb.toString().indexOf(SymbolTable.ANON_TOKEN)) > -1) {
sb.replace(aidx, aidx + SymbolTable.ANON_TOKEN.length(), "");
char c = sb.charAt(aidx);
if (Character.isLetter(c) && Character.isLowerCase(c)) {
sb.setCharAt(aidx, Character.toUpperCase(c));
}
}
localName = sb.toString();
typeQName = new QName(typeQName.getNamespaceURI(),
localName);
if (emitter.isTypeCollisionProtection() &&
!emitter.getNamespaceExcludes().contains(new NamespaceSelector(typeQName.getNamespaceURI()))) {
// If there is already an existing type,
// there will be a collision.
// If there is an existing anon type,
// there will be a collision.
// In both cases, mangle the name.
if (symbolTable.getType(typeQName) != null ||
anonQNames.get(typeQName) != null) {
localName += "Type" + uniqueNum++;
typeQName =
new QName(typeQName.getNamespaceURI(),
localName);
}
anonQNames.put(typeQName, typeQName);
}
// Now set the name with the constructed qname
tEntry.setName(emitter.getJavaName(typeQName));
}
} // if (!processed)
Vector elements = tEntry.getContainedElements();
if (elements != null) {
for (int i = 0; i < elements.size(); i++) {
ElementDecl elem = (ElementDecl) elements.get(i);
String varName = emitter.getJavaVariableName(typeQName, elem.getQName(), true);
elem.setName(varName);
}
}
Vector attributes = tEntry.getContainedAttributes();
if (attributes != null) {
for (int i = 0; i < attributes.size(); i++) {
ContainedAttribute attr = (ContainedAttribute) attributes.get(i);
String varName = emitter.getJavaVariableName(typeQName, attr.getQName(), false);
attr.setName(varName);
}
}
}
// Set the entry with the same name as the ref'd entry
// but add the appropriate amount of dimensions
entry.setName(tEntry.getName() + dims);
return uniqueNum;
}
/**
* Gets class name from Java class.
* If the class is an array, get its component type's name
* @param clazz a java class
* @return the class name in string
*/
private static String getJavaClassName(Class clazz) {
Class class1 = clazz;
while (class1.isArray()) {
class1 = class1.getComponentType();
}
String name = class1.getName();
name.replace('$', '.');
return name;
}
/**
* setFaultContext:
* Processes the symbol table and sets the COMPLEX_TYPE_FAULT
* on each TypeEntry that is a complexType and is referenced in
* a fault message. TypeEntries that are the base or derived
* from such a TypeEntry are also marked with COMPLEX_TYPE_FAULT.
* The containing MessageEntry is marked with cOMPLEX_TYPE_FAULT, and
* all MessageEntries for faults are tagged with the
* EXCEPTION_CLASS_NAME variable, which indicates the java exception
* class name.
*
* @param symbolTable SymbolTable
*/
private void setFaultContext(SymbolTable symbolTable) {
Iterator it = symbolTable.getHashMap().values().iterator();
while (it.hasNext()) {
Vector v = (Vector) it.next();
for (int i = 0; i < v.size(); ++i) {
SymTabEntry entry = (SymTabEntry) v.elementAt(i);
// Inspect each BindingEntry in the Symbol Table
if (entry instanceof BindingEntry) {
BindingEntry bEntry = (BindingEntry) entry;
HashMap allOpFaults = bEntry.getFaults();
Iterator ops = allOpFaults.values().iterator();
// set the context for all faults for this binding.
while (ops.hasNext()) {
ArrayList faults = (ArrayList) ops.next();
for (int j = 0; j < faults.size(); ++j) {
FaultInfo info = (FaultInfo) faults.get(j);
setFaultContext(info, symbolTable);
}
}
}
}
}
} // setFaultContext
/**
* setFaultContext:
* Helper routine for the setFaultContext method above.
* Examines the indicated fault and sets COMPLEX_TYPE_FAULT
* EXCEPTION_DATA_TYPE and EXCEPTION_CLASS_NAME as appropriate.
*
* @param fault FaultInfo to analyze
* @param symbolTable SymbolTable
*/
private void setFaultContext(FaultInfo fault, SymbolTable symbolTable) {
QName faultXmlType = null;
Vector parts = new Vector();
// Get the parts of the fault's message.
// An IOException is thrown if the parts cannot be
// processed. Skip such parts for this analysis
try {
symbolTable.getParametersFromParts(
parts, fault.getMessage().getOrderedParts(null), false,
fault.getName(), null);
} catch (IOException e) {
}
// Inspect each TypeEntry referenced in a Fault Message Part
String exceptionClassName = null;
for (int j = 0; j < parts.size(); j++) {
TypeEntry te = ((Parameter) (parts.elementAt(j))).getType();
// If the TypeEntry is an element, advance to the type.
// This occurs if the message part uses the element= attribute
TypeEntry elementTE = null;
if (te instanceof Element) {
elementTE = te;
te = te.getRefType();
}
// remember the QName of the type.
faultXmlType = te.getQName();
// Determine if the te should be processed using the
// simple type mapping or the complex type mapping
// NOTE: treat array types as simple types
if ((te.getBaseType() != null) || te.isSimpleType()
|| ((te.getDimensions().length() > 0)
&& (te.getRefType().getBaseType() != null))) {
// Simple Type Exception
} else {
// Complex Type Exception
if (!Utils.isFaultComplex(te)) {
// Mark the type as a complex type fault
te.setDynamicVar(JavaGeneratorFactory.COMPLEX_TYPE_FAULT,
Boolean.TRUE);
if (elementTE != null) {
te.setDynamicVar(
JavaGeneratorFactory.COMPLEX_TYPE_FAULT,
Boolean.TRUE);
}
// Mark all derived types as Complex Faults
HashSet derivedSet =
org.apache.axis.wsdl.symbolTable.Utils.getDerivedTypes(
te, symbolTable);
Iterator derivedI = derivedSet.iterator();
while (derivedI.hasNext()) {
TypeEntry derivedTE = (TypeEntry) derivedI.next();
derivedTE.setDynamicVar(
JavaGeneratorFactory.COMPLEX_TYPE_FAULT,
Boolean.TRUE);
}
// Mark all base types as Complex Faults
TypeEntry base =
SchemaUtils.getComplexElementExtensionBase(te.getNode(),
symbolTable);
while (base != null) {
base.setDynamicVar(
JavaGeneratorFactory.COMPLEX_TYPE_FAULT,
Boolean.TRUE);
base = SchemaUtils.getComplexElementExtensionBase(
base.getNode(), symbolTable);
}
}
// The exception class name is the name of the type
exceptionClassName = te.getName();
}
}
String excName = getExceptionJavaNameHook(fault.getMessage().getQName()); // for derived class
if (excName != null) {
exceptionClassName = excName;
}
// Set the name of the exception and
// whether the exception is a complex type
MessageEntry me =
symbolTable.getMessageEntry(fault.getMessage().getQName());
if (me != null) {
me.setDynamicVar(JavaGeneratorFactory.EXCEPTION_DATA_TYPE,
faultXmlType);
if (exceptionClassName != null) {
me.setDynamicVar(JavaGeneratorFactory.COMPLEX_TYPE_FAULT,
Boolean.TRUE);
me.setDynamicVar(JavaGeneratorFactory.EXCEPTION_CLASS_NAME,
exceptionClassName);
} else {
me.setDynamicVar(JavaGeneratorFactory.EXCEPTION_CLASS_NAME,
emitter.getJavaName(me.getQName()));
}
}
}
protected String getExceptionJavaNameHook(QName qname) {
return null;
}
/**
* Method determineInterfaceNames
*
* @param symbolTable
*/
protected void determineInterfaceNames(SymbolTable symbolTable) {
Iterator it = symbolTable.getHashMap().values().iterator();
while (it.hasNext()) {
Vector v = (Vector) it.next();
for (int i = 0; i < v.size(); ++i) {
SymTabEntry entry = (SymTabEntry) v.elementAt(i);
if (entry instanceof BindingEntry) {
// The SEI (Service Endpoint Interface) name
// is always the portType name.
BindingEntry bEntry = (BindingEntry) entry;
PortTypeEntry ptEntry = symbolTable.getPortTypeEntry(
bEntry.getBinding().getPortType().getQName());
String seiName = getServiceEndpointInterfaceJavaNameHook(ptEntry, bEntry);
if (seiName == null) {
seiName = ptEntry.getName();
}
bEntry.setDynamicVar(JavaBindingWriter.INTERFACE_NAME,
seiName);
} else if (entry instanceof ServiceEntry) {
ServiceEntry sEntry = (ServiceEntry) entry;
String siName = getServiceInterfaceJavaNameHook(sEntry); // for derived class
if (siName != null) {
sEntry.setName(siName);
}
Service service = sEntry.getService();
Map portMap = service.getPorts();
Iterator portIterator = portMap.values().iterator();
while (portIterator.hasNext()) {
Port p = (Port) portIterator.next();
Binding binding = p.getBinding();
BindingEntry bEntry =
symbolTable.getBindingEntry(binding.getQName());
// If this isn't a SOAP binding, skip it
if (bEntry.getBindingType() != BindingEntry.TYPE_SOAP) {
continue;
}
String portName = getPortJavaNameHook(p.getName()); // for derived class
if (portName != null) {
bEntry.setDynamicVar(JavaServiceWriter.PORT_NAME + ":" + p.getName(),
portName);
}
}
}
}
}
} // determineInterfaceNames
protected String getServiceEndpointInterfaceJavaNameHook(PortTypeEntry ptEntry, BindingEntry bEntry) {
return null;
}
protected String getServiceInterfaceJavaNameHook(ServiceEntry sEntry) {
return null;
}
protected String getPortJavaNameHook(String portName) {
return null;
}
/**
* Messages, PortTypes, Bindings, and Services can share the same name. If they do in this
* Definition, force their names to be suffixed with _PortType and _Service, respectively.
*
* @param symbolTable
*/
protected void resolveNameClashes(SymbolTable symbolTable) {
// Keep a list of anonymous types so we don't try to resolve them twice.
HashSet anonTypes = new HashSet();
List collisionCandidates = new ArrayList(); // List of vector of SymbolTable entry
List localParts = new ArrayList(); // all localparts in all symboltable entries
for (Iterator i = symbolTable.getHashMap().keySet().iterator(); i.hasNext(); ) {
QName qName = (QName)i.next();
String localPart = qName.getLocalPart();
if (!localParts.contains(localPart))
localParts.add(localPart);
}
Map pkg2NamespacesMap = emitter.getNamespaces().getPkg2NamespacesMap();
for (Iterator i = pkg2NamespacesMap.values().iterator(); i.hasNext(); ) {
Vector namespaces = (Vector)i.next(); // namepaces mapped to same package
// Combine entry vectors, which have the same entry name, into a new entry vector.
for (int j = 0; j < localParts.size(); j++) {
Vector v = new Vector();
for (int k = 0; k < namespaces.size(); k++) {
QName qName = new QName((String)namespaces.get(k), (String)localParts.get(j));
if (symbolTable.getHashMap().get(qName) != null) {
v.addAll((Vector)symbolTable.getHashMap().get(qName));
}
}
if(v.size()>0) {
collisionCandidates.add(v);
}
}
}
Iterator it = collisionCandidates.iterator();
while (it.hasNext()) {
Vector v = new Vector(
(Vector) it.next()); // New vector we can temporarily add to it
// Remove MessageEntries since they are not mapped
int index = 0;
while (index < v.size()) {
if (v.elementAt(index) instanceof MessageEntry) {
// Need to resolve a Exception message.
MessageEntry msgEntry = (MessageEntry) v.elementAt(index);
// AXIS-2900: Only simple type faults generate additional classes; message entries for
// complex type faults don't cause any collisions.
if (Utils.isFaultComplex(msgEntry) || msgEntry.getDynamicVar(EXCEPTION_CLASS_NAME) == null) {
v.removeElementAt(index);
} else {
index++;
}
} else {
index++;
}
}
if (v.size() > 1) {
boolean resolve = true;
// Common Special Case:
// If a Type and Element have the same QName, and the Element
// references the Type, then they are the same class so
// don't bother mangling.
if (v.size() == 2 &&
((v.elementAt(0) instanceof Element &&
v.elementAt(1) instanceof Type) ||
(v.elementAt(1) instanceof Element &&
v.elementAt(0) instanceof Type))) {
Element e;
Type t;
if (v.elementAt(0) instanceof Element) {
e = (Element) v.elementAt(0);
t = (Type) v.elementAt(1);
} else {
e = (Element) v.elementAt(1);
t = (Type) v.elementAt(0);
}
BooleanHolder forElement = new BooleanHolder();
QName eType = Utils.getTypeQName(e.getNode(),
forElement, false);
if ((eType != null) && !forElement.value && eType.equals(t.getQName())) {
resolve = false;
}
}
// Other Special Case:
// If the names are already different, no mangling is needed.
if (resolve) {
resolve = false; // Assume false
String name = null;
for (int i = 0; (i < v.size()) && !resolve; ++i) {
SymTabEntry entry = (SymTabEntry) v.elementAt(i);
if ((entry instanceof MessageEntry)
|| (entry instanceof BindingEntry)) {
// Need to resolve a exception class name
String exceptionClassName = (String) entry.getDynamicVar(EXCEPTION_CLASS_NAME);
if (exceptionClassName != null) {
if (name == null) {
name = exceptionClassName;
} else if (name.equals(exceptionClassName)) {
resolve = true;
}
}
} else if (name == null) {
name = entry.getName();
} else if (name.equals(entry.getName())) {
resolve = true; // Need to do resolution
}
}
}
// Full Mangle if resolution is necessary.
if (resolve) {
boolean firstType = true;
for (int i = 0; i < v.size(); ++i) {
SymTabEntry entry = (SymTabEntry) v.elementAt(i);
if (entry instanceof Element) {
mangleName(entry, ELEMENT_SUFFIX);
// If this global element was defined using
// an anonymous type, then need to change the
// java name of the anonymous type to match.
QName anonQName =
new QName(entry.getQName().getNamespaceURI(),
SymbolTable.ANON_TOKEN
+ entry.getQName().getLocalPart());
TypeEntry anonType =
symbolTable.getType(anonQName);
if (anonType != null) {
anonType.setName(entry.getName());
anonTypes.add(anonType);
}
} else if (entry instanceof TypeEntry) {
// Search all other types for java names that match this one.
// The sameJavaClass method returns true if the java names are
// the same (ignores [] ).
if (firstType) {
firstType = false;
Iterator types =
symbolTable.getTypeIndex().values().iterator();
while (types.hasNext()) {
TypeEntry type = (TypeEntry) types.next();
if ((type != entry)
&& (type.getBaseType() == null)
&& sameJavaClass(entry.getName(),
type.getName())) {
v.add(type);
}
}
}
// If this is an anonymous type, it's name was resolved in
// the previous if block. Don't reresolve it.
if (!anonTypes.contains(entry)) {
// In case that other entry in name collision among
// PortTypeEntry, ServiceEntry and BindingEntry
boolean needResolve = false;
// check collision of TypeEntry with PortTypeEntry, ServiceEtnry and/or BindingEntry
for (int j = 0; j < v.size(); j++) {
SymTabEntry e = (SymTabEntry) v.elementAt(j);
if ((e instanceof PortTypeEntry
|| e instanceof ServiceEntry
|| e instanceof BindingEntry)) {
needResolve = true;
break;
}
}
if (!needResolve) {
continue;
}
// Appended Suffix for avoiding name collisions (JAX-RPC 1.1)
boolean isComplexTypeFault = Utils.isFaultComplex(entry);
mangleName(entry, isComplexTypeFault ? EXCEPTION_SUFFIX : TYPE_SUFFIX);
// should update the class name of ElementEntry which references this type entry
Map elementIndex = symbolTable.getElementIndex();
List elements = new ArrayList(elementIndex.values());
for (int j = 0; j < elementIndex.size(); j++) {
TypeEntry te = (TypeEntry) elements.get(j);
TypeEntry ref = te.getRefType();
if (ref != null && entry.getQName().equals(ref.getQName())) {
te.setName(entry.getName());
}
}
// Need to resolve a complex-type exception message.
if (isComplexTypeFault) {
// SHOULD update the exception class name of a referencing message entry.
List messageEntries = symbolTable.getMessageEntries();
for (int j = 0; j < messageEntries.size(); j++) {
MessageEntry messageEntry = (MessageEntry)messageEntries.get(j);
if (Utils.isFaultComplex(messageEntry)) {
QName exceptionDataType = (QName)messageEntry.getDynamicVar(EXCEPTION_DATA_TYPE);
if (((TypeEntry)entry).getQName().equals(exceptionDataType)) {
String className = (String)messageEntry.getDynamicVar(EXCEPTION_CLASS_NAME);
messageEntry.setDynamicVar(EXCEPTION_CLASS_NAME, className + EXCEPTION_SUFFIX);
}
}
}
}
}
} else if (entry instanceof PortTypeEntry) {
mangleName(entry, PORT_TYPE_SUFFIX); // "_Port" --> "_PortType" for JAX-RPC 1.1
} else if (entry instanceof ServiceEntry) {
mangleName(entry, SERVICE_SUFFIX);
} else if (entry instanceof MessageEntry) {
if (!Utils.isFaultComplex(entry)) {
String exceptionClassName = (String) entry.getDynamicVar(EXCEPTION_CLASS_NAME);
entry.setDynamicVar(EXCEPTION_CLASS_NAME, exceptionClassName + EXCEPTION_SUFFIX);
}
}
// else if (entry instanceof MessageEntry) {
// we don't care about messages
// }
else if (entry instanceof BindingEntry) {
BindingEntry bEntry = (BindingEntry) entry;
// If there is no literal use, then we never see a
// class named directly from the binding name. They
// all have suffixes: Stub, Skeleton, Impl.
// If there IS literal use, then the SDI will be
// named after the binding name, so there is the
// possibility of a name clash.
if (bEntry.hasLiteral()) {
mangleName(entry, BINDING_SUFFIX);
}
}
}
}
}
}
} // resolveNameClashes
/**
* Change the type name of the given symbol table entry into a mangled
* form using the given suffix.
*
* @param entry
* @param suffix
*/
private void mangleName(SymTabEntry entry, String suffix) {
String name = entry.getName();
int index = name.indexOf("[");
String newName;
if (index >= 0) {
String pre = name.substring(0, index);
String post = name.substring(index);
newName = pre + suffix + post;
} else {
newName = name + suffix;
}
entry.setName(newName);
if (log.isDebugEnabled()) {
log.debug("Symbol table of type " + entry.getClass().getName() + " mangled: " + name + " -> " + newName);
}
}
/**
* Returns true if same java class, ignore []
*
* @param one
* @param two
* @return
*/
private boolean sameJavaClass(String one, String two) {
int index1 = one.indexOf("[");
int index2 = two.indexOf("[");
if (index1 > 0) {
one = one.substring(0, index1);
}
if (index2 > 0) {
two = two.substring(0, index2);
}
return one.equals(two);
}
/**
* The --all flag is set on the command line (or generateAll(true) is called
* on WSDL2Java). Set all symbols as referenced (except nonSOAP bindings
* which we don't know how to deal with).
*/
protected void setAllReferencesToTrue() {
Iterator it = symbolTable.getHashMap().values().iterator();
while (it.hasNext()) {
Vector v = (Vector) it.next();
for (int i = 0; i < v.size(); ++i) {
SymTabEntry entry = (SymTabEntry) v.elementAt(i);
if ((entry instanceof BindingEntry)
&& ((BindingEntry) entry).getBindingType()
!= BindingEntry.TYPE_SOAP) {
entry.setIsReferenced(false);
} else {
entry.setIsReferenced(true);
}
}
}
} // setAllReferencesToTrue
/**
* If a binding's type is not TYPE_SOAP, then we don't use that binding
* or that binding's portType.
*
* @param symbolTable
*/
protected void ignoreNonSOAPBindings(SymbolTable symbolTable) {
// Look at all uses of the portTypes. If none of the portType's bindings are of type
// TYPE_SOAP, then turn off that portType's isReferenced flag.
Vector unusedPortTypes = new Vector();
Vector usedPortTypes = new Vector();
Iterator it = symbolTable.getHashMap().values().iterator();
while (it.hasNext()) {
Vector v = (Vector) it.next();
for (int i = 0; i < v.size(); ++i) {
SymTabEntry entry = (SymTabEntry) v.elementAt(i);
if (entry instanceof BindingEntry) {
BindingEntry bEntry = (BindingEntry) entry;
Binding binding = bEntry.getBinding();
PortType portType = binding.getPortType();
PortTypeEntry ptEntry =
symbolTable.getPortTypeEntry(portType.getQName());
if (bEntry.getBindingType() == BindingEntry.TYPE_SOAP) {
// If a binding is of type TYPE_SOAP, then mark its portType used
// (ie., add it to the usedPortTypes list. If the portType was
// previously marked as unused, unmark it (in other words, remove it
// from the unusedPortTypes list).
usedPortTypes.add(ptEntry);
if (unusedPortTypes.contains(ptEntry)) {
unusedPortTypes.remove(ptEntry);
}
} else {
bEntry.setIsReferenced(false);
// If a binding is not of type TYPE_SOAP, then mark its portType as
// unused ONLY if it hasn't already been marked as used.
if (!usedPortTypes.contains(ptEntry)) {
unusedPortTypes.add(ptEntry);
}
}
}
}
}
// Go through all the portTypes that are marked as unused and set their isReferenced flags
// to false.
for (int i = 0; i < unusedPortTypes.size(); ++i) {
PortTypeEntry ptEntry = (PortTypeEntry) unusedPortTypes.get(i);
ptEntry.setIsReferenced(false);
}
} // ignoreNonSOAPBindings
/**
* Method constructSignatures
*
* @param symbolTable
*/
protected void constructSignatures(SymbolTable symbolTable) {
Iterator it = symbolTable.getHashMap().values().iterator();
while (it.hasNext()) {
Vector v = (Vector) it.next();
for (int i = 0; i < v.size(); ++i) {
SymTabEntry entry = (SymTabEntry) v.elementAt(i);
if (entry instanceof BindingEntry) {
BindingEntry bEntry = (BindingEntry) entry;
Binding binding = bEntry.getBinding();
PortType portType = binding.getPortType();
Iterator operations =
portType.getOperations().iterator();
while (operations.hasNext()) {
Operation operation =
(Operation) operations.next();
String wsdlOpName = operation.getName();
OperationType type = operation.getStyle();
String javaOpName = getOperationJavaNameHook(bEntry, wsdlOpName); // for derived class
if (javaOpName == null) {
javaOpName = operation.getName();
}
Parameters parameters =
bEntry.getParameters(operation);
if (OperationType.SOLICIT_RESPONSE.equals(type)) {
parameters.signature =
" // "
+ Messages.getMessage("invalidSolResp00", javaOpName);
System.err.println(
Messages.getMessage("invalidSolResp00", javaOpName));
} else if (OperationType.NOTIFICATION.equals(type)) {
parameters.signature =
" // "
+ Messages.getMessage("invalidNotif00", javaOpName);
System.err.println(
Messages.getMessage("invalidNotif00", javaOpName));
} else { // ONE_WAY or REQUEST_RESPONSE
if (parameters != null) {
String returnType = getReturnTypeJavaNameHook(bEntry, wsdlOpName);
if (returnType != null) {
if (parameters.returnParam != null) { // 'void' return type???
parameters.returnParam.getType().setName(returnType);
}
}
for (int j = 0; j < parameters.list.size(); ++j) {
Parameter p = (Parameter) parameters.list.get(j);
String paramType = getParameterTypeJavaNameHook(bEntry, wsdlOpName, j);
if (paramType != null) {
p.getType().setName(paramType);
}
}
parameters.signature =
constructSignature(parameters, javaOpName);
}
}
}
}
}
}
} // constructSignatures
protected String getOperationJavaNameHook(BindingEntry bEntry, String wsdlOpName) {
return null;
}
protected String getReturnTypeJavaNameHook(BindingEntry bEntry, String wsdlOpName) {
return null;
}
protected String getParameterTypeJavaNameHook(BindingEntry bEntry, String wsdlOpName, int pos) {
return null;
}
/**
* Construct the signature, which is used by both the interface and the stub.
*
* @param parms
* @param opName
* @return
*/
private String constructSignature(Parameters parms, String opName) {
String name = JavaUtils.xmlNameToJava(opName);
String ret = "void";
if ((parms != null) && (parms.returnParam != null)) {
ret = Utils.getParameterTypeName(parms.returnParam);
}
String signature = " public " + ret + " " + name + "(";
boolean needComma = false;
for (int i = 0; (parms != null) && (i < parms.list.size()); ++i) {
Parameter p = (Parameter) parms.list.get(i);
if (needComma) {
signature = signature + ", ";
} else {
needComma = true;
}
String javifiedName = JavaUtils.xmlNameToJava(p.getName());
if (p.getMode() == Parameter.IN) {
signature += Utils.getParameterTypeName(p) + " " + javifiedName;
} else {
signature += Utils.holder(p, emitter) + " " + javifiedName;
}
}
signature = signature + ") throws java.rmi.RemoteException";
if ((parms != null) && (parms.faults != null)) {
// Collect the list of faults into a single string, separated by commas.
Iterator i = parms.faults.values().iterator();
while (i.hasNext()) {
Fault fault = (Fault) i.next();
String exceptionName =
Utils.getFullExceptionName(fault.getMessage(), symbolTable);
if (exceptionName != null) {
signature = signature + ", " + exceptionName;
}
}
}
return signature;
} // constructSignature
/**
* Find all inout/out parameters and add a flag to the Type of that parameter saying a holder
* is needed.
*
* @param symbolTable
*/
protected void determineIfHoldersNeeded(SymbolTable symbolTable) {
Iterator it = symbolTable.getHashMap().values().iterator();
while (it.hasNext()) {
Vector v = (Vector) it.next();
for (int i = 0; i < v.size(); ++i) {
if (v.get(i) instanceof BindingEntry) {
// If entry is a BindingEntry, look at all the Parameters
// in its portType
BindingEntry bEntry = (BindingEntry) v.get(i);
// PortTypeEntry ptEntry =
// symbolTable.getPortTypeEntry(bEntry.getBinding().getPortType().getQName());
Iterator operations =
bEntry.getParameters().values().iterator();
while (operations.hasNext()) {
Parameters parms = (Parameters) operations.next();
for (int j = 0; j < parms.list.size(); ++j) {
Parameter p = (Parameter) parms.list.get(j);
// If the given parameter is an inout or out parameter, then
// set a HOLDER_IS_NEEDED flag using the dynamicVar design.
if (p.getMode() != Parameter.IN) {
TypeEntry typeEntry = p.getType();
typeEntry.setDynamicVar(
JavaTypeWriter.HOLDER_IS_NEEDED,
Boolean.TRUE);
// If this is a complex then set the HOLDER_IS_NEEDED
// for the reftype too.
if (!typeEntry.isSimpleType()
&& (typeEntry.getRefType() != null)) {
typeEntry.getRefType().setDynamicVar(
JavaTypeWriter.HOLDER_IS_NEEDED,
Boolean.TRUE);
}
// If the type is a DefinedElement, need to
// set HOLDER_IS_NEEDED on the anonymous type.
QName anonQName =
SchemaUtils.getElementAnonQName(
p.getType().getNode());
if (anonQName != null) {
TypeEntry anonType =
symbolTable.getType(anonQName);
if (anonType != null) {
anonType.setDynamicVar(
JavaTypeWriter.HOLDER_IS_NEEDED,
Boolean.TRUE);
}
}
}
}
}
}
}
}
} // determineIfHoldersNeeded
/**
* Get TypeMapping to use for translating
* QNames to java base types
*/
BaseTypeMapping btm = null;
/**
* Method setBaseTypeMapping
*
* @param btm
*/
public void setBaseTypeMapping(BaseTypeMapping btm) {
this.btm = btm;
}
/**
* Method getBaseTypeMapping
*
* @return
*/
public BaseTypeMapping getBaseTypeMapping() {
if (btm == null) {
btm = new BaseTypeMapping() {
public String getBaseName(QName qNameIn) {
javax.xml.namespace.QName qName =
new javax.xml.namespace.QName(qNameIn.getNamespaceURI(),
qNameIn.getLocalPart());
Class cls =
emitter.getDefaultTypeMapping().getClassForQName(qName);
if (cls == null) {
return null;
} else {
return JavaUtils.getTextClassName(cls.getName());
}
}
};
}
return btm;
}
/**
* Determines whether the QName supplied should be generated by comparing
* the namespace for the QName against the included and excluded names.
* <ul>
* <li>if both the includes and excludes are both empty,
* the element is generated</li>
* <li>if the namespace is in the includes,
* the element is generated</li>
* <li>if the namespace is not in the excludes and the includes are empty,
* the element will be generated.
* <li>if the namespace is only in the excludes,
* the element is not generated</li>
* <li>if the namespace is not in the includes and the includes are not
* empty, the element is not generated</li>
* </ul>
* @param qName
* @return
*/
protected boolean include(QName qName) {
String namespace =
(qName != null && qName.getNamespaceURI() != null)
? qName.getNamespaceURI()
: "";
boolean doInclude = false;
NamespaceSelector selector = new NamespaceSelector(namespace);
if (qName == null
|| emitter == null
|| emitter.getNamespaceIncludes().contains(selector)
|| (emitter.getNamespaceIncludes().size() == 0
&& !emitter.getNamespaceExcludes().contains(selector))) {
doInclude = true;
}
else {
log.info(
"excluding code generation for non-included QName:" + qName);
}
return doInclude;
}
} // class JavaGeneratorFactory