blob: 3c550d978185c9383b69457ad3d9daeb341b01fc [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.tuscany.sca.interfacedef.wsdl.xml;
import static javax.xml.stream.XMLStreamConstants.END_ELEMENT;
import java.net.URI;
import java.util.List;
import javax.wsdl.PortType;
import javax.wsdl.WSDLElement;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import org.apache.tuscany.sca.assembly.xml.PolicySubjectProcessor;
import org.apache.tuscany.sca.contribution.Artifact;
import org.apache.tuscany.sca.contribution.processor.BaseStAXArtifactProcessor;
import org.apache.tuscany.sca.contribution.processor.ContributionReadException;
import org.apache.tuscany.sca.contribution.processor.ContributionResolveException;
import org.apache.tuscany.sca.contribution.processor.ContributionWriteException;
import org.apache.tuscany.sca.contribution.processor.ProcessorContext;
import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor;
import org.apache.tuscany.sca.contribution.resolver.ModelResolver;
import org.apache.tuscany.sca.core.ExtensionPointRegistry;
import org.apache.tuscany.sca.core.FactoryExtensionPoint;
import org.apache.tuscany.sca.core.UtilityExtensionPoint;
import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper;
import org.apache.tuscany.sca.interfacedef.InvalidInterfaceException;
import org.apache.tuscany.sca.interfacedef.wsdl.WSDLDefinition;
import org.apache.tuscany.sca.interfacedef.wsdl.WSDLFactory;
import org.apache.tuscany.sca.interfacedef.wsdl.WSDLInterface;
import org.apache.tuscany.sca.interfacedef.wsdl.WSDLInterfaceContract;
import org.apache.tuscany.sca.interfacedef.wsdl.WSDLObject;
import org.apache.tuscany.sca.monitor.Monitor;
import org.apache.tuscany.sca.monitor.Problem;
import org.apache.tuscany.sca.monitor.Problem.Severity;
import org.apache.tuscany.sca.policy.PolicyFactory;
/**
* Handles a <interface.wsdl ... /> element in a SCDL file
* @version $Rev$ $Date$
*/
public class WSDLInterfaceProcessor extends BaseStAXArtifactProcessor implements StAXArtifactProcessor<WSDLInterfaceContract>, WSDLConstants {
private WSDLFactory wsdlFactory;
private InterfaceContractMapper interfaceContractMapper;
private PolicyFactory policyFactory;
private PolicySubjectProcessor policyProcessor;
public WSDLInterfaceProcessor(ExtensionPointRegistry registry) {
FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class);
this.interfaceContractMapper =
registry.getExtensionPoint(UtilityExtensionPoint.class).getUtility(InterfaceContractMapper.class);
this.wsdlFactory = modelFactories.getFactory(WSDLFactory.class);
this.policyFactory = modelFactories.getFactory(PolicyFactory.class);
this.policyProcessor = new PolicySubjectProcessor(policyFactory);
}
/**
* Report a warning.
*
* @param problems
* @param message
* @param model
*/
private void warning(Monitor monitor, String message, Object model, Object... messageParameters) {
if (monitor != null) {
Problem problem = monitor.createProblem(this.getClass().getName(), "interface-wsdlxml-validation-messages", Severity.WARNING, model, message, (Object[])messageParameters);
monitor.problem(problem);
}
}
/**
* Report a error.
*
* @param problems
* @param message
* @param model
*/
private void error(Monitor monitor, String message, Object model, Object... messageParameters) {
if (monitor != null) {
Problem problem = monitor.createProblem(this.getClass().getName(), "interface-wsdlxml-validation-messages", Severity.ERROR, model, message, (Object[])messageParameters);
monitor.problem(problem);
}
}
/**
* Report a exception.
*
* @param problems
* @param message
* @param model
*/
private void error(Monitor monitor, String message, Object model, Exception ex) {
if (monitor != null) {
Problem problem = monitor.createProblem(this.getClass().getName(), "interface-wsdlxml-validation-messages", Severity.ERROR, model, message, ex);
monitor.problem(problem);
}
}
/**
* Create a WSDL interface from a URI.
* @param uri - the URI in the form nameSpace#wsdl.interface(porttypeName) or nameSpace#wsdl.porttype(porttypeName)
* @return a WSDLInterface object
* @throws ContributionReadException
*/
private static String FRAGMENT_INTERFACE = "wsdl.interface";
private static String FRAGMENT_PORTTYPE = "wsdl.porttype";
private WSDLInterface createWSDLInterface(String uri, Monitor monitor) throws ContributionReadException {
WSDLInterface wsdlInterface = null;
// Read a QName in the form:
// namespace#wsdl.interface(name)
int index = uri.indexOf('#');
if (index == -1) {
error(monitor, "InvalidWSDLInterfaceAttr", wsdlFactory, uri);
//throw new ContributionReadException("Invalid WSDL interface attribute: " + uri);
} else {
// Read the URI and extract namespace and fragment
String namespace = uri.substring(0, index);
String name = uri.substring(index + 1);
String porttype = null;
if( name.contains(FRAGMENT_INTERFACE)) {
// Deal with the case where #wsdl.interface is used
porttype = name.substring("wsdl.interface(".length(), name.length() - 1);
} // end if
if( name.contains(FRAGMENT_PORTTYPE)) {
// Deal with the case where #wsdl.porttype is used
porttype = name.substring("wsdl.porttype(".length(), name.length() - 1);
} // end if
if( porttype == null ) {
error(monitor, "InvalidWSDLInterfaceAttr", wsdlFactory, uri);
return null;
} // end if
wsdlInterface = wsdlFactory.createWSDLInterface();
wsdlInterface.setUnresolved(true);
wsdlInterface.setName(new QName(namespace, porttype));
} // end if
return wsdlInterface;
} // end method createWSDLInterface
/**
* Creates a WSDLInterfaceContract from a <interface.wsdl/> element in a SCDL file
*
* The form of the <interface.wsdl/> element is as follows:
*
* <interface.wsdl interface="http://sampleNamespace#wsdl.interface(porttypeName)"
* callbackInterface="http://sampleNamespace#wsdl.porttype(callbackPorttypeName)"/>
* where interface = URI pointing to the WSDL document containing a WSDL interface or porttype for the forward call interface
* callbackInterface = URI pointing to the WSDL document containing a WSDL interface or porttype for the callback interface
*
* @param reader - XMLStreamReader holding the <interface.wsdl/> element
* @return - the WSDLInterfaceContract
*/
public WSDLInterfaceContract read(XMLStreamReader reader, ProcessorContext context) throws ContributionReadException, XMLStreamException {
// Read an <interface.wsdl>
WSDLInterfaceContract wsdlInterfaceContract = wsdlFactory.createWSDLInterfaceContract();
Monitor monitor = context.getMonitor();
// Read wsdlLocation
String location = reader.getAttributeValue(WSDLI_NS, WSDL_LOCATION);
wsdlInterfaceContract.setLocation(location);
String uri = getURIString(reader, INTERFACE);
if (uri != null) {
WSDLInterface wsdlInterface = createWSDLInterface(uri, monitor);
if (wsdlInterface != null)
wsdlInterfaceContract.setInterface(wsdlInterface);
}
uri = getURIString(reader, CALLBACK_INTERFACE);
if (uri != null) {
WSDLInterface wsdlCallbackInterface = createWSDLInterface(uri, monitor);
if (wsdlCallbackInterface != null)
wsdlInterfaceContract.setCallbackInterface(wsdlCallbackInterface);
}
String remotable = reader.getAttributeValue(null, REMOTABLE);
if (remotable != null &&
!remotable.equals("true")){
Monitor.error(monitor,
this,
"interface-wsdlxml-validation-messages",
"InvalidRemotableValue",
((WSDLInterface)wsdlInterfaceContract.getInterface()).getName().toString(),
remotable);
}
// Read intents and policy sets
policyProcessor.readPolicies(wsdlInterfaceContract.getInterface(), reader);
// Skip to end element
while (reader.hasNext()) {
if (reader.next() == END_ELEMENT && INTERFACE_WSDL_QNAME.equals(reader.getName())) {
break;
}
}
return wsdlInterfaceContract;
}
public void write(WSDLInterfaceContract wsdlInterfaceContract, XMLStreamWriter writer, ProcessorContext context) throws ContributionWriteException, XMLStreamException {
// Write an <interface.wsdl>
writer.writeStartElement(WSDLConstants.SCA11_NS, INTERFACE_WSDL);
// Write interface name
WSDLInterface wsdlInterface = (WSDLInterface)wsdlInterfaceContract.getInterface();
if (wsdlInterface != null) {
QName qname = wsdlInterface.getName();
String uri = qname.getNamespaceURI() + "#wsdl.interface(" + qname.getLocalPart() + ")";
writer.writeAttribute(INTERFACE, uri);
}
WSDLInterface wsdlCallbackInterface = (WSDLInterface)wsdlInterfaceContract.getCallbackInterface();
if (wsdlCallbackInterface != null) {
QName qname = wsdlCallbackInterface.getName();
String uri = qname.getNamespaceURI() + "#wsdl.interface(" + qname.getLocalPart() + ")";
writer.writeAttribute(CALLBACK_INTERFACE, uri);
}
// Write location
if (wsdlInterfaceContract.getLocation() != null) {
writer.writeAttribute(WSDLI_NS, WSDL_LOCATION, wsdlInterfaceContract.getLocation());
}
policyProcessor.writePolicyAttributes(wsdlInterface, writer);
writer.writeEndElement();
}
private WSDLInterface resolveWSDLInterface(WSDLInterface wsdlInterface, ModelResolver resolver, ProcessorContext context) throws ContributionResolveException {
if (wsdlInterface != null && wsdlInterface.isUnresolved()) {
Monitor monitor = context.getMonitor();
// Resolve the WSDL interface
wsdlInterface = resolver.resolveModel(WSDLInterface.class, wsdlInterface, context);
if (wsdlInterface.isUnresolved()) {
// If the WSDL interface has never been resolved yet, do it now
// First, resolve the WSDL definition for the given namespace
WSDLDefinition wsdlDefinition = wsdlFactory.createWSDLDefinition();
wsdlDefinition.setUnresolved(true);
wsdlDefinition.setNamespace(wsdlInterface.getName().getNamespaceURI());
wsdlDefinition.setNameOfPortTypeToResolve(wsdlInterface.getName());
WSDLDefinition resolved = resolver.resolveModel(WSDLDefinition.class, wsdlDefinition, context);
if (!resolved.isUnresolved()) {
wsdlDefinition.setDefinition(resolved.getDefinition());
wsdlDefinition.setLocation(resolved.getLocation());
wsdlDefinition.setURI(resolved.getURI());
wsdlDefinition.getImportedDefinitions().addAll(resolved.getImportedDefinitions());
wsdlDefinition.getXmlSchemas().addAll(resolved.getXmlSchemas());
wsdlDefinition.setUnresolved(false);
WSDLObject<PortType> portType = wsdlDefinition.getWSDLObject(PortType.class, wsdlInterface.getName());
if (portType != null) {
// Introspect the WSDL portType and add the resulting
// WSDLInterface to the resolver
try {
wsdlDefinition.setDefinition(portType.getDefinition());
WSDLInterface newWSDLInterface = wsdlFactory.createWSDLInterface(portType.getElement(), wsdlDefinition, resolver, monitor);
newWSDLInterface.setWsdlDefinition(wsdlDefinition);
newWSDLInterface.getRequiredIntents().addAll(wsdlInterface.getRequiredIntents());
newWSDLInterface.getPolicySets().addAll(wsdlInterface.getPolicySets());
resolver.addModel(newWSDLInterface, context);
wsdlInterface = newWSDLInterface;
} catch (InvalidInterfaceException e) {
ContributionResolveException ce = new ContributionResolveException("Invalid interface when resolving " +
portType.toString(), e);
error(monitor, "ContributionResolveException", wsdlFactory, ce);
//throw ce;
} // end try
}
else {
warning(monitor, "WsdlInterfaceDoesNotMatch", wsdlDefinition, wsdlInterface.getName());
} // end if
} else {
// If we get here, the WSDLDefinition is unresolved...
ContributionResolveException ce = new ContributionResolveException("WSDLDefinition unresolved " +
wsdlInterface.getName() );
error(monitor, "ContributionResolveException", wsdlFactory, ce);
} // end if
} // end if
} // end if
return wsdlInterface;
}
public static WSDLInterface resolveWSDLInterface( WSDLInterface wsdlInterface, ModelResolver resolver,
Monitor monitor, WSDLFactory wsdlFactory) {
if (wsdlInterface != null && wsdlInterface.isUnresolved()) {
ProcessorContext context = new ProcessorContext(monitor);
// Resolve the WSDL interface
wsdlInterface = resolver.resolveModel(WSDLInterface.class, wsdlInterface, context);
if (wsdlInterface.isUnresolved()) {
// If the WSDL interface has never been resolved yet, do it now
// First, resolve the WSDL definition for the given namespace
WSDLDefinition wsdlDefinition = wsdlFactory.createWSDLDefinition();
wsdlDefinition.setUnresolved(true);
wsdlDefinition.setNamespace(wsdlInterface.getName().getNamespaceURI());
WSDLDefinition resolved = resolver.resolveModel(WSDLDefinition.class, wsdlDefinition, context);
if (!resolved.isUnresolved()) {
wsdlDefinition.setDefinition(resolved.getDefinition());
wsdlDefinition.setLocation(resolved.getLocation());
wsdlDefinition.setURI(resolved.getURI());
wsdlDefinition.getImportedDefinitions().addAll(resolved.getImportedDefinitions());
wsdlDefinition.getXmlSchemas().addAll(resolved.getXmlSchemas());
wsdlDefinition.setUnresolved(false);
WSDLObject<PortType> portType = wsdlDefinition.getWSDLObject(PortType.class, wsdlInterface.getName());
if (portType != null) {
// Introspect the WSDL portType and add the resulting
// WSDLInterface to the resolver
try {
wsdlDefinition.setDefinition(portType.getDefinition());
wsdlInterface = wsdlFactory.createWSDLInterface(portType.getElement(), wsdlDefinition, resolver, monitor);
wsdlInterface.setWsdlDefinition(wsdlDefinition);
resolver.addModel(wsdlInterface, context);
} catch (InvalidInterfaceException e) {
ContributionResolveException ce = new ContributionResolveException("Invalid interface when resolving " +
portType.toString(), e);
Monitor.error(monitor, WSDLInterfaceProcessor.class.getName(),
"interface-wsdlxml-validation-messages", "ContributionResolveException",
wsdlFactory.getClass().getName(), ce.getMessage());
//throw ce;
} // end try
}
else {
Monitor.warning(monitor, WSDLInterfaceProcessor.class.getName(),
"interface-wsdlxml-validation-messages", "WsdlInterfaceDoesNotMatch",
wsdlDefinition.getNamespace(), wsdlInterface.getName().toString() );
} // end if
} else {
// If we get here, the WSDLDefinition is unresolved...
ContributionResolveException ce = new ContributionResolveException("WSDLDefinition unresolved " +
wsdlInterface.getName() );
Monitor.error(monitor, WSDLInterfaceProcessor.class.getName(),
"interface-wsdlxml-validation-messages", "ContributionResolveException",
wsdlFactory.getClass().getName(), ce.getMessage());
} // end if
} // end if
} // end if
return wsdlInterface;
} // end method resolveWSDLInterface
/**
* Resolve a WSDLInterfaceContract
*/
public void resolve(WSDLInterfaceContract wsdlInterfaceContract, ModelResolver resolver, ProcessorContext context) throws ContributionResolveException {
Monitor monitor = context.getMonitor();
WSDLInterface wsdlInterface = (WSDLInterface)wsdlInterfaceContract.getInterface();
// if the contract has a location but no WSDL definition yet we need to read the WSDL
// from the specified location and create an interface based on the first port type
// this is required if the user uses the @WebService(wsdlLocation="") or
// @WebServiceProvider(wsdlLocation="") annotation in a Java component implementation.
if (wsdlInterfaceContract.getLocation() != null &&
wsdlInterface.getWsdlDefinition() == null){
WSDLDefinition wsdlDefinition = null;
URI wsdlFileURI = null;
try {
wsdlFileURI = new URI(wsdlInterfaceContract.getLocation());
} catch (Exception ex) {
Monitor.error(context.getMonitor(),
WSDLInterfaceProcessor.class.getName(),
"interface-wsdlxml-validation-messages",
"wsdliLocationException",
ex.getMessage() );
return;
}
// We need to find a portType from the user specified WSDL (the first one?) from which to defined
// the service interface. We can't just use the Tuscany resolution mechanism to find the WSDL file
// as that lumps together all WSDL in the same namespace. That's fine if you already know what portType
// your after. In this case we don't so we have to get the WSDL specified, find out what it's first portType
// is and then go from there with the usual Tuscany resolution mechanism
try {
if (wsdlFileURI.isAbsolute()){
// use the wsdli:wsdlLocation mechanism in the WSDLModelResolver to
// load the WSDL from an absolute location
wsdlDefinition = wsdlFactory.createWSDLDefinition();
wsdlDefinition.setUnresolved(true);
wsdlDefinition.setNamespace("nonamespace");
wsdlDefinition.getWsdliLocations().put("nonamespace", wsdlInterfaceContract.getLocation());
wsdlDefinition.setLocation(new URI(wsdlInterfaceContract.getLocation()));
} else {
// Find the wsdl in the contribution ready for further resolution
for (Artifact artifact : context.getContribution().getArtifacts()) {
if (artifact.getLocation().endsWith(wsdlInterfaceContract.getLocation())){
WSDLDefinition artifactWSDLDefinition = artifact.getModel();
wsdlDefinition = wsdlFactory.createWSDLDefinition();
wsdlDefinition.setUnresolved(true);
wsdlDefinition.setNamespace(artifactWSDLDefinition.getNamespace());
wsdlDefinition.getWsdliLocations().put(artifactWSDLDefinition.getNamespace(),
artifact.getLocation());
wsdlDefinition.setLocation(new URI(artifact.getLocation()));
break;
}
}
if (wsdlDefinition == null){
Monitor.error(context.getMonitor(),
WSDLInterfaceProcessor.class.getName(),
"interface-wsdlxml-validation-messages",
"wsdliLocationException",
"WSDL not found inside contribution at relative URI " + wsdlFileURI );
return;
}
}
} catch (Exception ex) {
Monitor.error(context.getMonitor(),
WSDLInterfaceProcessor.class.getName(),
"interface-wsdlxml-validation-messages",
"wsdliLocationException",
ex.getMessage() );
return;
}
wsdlDefinition.setUnresolved(true);
wsdlDefinition = resolver.resolveModel(WSDLDefinition.class, wsdlDefinition, context);
// create the interface based on the first port type
PortType portType = (PortType)wsdlDefinition.getDefinition().getAllPortTypes().values().iterator().next();
try {
WSDLInterface newWSDLInterface = wsdlFactory.createWSDLInterface(portType, wsdlDefinition, resolver, monitor);
newWSDLInterface.getRequiredIntents().addAll(wsdlInterface.getRequiredIntents());
newWSDLInterface.getPolicySets().addAll(wsdlInterface.getPolicySets());
wsdlInterface = newWSDLInterface;
} catch (InvalidInterfaceException e) {
ContributionResolveException ce = new ContributionResolveException("Invalid interface when resolving " +
portType.toString(), e);
error(monitor, "ContributionResolveException", wsdlFactory, ce);
}
wsdlInterface.setWsdlDefinition(wsdlDefinition);
wsdlInterfaceContract.setInterface(wsdlInterface);
}
// Resolve the interface and callback interface
wsdlInterface = resolveWSDLInterface(wsdlInterface, resolver, context);
wsdlInterfaceContract.setInterface(wsdlInterface);
// The forward interface (portType) may have a callback interface declared on it using an sca:callback attribute
WSDLInterface intrinsicWSDLCallbackInterface = wsdlInterface.getCallbackInterface();
// There may be a callback interface explicitly declared on the <interface.wsdl .../> element
WSDLInterface wsdlCallbackInterface = resolveWSDLInterface((WSDLInterface)wsdlInterfaceContract.getCallbackInterface(), resolver, context);
if( intrinsicWSDLCallbackInterface != null ) {
if( wsdlCallbackInterface != null ) {
// If there is both a callback interface declared on the forward interface and also one declared on the
// interface.wsdl element, then the two interfaces must match [ASM80011]
if( !interfaceContractMapper.isMutuallyCompatible(intrinsicWSDLCallbackInterface, wsdlCallbackInterface) ) {
Monitor.error(context.getMonitor(), WSDLInterfaceProcessor.class.getName(),
"interface-wsdlxml-validation-messages", "IncompatibleCallbacks",
intrinsicWSDLCallbackInterface.getName().toString(),
wsdlCallbackInterface.getName().toString() );
} // end if
} // end if
wsdlInterfaceContract.setCallbackInterface(intrinsicWSDLCallbackInterface);
} else {
wsdlInterfaceContract.setCallbackInterface(wsdlCallbackInterface);
} // end if
} // end method resolve( WSDLInterfaceContract, ModelResolver)
public QName getArtifactType() {
return WSDLConstants.INTERFACE_WSDL_QNAME;
}
public Class<WSDLInterfaceContract> getModelType() {
return WSDLInterfaceContract.class;
}
}