blob: 50bb5f86d3d94f230a26ba342e0ccb38841b45a9 [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.implementation.java.introspect.impl;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.xml.ws.BindingType;
import javax.xml.ws.ServiceMode;
import javax.xml.ws.WebServiceProvider;
import org.apache.tuscany.sca.assembly.AssemblyFactory;
import org.apache.tuscany.sca.assembly.Service;
import org.apache.tuscany.sca.assembly.xml.Constants;
import org.apache.tuscany.sca.binding.ws.WebServiceBinding;
import org.apache.tuscany.sca.binding.ws.WebServiceBindingFactory;
import org.apache.tuscany.sca.binding.ws.xml.WebServiceConstants;
import org.apache.tuscany.sca.core.ExtensionPointRegistry;
import org.apache.tuscany.sca.core.FactoryExtensionPoint;
import org.apache.tuscany.sca.implementation.java.IntrospectionException;
import org.apache.tuscany.sca.implementation.java.JavaImplementation;
import org.apache.tuscany.sca.implementation.java.introspect.BaseJavaClassVisitor;
import org.apache.tuscany.sca.interfacedef.InvalidInterfaceException;
import org.apache.tuscany.sca.interfacedef.java.JavaInterface;
import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceContract;
import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory;
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.policy.ExtensionType;
import org.apache.tuscany.sca.policy.Intent;
import org.apache.tuscany.sca.policy.PolicyFactory;
import org.apache.tuscany.sca.policy.PolicySubject;
/**
* Process JAXWS annotations and updates the component type accordingly
*
*/
public class JAXWSProcessor extends BaseJavaClassVisitor {
private PolicyFactory policyFactory;
private WSDLFactory wsdlFactory;
private WebServiceBindingFactory wsBindingFactory;
public JAXWSProcessor(ExtensionPointRegistry registry) {
super(registry);
FactoryExtensionPoint factories = registry.getExtensionPoint(FactoryExtensionPoint.class);
this.wsdlFactory = factories.getFactory(WSDLFactory.class);
this.assemblyFactory = factories.getFactory(AssemblyFactory.class);
this.policyFactory = factories.getFactory(PolicyFactory.class);
this.javaInterfaceFactory = factories.getFactory(JavaInterfaceFactory.class);
this.wsBindingFactory = factories.getFactory(WebServiceBindingFactory.class);
}
@Override
public <T> void visitClass(Class<T> clazz, JavaImplementation type) throws IntrospectionException {
boolean hasJaxwsAnnotation = false;
// Process @ServiceMode annotation - JCA 11013
if ( clazz.getAnnotation(ServiceMode.class) != null ) {
addSOAPIntent(type);
hasJaxwsAnnotation = true;
}
// Process @WebService annotation - POJO_8029, POJO_8030
WebService webServiceAnnotation = clazz.getAnnotation(WebService.class);
org.oasisopen.sca.annotation.Service serviceAnnotation = clazz.getAnnotation(org.oasisopen.sca.annotation.Service.class);
if (webServiceAnnotation != null &&
serviceAnnotation == null) {
String serviceName = clazz.getSimpleName();
serviceName = getValue(webServiceAnnotation.name(), serviceName);
String serviceInterfaceClassName = webServiceAnnotation.endpointInterface();
String wsdlLocation = webServiceAnnotation.wsdlLocation();
try {
createService(type, clazz, serviceName, serviceInterfaceClassName, wsdlLocation, false);
} catch (InvalidInterfaceException e) {
throw new IntrospectionException(e);
}
hasJaxwsAnnotation = true;
}
// Process @WebServiceProvider annotation - JCA_11015, POJO_8034
WebServiceProvider webServiceProviderAnnotation = clazz.getAnnotation(WebServiceProvider.class);
if (webServiceProviderAnnotation != null) {
// if the implmentation already has a service set, use it's name
// and the new service, which uses the implementation as an interface,
// will be replaced
String serviceName = clazz.getSimpleName();
if (type.getServices().size() > 0){
serviceName = ((Service)type.getServices().get(0)).getName();
}
// the annotation may specify a service name
serviceName = getValue(webServiceProviderAnnotation.serviceName(), serviceName);
String wsdlLocation = webServiceProviderAnnotation.wsdlLocation();
// Make sure that there is a service with an interface
// based on the implementation class and have it replace
// any service with the same name
try {
createService(type, clazz, serviceName, null, wsdlLocation, true);
} catch (InvalidInterfaceException e) {
throw new IntrospectionException(e);
}
// Make sure all service references are remotable
for ( Service service : type.getServices() ) {
service.getInterfaceContract().getInterface().setRemotable(true);
}
hasJaxwsAnnotation = true;
}
// Process @WebParam and @WebResult annotations - POJO_8031, POJO_8032
Class<?> interfaze = clazz;
Method[] implMethods = interfaze.getDeclaredMethods();
for ( Service service : type.getServices() ) {
JavaInterface javaInterface = (JavaInterface)service.getInterfaceContract().getInterface();
interfaze = javaInterface.getJavaClass();
if (interfaze == null){
// this interface has come from an @WebService enpointInterface annotation
// so hasn't been resolved. Use the implementation class as the interface
interfaze = clazz;
}
boolean hasHeaderParam = false;
for (Method method : interfaze.getDeclaredMethods()){
// find the impl method for this service method
for (int i = 0; i < implMethods.length; i++){
Method implMethod = implMethods[i];
if (implMethod.getName().equals(method.getName())){
for (int j = 0; j < implMethod.getParameterTypes().length; j++) {
WebParam webParamAnnotation = getParameterAnnotation(implMethod, j, WebParam.class);
if (webParamAnnotation != null &&
webParamAnnotation.header()) {
hasHeaderParam = true;
break;
}
}
WebResult webResultAnnotation = implMethod.getAnnotation(WebResult.class);
if (webResultAnnotation != null &&
webResultAnnotation.header()){
hasHeaderParam = true;
break;
}
}
}
}
if (hasHeaderParam){
// Add a SOAP intent to the service
addSOAPIntent(service);
hasJaxwsAnnotation = true;
}
}
// Process @SOAPBinding annotation - POJO_8033
if ( clazz.getAnnotation(SOAPBinding.class) != null ) {
// If the implementation is annotated with @SOAPBinding,
// give all services a SOAP intent
for ( Service service : type.getServices() ) {
addSOAPIntent(service);
}
hasJaxwsAnnotation = true;
}
// Process @BindingType annotation - POJO_8037
BindingType bindingType = clazz.getAnnotation(BindingType.class);
if ( bindingType != null ) {
String bindingTypeValue = bindingType.value();
for ( Service service : type.getServices() ) {
addBindingTypeIntent(service, bindingTypeValue);
}
hasJaxwsAnnotation = true;
}
if (hasJaxwsAnnotation == true){
// Note that services are based on JAXWS annotations in case
// we need to know later. Add a ws binding and a JAXWS annotation
// implies a WS binding
for ( Service service : type.getServices() ) {
service.setJAXWSService(true);
createWSBinding(type, service);
}
}
}
private void addBindingTypeIntent(PolicySubject subject,
String bindingTypeValue) {
Intent soapIntent = policyFactory.createIntent();
if ( javax.xml.ws.soap.SOAPBinding.SOAP11HTTP_BINDING.equals(bindingTypeValue)) {
soapIntent.setName(Constants.SOAP11_INTENT);
} else if ( javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING.equals(bindingTypeValue)) {
soapIntent.setName(Constants.SOAP12_INTENT);
} else {
soapIntent.setName(Constants.SOAP11_INTENT);
}
subject.getRequiredIntents().add(soapIntent);
}
/**
* Utility methods
*/
private static String getValue(String value, String defaultValue) {
return "".equals(value) ? defaultValue : value;
}
private Service createService(JavaImplementation type, Class<?> clazz, String serviceName, String javaInterfaceName, String wsdlFileName, boolean replace) throws InvalidInterfaceException, IntrospectionException {
Service service = assemblyFactory.createService();
if (serviceName != null) {
service.setName(serviceName);
} else if (javaInterfaceName != null){
service.setName(javaInterfaceName.substring(javaInterfaceName.lastIndexOf('.')));
}
// create the physical Java interface contract
JavaInterfaceContract javaInterfaceContract = javaInterfaceFactory.createJavaInterfaceContract();;
service.setInterfaceContract(javaInterfaceContract);
if (javaInterfaceName != null &&
javaInterfaceName.length() > 0){
JavaInterface callInterface = javaInterfaceFactory.createJavaInterface();
callInterface.setName(javaInterfaceName);
callInterface.setRemotable(true);
callInterface.setUnresolved(true);
javaInterfaceContract.setInterface(callInterface);
} else {
// we use the bean class as the service interface
JavaInterface callInterface = javaInterfaceFactory.createJavaInterface(clazz);
callInterface.setRemotable(true);
callInterface.setUnresolved(false); // this will already be false but this makes it easy to follow the logic
javaInterfaceContract.setInterface(callInterface);
}
// create the logical WSDL interface if it's specified in
// the @WebService annotation
if (wsdlFileName != null &&
wsdlFileName.length() > 0){
WSDLInterface callInterface = wsdlFactory.createWSDLInterface();
callInterface.setUnresolved(true);
callInterface.setRemotable(true);
WSDLInterfaceContract wsdlInterfaceContract = wsdlFactory.createWSDLInterfaceContract();
wsdlInterfaceContract.setInterface(callInterface);
wsdlInterfaceContract.setLocation(wsdlFileName);
javaInterfaceContract.setNormailizedWSDLContract(wsdlInterfaceContract);
}
// add the service model into the implementation type
Service serviceAlreadyPresent = null;
for (Service typeService : type.getServices()){
if (typeService.getName().equals(service.getName())){
serviceAlreadyPresent = typeService;
break;
}
}
if (replace == true){
type.getServices().remove(serviceAlreadyPresent);
type.getServices().add(service);
} else {
if (serviceAlreadyPresent == null){
type.getServices().add(service);
}
}
return service;
}
private <T extends Annotation> T getParameterAnnotation(Method method, int index, Class<T> annotationType) {
Annotation[] annotations = method.getParameterAnnotations()[index];
for (Annotation annotation : annotations) {
if (annotation.annotationType() == annotationType) {
return annotationType.cast(annotation);
}
}
return null;
}
private void addSOAPIntent(PolicySubject policySubject){
Intent soapIntent = policyFactory.createIntent();
soapIntent.setName(Constants.SOAP_INTENT);
policySubject.getRequiredIntents().add(soapIntent);
}
private void createWSBinding(JavaImplementation javaImplementation, Service service){
if(service.getBindings().size() == 0){
WebServiceBinding wsBinding = wsBindingFactory.createWebServiceBinding();
wsBinding.setName(service.getName());
ExtensionType bindingType = policyFactory.createBindingType();
bindingType.setType(WebServiceConstants.BINDING_WS_QNAME);
bindingType.setUnresolved(true);
((PolicySubject)wsBinding).setExtensionType(bindingType);
service.getBindings().add(wsBinding);
}
}
}