org.fabric3.introspection.impl.contract.DefaultContractProcessor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of fabric3-introspection Show documentation
Show all versions of fabric3-introspection Show documentation
Fabric3 Introspection Implementation.
/*
* Fabric3
* Copyright ? 2008 Metaform Systems Limited
*
* This proprietary software may be used only connection with the Fabric3 license
* (the ?License?), a copy of which is included in the software or may be
* obtained at: http://www.metaformsystems.com/licenses/license.html.
* Software distributed under the License is distributed on an ?as is? basis,
* without warranties or conditions of any kind. See the License for the
* specific language governing permissions and limitations of use of the software.
* This software is distributed in conjunction with other software licensed under
* different terms. See the separate licenses for those programs included in the
* distribution for the permitted and restricted uses of such software.
*
* --- Original Apache License ---
*
* 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.fabric3.introspection.impl.contract;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import javax.xml.namespace.QName;
import org.osoa.sca.Constants;
import org.osoa.sca.annotations.Callback;
import org.osoa.sca.annotations.Conversational;
import org.osoa.sca.annotations.EndsConversation;
import org.osoa.sca.annotations.OneWay;
import org.osoa.sca.annotations.Reference;
import org.osoa.sca.annotations.Remotable;
import org.fabric3.spi.introspection.contract.ContractProcessor;
import org.fabric3.spi.introspection.contract.InterfaceIntrospector;
import org.fabric3.spi.introspection.contract.OperationIntrospector;
import org.fabric3.spi.introspection.IntrospectionHelper;
import org.fabric3.spi.introspection.TypeMapping;
import org.fabric3.model.type.service.DataType;
import org.fabric3.model.type.service.Operation;
import static org.fabric3.model.type.service.Operation.CONVERSATION_END;
import static org.fabric3.model.type.service.Operation.NO_CONVERSATION;
import org.fabric3.model.type.service.ServiceContract;
import org.fabric3.model.type.ValidationContext;
import org.fabric3.model.type.service.JavaServiceContract;
/**
* Default implementation of a ContractProcessor for Java interfaces.
*
* @version $Rev: 6194 $ $Date: 2008-12-05 15:52:09 +0000 (Fri, 05 Dec 2008) $
*/
public class DefaultContractProcessor implements ContractProcessor {
public static final String IDL_INPUT = "idl:input";
public static final QName ONEWAY_INTENT = new QName(Constants.SCA_NS, "oneWay");
private final IntrospectionHelper helper;
private List interfaceIntrospectors;
private List operationIntrospectors;
public DefaultContractProcessor(@Reference IntrospectionHelper helper) {
this.helper = helper;
interfaceIntrospectors = new ArrayList();
operationIntrospectors = new ArrayList();
}
@Reference(required = false)
public void setInterfaceIntrospectors(List interfaceIntrospectors) {
this.interfaceIntrospectors = interfaceIntrospectors;
}
@Reference(required = false)
public void setOperationIntrospectors(List operationIntrospectors) {
this.operationIntrospectors = operationIntrospectors;
}
public ServiceContract introspect(TypeMapping typeMapping, Type type, ValidationContext context) {
if (type instanceof Class) {
return introspect(typeMapping, (Class>) type, context);
} else {
throw new UnsupportedOperationException("Interface introspection is only supported for classes");
}
}
private JavaServiceContract introspect(TypeMapping typeMapping, Class> interfaze, ValidationContext context) {
JavaServiceContract contract = introspectInterface(typeMapping, interfaze, context);
Callback callback = interfaze.getAnnotation(Callback.class);
if (callback != null) {
Class> callbackClass = callback.value();
if (Void.class.equals(callbackClass)) {
context.addError(new MissingCallback(interfaze));
return contract;
}
JavaServiceContract callbackContract = introspectInterface(typeMapping, callbackClass, context);
contract.setCallbackContract(callbackContract);
}
return contract;
}
/**
* Introspects a class, returning its service contract. Errors and warnings are reported in the ValidationContext.
*
* @param typeMapping generics mappings
* @param interfaze the interface to introspect
* @param context the current validation context to report errors
* @return the service contract
*/
private JavaServiceContract introspectInterface(TypeMapping typeMapping, Class> interfaze, ValidationContext context) {
JavaServiceContract contract = new JavaServiceContract(interfaze);
contract.setInterfaceName(interfaze.getSimpleName());
boolean remotable = interfaze.isAnnotationPresent(Remotable.class);
contract.setRemotable(remotable);
boolean conversational = helper.isAnnotationPresent(interfaze, Conversational.class);
contract.setConversational(conversational);
List> operations = getOperations(typeMapping, interfaze, remotable, conversational, context);
contract.setOperations(operations);
for (InterfaceIntrospector introspector : interfaceIntrospectors) {
introspector.introspect(contract, interfaze, context);
}
return contract;
}
private List> getOperations(TypeMapping typeMapping,
Class type,
boolean remotable,
boolean conversational,
ValidationContext context) {
Method[] methods = type.getMethods();
List> operations = new ArrayList>(methods.length);
for (Method method : methods) {
String name = method.getName();
if (remotable) {
boolean error = false;
for (Operation operation : operations) {
if (operation.getName().equals(name)) {
context.addError(new OverloadedOperation(method));
error = true;
break;
}
}
if (error) {
continue;
}
}
Class> returnType = method.getReturnType();
Class>[] paramTypes = method.getParameterTypes();
Class>[] faultTypes = method.getExceptionTypes();
int conversationSequence = NO_CONVERSATION;
if (method.isAnnotationPresent(EndsConversation.class)) {
if (!conversational) {
context.addError(new InvalidConversationalOperation(method));
}
conversationSequence = CONVERSATION_END;
} else if (conversational) {
conversationSequence = Operation.CONVERSATION_CONTINUE;
}
Type actualReturnType = typeMapping.getActualType(returnType);
DataType returnDataType = new DataType(actualReturnType, actualReturnType);
List> paramDataTypes = new ArrayList>(paramTypes.length);
for (Type paramType : paramTypes) {
Type actualType = typeMapping.getActualType(paramType);
paramDataTypes.add(new DataType(actualType, actualType));
}
List> faultDataTypes = new ArrayList>(faultTypes.length);
for (Type faultType : faultTypes) {
Type actualType = typeMapping.getActualType(faultType);
faultDataTypes.add(new DataType(actualType, actualType));
}
DataType>> inputType = new DataType>>(Object[].class, paramDataTypes);
Operation operation = new Operation(name, inputType, returnDataType, faultDataTypes, conversationSequence);
if (method.isAnnotationPresent(OneWay.class)) {
operation.addIntent(ONEWAY_INTENT);
}
for (OperationIntrospector introspector : operationIntrospectors) {
introspector.introspect(operation, method, context);
}
operations.add(operation);
}
return operations;
}
}