diff options
author | slaws <slaws@13f79535-47bb-0310-9956-ffa450edef68> | 2010-07-13 09:12:08 +0000 |
---|---|---|
committer | slaws <slaws@13f79535-47bb-0310-9956-ffa450edef68> | 2010-07-13 09:12:08 +0000 |
commit | 47f6879e357c5f878e3e43164e243cd41e056df0 (patch) | |
tree | e3328adfcd5a92c5103d112c0b1e73925719311b /sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany | |
parent | 6aeeb05d754515b86100efe8e2efc397556076ee (diff) |
TUSCANY-3616 - Add code to check that that interface contracts a reference and reference binding and at service and service binding match. Motivated by BWS_2007. TO do this properly we have to test that the interfaces are described using the same IDL and if not convert to WSDL1.1 are required by the SCA specifications. There are a lot of changes here as doing this upset quite a few tests. Further work is required to look at the details of our WSDL generation process which looks a little suspect around wrapper namespaces.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@963624 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to '')
8 files changed, 300 insertions, 34 deletions
diff --git a/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/BuilderExtensionPoint.java b/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/BuilderExtensionPoint.java index d432bf3f29..14ae2042d3 100644 --- a/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/BuilderExtensionPoint.java +++ b/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/BuilderExtensionPoint.java @@ -33,6 +33,28 @@ import org.apache.tuscany.sca.assembly.Implementation; * @tuscany.spi.extension.asclient */ public interface BuilderExtensionPoint { + + /** + * Adds a contract builder. + * + * @param compositeBuilder + */ + void addContractBuilder(ContractBuilder contractBuilder); + + /** + * Removes a contract builder. + * + * @param compositeBuilder + */ + void removeContractBuilder(ContractBuilder contractBuilder); + + /** + * Returns the contract builder + * + * @param id + * @return + */ + ContractBuilder getContractBuilder(); /** * Adds a composite builder. diff --git a/sca-java-2.x/trunk/itest/jms/format-jmstextxml/src/main/java/org/apache/tuscany/sca/binding/jms/format/jmsbytes/helloworld/HelloWorldService.java b/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/ContractBuilder.java index b9a1ffd5ef..99a58dc1c8 100644 --- a/sca-java-2.x/trunk/itest/jms/format-jmstextxml/src/main/java/org/apache/tuscany/sca/binding/jms/format/jmsbytes/helloworld/HelloWorldService.java +++ b/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/ContractBuilder.java @@ -16,20 +16,22 @@ * specific language governing permissions and limitations
* under the License.
*/
-package org.apache.tuscany.sca.binding.jms.format.jmsbytes.helloworld;
-import org.oasisopen.sca.annotation.Remotable;
+package org.apache.tuscany.sca.assembly.builder;
+
+import org.apache.tuscany.sca.assembly.Endpoint;
+import org.apache.tuscany.sca.assembly.EndpointReference;
+import org.apache.tuscany.sca.interfacedef.InterfaceContract;
/**
- * This is the business interface of the HelloWorld greetings service.
+ * A builder that builds WSDL versions of component contracts so that the
+ * component contracts can be compared with binding contracts in a generic way.
+ * The generic interface format defined by the Assembly spec is WSDL 1.1
*/
-@Remotable
-public interface HelloWorldService {
-
- public byte[] getByteArrayGreetings(byte[] msg);
-
- public void throwChecked(byte[] msg) throws CheckedException;
- public void throwUnChecked(byte[] msg);
-
+public interface ContractBuilder {
+
+ /**
+ * Build the WSDL version of the Interface Contract
+ */
+ boolean build(InterfaceContract interfaceContract, BuilderContext context);
}
-
diff --git a/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/DefaultBuilderExtensionPoint.java b/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/DefaultBuilderExtensionPoint.java index 64f929c659..8b037a7534 100644 --- a/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/DefaultBuilderExtensionPoint.java +++ b/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/DefaultBuilderExtensionPoint.java @@ -41,6 +41,7 @@ import org.apache.tuscany.sca.core.UtilityExtensionPoint; import org.apache.tuscany.sca.extensibility.ServiceDeclaration; import org.apache.tuscany.sca.extensibility.ServiceDeclarationParser; import org.apache.tuscany.sca.extensibility.ServiceDiscovery; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; /** @@ -56,6 +57,7 @@ public class DefaultBuilderExtensionPoint implements BuilderExtensionPoint, Life private final Map<QName, ImplementationBuilder> implementationBuilders = new HashMap<QName, ImplementationBuilder>(); private final Map<QName, PolicyBuilder> policyBuilders = new HashMap<QName, PolicyBuilder>(); + private ContractBuilder contractBuilder = null; private boolean loaded; @@ -85,6 +87,19 @@ public class DefaultBuilderExtensionPoint implements BuilderExtensionPoint, Life loadBuilders(); return builders.get(id); } + + public void addContractBuilder(ContractBuilder contractBuilder){ + this.contractBuilder = contractBuilder; + } + + public void removeContractBuilder(ContractBuilder contractBuilder){ + this.contractBuilder = null; + } + + public ContractBuilder getContractBuilder(){ + loadBuilders(); + return contractBuilder; + } /** * Load builders declared under META-INF/services. @@ -147,6 +162,16 @@ public class DefaultBuilderExtensionPoint implements BuilderExtensionPoint, Life PolicyBuilder<?> builder = new LazyPolicyBuilder(builderDeclaration); policyBuilders.put(builder.getPolicyType(), builder); } + + try { + builderDeclarations = serviceDiscovery.getServiceDeclarations(ContractBuilder.class); + } catch (Exception e) { + throw new IllegalStateException(e); + } + + for (ServiceDeclaration builderDeclaration : builderDeclarations) { + contractBuilder = new LazyContractBuilder(builderDeclaration); + } loaded = true; @@ -405,4 +430,50 @@ public class DefaultBuilderExtensionPoint implements BuilderExtensionPoint, Life return getBuilder().build(endpointReference, endpoint, context); } } + + private class LazyContractBuilder implements ContractBuilder { + private ServiceDeclaration sd; + private ContractBuilder builder; + + /** + * @param sd + */ + public LazyContractBuilder(ServiceDeclaration sd) { + super(); + this.sd = sd; + } + +/* + public boolean build(EndpointReference endpointReference, BuilderContext context){ + return getBuilder().build(endpointReference, context); + } + + public boolean build(Endpoint endpoint, BuilderContext context){ + return getBuilder().build(endpoint, context); + } +*/ + + public boolean build(InterfaceContract interfaceContract, BuilderContext context){ + return getBuilder().build(interfaceContract, context); + } + + private synchronized ContractBuilder getBuilder() { + if (builder == null) { + try { + Class<?> builderClass = sd.loadClass(); + try { + Constructor<?> constructor = builderClass.getConstructor(ExtensionPointRegistry.class); + builder = (ContractBuilder)constructor.newInstance(registry); + } catch (NoSuchMethodException e) { + Constructor<?> constructor = builderClass.getConstructor(); + builder = (ContractBuilder)constructor.newInstance(); + + } + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + return builder; + } + } } diff --git a/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/impl/EndpointImpl.java b/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/impl/EndpointImpl.java index 34ece5a24b..65af22c3e7 100644 --- a/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/impl/EndpointImpl.java +++ b/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/impl/EndpointImpl.java @@ -26,6 +26,8 @@ import org.apache.tuscany.sca.assembly.Component; import org.apache.tuscany.sca.assembly.ComponentService; import org.apache.tuscany.sca.assembly.Endpoint; import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.assembly.builder.BuilderExtensionPoint; +import org.apache.tuscany.sca.assembly.builder.ContractBuilder; import org.apache.tuscany.sca.core.ExtensionPointRegistry; import org.apache.tuscany.sca.interfacedef.InterfaceContract; import org.apache.tuscany.sca.policy.ExtensionType; @@ -42,6 +44,8 @@ public class EndpointImpl implements Endpoint { private static final long serialVersionUID = 7344399683703812593L; protected transient ExtensionPointRegistry registry; + protected transient BuilderExtensionPoint builders; + protected transient ContractBuilder contractBuilder; protected boolean unresolved; protected String uri; protected Component component; diff --git a/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/impl/EndpointReferenceImpl.java b/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/impl/EndpointReferenceImpl.java index d13740b287..ac35b45678 100644 --- a/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/impl/EndpointReferenceImpl.java +++ b/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/impl/EndpointReferenceImpl.java @@ -26,6 +26,8 @@ import org.apache.tuscany.sca.assembly.Component; import org.apache.tuscany.sca.assembly.ComponentReference; import org.apache.tuscany.sca.assembly.Endpoint; import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.assembly.builder.BuilderExtensionPoint; +import org.apache.tuscany.sca.assembly.builder.ContractBuilder; import org.apache.tuscany.sca.core.ExtensionPointRegistry; import org.apache.tuscany.sca.interfacedef.InterfaceContract; import org.apache.tuscany.sca.policy.ExtensionType; @@ -41,7 +43,9 @@ import org.apache.tuscany.sca.policy.PolicySubject; public class EndpointReferenceImpl implements EndpointReference { private static final long serialVersionUID = 8838066441709300972L; - protected ExtensionPointRegistry registry; + protected transient ExtensionPointRegistry registry; + protected transient BuilderExtensionPoint builders; + protected transient ContractBuilder contractBuilder; protected boolean unresolved = true; protected String uri; protected Component component; diff --git a/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/interfacedef/InterfaceContract.java b/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/interfacedef/InterfaceContract.java index 054b18c349..3eda9f37e5 100644 --- a/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/interfacedef/InterfaceContract.java +++ b/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/interfacedef/InterfaceContract.java @@ -78,5 +78,23 @@ public interface InterfaceContract extends Cloneable { * Implementations must support cloning. */ Object clone() throws CloneNotSupportedException; + + /** + * For matching purposes the Java interface contract is + * turned into a WSDL contract in the cases where it needs to be matched + * against another WSDL contract + * + * @return WSDL interface contract + */ + InterfaceContract getNormalizedWSDLContract(); + + /** + * For matching purposes the Java interface contract is + * turned into a WSDL contract in the cases where it needs to be matched + * against another WSDL contract + * + * @param wsdlInterfaceContract + */ + void setNormailizedWSDLContract(InterfaceContract wsdlInterfaceContract); } diff --git a/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/interfacedef/impl/InterfaceContractImpl.java b/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/interfacedef/impl/InterfaceContractImpl.java index a62813edd4..4fad64ac89 100644 --- a/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/interfacedef/impl/InterfaceContractImpl.java +++ b/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/interfacedef/impl/InterfaceContractImpl.java @@ -125,5 +125,18 @@ public abstract class InterfaceContractImpl implements InterfaceContract { } return true; } + + // By default there is no normailized contract + // as only Java needs it + public InterfaceContract getNormalizedWSDLContract() { + return null; + } + + // By default there is no normailized contract + // as only Java needs it + public void setNormailizedWSDLContract( + InterfaceContract wsdlInterfaceContract) { + // do nothing + } } diff --git a/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/interfacedef/impl/InterfaceContractMapperImpl.java b/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/interfacedef/impl/InterfaceContractMapperImpl.java index 468083c839..c507dcaa9e 100644 --- a/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/interfacedef/impl/InterfaceContractMapperImpl.java +++ b/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/interfacedef/impl/InterfaceContractMapperImpl.java @@ -21,6 +21,11 @@ package org.apache.tuscany.sca.interfacedef.impl; import java.util.List; +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.assembly.builder.BuilderExtensionPoint; +import org.apache.tuscany.sca.assembly.builder.ContractBuilder; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; import org.apache.tuscany.sca.interfacedef.Compatibility; import org.apache.tuscany.sca.interfacedef.DataType; import org.apache.tuscany.sca.interfacedef.IncompatibleInterfaceContractException; @@ -28,27 +33,95 @@ import org.apache.tuscany.sca.interfacedef.Interface; import org.apache.tuscany.sca.interfacedef.InterfaceContract; import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.interfacedef.util.XMLType; +import org.apache.tuscany.sca.policy.ExtensionType; /** * @version $Rev$ $Date$ */ public class InterfaceContractMapperImpl implements InterfaceContractMapper { - + + protected ExtensionPointRegistry registry; + protected BuilderExtensionPoint builders; + protected ContractBuilder contractBuilder; + + public InterfaceContractMapperImpl(ExtensionPointRegistry registry){ + this.registry = registry; + this.builders = registry.getExtensionPoint(BuilderExtensionPoint.class); + } + public boolean isCompatible(DataType source, DataType target, boolean passByValue) { + return isCompatible(source, target, passByValue, null); + } + + public boolean isCompatible(DataType source, DataType target, boolean passByValue, StringBuffer audit) { if (source == target) { return true; } if (!passByValue) { if (source == null || target == null) { + if (audit != null){ + audit.append("One of either the source or target data types is null for"); + } return false; } // For local case return target.getPhysical().isAssignableFrom(source.getPhysical()); } else { - // FIXME: [rfeng] How to test if two remotable data type is compatible? - // We will need to understand the different typing system used by the databindings - // We should probably delegate to some extensions here - return true; + // For remote interfaces where the target is represented with WSDL + // the source will have been converted to WSDL so we rely on JAXB mappings + // being the same in both cases and just compare the type names directly. + // TODO - is this right? + XMLType sourceLogicalType = null; + + // There is some nesting of data types (when GeneratedDataType is used) so + // dig a bit deeper to find the real data type + if (source.getLogical() instanceof DataType<?>){ + sourceLogicalType = (XMLType)((DataType<?>)source.getLogical()).getLogical(); + } else { + sourceLogicalType = (XMLType)source.getLogical(); + } + + XMLType targetLogicalType = null; + + if (target.getLogical() instanceof DataType<?>){ + targetLogicalType = (XMLType)((DataType<?>)target.getLogical()).getLogical(); + } else { + targetLogicalType = (XMLType)target.getLogical(); + } + + // The logical type seems to be null in some cases, e.g. when the + // argument or return type is something like a Map. + // TODO - check when some type give rise to a null logical type + if (sourceLogicalType.getTypeName() == null || + targetLogicalType.getTypeName() == null) { + return true; + } + + boolean match = sourceLogicalType.getTypeName().equals(targetLogicalType.getTypeName()); + + if (!match){ + + QName anyType = new QName("http://www.w3.org/2001/XMLSchema", "anyType"); + if (sourceLogicalType.getTypeName().equals(anyType) || + targetLogicalType.getTypeName().equals(anyType)){ + // special case where a Java interface uses a generic type, e.g. + // public OMElement getGreetings(OMElement om) + // while the provided WSDL uses a specific type. So we assume + // that xsd:anyType matched anything + match = true; + } else { + if (audit != null){ + audit.append("Operation argument types source = " + + sourceLogicalType.getTypeName() + + " target = " + + targetLogicalType.getTypeName() + + " don't match for"); + } + } + } + + return match; } } @@ -62,6 +135,9 @@ public class InterfaceContractMapperImpl implements InterfaceContractMapper { * @return */ public boolean isMutuallyCompatible(InterfaceContract source, InterfaceContract target) { + ExtensionType ext = source.getInterface().getExtensionType(); + InterfaceContract sourceContract = null; + // Are the forward interfaces equal? if (isMutuallyCompatible(source.getInterface(), target.getInterface())) { // Is there a Callback interface? @@ -120,6 +196,10 @@ public class InterfaceContractMapperImpl implements InterfaceContractMapper { } public boolean isCompatible(Operation source, Operation target, Compatibility compatibilityType, boolean byValue) { + return isCompatible(source, target, compatibilityType, true, null); + } + + public boolean isCompatible(Operation source, Operation target, Compatibility compatibilityType, boolean byValue, StringBuffer audit) { if (source == target) { return true; } @@ -130,10 +210,22 @@ public class InterfaceContractMapperImpl implements InterfaceContractMapper { // Check name if (!source.getName().equals(target.getName())) { + if (audit != null){ + audit.append("operation names are not the same source = " + + source.getName() + + " target = " + + target.getName()); + } return false; } if (source.getInterface().isRemotable() != target.getInterface().isRemotable()) { + if (audit != null){ + audit.append("Interfaces have different remote settings source = " + + source.getName() + + " target = " + + target.getName()); + } return false; } @@ -164,21 +256,32 @@ public class InterfaceContractMapperImpl implements InterfaceContractMapper { checkTargetWrapper = false; } +/* TODO - Why are we assuming compatibility if one side is wrapped and the other is not? if (checkSourceWrapper != checkTargetWrapper) { return true; } +*/ - if (!isCompatible(targetOutputType, sourceOutputType, passByValue)) { + if (!isCompatible(targetOutputType, sourceOutputType, passByValue, audit)) { + if (audit != null){ + audit.append(" output types"); + } return false; } if (sourceInputType.size() != targetInputType.size()) { + if (audit != null){ + audit.append("different number of input types"); + } return false; } int size = sourceInputType.size(); for (int i = 0; i < size; i++) { - if (!isCompatible(sourceInputType.get(i), targetInputType.get(i), passByValue)) { + if (!isCompatible(sourceInputType.get(i), targetInputType.get(i), passByValue, audit)) { + if (audit != null){ + audit.append(" input types"); + } return false; } } @@ -190,13 +293,16 @@ public class InterfaceContractMapperImpl implements InterfaceContractMapper { boolean found = true; for (DataType sourceFaultType : source.getFaultTypes()) { found = false; - if (isCompatible(targetFaultType, sourceFaultType, passByValue)) { + if (isCompatible(targetFaultType, sourceFaultType, passByValue, audit)) { // Target fault type can be covered by the source fault type found = true; break; } } if (!found) { + if (audit != null){ + audit.append("Fault types incompatible"); + } return false; } } @@ -226,6 +332,7 @@ public class InterfaceContractMapperImpl implements InterfaceContractMapper { Compatibility compatibility, boolean ignoreCallback, boolean silent) throws IncompatibleInterfaceContractException { + if (source == target) { // Shortcut for performance return true; @@ -268,18 +375,20 @@ public class InterfaceContractMapperImpl implements InterfaceContractMapper { return false; } } - if (!source.getInterface().isRemotable()) { - // FIXME: for remotable operation, only compare name for now + + if (!silent) { + StringBuffer audit = new StringBuffer(); + if (!isCompatible(operation, targetOperation, Compatibility.SUBSET, true, audit)){ + throw new IncompatibleInterfaceContractException("Operations called " + + operation.getName() + + " are not compatible " + + audit, + source, + target); + } + } else { if (!isCompatible(operation, targetOperation, Compatibility.SUBSET)) { - if (!silent) { - throw new IncompatibleInterfaceContractException("Target operations called " + - operation.getName() + - " are not compatible", - source, - target); - } else { - return false; - } + return false; } } } @@ -294,7 +403,7 @@ public class InterfaceContractMapperImpl implements InterfaceContractMapper { } if (source.getCallbackInterface() == null || target.getCallbackInterface() == null) { if (!silent) { - throw new IncompatibleInterfaceContractException("Callback interface doesn't match", source, target); + throw new IncompatibleInterfaceContractException("Callback interface doesn't match as one of the callback interfaces is null", source, target); } else { return false; } @@ -386,7 +495,30 @@ public class InterfaceContractMapperImpl implements InterfaceContractMapper { } return null; } - } + + /** + * In various places in the process of an SCA application we match one interface against + * another. Sometimes the two interfaces can be presented using different IDLs, for example + * Java and WSDL. In this case interfaces are converted so that they are both WSDL1.1 interfaces + * and they are then compared. The generated WSDL is cached on the interface object for + * any subsequent matching + * + * @param interfaceA + * @param interfaceB + */ +/* + public void normalizeContractsForComparison(InterfaceContract interfaceA, InterfaceContract interfaceB){ + // normalize interfaces + if (interfaceA.getInterface().getClass() != interfaceB.getInterface().getClass()) { + this.contractBuilder = builders.getContractBuilder(); + if (interfaceA.getInterface() instanceof Interface){ + contractBuilder.build(interfaceA, null); + } else { + contractBuilder.build(interfaceB, null); + } + } + } +*/ } |