From 132aa8a77685ec92bc90c03f987650d275a7b639 Mon Sep 17 00:00:00 2001 From: lresende Date: Mon, 30 Sep 2013 06:59:11 +0000 Subject: 2.0.1 RC1 release tag git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1527464 13f79535-47bb-0310-9956-ffa450edef68 --- .../sca/core/assembly/RuntimeAssemblyFactory.java | 75 ++ .../core/assembly/impl/CompositeActivatorImpl.java | 689 +++++++++++ .../sca/core/assembly/impl/DomainRegistryImpl.java | 285 +++++ .../core/assembly/impl/EndpointSerializerImpl.java | 198 +++ .../assembly/impl/LocalDomainRegistryFactory.java | 49 + .../assembly/impl/ReferenceParameterProcessor.java | 98 ++ .../assembly/impl/ReferenceParametersImpl.java | 121 ++ .../core/assembly/impl/RuntimeComponentImpl.java | 139 +++ .../impl/RuntimeComponentReferenceImpl.java | 66 + .../assembly/impl/RuntimeComponentServiceImpl.java | 40 + .../core/assembly/impl/RuntimeEndpointImpl.java | 1285 ++++++++++++++++++++ .../impl/RuntimeEndpointReferenceImpl.java | 840 +++++++++++++ .../tuscany/sca/core/assembly/impl/WSDLHelper.java | 514 ++++++++ .../context/DefaultComponentContextFactory.java | 72 ++ .../core/context/DefaultRequestContextFactory.java | 40 + .../sca/core/context/ServiceReferenceExt.java | 41 + .../context/impl/CallbackServiceReferenceImpl.java | 292 +++++ .../core/context/impl/ComponentContextImpl.java | 558 +++++++++ .../sca/core/context/impl/RequestContextImpl.java | 126 ++ .../core/context/impl/ServiceReferenceImpl.java | 430 +++++++ .../tuscany/sca/core/factory/InstanceWrapper.java | 49 + .../sca/core/factory/ObjectCreationException.java | 48 + .../tuscany/sca/core/factory/ObjectFactory.java | 36 + .../tuscany/sca/core/invocation/AsyncContext.java | 42 + .../sca/core/invocation/AsyncFaultWrapper.java | 107 ++ .../core/invocation/AsyncResponseException.java | 47 + .../sca/core/invocation/AsyncResponseHandler.java | 58 + .../sca/core/invocation/AsyncResponseInvoker.java | 351 ++++++ .../sca/core/invocation/AsyncResponseService.java | 50 + .../invocation/CallableReferenceObjectFactory.java | 58 + .../sca/core/invocation/CallbackHandler.java | 53 + .../invocation/CallbackInterfaceInterceptor.java | 60 + .../invocation/CallbackReferenceObjectFactory.java | 50 + .../core/invocation/CallbackWireObjectFactory.java | 48 + .../sca/core/invocation/CglibProxyFactory.java | 155 +++ .../tuscany/sca/core/invocation/Constants.java | 38 + .../DefaultProxyFactoryExtensionPoint.java | 95 ++ .../core/invocation/ExtensibleProxyFactory.java | 128 ++ .../core/invocation/ExtensibleWireProcessor.java | 51 + .../sca/core/invocation/InterceptorAsyncImpl.java | 111 ++ .../core/invocation/JDKAsyncResponseInvoker.java | 40 + .../core/invocation/NonBlockingInterceptor.java | 197 +++ .../core/invocation/ProxyCreationException.java | 48 + .../tuscany/sca/core/invocation/ProxyFactory.java | 96 ++ .../invocation/ProxyFactoryExtensionPoint.java | 54 + .../sca/core/invocation/RuntimeInvoker.java | 210 ++++ .../sca/core/invocation/WireObjectFactory.java | 56 + .../invocation/impl/AsyncInvocationFutureImpl.java | 285 +++++ .../invocation/impl/AsyncJDKInvocationHandler.java | 740 +++++++++++ .../sca/core/invocation/impl/AsyncResponse.java | 68 ++ .../invocation/impl/AsyncResponseHandlerImpl.java | 197 +++ .../core/invocation/impl/InvocationChainImpl.java | 313 +++++ .../impl/JDKCallbackInvocationHandler.java | 153 +++ .../core/invocation/impl/JDKInvocationHandler.java | 436 +++++++ .../sca/core/invocation/impl/JDKProxyFactory.java | 248 ++++ .../core/invocation/impl/MessageFactoryImpl.java | 43 + .../sca/core/invocation/impl/MessageImpl.java | 114 ++ .../impl/NoMethodForOperationException.java | 45 + .../sca/core/invocation/impl/PhaseManager.java | 313 +++++ .../sca/core/invocation/impl/PhaseSorter.java | 236 ++++ .../runtime/impl/EndpointReferenceBinderImpl.java | 1206 ++++++++++++++++++ .../core/runtime/impl/RuntimePropertiesImpl.java | 38 + .../sca/core/scope/AbstractScopeContainer.java | 181 +++ .../sca/core/scope/DefaultScopeRegistry.java | 40 + .../org/apache/tuscany/sca/core/scope/Scope.java | 63 + .../tuscany/sca/core/scope/ScopeContainer.java | 160 +++ .../sca/core/scope/ScopeContainerFactory.java | 32 + .../tuscany/sca/core/scope/ScopeRegistry.java | 43 + .../core/scope/ScopedImplementationProvider.java | 56 + .../sca/core/scope/ScopedRuntimeComponent.java | 41 + .../sca/core/scope/TargetDestructionException.java | 45 + .../core/scope/TargetInitializationException.java | 45 + .../sca/core/scope/TargetNotFoundException.java | 44 + .../sca/core/scope/TargetResolutionException.java | 45 + .../core/scope/impl/CompositeScopeContainer.java | 89 ++ .../scope/impl/CompositeScopeContainerFactory.java | 40 + .../sca/core/scope/impl/ScopeRegistryImpl.java | 70 ++ .../core/scope/impl/StatelessScopeContainer.java | 61 + .../scope/impl/StatelessScopeContainerFactory.java | 40 + .../sca/core/work/impl/DefaultWorkScheduler.java | 210 ++++ .../sca/core/work/impl/ThreadPoolWorkManager.java | 232 ++++ .../apache/tuscany/sca/core/work/impl/Work.java | 65 + .../tuscany/sca/core/work/impl/WorkEvent.java | 80 ++ .../tuscany/sca/core/work/impl/WorkItem.java | 167 +++ .../tuscany/sca/core/work/impl/WorkListener.java | 32 + ...org.apache.tuscany.sca.assembly.AssemblyFactory | 18 + ...che.tuscany.sca.context.ComponentContextFactory | 17 + ...pache.tuscany.sca.context.RequestContextFactory | 17 + ...ca.contribution.processor.StAXArtifactProcessor | 20 + ....sca.core.invocation.ProxyFactoryExtensionPoint | 19 + ...org.apache.tuscany.sca.core.scope.ScopeRegistry | 19 + ...rg.apache.tuscany.sca.invocation.MessageFactory | 19 + ...g.apache.tuscany.sca.runtime.CompositeActivator | 19 + ...pache.tuscany.sca.runtime.DomainRegistryFactory | 17 + ...che.tuscany.sca.runtime.EndpointReferenceBinder | 18 + ...g.apache.tuscany.sca.runtime.EndpointSerializer | 17 + ...rg.apache.tuscany.sca.runtime.RuntimeProperties | 18 + .../org.apache.tuscany.sca.work.WorkScheduler | 17 + .../src/main/resources/core-messages.properties | 21 + .../endpoint-validation-messages.properties | 26 + .../impl/InvocationChainImplTestCase.java | 93 ++ .../core/invocation/impl/PhaseManagerTestCase.java | 50 + .../core/invocation/impl/PhaseSorterTestCase.java | 67 + .../tuscany/sca/core/work/impl/FailingWork.java | 54 + .../core/work/impl/JSR237MyFailingRunnable.java | 43 + .../sca/core/work/impl/JSR237MyRunnable.java | 71 ++ .../sca/core/work/impl/JSR237MyRunnerListener.java | 154 +++ .../work/impl/Jsr237WorkSchedulerTestCase.java | 240 ++++ .../sca/core/work/impl/TestWorkListener.java | 153 +++ .../work/impl/ThreadPoolWorkManagerTestCase.java | 227 ++++ .../tuscany/sca/core/work/impl/TimeDelayWork.java | 86 ++ .../apache/tuscany/sca/scope/ScopeTestCase.java | 66 + .../org.apache.tuscany.sca.invocation.PhaseTest | 24 + 113 files changed, 16220 insertions(+) create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/RuntimeAssemblyFactory.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/CompositeActivatorImpl.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/DomainRegistryImpl.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/EndpointSerializerImpl.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/LocalDomainRegistryFactory.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/ReferenceParameterProcessor.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/ReferenceParametersImpl.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeComponentImpl.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeComponentReferenceImpl.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeComponentServiceImpl.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeEndpointImpl.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeEndpointReferenceImpl.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/WSDLHelper.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/context/DefaultComponentContextFactory.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/context/DefaultRequestContextFactory.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/context/ServiceReferenceExt.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/CallbackServiceReferenceImpl.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/ComponentContextImpl.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/RequestContextImpl.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/ServiceReferenceImpl.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/factory/InstanceWrapper.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/factory/ObjectCreationException.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/factory/ObjectFactory.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/AsyncContext.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/AsyncFaultWrapper.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/AsyncResponseException.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/AsyncResponseHandler.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/AsyncResponseInvoker.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/AsyncResponseService.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallableReferenceObjectFactory.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackHandler.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackInterfaceInterceptor.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackReferenceObjectFactory.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackWireObjectFactory.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CglibProxyFactory.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/Constants.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/DefaultProxyFactoryExtensionPoint.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ExtensibleProxyFactory.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ExtensibleWireProcessor.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/InterceptorAsyncImpl.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/JDKAsyncResponseInvoker.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/NonBlockingInterceptor.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyCreationException.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyFactory.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyFactoryExtensionPoint.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/RuntimeInvoker.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/WireObjectFactory.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/AsyncInvocationFutureImpl.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/AsyncJDKInvocationHandler.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/AsyncResponse.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/AsyncResponseHandlerImpl.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/InvocationChainImpl.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/JDKCallbackInvocationHandler.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/JDKInvocationHandler.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/JDKProxyFactory.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/MessageFactoryImpl.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/MessageImpl.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/NoMethodForOperationException.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/PhaseManager.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/PhaseSorter.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/runtime/impl/EndpointReferenceBinderImpl.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/runtime/impl/RuntimePropertiesImpl.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/AbstractScopeContainer.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/DefaultScopeRegistry.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/Scope.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopeContainer.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopeContainerFactory.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopeRegistry.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopedImplementationProvider.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopedRuntimeComponent.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetDestructionException.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetInitializationException.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetNotFoundException.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetResolutionException.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/impl/CompositeScopeContainer.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/impl/CompositeScopeContainerFactory.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/impl/ScopeRegistryImpl.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/impl/StatelessScopeContainer.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/impl/StatelessScopeContainerFactory.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/DefaultWorkScheduler.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/ThreadPoolWorkManager.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/Work.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/WorkEvent.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/WorkItem.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/WorkListener.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.assembly.AssemblyFactory create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.context.ComponentContextFactory create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.context.RequestContextFactory create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.core.invocation.ProxyFactoryExtensionPoint create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.core.scope.ScopeRegistry create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.invocation.MessageFactory create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.runtime.CompositeActivator create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.runtime.DomainRegistryFactory create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.runtime.EndpointReferenceBinder create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.runtime.EndpointSerializer create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.runtime.RuntimeProperties create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.work.WorkScheduler create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/core-messages.properties create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/endpoint-validation-messages.properties create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/invocation/impl/InvocationChainImplTestCase.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/invocation/impl/PhaseManagerTestCase.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/invocation/impl/PhaseSorterTestCase.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/work/impl/FailingWork.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/work/impl/JSR237MyFailingRunnable.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/work/impl/JSR237MyRunnable.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/work/impl/JSR237MyRunnerListener.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/work/impl/Jsr237WorkSchedulerTestCase.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/work/impl/TestWorkListener.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/work/impl/ThreadPoolWorkManagerTestCase.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/work/impl/TimeDelayWork.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/scope/ScopeTestCase.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/resources/META-INF/services/org.apache.tuscany.sca.invocation.PhaseTest (limited to 'sca-java-2.x/tags/2.0.1-RC1/modules/core/src') diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/RuntimeAssemblyFactory.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/RuntimeAssemblyFactory.java new file mode 100644 index 0000000000..790cc6ec98 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/RuntimeAssemblyFactory.java @@ -0,0 +1,75 @@ +/* + * 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.core.assembly; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.ComponentReference; +import org.apache.tuscany.sca.assembly.ComponentService; +import org.apache.tuscany.sca.assembly.DefaultAssemblyFactory; +import org.apache.tuscany.sca.assembly.Endpoint; +import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.assembly.impl.RuntimeComponentImpl; +import org.apache.tuscany.sca.core.assembly.impl.RuntimeComponentReferenceImpl; +import org.apache.tuscany.sca.core.assembly.impl.RuntimeComponentServiceImpl; +import org.apache.tuscany.sca.core.assembly.impl.RuntimeEndpointImpl; +import org.apache.tuscany.sca.core.assembly.impl.RuntimeEndpointReferenceImpl; + + +/** + * The runtime version of assembly factory + * @version $Rev$ $Date$ + * @tuscany.spi.extension.asclient + */ +public class RuntimeAssemblyFactory extends DefaultAssemblyFactory implements AssemblyFactory { + + public RuntimeAssemblyFactory(ExtensionPointRegistry registry) { + super(registry); + } + + @Override + public Component createComponent() { + return new RuntimeComponentImpl(); + } + + @Override + public ComponentReference createComponentReference() { + return new RuntimeComponentReferenceImpl(); + } + + @Override + public ComponentService createComponentService() { + return new RuntimeComponentServiceImpl(); + } + + @Override + public Endpoint createEndpoint() { + // Create an instance of EndpointImpl that can be serialized/deserialized using the Tuscany + // runtime extension points and extensions + return new RuntimeEndpointImpl(registry); + } + + @Override + public EndpointReference createEndpointReference() { + return new RuntimeEndpointReferenceImpl(registry); + } + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/CompositeActivatorImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/CompositeActivatorImpl.java new file mode 100644 index 0000000000..c3cb51d8d1 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/CompositeActivatorImpl.java @@ -0,0 +1,689 @@ +/* + * 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.core.assembly.impl; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.ComponentReference; +import org.apache.tuscany.sca.assembly.ComponentService; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.assembly.Endpoint; +import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.assembly.Implementation; +import org.apache.tuscany.sca.assembly.Service; +import org.apache.tuscany.sca.context.CompositeContext; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.UtilityExtensionPoint; +import org.apache.tuscany.sca.core.scope.ScopeContainer; +import org.apache.tuscany.sca.core.scope.ScopeRegistry; +import org.apache.tuscany.sca.core.scope.ScopedRuntimeComponent; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.monitor.MonitorFactory; +import org.apache.tuscany.sca.provider.EndpointReferenceAsyncProvider; +import org.apache.tuscany.sca.provider.ImplementationProvider; +import org.apache.tuscany.sca.provider.ImplementationProviderFactory; +import org.apache.tuscany.sca.provider.PolicyProvider; +import org.apache.tuscany.sca.provider.PolicyProviderFactory; +import org.apache.tuscany.sca.provider.ProviderFactoryExtensionPoint; +import org.apache.tuscany.sca.provider.ReferenceBindingProvider; +import org.apache.tuscany.sca.provider.RuntimeProvider; +import org.apache.tuscany.sca.provider.ServiceBindingProvider; +import org.apache.tuscany.sca.runtime.ActivationException; +import org.apache.tuscany.sca.runtime.CompositeActivator; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeComponentReference; +import org.apache.tuscany.sca.runtime.RuntimeComponentService; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; +import org.apache.tuscany.sca.runtime.RuntimeEndpointReference; + +/** + * @version $Rev$ $Date$ + */ +public class CompositeActivatorImpl implements CompositeActivator { + final Logger logger = Logger.getLogger(CompositeActivatorImpl.class.getName()); + + private final ScopeRegistry scopeRegistry; + private final ProviderFactoryExtensionPoint providerFactories; + private Monitor monitor; + + public CompositeActivatorImpl(ExtensionPointRegistry extensionPoints) { + UtilityExtensionPoint utilities = extensionPoints.getExtensionPoint(UtilityExtensionPoint.class); + this.scopeRegistry = utilities.getUtility(ScopeRegistry.class); + this.providerFactories = extensionPoints.getExtensionPoint(ProviderFactoryExtensionPoint.class); + this.monitor = utilities.getUtility(MonitorFactory.class).createMonitor(); + } + + //========================================================================= + // Activation + //========================================================================= + + // Composite activation/deactivation + + public void activate(CompositeContext compositeContext, Composite composite) throws ActivationException { + try { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Activating composite: " + composite.getName()); + } + for (Component component : composite.getComponents()) { + activateComponent(compositeContext, component); + } + } catch (Exception e) { + throw new ActivationException(e); + } + } + + public void deactivate(Composite composite) throws ActivationException { + try { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Deactivating composite: " + composite.getName()); + } + for (Component component : composite.getComponents()) { + deactivateComponent(component); + } + } catch (Exception e) { + throw new ActivationException(e); + } + } + + // Component activation/deactivation + + public void activateComponent(CompositeContext compositeContext, Component component) + throws ActivationException { + try { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Activating component: " + component.getURI()); + } + + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + activate(compositeContext, (Composite) implementation); + } else if (implementation != null) { + addImplementationProvider((RuntimeComponent) component, + implementation); + addScopeContainer(component); + } + + for (ComponentService service : component.getServices()) { + activate(compositeContext, + (RuntimeComponent) component, (RuntimeComponentService) service); + } + + for (ComponentReference reference : component.getReferences()) { + activate(compositeContext, + (RuntimeComponent) component, (RuntimeComponentReference) reference); + } + } catch (Exception e) { + throw new ActivationException(e); + } + } + + public void deactivateComponent(Component component) + throws ActivationException { + try { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Deactivating component: " + component.getURI()); + } + for (ComponentService service : component.getServices()) { + deactivate((RuntimeComponent) component, + (RuntimeComponentService) service); + } + + for (ComponentReference reference : component.getReferences()) { + deactivate((RuntimeComponent) component, + (RuntimeComponentReference) reference); + } + + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + deactivate((Composite) implementation); + } else if (implementation != null) { + removeImplementationProvider((RuntimeComponent) component); + removeScopeContainer(component); + } + } catch (Exception e) { + throw new ActivationException(e); + } + } + + // add/remove artifacts required to get the implementation going + + private void addImplementationProvider(RuntimeComponent component, Implementation implementation) { + ImplementationProviderFactory providerFactory = + (ImplementationProviderFactory)providerFactories.getProviderFactory(implementation.getClass()); + if (providerFactory != null) { + @SuppressWarnings("unchecked") + ImplementationProvider implementationProvider = + providerFactory.createImplementationProvider(component, implementation); + if (implementationProvider != null) { + component.setImplementationProvider(implementationProvider); + } + } else { + throw new IllegalStateException("Provider factory not found for class: " + implementation.getClass() + .getName()); + } + for (PolicyProviderFactory f : providerFactories.getPolicyProviderFactories()) { + PolicyProvider policyProvider = f.createImplementationPolicyProvider(component); + if (policyProvider != null) { + component.addPolicyProvider(policyProvider); + } + } + + } + + private void removeImplementationProvider(RuntimeComponent component) { + component.setImplementationProvider(null); + component.getPolicyProviders().clear(); + } + + private void addScopeContainer(Component component) { + if (!(component instanceof ScopedRuntimeComponent)) { + return; + } + ScopedRuntimeComponent runtimeComponent = (ScopedRuntimeComponent)component; + ScopeContainer scopeContainer = scopeRegistry.getScopeContainer(runtimeComponent); + runtimeComponent.setScopeContainer(scopeContainer); + } + + private void removeScopeContainer(Component component) { + if (!(component instanceof ScopedRuntimeComponent)) { + return; + } + ScopedRuntimeComponent runtimeComponent = (ScopedRuntimeComponent)component; + ScopeContainer scopeContainer = runtimeComponent.getScopeContainer(); + runtimeComponent.setScopeContainer(null); + } + + + // Service activation/deactivation + + public void activate(CompositeContext compositeContext, RuntimeComponent component, RuntimeComponentService service) { + if (service.getService() == null) { + if (logger.isLoggable(Level.WARNING)) { + logger.warning("Skipping component service not defined in the component type: " + component.getURI() + + "#" + + service.getName()); + } + return; + } + + if (logger.isLoggable(Level.FINE)) { + logger.fine("Activating component service: " + component.getURI() + "#" + service.getName()); + } + + // Add a wire for each service Endpoint + for ( Endpoint endpoint : service.getEndpoints()){ + RuntimeEndpoint ep = (RuntimeEndpoint) endpoint; + activate(compositeContext, ep); + + // create the interface contract for the binding and service ends of the wire + // that are created as forward only contracts + // FIXME: [rfeng] We might need a better way to get the impl interface contract + Service targetService = service.getService(); + if (targetService == null) { + targetService = service; + } + // endpoint.setInterfaceContract(targetService.getInterfaceContract().makeUnidirectional(false)); + } + } + + public void activate(CompositeContext compositeContext, RuntimeEndpoint ep) { + ep.bind(compositeContext); + + // Check that the service binding interface is compatible with the + // service interface + ep.validateServiceInterfaceCompatibility(); + } + + public void deactivate(RuntimeComponent component, RuntimeComponentService service) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Deactivating component service: " + component.getURI() + "#" + service.getName()); + } + for(Endpoint ep: service.getEndpoints()) { + if(ep instanceof RuntimeEndpoint) { + deactivate((RuntimeEndpoint) ep); + } + } + } + + public void deactivate(RuntimeEndpoint ep) { + ep.unbind(); + } + + // Reference activation/deactivation + + public void activate(CompositeContext compositeContext, RuntimeComponent component, RuntimeComponentReference reference) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Activating component reference: " + component.getURI() + "#" + reference.getName()); + } + + // set the parent component onto the reference. It's used at start time when the + // reference is asked to return it's runtime wires. If there are none the reference + // asks the component context to start the reference which creates the wires + reference.setComponent(component); + for(EndpointReference epr: reference.getEndpointReferences()) { + activate(compositeContext, (RuntimeEndpointReference) epr); + } + + } + + public void deactivate(RuntimeComponent component, RuntimeComponentReference reference) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Deactivating component reference: " + component.getURI() + "#" + reference.getName()); + } + for(EndpointReference endpointReference: reference.getEndpointReferences()) { + deactivate((RuntimeEndpointReference)endpointReference); + } + } + + public void activate(CompositeContext compositeContext, RuntimeEndpointReference epr) { + // create the wire + // null endpoint passed in here as the endpoint reference may + // not be resolved yet + epr.bind(compositeContext); + + ComponentReference reference = epr.getReference(); + InterfaceContract sourceContract = epr.getComponentTypeReferenceInterfaceContract(); + + // TODO - EPR - interface contract seems to be null in the implementation.web + // case. Not introspecting the CT properly? + if (sourceContract == null){ + // TODO - Can't do this with move of matching to wire + // take the contract from the service to which the reference is connected + sourceContract = ((RuntimeEndpoint) epr.getTargetEndpoint()).getComponentTypeServiceInterfaceContract(); + reference.setInterfaceContract(sourceContract); + } + + // endpointReference.setInterfaceContract(sourceContract.makeUnidirectional(false)); + + // if the reference already has a binding we can check the reference binding interface + // and reference interfaces for compatibility. If we can't check now compatibility + // will be checked when the endpoint reference is resolved. + if (epr.getStatus() == EndpointReference.Status.RESOLVED_BINDING){ + epr.validateReferenceInterfaceCompatibility(); + } + } + + public void deactivate(RuntimeEndpointReference endpointReference) { + endpointReference.unbind(); + } + + //========================================================================= + // Start + //========================================================================= + + // Composite start/stop + + public void start(CompositeContext compositeContext, Composite composite) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Starting composite: " + composite.getName()); + } + for (Component component : composite.getComponents()) { + start(compositeContext, component); + } + + for (Component component : composite.getComponents()) { + if (component instanceof ScopedRuntimeComponent) { + start(compositeContext, (ScopedRuntimeComponent)component); + } + } + + // start reference last. In allowing references to start at "start" time + // as well as when they are first used (for late bound references) we need + // to make sure that all potential target services and component implementations + // are started first to take account of the default binding optimization case + for (Component component : composite.getComponents()) { + for (ComponentReference reference : component.getReferences()) { + start(compositeContext, + (RuntimeComponent)component, + (RuntimeComponentReference)reference); + } + } + } + + public void stop(CompositeContext compositeContext, Composite composite) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Stopping composite: " + composite.getName()); + } + for (final Component component : composite.getComponents()) { + stop(compositeContext, component); + } + } + + // Component start/stop + + public void start(CompositeContext compositeContext, Component component) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Starting component: " + component.getURI()); + } + RuntimeComponent runtimeComponent = ((RuntimeComponent)component); + if(runtimeComponent.isStarted()) { + return; + } + + compositeContext.bindComponent(runtimeComponent); + Implementation implementation = component.getImplementation(); + + List providers = new ArrayList(); + try { + + if (implementation instanceof Composite) { + try { + start(compositeContext, (Composite)implementation); + } catch (Throwable e) { + try { + stop(compositeContext, (Composite) implementation); + } catch (Throwable e1) { + Monitor.error(monitor, this, "core-messages", "StopException", e1); + } + rethrow(e); + } + } else { + for (PolicyProvider policyProvider : runtimeComponent.getPolicyProviders()) { + policyProvider.start(); + providers.add(policyProvider); + } + ImplementationProvider implementationProvider = runtimeComponent.getImplementationProvider(); + if (implementationProvider != null) { + implementationProvider.start(); + providers.add(implementationProvider); + } + } + + for (ComponentService service : component.getServices()) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Starting component service: " + component.getURI() + "#" + service.getName()); + } + for (Endpoint endpoint : service.getEndpoints()) { + RuntimeEndpoint ep = (RuntimeEndpoint)endpoint; + startEndpoint(compositeContext, ep, providers); + } + } + + // Reference start is done after all components have been started to make sure everything + // is up and running before we try and connect references to services + + } catch (Throwable e) { + // any providers (binding, implementation, policy) that were started + // before the error occured are stopped here + for (int i = providers.size() - 1; i >= 0; i--) { + try { + providers.get(i).stop(); + } catch (Throwable e1) { + Monitor.error(monitor, this, "core-messages", "StopException", e1); + } + } + rethrow(e); + } finally { + providers.clear(); + } + + // mark a successful start + runtimeComponent.setStarted(true); + } + + private void rethrow(Throwable e) throws Error { + if(e instanceof RuntimeException) { + throw (RuntimeException) e; + } else if(e instanceof Error) { + throw (Error) e; + } + } + + public void stop(CompositeContext compositeContext, Component component) { + if (!((RuntimeComponent)component).isStarted()) { + return; + } + if (logger.isLoggable(Level.FINE)) { + logger.fine("Stopping component: " + component.getURI()); + } + for (ComponentService service : component.getServices()) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Stopping component service: " + component.getURI() + "#" + service.getName()); + } + for (Endpoint endpoint : service.getEndpoints()) { + RuntimeEndpoint ep = (RuntimeEndpoint) endpoint; + stop(ep); + } + } + for (ComponentReference reference : component.getReferences()) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Stopping component reference: " + component.getURI() + "#" + reference.getName()); + } + + for (EndpointReference endpointReference : reference.getEndpointReferences()) { + RuntimeEndpointReference epr = (RuntimeEndpointReference) endpointReference; + stop(epr); + } + } + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + stop(compositeContext, (Composite)implementation); + } else { + final ImplementationProvider implementationProvider = ((RuntimeComponent)component).getImplementationProvider(); + if (implementationProvider != null) { + try { + // Allow bindings to read properties. Requires PropertyPermission read in security policy. + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + implementationProvider.stop(); + return null; + } + }); + } catch (Throwable ex){ + Monitor.error(monitor, this, "core-messages", "StopException", ex); + } + } + for (PolicyProvider policyProvider : ((RuntimeComponent)component).getPolicyProviders()) { + try { + policyProvider.stop(); + } catch (Throwable ex){ + Monitor.error(monitor, this, "core-messages", "StopException", ex); + } + } + } + + if (component instanceof ScopedRuntimeComponent) { + ScopedRuntimeComponent runtimeComponent = (ScopedRuntimeComponent)component; + if (runtimeComponent.getScopeContainer() != null && + runtimeComponent.getScopeContainer().getLifecycleState() != ScopeContainer.STOPPED) { + try { + runtimeComponent.getScopeContainer().stop(); + } catch (Throwable ex){ + Monitor.error(monitor, this, "core-messages", "StopException", ex); + } + } + } + + ((RuntimeComponent)component).setStarted(false); + } + + + // Scope container start/stop + // separate off from component start that all endpoints are + // registered before any @EagerInit takes place + public void start(CompositeContext compositeContext, ScopedRuntimeComponent scopedRuntimeComponent) { + if (scopedRuntimeComponent.getScopeContainer() != null) { + try { + scopedRuntimeComponent.getScopeContainer().start(); + } catch (Throwable ex){ + Monitor.error(monitor, this, "core-messages", "StartException", ex); + rethrow(ex); + } + } + } + + // Service start/stop + + public void start(CompositeContext compositeContext, RuntimeEndpoint ep) { + startEndpoint(compositeContext, ep, null); + } + + private void startEndpoint(CompositeContext compositeContext, RuntimeEndpoint ep, final List providers) { + // FIXME: Should the policy providers be started before the endpoint is started? + for (PolicyProvider policyProvider : ep.getPolicyProviders()) { + policyProvider.start(); + if (providers != null) { + try { + providers.add(policyProvider); + } catch (Throwable ex){ + Monitor.error(monitor, this, "core-messages", "StartException", ex); + rethrow(ex); + } + } + } + + final ServiceBindingProvider bindingProvider = ep.getBindingProvider(); + if (bindingProvider != null) { + try { + // bindingProvider.start(); + // Allow bindings to add shutdown hooks. Requires RuntimePermission shutdownHooks in policy. + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + bindingProvider.start(); + if (providers != null) { + providers.add(bindingProvider); + } + return null; + } + }); + compositeContext.getEndpointRegistry().addEndpoint(ep); + } catch (Throwable ex){ + Monitor.error(monitor, this, "core-messages", "StartException", ex); + rethrow(ex); + } + } + } + + public void stop(RuntimeEndpoint ep) { + ep.getCompositeContext().getEndpointRegistry().removeEndpoint(ep); + final ServiceBindingProvider bindingProvider = ep.getBindingProvider(); + if (bindingProvider != null) { + try { + // Allow bindings to read properties. Requires PropertyPermission read in security policy. + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + bindingProvider.stop(); + return null; + } + }); + } catch (Throwable ex){ + Monitor.error(monitor, this, "core-messages", "StopException", ex); + } + } + for (PolicyProvider policyProvider : ep.getPolicyProviders()) { + try { + policyProvider.stop(); + } catch (Throwable ex){ + Monitor.error(monitor, this, "core-messages", "StopException", ex); + } + } + } + + + // Reference start/stop + + public void start(CompositeContext compositeContext, RuntimeComponent component, RuntimeComponentReference reference) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Starting component reference: " + component.getURI() + "#" + reference.getName()); + } + + for (EndpointReference endpointReference : reference.getEndpointReferences()){ + RuntimeEndpointReference epr = (RuntimeEndpointReference)endpointReference; + + // If the reference is already resolved then start it now. This currently + // important for async references which have native async bindings as the + // reference provider has to register a response listener regardless of + // whether the reference has been used or not. + if (epr.getStatus() == EndpointReference.Status.WIRED_TARGET_FOUND_AND_MATCHED || + epr.getStatus() == EndpointReference.Status.RESOLVED_BINDING){ + + // As we only care about starting references at build time in the + // async case at the moment check that the binding supports native async + // and that the reference is an async reference + ReferenceBindingProvider bindingProvider = epr.getBindingProvider(); + if (bindingProvider instanceof EndpointReferenceAsyncProvider && + ((EndpointReferenceAsyncProvider)bindingProvider).supportsNativeAsync() && + epr.isAsyncInvocation()){ + // it's resolved so start it now + try { + // The act of getting invocation chains starts the reference in the late binding case + // so just use that here + epr.getInvocationChains(); + } catch (Throwable ex){ + Monitor.error(monitor, this, "core-messages", "StartException", ex); + rethrow(ex); + } + } + } + } + } + + public void stop(Component component, ComponentReference reference) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Stopping component reference: " + component.getURI() + "#" + reference.getName()); + } + RuntimeComponentReference runtimeRef = ((RuntimeComponentReference)reference); + for ( EndpointReference endpointReference : runtimeRef.getEndpointReferences()){ + RuntimeEndpointReference epr = (RuntimeEndpointReference) endpointReference; + stop(epr); + } + } + + @Deprecated + public void start(CompositeContext compositeContext, RuntimeEndpointReference endpointReference) { + compositeContext.getEndpointRegistry().addEndpointReference(endpointReference); + + // The act of getting invocation chains starts the reference in the late binding case + // so just use that here + endpointReference.getInvocationChains(); + } + + public void stop(RuntimeEndpointReference epr) { + if (epr.isStarted()) { + CompositeContext compositeContext = epr.getCompositeContext(); + if (compositeContext == null) { + throw new IllegalStateException("The endpoint reference is not bound"); + } + compositeContext.getEndpointRegistry().removeEndpointReference(epr); + ReferenceBindingProvider bindingProvider = epr.getBindingProvider(); + if (bindingProvider != null) { + try { + bindingProvider.stop(); + } catch (Throwable ex){ + Monitor.error(monitor, this, "core-messages", "StopException", ex); + } + } + for (PolicyProvider policyProvider : epr.getPolicyProviders()) { + try { + policyProvider.stop(); + } catch (Throwable ex){ + Monitor.error(monitor, this, "core-messages", "StopException", ex); + } + } + } + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/DomainRegistryImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/DomainRegistryImpl.java new file mode 100644 index 0000000000..21e1e4cf38 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/DomainRegistryImpl.java @@ -0,0 +1,285 @@ +/* + * 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.core.assembly.impl; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Callable; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.assembly.Endpoint; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.LifeCycleListener; +import org.apache.tuscany.sca.core.UtilityExtensionPoint; +import org.apache.tuscany.sca.runtime.BaseDomainRegistry; +import org.apache.tuscany.sca.runtime.ContributionDescription; +import org.apache.tuscany.sca.runtime.ContributionListener; +import org.apache.tuscany.sca.runtime.DomainRegistry; +import org.apache.tuscany.sca.runtime.EndpointListener; +import org.apache.tuscany.sca.runtime.RuntimeProperties; + +/** + * A DomainRegistry implementation that sees registrations from the same JVM + */ +public class DomainRegistryImpl extends BaseDomainRegistry implements DomainRegistry, LifeCycleListener { + private final Logger logger = Logger.getLogger(DomainRegistryImpl.class.getName()); + + private List endpoints = new ArrayList(); + private Map> runningComposites = new HashMap>(); + private Map contributionDescriptions = new HashMap(); + + protected boolean quietLogging; + + public DomainRegistryImpl(ExtensionPointRegistry extensionPoints, String endpointRegistryURI, String domainURI) { + super(extensionPoints, null, endpointRegistryURI, domainURI); + Properties runtimeProps = extensionPoints.getExtensionPoint(UtilityExtensionPoint.class).getUtility(RuntimeProperties.class).getProperties(); + quietLogging = Boolean.parseBoolean(runtimeProps.getProperty(RuntimeProperties.QUIET_LOGGING)); + } + + public synchronized void addEndpoint(Endpoint endpoint) { + endpoints.add(endpoint); + for (EndpointListener listener : listeners) { + listener.endpointAdded(endpoint); + } + if (logger.isLoggable(quietLogging ? Level.FINE : Level.INFO)) { + String uri = null; + Binding b = endpoint.getBinding(); + if (b != null) { + uri = b.getURI(); + if (uri != null && uri.startsWith("/")) { + uri = uri.substring(1); + } + } + String msg = "Add endpoint - " + (uri == null ? endpoint.getURI() : b.getType().getLocalPart()+" - " + uri); + if (quietLogging) { + logger.fine(msg); + } else { + logger.info(msg); + } + } + } + + public List findEndpoint(String uri) { + List foundEndpoints = new ArrayList(); + for (Endpoint endpoint : endpoints) { + if (endpoint.matches(uri)) { + foundEndpoints.add(endpoint); + logger.fine("Found endpoint with matching service - " + endpoint); + } + // else the service name doesn't match + } + return foundEndpoints; + } + + public synchronized void removeEndpoint(Endpoint endpoint) { + endpoints.remove(endpoint); + endpointRemoved(endpoint); + if (logger.isLoggable(quietLogging ? Level.FINE : Level.INFO)) { + String uri = null; + Binding b = endpoint.getBinding(); + if (b != null) { + uri = b.getURI(); + if (uri != null && uri.startsWith("/")) { + uri = uri.substring(1); + } + } + String msg = "Remove endpoint - " + (uri == null ? endpoint.getURI() : b.getType().getLocalPart()+" - "+uri); + if (quietLogging) { + logger.fine(msg); + } else { + logger.info(msg); + } + } + } + + public synchronized List getEndpoints() { + return endpoints; + } + + public synchronized Endpoint getEndpoint(String uri) { + for (Endpoint ep : endpoints) { + String epURI = + ep.getComponent().getURI() + "#" + ep.getService().getName() + "/" + ep.getBinding().getName(); + if (epURI.equals(uri)) { + return ep; + } + if (ep.getBinding().getName() == null || ep.getBinding().getName().equals(ep.getService().getName())) { + epURI = ep.getComponent().getURI() + "#" + ep.getService().getName(); + if (epURI.equals(uri)) { + return ep; + } + } + } + return null; + + } + + public synchronized void updateEndpoint(String uri, Endpoint endpoint) { + Endpoint oldEndpoint = getEndpoint(uri); + if (oldEndpoint == null) { + throw new IllegalArgumentException("Endpoint is not found: " + uri); + } + endpoints.remove(oldEndpoint); + endpoints.add(endpoint); + for (EndpointListener listener : listeners) { + listener.endpointUpdated(oldEndpoint, endpoint); + } + } + + public synchronized void start() { + } + + public synchronized void stop() { + for (Iterator i = endpoints.iterator(); i.hasNext();) { + Endpoint ep = i.next(); + i.remove(); + endpointRemoved(ep); + } + endpointreferences.clear(); + listeners.clear(); + } + + public void addRunningComposite(String curi, Composite composite) { + Map cs = runningComposites.get(curi); + if (cs == null) { + cs = new HashMap(); + runningComposites.put(curi, cs); + } + cs.put(composite.getURI(), composite); + } + + public void removeRunningComposite(String curi, String compositeURI) { + Map cs = runningComposites.get(curi); + if (cs != null) { + cs.remove(compositeURI); + } + } + + public Composite getRunningComposite(String curi, String compositeURI) { + Map cs = runningComposites.get(curi); + if (cs != null) { + return cs.get(compositeURI); + } + return null; + } + + public Map> getRunningCompositeURIs() { + Map> compositeURIs = new HashMap>(); + for (String curi : runningComposites.keySet()) { + if (runningComposites.get(curi).size() > 0) { + List uris = new ArrayList(); + compositeURIs.put(curi, uris); + for (String uri : runningComposites.get(curi).keySet()) { + uris.add(uri); + } + } + } + return compositeURIs; + } + + public void installContribution(ContributionDescription cd) { + contributionDescriptions.put(cd.getURI(), cd); + for (ContributionListener listener : contributionlisteners) { + listener.contributionInstalled(cd.getURI()); + } + } + + public void uninstallContribution(String uri) { + // TUSCANY-4025 - iterate through this list in reverse + // in the expectation that a node listener + // will appear in the list before and other + // listener that appears in the list and which + // relies on the node still have the contribution + // information. + ListIterator listenerIterator = contributionlisteners.listIterator(contributionlisteners.size()); + while (listenerIterator.hasPrevious()) { + ContributionListener listener = listenerIterator.previous(); + listener.contributionRemoved(uri); + } + contributionDescriptions.remove(uri); + } + + public List getInstalledContributionURIs() { + return new ArrayList(contributionDescriptions.keySet()); + } + + public ContributionDescription getInstalledContribution(String uri) { + return contributionDescriptions.get(uri); + } + + @Override + public void updateInstalledContribution(ContributionDescription cd) { + contributionDescriptions.put(cd.getURI(), cd); + for (ContributionListener listener : contributionlisteners) { + listener.contributionUpdated(cd.getURI()); + } + } + + private static final String LOCAL_MEMBER_NAME = "LocalOnly"; + @Override + public List getNodeNames() { + return Arrays.asList(new String[]{LOCAL_MEMBER_NAME}); + } + + @Override + public String getLocalNodeName() { + return LOCAL_MEMBER_NAME; + } + + @Override + public String getRunningNodeName(String contributionURI, String compositeURI) { + if (getRunningComposite(contributionURI, compositeURI) != null) { + return LOCAL_MEMBER_NAME; + } + return null; + } + + @Override + public String remoteCommand(String memberName, Callable command) { + // TODO or should it just ensure the member name is LocalOnly and the run the command locally? + throw new IllegalStateException("not supportted for " + LOCAL_MEMBER_NAME); + } + + @Override + public String getContainingCompositesContributionURI(String componentName) { + for (Map cs : runningComposites.values()) { + for (Composite c : cs.values()) { + if (c.getComponent(componentName) != null) { + return c.getContributionURI(); + } + } + } + return null; + } + + @Override + public boolean isDistributed() { + return false; + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/EndpointSerializerImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/EndpointSerializerImpl.java new file mode 100644 index 0000000000..8cdb0363e9 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/EndpointSerializerImpl.java @@ -0,0 +1,198 @@ +/* + * 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.core.assembly.impl; + +import java.io.StringReader; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.List; + +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; + +import org.apache.tuscany.sca.assembly.Endpoint; +import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.context.CompositeContext; +import org.apache.tuscany.sca.contribution.Contribution; +import org.apache.tuscany.sca.contribution.processor.ProcessorContext; +import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor; +import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessorExtensionPoint; +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.definitions.Definitions; +import org.apache.tuscany.sca.policy.BindingType; +import org.apache.tuscany.sca.policy.Intent; +import org.apache.tuscany.sca.policy.PolicySet; +import org.apache.tuscany.sca.policy.util.PolicyHelper; +import org.apache.tuscany.sca.runtime.EndpointSerializer; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; +import org.oasisopen.sca.ServiceRuntimeException; + +public class EndpointSerializerImpl implements EndpointSerializer { + private ExtensionPointRegistry registry; + private XMLInputFactory inputFactory; + private XMLOutputFactory outputFactory; + private StAXArtifactProcessor processor; + private StAXArtifactProcessor refProcessor; + + public EndpointSerializerImpl(ExtensionPointRegistry registry) { + this.registry = registry; + FactoryExtensionPoint factories = registry.getExtensionPoint(FactoryExtensionPoint.class); + inputFactory = factories.getFactory(XMLInputFactory.class); + outputFactory = factories.getFactory(XMLOutputFactory.class); + StAXArtifactProcessorExtensionPoint processors = + registry.getExtensionPoint(StAXArtifactProcessorExtensionPoint.class); + processor = processors.getProcessor(Endpoint.class); + refProcessor = processors.getProcessor(EndpointReference.class); + } + + public Endpoint readEndpoint(String xml) { + try { + //System.out.println("Read Endpoint string >> " + xml); + XMLStreamReader reader = inputFactory.createXMLStreamReader(new StringReader(xml)); + Endpoint result = processor.read(reader, new ProcessorContext(registry)); + result.setRemote(true); + reader.close(); + return result; + } catch (Exception e) { + throw new ServiceRuntimeException(e); + } + } + + public void resolveEndpoint(Endpoint endpoint) { + CompositeContext compositeContext = ((RuntimeEndpoint)endpoint).getCompositeContext(); + + if (compositeContext == null){ + // will be null if this is the SCAClient + return; + } + + Definitions systemDefinitions = compositeContext.getSystemDefinitions(); + if (systemDefinitions != null){ + // Find pre-resolved intents from the system definition + List intents = new ArrayList(); + + for (Intent intent : endpoint.getRequiredIntents()){ + Intent resolvedIntent = PolicyHelper.getIntent(systemDefinitions, intent.getName()); + + if (resolvedIntent != null){ + intents.add(resolvedIntent); + } else { + // look to see if this intent is provided by the binding + BindingType bindingType = systemDefinitions.getBindingType(endpoint.getBinding().getType()); + + if (bindingType != null){ + for (Intent apIntent : bindingType.getAlwaysProvidedIntents()){ + if (apIntent.getName().equals(intent.getName())){ + resolvedIntent = apIntent; + break; + } + } + + if (resolvedIntent == null){ + for (Intent mpIntent : bindingType.getMayProvidedIntents()){ + if (mpIntent.getName().equals(intent.getName())){ + resolvedIntent = mpIntent; + break; + } + } + } + } + + if (resolvedIntent != null){ + intents.add(resolvedIntent); + } else { + throw new ServiceRuntimeException("Remote endpoint " + + endpoint + + " has intent " + + intent + + " that can't be found in the local system definitions in node " + + compositeContext.getNodeURI()); + } + } + } + + endpoint.getRequiredIntents().clear(); + endpoint.getRequiredIntents().addAll(intents); + + // Find pre-resolved policy sets from the system definition + List policySets = new ArrayList(); + + for (PolicySet policySet : endpoint.getPolicySets()){ + PolicySet resolvedPolicySet = PolicyHelper.getPolicySet(systemDefinitions, policySet.getName()); + if (resolvedPolicySet != null){ + policySets.add(resolvedPolicySet); + } else { + throw new ServiceRuntimeException("Remote endpoint " + + endpoint + + " has policy set " + + policySet + + " that can't be found in the local system definitions in node " + + compositeContext.getNodeURI()); + } + } + + endpoint.getPolicySets().clear(); + endpoint.getPolicySets().addAll(policySets); + } + } + + public String write(Endpoint endpoint) { + StringWriter sw = new StringWriter(); + try { + XMLStreamWriter writer = outputFactory.createXMLStreamWriter(sw); + processor.write(endpoint, writer, new ProcessorContext(registry)); + writer.flush(); + writer.close(); + String endpointString = sw.toString(); + //System.out.println("Write Endpoint string >> " + endpointString); + return endpointString; + } catch (Exception e) { + throw new ServiceRuntimeException(e); + } + } + + public EndpointReference readEndpointReference(String xml) { + try { + XMLStreamReader reader = inputFactory.createXMLStreamReader(new StringReader(xml)); + EndpointReference result = refProcessor.read(reader, new ProcessorContext(registry)); + reader.close(); + return result; + } catch (Exception e) { + throw new ServiceRuntimeException(e); + } + } + + public String write(EndpointReference endpointReference) { + StringWriter sw = new StringWriter(); + try { + XMLStreamWriter writer = outputFactory.createXMLStreamWriter(sw); + refProcessor.write(endpointReference, writer, new ProcessorContext(registry)); + writer.flush(); + writer.close(); + return sw.toString(); + } catch (Exception e) { + throw new ServiceRuntimeException(e); + } + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/LocalDomainRegistryFactory.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/LocalDomainRegistryFactory.java new file mode 100644 index 0000000000..002eb774ef --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/LocalDomainRegistryFactory.java @@ -0,0 +1,49 @@ +/* + * 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.core.assembly.impl; + +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.runtime.BaseDomainRegistryFactory; +import org.apache.tuscany.sca.runtime.DomainRegistry; + +/** + * The utility responsible for finding the endpoint regstry by the scheme and creating instances for the + * given domain + */ +public class LocalDomainRegistryFactory extends BaseDomainRegistryFactory { + private final static String[] schemes = new String[] {"local", "vm"}; + + /** + * @param extensionRegistry + */ + public LocalDomainRegistryFactory(ExtensionPointRegistry registry) { + super(registry); + } + + protected DomainRegistry createEndpointRegistry(String endpointRegistryURI, String domainURI) { + DomainRegistry domainRegistry = + new DomainRegistryImpl(registry, endpointRegistryURI, domainURI); + return domainRegistry; + } + + public String[] getSupportedSchemes() { + return schemes; + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/ReferenceParameterProcessor.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/ReferenceParameterProcessor.java new file mode 100644 index 0000000000..4d6a98ca5f --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/ReferenceParameterProcessor.java @@ -0,0 +1,98 @@ +/* + * 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.core.assembly.impl; + +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.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.FactoryExtensionPoint; +import org.apache.tuscany.sca.runtime.ReferenceParameters; + +/** + * Artifact processor for reference parameters. + * + * @version $Rev$ $Date$ + */ +public class ReferenceParameterProcessor implements StAXArtifactProcessor { + private static final QName REFERENCE_PARAMETERS = + new QName("http://tuscany.apache.org/xmlns/sca/1.1", "referenceParameters", "tuscany"); + + /** + * Constructs a new processor. + * + * @param modelFactories + */ + public ReferenceParameterProcessor(FactoryExtensionPoint modelFactories) { + } + + /** + * @see org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor#getArtifactType() + */ + public QName getArtifactType() { + return REFERENCE_PARAMETERS; + } + + /** + * @see org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor#read(javax.xml.stream.XMLStreamReader, ProcessorContext) + */ + public ReferenceParameters read(XMLStreamReader reader, ProcessorContext context) throws ContributionReadException, XMLStreamException { + ReferenceParameters parameters = new ReferenceParametersImpl(); + parameters.setCallbackID(reader.getAttributeValue(null, "callbackID")); + return parameters; + } + + /** + * @see org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor#write(java.lang.Object, javax.xml.stream.XMLStreamWriter, ProcessorContext) + */ + public void write(ReferenceParameters model, XMLStreamWriter writer, ProcessorContext context) throws ContributionWriteException, + XMLStreamException { + writer.writeStartElement(REFERENCE_PARAMETERS.getPrefix(), + REFERENCE_PARAMETERS.getLocalPart(), + REFERENCE_PARAMETERS.getNamespaceURI()); + writer.writeNamespace(REFERENCE_PARAMETERS.getPrefix(), REFERENCE_PARAMETERS.getNamespaceURI()); + + if (model.getCallbackID() != null) { + writer.writeAttribute("callbackID", model.getCallbackID().toString()); + } + writer.writeEndElement(); + } + + /** + * @see org.apache.tuscany.sca.contribution.processor.ArtifactProcessor#getModelType() + */ + public Class getModelType() { + return ReferenceParameters.class; + } + + /** + * @see org.apache.tuscany.sca.contribution.processor.ArtifactProcessor#resolve(java.lang.Object, org.apache.tuscany.sca.contribution.resolver.ModelResolver, ProcessorContext) + */ + public void resolve(ReferenceParameters model, ModelResolver resolver, ProcessorContext context) throws ContributionResolveException { + } + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/ReferenceParametersImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/ReferenceParametersImpl.java new file mode 100644 index 0000000000..7bd56271a5 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/ReferenceParametersImpl.java @@ -0,0 +1,121 @@ +/* + * 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.core.assembly.impl; + +import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.runtime.ReferenceParameters; + +/** + * @version $Rev$ $Date$ + */ +public class ReferenceParametersImpl implements ReferenceParameters { + private Object callbackID; + private EndpointReference callbackReference; + private Object callbackObjectID; + + /** + * @return the callbackID + */ + public Object getCallbackID() { + return callbackID; + } + /** + * @param callbackID the callbackID to set + */ + public void setCallbackID(Object callbackID) { + this.callbackID = callbackID; + } + + /** + * @see org.apache.tuscany.sca.runtime.ReferenceParameters#getCallbackReference() + */ + public EndpointReference getCallbackReference() { + return callbackReference; + } + /** + * @see org.apache.tuscany.sca.runtime.ReferenceParameters#setCallback(java.lang.Object) + */ + public void setCallbackReference(EndpointReference callback) { + this.callbackReference = callback; + } + + /** + * @see java.lang.Object#clone() + */ + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + + /** + * @return the callbackObjectID + */ + public Object getCallbackObjectID() { + return callbackObjectID; + } + /** + * @param callbackObjectID the callbackObjectID to set + */ + public void setCallbackObjectID(Object callbackObjectID) { + this.callbackObjectID = callbackObjectID; + } + /** + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((callbackID == null) ? 0 : callbackID.hashCode()); + result = prime * result + ((callbackObjectID == null) ? 0 : callbackObjectID.hashCode()); + result = prime * result + ((callbackReference == null) ? 0 : callbackReference.hashCode()); + return result; + } + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (!(obj instanceof ReferenceParametersImpl)) + return false; + final ReferenceParametersImpl other = (ReferenceParametersImpl)obj; + if (callbackID == null) { + if (other.callbackID != null) + return false; + } else if (!callbackID.equals(other.callbackID)) + return false; + if (callbackObjectID == null) { + if (other.callbackObjectID != null) + return false; + } else if (!callbackObjectID.equals(other.callbackObjectID)) + return false; + if (callbackReference == null) { + if (other.callbackReference != null) + return false; + } else if (!callbackReference.equals(other.callbackReference)) + return false; + + return true; + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeComponentImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeComponentImpl.java new file mode 100644 index 0000000000..a78cf6057e --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeComponentImpl.java @@ -0,0 +1,139 @@ +/* + * 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.core.assembly.impl; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.tuscany.sca.assembly.ComponentService; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.assembly.CompositeService; +import org.apache.tuscany.sca.assembly.impl.ComponentImpl; +import org.apache.tuscany.sca.contribution.resolver.ModelResolver; +import org.apache.tuscany.sca.contribution.resolver.ResolverExtension; +import org.apache.tuscany.sca.core.scope.ScopeContainer; +import org.apache.tuscany.sca.core.scope.ScopedRuntimeComponent; +import org.apache.tuscany.sca.provider.ImplementationProvider; +import org.apache.tuscany.sca.provider.PolicyProvider; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeComponentContext; +import org.oasisopen.sca.ServiceReference; +import org.oasisopen.sca.ServiceRuntimeException; + +/** + * @version $Rev$ $Date$ + */ +public class RuntimeComponentImpl extends ComponentImpl implements RuntimeComponent, + ScopedRuntimeComponent, ResolverExtension { + protected RuntimeComponentContext componentContext; + protected ImplementationProvider implementationProvider; + protected List policyProviders = new ArrayList(); + protected ScopeContainer scopeContainer; + protected boolean started; + protected ModelResolver modelResolver; + + /** + */ + public RuntimeComponentImpl() { + super(); + } + + public ImplementationProvider getImplementationProvider() { + return implementationProvider; + } + + public void setImplementationProvider(ImplementationProvider provider) { + this.implementationProvider = provider; + } + + public ScopeContainer getScopeContainer() { + return scopeContainer; + } + + public void setScopeContainer(ScopeContainer scopeContainer) { + this.scopeContainer = scopeContainer; + } + + public boolean isStarted() { + return started; + } + + public void setStarted(boolean started) { + this.started = started; + } + + /** + * @return the componentContext + */ + public RuntimeComponentContext getComponentContext() { + return componentContext; + } + + /** + * @param componentContext the componentContext to set + */ + public void setComponentContext(RuntimeComponentContext componentContext) { + this.componentContext = componentContext; + } + + public void addPolicyProvider(PolicyProvider policyProvider) { + policyProviders.add(policyProvider); + } + + public List getPolicyProviders() { + return policyProviders; + } + + public ModelResolver getModelResolver() { + return modelResolver; + } + + public void setModelResolver(ModelResolver modelResolver) { + this.modelResolver = modelResolver; + } + + @Override + public String toString() { + return getName(); + } + + @Override + public ServiceReference getServiceReference(Class businessInterface, String serviceName) { + RuntimeComponentContext componentContext = null; + + // TUSCANY-3904 Removed implementation.composite path + + componentContext = getComponentContext(); + if (serviceName != null) { + return componentContext.createSelfReference(businessInterface, serviceName); + } else { + return componentContext.createSelfReference(businessInterface); + } + + } + + // TUSCANY-3988 + @Override + public Object clone() throws CloneNotSupportedException { + RuntimeComponentImpl clone = (RuntimeComponentImpl)super.clone(); + clone.policyProviders = new ArrayList(); + return clone; + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeComponentReferenceImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeComponentReferenceImpl.java new file mode 100644 index 0000000000..2eea60ccea --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeComponentReferenceImpl.java @@ -0,0 +1,66 @@ +/* + * 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.core.assembly.impl; + +import org.apache.tuscany.sca.assembly.impl.ComponentReferenceImpl; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeComponentReference; + +/** + * Implementation of a Component Reference. + * + * @version $Rev$ $Date$ + */ +public class RuntimeComponentReferenceImpl extends ComponentReferenceImpl implements RuntimeComponentReference { + + private RuntimeComponent component; + + public RuntimeComponentReferenceImpl() { + super(); + } + + /** + * @return the component + */ + public RuntimeComponent getComponent() { + return component; + } + + /** + * @param component the component to set + */ + public void setComponent(RuntimeComponent component) { + this.component = component; + } + + /** + * @see org.apache.tuscany.sca.assembly.impl.ComponentReferenceImpl#clone() + */ + @Override + public Object clone() throws CloneNotSupportedException { + RuntimeComponentReferenceImpl ref = (RuntimeComponentReferenceImpl)super.clone(); + return ref; + } + + @Override + public String toString() { + return getName(); + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeComponentServiceImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeComponentServiceImpl.java new file mode 100644 index 0000000000..bc7e6df878 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeComponentServiceImpl.java @@ -0,0 +1,40 @@ +/* + * 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.core.assembly.impl; + +import org.apache.tuscany.sca.assembly.impl.ComponentServiceImpl; +import org.apache.tuscany.sca.runtime.RuntimeComponentService; + +/** + * Implementation of a Component Service. + * + * @version $Rev$ $Date$ + */ +public class RuntimeComponentServiceImpl extends ComponentServiceImpl implements RuntimeComponentService { + + public RuntimeComponentServiceImpl() { + super(); + } + + @Override + public String toString() { + return getName(); + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeEndpointImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeEndpointImpl.java new file mode 100644 index 0000000000..09cbab76d1 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeEndpointImpl.java @@ -0,0 +1,1285 @@ +/* + * 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.core.assembly.impl; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.OutputStream; +import java.io.StringReader; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import javax.wsdl.Definition; +import javax.wsdl.WSDLException; +import javax.wsdl.factory.WSDLFactory; +import javax.wsdl.xml.WSDLWriter; +import javax.xml.namespace.QName; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; +import javax.xml.transform.stream.StreamSource; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.ComponentReference; +import org.apache.tuscany.sca.assembly.ComponentService; +import org.apache.tuscany.sca.assembly.CompositeReference; +import org.apache.tuscany.sca.assembly.CompositeService; +import org.apache.tuscany.sca.assembly.Contract; +import org.apache.tuscany.sca.assembly.Endpoint; +import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.assembly.Reference; +import org.apache.tuscany.sca.assembly.Service; +import org.apache.tuscany.sca.assembly.builder.BindingBuilder; +import org.apache.tuscany.sca.assembly.builder.BuilderContext; +import org.apache.tuscany.sca.assembly.builder.BuilderExtensionPoint; +import org.apache.tuscany.sca.assembly.impl.EndpointImpl; +import org.apache.tuscany.sca.assembly.xml.InterfaceContractProcessor; +import org.apache.tuscany.sca.context.CompositeContext; +import org.apache.tuscany.sca.contribution.processor.ContributionReadException; +import org.apache.tuscany.sca.contribution.processor.ProcessorContext; +import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor; +import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessorExtensionPoint; +import org.apache.tuscany.sca.contribution.processor.ValidatingXMLInputFactory; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.ExtensionPointRegistryLocator; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +import org.apache.tuscany.sca.core.UtilityExtensionPoint; +import org.apache.tuscany.sca.core.assembly.RuntimeAssemblyFactory; +import org.apache.tuscany.sca.core.invocation.AsyncResponseService; +import org.apache.tuscany.sca.core.invocation.Constants; +import org.apache.tuscany.sca.core.invocation.ExtensibleWireProcessor; +import org.apache.tuscany.sca.core.invocation.NonBlockingInterceptor; +import org.apache.tuscany.sca.core.invocation.RuntimeInvoker; +import org.apache.tuscany.sca.core.invocation.impl.InvocationChainImpl; +import org.apache.tuscany.sca.core.invocation.impl.PhaseManager; +import org.apache.tuscany.sca.interfacedef.Compatibility; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.interfacedef.InvalidInterfaceException; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceContract; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; +import org.apache.tuscany.sca.interfacedef.wsdl.WSDLDefinition; +import org.apache.tuscany.sca.interfacedef.wsdl.WSDLInterface; +import org.apache.tuscany.sca.interfacedef.wsdl.WSDLInterfaceContract; +import org.apache.tuscany.sca.invocation.Interceptor; +import org.apache.tuscany.sca.invocation.InterceptorAsync; +import org.apache.tuscany.sca.invocation.InvocationChain; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.InvokerAsyncResponse; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.invocation.Phase; +import org.apache.tuscany.sca.provider.BindingProviderFactory; +import org.apache.tuscany.sca.provider.EndpointAsyncProvider; +import org.apache.tuscany.sca.provider.EndpointProvider; +import org.apache.tuscany.sca.provider.ImplementationAsyncProvider; +import org.apache.tuscany.sca.provider.ImplementationProvider; +import org.apache.tuscany.sca.provider.OptimisingBindingProvider; +import org.apache.tuscany.sca.provider.PolicyProvider; +import org.apache.tuscany.sca.provider.PolicyProviderFactory; +import org.apache.tuscany.sca.provider.ProviderFactoryExtensionPoint; +import org.apache.tuscany.sca.provider.ServiceBindingProvider; +import org.apache.tuscany.sca.runtime.DomainRegistry; +import org.apache.tuscany.sca.runtime.DomainRegistryFactory; +import org.apache.tuscany.sca.runtime.EndpointSerializer; +import org.apache.tuscany.sca.runtime.ExtensibleDomainRegistryFactory; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeComponentService; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; +import org.apache.tuscany.sca.runtime.RuntimeEndpointReference; +import org.apache.tuscany.sca.runtime.RuntimeWireProcessor; +import org.apache.tuscany.sca.runtime.RuntimeWireProcessorExtensionPoint; +import org.apache.tuscany.sca.work.WorkScheduler; +import org.apache.tuscany.sca.xsd.XSDefinition; +import org.apache.ws.commons.schema.XmlSchema; +import org.apache.ws.commons.schema.XmlSchemaImport; +import org.apache.ws.commons.schema.XmlSchemaInclude; +import org.apache.ws.commons.schema.XmlSchemaObject; +import org.oasisopen.sca.ServiceRuntimeException; + +/** + * Runtime model for Endpoint that supports java serialization + */ +public class RuntimeEndpointImpl extends EndpointImpl implements RuntimeEndpoint, Externalizable { + private static final long serialVersionUID = 1L; + private static final byte separator[] = {'_', 'X', '_'}; + + private transient CompositeContext compositeContext; + private transient RuntimeWireProcessor wireProcessor; + private transient ProviderFactoryExtensionPoint providerFactories; + private transient InterfaceContractMapper interfaceContractMapper; + private transient WorkScheduler workScheduler; + private transient PhaseManager phaseManager; + private transient MessageFactory messageFactory; + private transient RuntimeInvoker invoker; + private transient EndpointSerializer serializer; + + private transient List chains; + private transient Map invocationChainMap = + new ConcurrentHashMap(); + private transient InvocationChain bindingInvocationChain; + + private transient ServiceBindingProvider bindingProvider; + private transient List policyProviders; + private String xml; + private String interfaceContractXML; + + protected InterfaceContract bindingInterfaceContract; + protected InterfaceContract serviceInterfaceContract; + + private RuntimeEndpoint delegateEndpoint; + + /** + * No-arg constructor for Java serialization + */ + public RuntimeEndpointImpl() { + super(null); + } + + public RuntimeEndpointImpl(ExtensionPointRegistry registry) { + super(registry); + } + + protected void copyFrom(RuntimeEndpointImpl copy) { + this.xml = copy.xml; + + this.component = copy.component; + this.service = copy.service; + this.interfaceContract = copy.interfaceContract; + this.serviceInterfaceContract = copy.serviceInterfaceContract; + + this.binding = copy.binding; + this.bindingInterfaceContract = copy.interfaceContract; + this.bindingInvocationChain = copy.bindingInvocationChain; + + this.callbackEndpointReferences = copy.callbackEndpointReferences; + + this.requiredIntents = copy.requiredIntents; + this.policySets = copy.policySets; + + this.uri = copy.uri; + this.remote = copy.remote; + this.unresolved = copy.unresolved; + + this.chains = copy.chains; + this.invocationChainMap = copy.invocationChainMap; + this.bindingProvider = copy.bindingProvider; + this.policyProviders = copy.policyProviders; + + if (this.compositeContext == null && copy.compositeContext != null) { + bind(copy.compositeContext); + } + } + + public void bind(CompositeContext compositeContext) { + this.compositeContext = compositeContext; + bind(compositeContext.getExtensionPointRegistry(), compositeContext.getEndpointRegistry()); + } + + public void bind(ExtensionPointRegistry registry, DomainRegistry domainRegistry) { + if (compositeContext == null) { + compositeContext = new CompositeContext(registry, domainRegistry); + } + + // if interfaceContractMapper is already initialized then all the rest will be too + if (interfaceContractMapper != null) { + return; + } + this.registry = registry; + UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); + this.interfaceContractMapper = utilities.getUtility(InterfaceContractMapper.class); + this.workScheduler = utilities.getUtility(WorkScheduler.class); + this.wireProcessor = + new ExtensibleWireProcessor(registry.getExtensionPoint(RuntimeWireProcessorExtensionPoint.class)); + + this.messageFactory = registry.getExtensionPoint(FactoryExtensionPoint.class).getFactory(MessageFactory.class); + this.invoker = new RuntimeInvoker(registry, this); + + this.phaseManager = utilities.getUtility(PhaseManager.class); + this.serializer = utilities.getUtility(EndpointSerializer.class); + this.providerFactories = registry.getExtensionPoint(ProviderFactoryExtensionPoint.class); + this.builders = registry.getExtensionPoint(BuilderExtensionPoint.class); + this.contractBuilder = builders.getContractBuilder(); + } + + public void unbind() { + compositeContext = null; + bindingInvocationChain = null; + chains = null; + bindingProvider = null; + policyProviders = null; + invocationChainMap.clear(); + } + + public synchronized List getInvocationChains() { + if (chains == null) { + initInvocationChains(); + } + return chains; + } + + public synchronized InvocationChain getBindingInvocationChain() { + if (bindingInvocationChain == null) { + bindingInvocationChain = new InvocationChainImpl(null, null, false, phaseManager, isAsyncInvocation()); + initServiceBindingInvocationChains(); + } + + // Init the operation invocation chains now. We know they will + // be needed as well as the binding invocation chain and this + // makes the wire processors run + getInvocationChains(); + + return bindingInvocationChain; + } + + /** + * A dummy invocation chain representing null as ConcurrentHashMap doesn't allow null values + */ + private static final InvocationChain NULL_CHAIN = new InvocationChainImpl(null, null, false, null, false); + + public InvocationChain getInvocationChain(Operation operation) { + InvocationChain cached = invocationChainMap.get(operation); + if (cached == null) { + for (InvocationChain chain : getInvocationChains()) { + Operation op = chain.getTargetOperation(); + + // We used to check compatibility here but this is now validated when the + // chain is created. As the chain operations are the real interface types + // they may be incompatible just because they are described in different + // IDLs + if (operation.getInterface().isRemotable()) { + if (operation.getName().equals(op.getName())) { + invocationChainMap.put(operation, chain); + return chain; + } + if (interfaceContractMapper.isCompatible(operation, op, Compatibility.SUBSET)) { + invocationChainMap.put(operation, chain); + return chain; + } + } else { + // [rfeng] We need to run the compatibility check for local operations as they + // can be overloaded + if (interfaceContractMapper.isCompatible(operation, op, Compatibility.SUBSET)) { + invocationChainMap.put(operation, chain); + return chain; + } + } + } + // Cache it with the NULL_CHAIN to avoid NPE + invocationChainMap.put(operation, NULL_CHAIN); + return null; + } else { + if (cached == NULL_CHAIN) { + cached = null; + } + return cached; + } + } + + public Message invoke(Message msg) { + // Deal with async callback + // Ensure invocation chains are built... + getInvocationChains(); + // async callback handling + if( this.isAsyncInvocation() && !this.getCallbackEndpointReferences().isEmpty() ) { + RuntimeEndpointReference asyncEPR = (RuntimeEndpointReference) this.getCallbackEndpointReferences().get(0); + // Place a link to the callback EPR into the message headers... + msg.getHeaders().put(Constants.ASYNC_CALLBACK, asyncEPR ); + } + // end of async callback handling + return invoker.invokeBinding(msg); + } + + public Object invoke(Operation operation, Object[] args) throws InvocationTargetException { + return invoker.invoke(operation, args); + } + + public Message invoke(Operation operation, Message msg) { + return invoker.invoke(operation, msg); + } + + public void invokeAsync(Message msg){ + invoker.invokeBindingAsync(msg); + } // end method invokeAsync(Message) + + public void invokeAsync(Operation operation, Message msg){ + msg.setOperation(operation); + invoker.invokeAsync(msg); + } // end method invokeAsync(Operation, Message) + + public void invokeAsyncResponse(Message msg){ + resolve(); + invoker.invokeAsyncResponse(msg); + } + + /** + * Navigate the component/componentType inheritance chain to find the leaf contract + * @param contract + * @return + */ + private Contract getLeafContract(Contract contract) { + Contract prev = null; + Contract current = contract; + while (current != null) { + prev = current; + if (current instanceof ComponentReference) { + current = ((ComponentReference)current).getReference(); + } else if (current instanceof CompositeReference) { + current = ((CompositeReference)current).getPromotedReferences().get(0); + } else if (current instanceof ComponentService) { + current = ((ComponentService)current).getService(); + } else if (current instanceof CompositeService) { + current = ((CompositeService)current).getPromotedService(); + } else { + break; + } + if (current == null) { + return prev; + } + } + return current; + } + + /** + * Initialize the invocation chains + */ + private void initInvocationChains() { + chains = new ArrayList(); + InterfaceContract sourceContract = getBindingInterfaceContract(); + + // It's the service wire + RuntimeComponentService service = (RuntimeComponentService)getService(); + RuntimeComponent serviceComponent = (RuntimeComponent)getComponent(); + + //InterfaceContract targetContract = getInterfaceContract(); + // TODO - EPR - why is this looking at the component types. The endpoint should have the right interface contract by this time + InterfaceContract targetContract = getComponentTypeServiceInterfaceContract(); + // setInterfaceContract(targetContract); + validateServiceInterfaceCompatibility(); + for (Operation operation : sourceContract.getInterface().getOperations()) { + Operation targetOperation = interfaceContractMapper.map(targetContract.getInterface(), operation); + if (targetOperation == null) { + throw new ServiceRuntimeException("No matching operation for " + operation.getName() + + " is found in service " + + serviceComponent.getURI() + + "#" + + service.getName()); + } + InvocationChain chain = new InvocationChainImpl(operation, targetOperation, false, phaseManager, isAsyncInvocation()); + if (operation.isNonBlocking()) { + addNonBlockingInterceptor(chain); + } + addServiceBindingInterceptor(chain, operation); + addImplementationInterceptor(serviceComponent, service, chain, targetOperation); + chains.add(chain); + + // Handle cases where the operation is an async server + if( targetOperation.isAsyncServer() ) { + createAsyncServerCallback(); + } // end if + } + + wireProcessor.process(this); + + // If we have to support async and there is no binding chain + // then set the response path to point directly to the + // binding provided async response handler + if (isAsyncInvocation() && + bindingInvocationChain == null){ + // fix up the operation chain response path to point back to the + // binding provided async response handler + ServiceBindingProvider serviceBindingProvider = getBindingProvider(); + if (serviceBindingProvider instanceof EndpointAsyncProvider){ + EndpointAsyncProvider asyncEndpointProvider = (EndpointAsyncProvider)serviceBindingProvider; + InvokerAsyncResponse asyncResponseInvoker = asyncEndpointProvider.createAsyncResponseInvoker(); + + for (InvocationChain chain : getInvocationChains()){ + Invoker invoker = chain.getHeadInvoker(); + if (invoker instanceof InterceptorAsync){ + ((InterceptorAsync)invoker).setPrevious(asyncResponseInvoker); + } else { + //TODO - throw error once the old async code is removed + } // end if + } // end for + } else { + // TODO - throw error once the old async code is removed + } // end if + } // end if + + ServiceBindingProvider provider = getBindingProvider(); + if ((provider != null) && (provider instanceof OptimisingBindingProvider)) { + //TODO - remove this comment once optimisation codepath is tested + ((OptimisingBindingProvider)provider).optimiseBinding( this ); + } // end if + + } // end method initInvocationChains + + /** + * Creates the async callback for this Endpoint, if it does not already exist + * and stores it into the Endpoint + */ + public void createAsyncServerCallback( ) { + // No need to create a callback if the Binding supports async natively... + if( hasNativeAsyncBinding(this) ) return; + + // Check to see if the callback already exists + if( asyncCallbackExists( this ) ) return; + + RuntimeEndpointReference asyncEPR = createAsyncEPR( this ); + + // Store the new callback EPR into the Endpoint + this.getCallbackEndpointReferences().add(asyncEPR); + + // Also store the callback EPR into the DomainRegistry + DomainRegistry epReg = getEndpointRegistry( registry ); + if( epReg != null ) epReg.addEndpointReference(asyncEPR); + } // end method createAsyncServerCallback + + public RuntimeEndpointReference getAsyncServerCallback() { + + return (RuntimeEndpointReference) this.getCallbackEndpointReferences().get(0); + } // end method getAsyncServerCallback + + + /** + * Indicates if a given endpoint has a Binding that supports native async invocation + * @param endpoint - the endpoint + * @return - true if the endpoint has a binding that supports native async, false otherwise + */ + private boolean hasNativeAsyncBinding(RuntimeEndpoint endpoint) { + ServiceBindingProvider provider = endpoint.getBindingProvider(); + if( provider instanceof EndpointAsyncProvider ) { + EndpointAsyncProvider asyncProvider = (EndpointAsyncProvider) provider; + if( asyncProvider.supportsNativeAsync() ) return true; + } // end if + return false; + } // end method hasNativeAsyncBinding + + /** + * Creates the Endpoint object for the async callback + * @param endpoint - the endpoint which has the async server operations + * @return the EndpointReference object representing the callback + */ + private RuntimeEndpointReference createAsyncEPR( RuntimeEndpoint endpoint ){ + CompositeContext compositeContext = endpoint.getCompositeContext(); + RuntimeAssemblyFactory assemblyFactory = getAssemblyFactory( compositeContext ); + RuntimeEndpointReference epr = (RuntimeEndpointReference)assemblyFactory.createEndpointReference(); + epr.bind( compositeContext ); + + // Create pseudo-component + epr.setComponent(component); + + // Create pseudo-reference + ComponentReference reference = assemblyFactory.createComponentReference(); + ExtensionPointRegistry registry = compositeContext.getExtensionPointRegistry(); + FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class); + JavaInterfaceFactory javaInterfaceFactory = (JavaInterfaceFactory)modelFactories.getFactory(JavaInterfaceFactory.class); + JavaInterfaceContract interfaceContract = javaInterfaceFactory.createJavaInterfaceContract(); + try { + interfaceContract.setInterface(javaInterfaceFactory.createJavaInterface(AsyncResponseService.class)); + } catch (InvalidInterfaceException e1) { + // Nothing to do here - will not happen + } // end try + reference.setInterfaceContract(interfaceContract); + String referenceName = endpoint.getService().getName() + "_asyncCallback"; + reference.setName(referenceName); + reference.setForCallback(true); + // Add in "implementation" reference (really a dummy, but with correct interface) + Reference implReference = assemblyFactory.createReference(); + implReference.setInterfaceContract(interfaceContract); + implReference.setName(referenceName); + implReference.setForCallback(true); + + reference.setReference(implReference); + // Set the created ComponentReference into the EPR + epr.setReference(reference); + + // Create a binding + Binding binding = createMatchingBinding( endpoint.getBinding(), (RuntimeComponent)endpoint.getComponent(), reference, registry ); + epr.setBinding(binding); + + // Need to establish policies here (binding has some...) + epr.getRequiredIntents().addAll( endpoint.getRequiredIntents() ); + epr.getPolicySets().addAll( endpoint.getPolicySets() ); + + // Attach a dummy endpoint to the epr + RuntimeEndpoint ep = (RuntimeEndpoint)assemblyFactory.createEndpoint(); + ep.setUnresolved(false); + epr.setTargetEndpoint(ep); + //epr.setStatus(EndpointReference.Status.RESOLVED_BINDING); + epr.setStatus(EndpointReference.Status.WIRED_TARGET_FOUND_AND_MATCHED); + epr.setUnresolved(false); + + // Set the URI for the EPR + String eprURI = endpoint.getComponent().getName() + "#reference-binding(" + referenceName + "/" + referenceName + ")"; + epr.setURI(eprURI); + + return epr; + } // end method RuntimeEndpointReference + + private boolean asyncCallbackExists( RuntimeEndpoint endpoint ) { + if( endpoint.getCallbackEndpointReferences().isEmpty() ) return false; + return true; + } // end method asyncCallbackExists + + /** + * Create a matching binding to a supplied binding + * - the matching binding has the same binding type, but is for the supplied component and service + * @param matchBinding - the binding to match + * @param component - the component + * @param service - the service + * @param registry - registry for extensions + * @return - the matching binding, or null if it could not be created + */ + @SuppressWarnings("unchecked") + private Binding createMatchingBinding( Binding matchBinding, RuntimeComponent component, + ComponentReference reference, ExtensionPointRegistry registry ) { + // Since there is no simple way to obtain a Factory for a binding where the type is not known ahead of + // time, the process followed here is to generate the XML element from the binding type QName + // and then read the XML using the processor for that XML... + QName bindingName = matchBinding.getType(); + String bindingXML = ""; + + StAXArtifactProcessorExtensionPoint processors = registry.getExtensionPoint(StAXArtifactProcessorExtensionPoint.class); + StAXArtifactProcessor processor = (StAXArtifactProcessor)processors.getProcessor(bindingName); + + FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class); + ValidatingXMLInputFactory inputFactory = modelFactories.getFactory(ValidatingXMLInputFactory.class); + StreamSource source = new StreamSource( new StringReader(bindingXML) ); + + ProcessorContext context = new ProcessorContext(); + try { + XMLStreamReader reader = inputFactory.createXMLStreamReader(source); + reader.next(); + Binding newBinding = (Binding) processor.read(reader, context ); + newBinding.setName(reference.getName()); + + // Create a URI address for the callback based on the Component_Name/Reference_Name pattern + //String callbackURI = "/" + component.getName() + "/" + reference.getName(); + //newBinding.setURI(callbackURI); + + BuilderExtensionPoint builders = registry.getExtensionPoint(BuilderExtensionPoint.class); + BindingBuilder builder = builders.getBindingBuilder(newBinding.getType()); + if (builder != null) { + org.apache.tuscany.sca.assembly.builder.BuilderContext builderContext = new BuilderContext(registry); + builder.build(component, reference, newBinding, builderContext, true); + } // end if + + return newBinding; + } catch (ContributionReadException e) { + e.printStackTrace(); + } catch (XMLStreamException e) { + e.printStackTrace(); + } + + return null; + } // end method createMatchingBinding + + /** + * Gets a RuntimeAssemblyFactory from the CompositeContext + * @param compositeContext + * @return the RuntimeAssemblyFactory + */ + private RuntimeAssemblyFactory getAssemblyFactory( CompositeContext compositeContext ) { + ExtensionPointRegistry registry = compositeContext.getExtensionPointRegistry(); + FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class); + return (RuntimeAssemblyFactory)modelFactories.getFactory(AssemblyFactory.class); + } // end method RuntimeAssemblyFactory + + /** + * Check that endpoint has compatible interface at the component and binding ends. + * The user can specify the interfaces at both ends so there is a danger that they won't be compatible. + */ + public void validateServiceInterfaceCompatibility() { + + InterfaceContract serviceContract = getComponentServiceInterfaceContract(); + InterfaceContract bindingContract = getBindingInterfaceContract(); + + if ((serviceContract != bindingContract) && + (serviceContract != null) && (bindingContract != null)) { + + boolean bindingHasCallback = bindingContract.getCallbackInterface() != null; + + try { + + // Use the normalized contract if the interface types are different or if + // a normalized contract has been previously generate, for example, by virtue + // of finding a JAXWS annotation on a Java class that references a WSDL file + if (serviceContract.getClass() != bindingContract.getClass() || + serviceContract.getNormalizedWSDLContract() != null || + bindingContract.getNormalizedWSDLContract() != null) { + interfaceContractMapper.checkCompatibility(getGeneratedWSDLContract(serviceContract), + getGeneratedWSDLContract(bindingContract), + Compatibility.SUBSET, + !bindingHasCallback, // ignore callbacks if binding doesn't have one + false); + } else { + interfaceContractMapper.checkCompatibility(serviceContract, + bindingContract, + Compatibility.SUBSET, + !bindingHasCallback, // ignore callbacks if binding doesn't have one + false); + } + } catch (Exception ex){ + throw new ServiceRuntimeException("Component " + + this.getComponent().getName() + + " Service " + + getService().getName() + + " interface is incompatible with the interface of the service binding - " + + getBinding().getName() + + " - " + + ex.getMessage() + + " - [" + this.toString() + "]"); + } + } + + } + + private void initServiceBindingInvocationChains() { + + // add the binding interceptors to the service binding wire + ServiceBindingProvider provider = getBindingProvider(); + if ((provider != null) && (provider instanceof EndpointProvider)) { + ((EndpointProvider)provider).configure(); + } + + // add the policy interceptors to the service binding wire + List pps = getPolicyProviders(); + if (pps != null) { + for (PolicyProvider p : pps) { + Interceptor interceptor = p.createBindingInterceptor(); + if (interceptor != null) { + bindingInvocationChain.addInterceptor(interceptor); + } // end if + } // end for + } // end if + + // This is strategically placed before the RuntimeInvoker is added to the end of the + // binding chain as the RuntimeInvoker doesn't need to take part in the response + // processing and doesn't implement InvokerAsyncResponse + ServiceBindingProvider serviceBindingProvider = getBindingProvider(); + if (isAsyncInvocation() && + serviceBindingProvider instanceof EndpointAsyncProvider && + ((EndpointAsyncProvider)serviceBindingProvider).supportsNativeAsync()){ + // fix up the invocation chains to point back to the + // binding chain so that async response messages + // are processed correctly + for (InvocationChain chain : getInvocationChains()){ + Invoker invoker = chain.getHeadInvoker(); + ((InterceptorAsync)invoker).setPrevious((InvokerAsyncResponse)bindingInvocationChain.getTailInvoker()); + } // end for + + // fix up the binding chain response path to point back to the + // binding provided async response handler + EndpointAsyncProvider asyncEndpointProvider = (EndpointAsyncProvider)serviceBindingProvider; + InvokerAsyncResponse asyncResponseInvoker = asyncEndpointProvider.createAsyncResponseInvoker(); + ((InterceptorAsync)bindingInvocationChain.getHeadInvoker()).setPrevious(asyncResponseInvoker); + } // end if + + // Add the runtime invoker to the end of the binding chain. + // It mediates between the binding chain and selects the + // correct invocation chain based on the operation that's + // been selected + bindingInvocationChain.addInvoker(invoker); + + } // end method initServiceBindingInvocationChains + + /** + * Add the interceptor for a binding + * + * @param reference + * @param binding + * @param chain + * @param operation + */ + private void addServiceBindingInterceptor(InvocationChain chain, Operation operation) { + List pps = getPolicyProviders(); + if (pps != null) { + for (PolicyProvider p : pps) { + Interceptor interceptor = p.createInterceptor(operation); + if (interceptor != null) { + chain.addInterceptor(interceptor); + } + } + } + } + + /** + * Add a non-blocking interceptor if the service binding needs it + * + * @param service + * @param binding + * @param chain + */ + private void addNonBlockingInterceptor(InvocationChain chain) { + ServiceBindingProvider provider = getBindingProvider(); + if (provider != null) { + if (!provider.supportsOneWayInvocation()) { + chain.addInterceptor(Phase.SERVICE, new NonBlockingInterceptor(workScheduler)); + } + } + } + + /** + * Add the interceptor for a component implementation + * + * @param component + * @param service + * @param chain + * @param operation + */ + private void addImplementationInterceptor(Component component, + ComponentService service, + InvocationChain chain, + Operation operation) { + + if (service.getService() instanceof CompositeService) { + CompositeService compositeService = (CompositeService)service.getService(); + component = getPromotedComponent(compositeService); + service = getPromotedComponentService(compositeService); + } + + ImplementationProvider provider = ((RuntimeComponent)component).getImplementationProvider(); + + if (provider != null) { + Invoker invoker = null; + RuntimeComponentService runtimeService = (RuntimeComponentService)service; + if (runtimeService.getName().endsWith("_asyncCallback")){ + if (provider instanceof ImplementationAsyncProvider){ + invoker = (Invoker)((ImplementationAsyncProvider)provider).createAsyncResponseInvoker(operation); + } else { + // TODO - This should be an error but taking account of the + // existing non-native async support + invoker = provider.createInvoker((RuntimeComponentService)service, operation); +/* + throw new ServiceRuntimeException("Component " + + this.getComponent().getName() + + " Service " + + getService().getName() + + " implementation provider doesn't implement ImplementationAsyncProvider but the implementation uses a " + + "refrence interface with the asyncInvocation intent set" + + " - [" + this.toString() + "]"); +*/ + } + } else if (isAsyncInvocation() && + provider instanceof ImplementationAsyncProvider){ + invoker = (Invoker)((ImplementationAsyncProvider)provider).createAsyncInvoker((RuntimeComponentService)service, operation); + } else { + invoker = provider.createInvoker((RuntimeComponentService)service, operation); + } + chain.addInvoker(invoker); + } + + List pps = ((RuntimeComponent)component).getPolicyProviders(); + if (pps != null) { + for (PolicyProvider p : pps) { + Interceptor interceptor = p.createInterceptor(operation); + if (interceptor != null) { + chain.addInterceptor(interceptor); + } + } + } + } + + /** + * @see java.lang.Object#clone() + */ + @Override + public Object clone() throws CloneNotSupportedException { + RuntimeEndpointImpl copy = (RuntimeEndpointImpl)super.clone(); + copy.invoker = new RuntimeInvoker(registry, copy); + return copy; + } + + /** + * Follow a service promotion chain down to the inner most (non composite) + * component service. + * + * @param topCompositeService + * @return + */ + public ComponentService getPromotedComponentService(CompositeService compositeService) { + ComponentService componentService = compositeService.getPromotedService(); + if (componentService != null) { + Service service = componentService.getService(); + if (componentService.getName() != null && service instanceof CompositeService) { + + // Continue to follow the service promotion chain + return getPromotedComponentService((CompositeService)service); + + } else { + + // Found a non-composite service + return componentService; + } + } else { + + // No promoted service + return null; + } + } + + /** + * Follow a service promotion chain down to the innermost (non-composite) component. + * + * @param compositeService + * @return + */ + public Component getPromotedComponent(CompositeService compositeService) { + ComponentService componentService = compositeService.getPromotedService(); + if (componentService != null) { + Service service = componentService.getService(); + if (componentService.getName() != null && service instanceof CompositeService) { + + // Continue to follow the service promotion chain + return getPromotedComponent((CompositeService)service); + + } else { + + // Found a non-composite service + return compositeService.getPromotedComponent(); + } + } else { + + // No promoted service + return null; + } + } + + public synchronized ServiceBindingProvider getBindingProvider() { + resolve(); + if (bindingProvider == null) { + BindingProviderFactory factory = + (BindingProviderFactory)providerFactories.getProviderFactory(getBinding().getClass()); + if (factory == null) { + throw new ServiceRuntimeException("No provider factory is registered for binding " + getBinding() + .getType()); + } + this.bindingProvider = factory.createServiceBindingProvider(this); + } + return bindingProvider; + } + + public synchronized List getPolicyProviders() { + resolve(); + if (policyProviders == null) { + policyProviders = new ArrayList(); + for (PolicyProviderFactory factory : providerFactories.getPolicyProviderFactories()) { + PolicyProvider provider = factory.createServicePolicyProvider(this); + if (provider != null) { + policyProviders.add(provider); + } + } + } + return policyProviders; + } + + public void setBindingProvider(ServiceBindingProvider provider) { + this.bindingProvider = provider; + } + + public Contract getContract() { + return getService(); + } + + public CompositeContext getCompositeContext() { + return compositeContext; + } + + @Override + protected void reset() { + super.reset(); + this.xml = null; + } + + @Override + protected synchronized void resolve() { + if (xml != null && component == null) { + // TUSCANY-3958 - when an endpoint arrives at the remote side of the + // domain registry it's composite context is set, but to + // a default that's not that useful. We can tell because it + // doesn't set the system definitions + if (compositeContext == null || + compositeContext.getSystemDefinitions() == null) { + compositeContext = CompositeContext.getCurrentCompositeContext(); + if (compositeContext != null) { + bind(compositeContext); + } + } // end if + if (serializer != null) { + RuntimeEndpointImpl ep = (RuntimeEndpointImpl)serializer.readEndpoint(xml); + copyFrom(ep); + serializer.resolveEndpoint(this); + } else { + // In this case, we assume that we're running on a detached (non Tuscany) thread and + // as a result we need to connect back to the Tuscany environment... + ExtensionPointRegistry registry = ExtensionPointRegistryLocator.getExtensionPointRegistry(); + if( registry != null ) { + this.registry = registry; + UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); + this.interfaceContractMapper = utilities.getUtility(InterfaceContractMapper.class); + this.serializer = utilities.getUtility(EndpointSerializer.class); + RuntimeEndpointImpl ep = (RuntimeEndpointImpl)serializer.readEndpoint(xml); + // Find the actual Endpoint in the DomainRegistry + ep = findActualEP( ep, registry ); + if( ep != null ){ + copyFrom( ep ); + } // end if + } // end if + } // end if + setNormalizedWSDLContract(); + } // end if + super.resolve(); + } // end method resolve + + /** + * Find the actual Endpoint in the DomainRegistry which corresponds to the configuration described + * in a deserialized Endpoint + * @param ep The deserialized endpoint + * @param registry - the main extension point Registry + * @return the corresponding Endpoint from the DomainRegistry, or null if no match can be found + */ + private RuntimeEndpointImpl findActualEP(RuntimeEndpointImpl ep, + ExtensionPointRegistry registry) { + DomainRegistry domainRegistry = getEndpointRegistry( registry ); + + if( domainRegistry == null ) return null; + + for( Endpoint endpoint : domainRegistry.findEndpoint(ep.getURI()) ) { + // TODO: For the present, simply return the first matching endpoint + return (RuntimeEndpointImpl) endpoint; + } // end for + + return null; + } // end method findActualEP + + /** + * Get the DomainRegistry + * @param registry - the ExtensionPoint registry + * @return the DomainRegistry - will be null if the DomainRegistry cannot be found + */ + private DomainRegistry getEndpointRegistry( ExtensionPointRegistry registry) { + DomainRegistryFactory domainRegistryFactory = ExtensibleDomainRegistryFactory.getInstance(registry); + + if( domainRegistryFactory == null ) return null; + + // TODO: For the moment, just use the first (and only!) DomainRegistry... + DomainRegistry domainRegistry = (DomainRegistry) domainRegistryFactory.getEndpointRegistries().toArray()[0]; + + return domainRegistry; + } // end method + + public InterfaceContract getBindingInterfaceContract() { + resolve(); + if (bindingInterfaceContract != null) { + return bindingInterfaceContract; + } + bindingInterfaceContract = getBindingProvider().getBindingInterfaceContract(); + if (bindingInterfaceContract == null) { + bindingInterfaceContract = getComponentServiceInterfaceContract(); + } + if (bindingInterfaceContract == null) { + bindingInterfaceContract = getComponentTypeServiceInterfaceContract(); + } + return bindingInterfaceContract; + } + + public InterfaceContract getComponentTypeServiceInterfaceContract() { + resolve(); + if (serviceInterfaceContract != null) { + return serviceInterfaceContract; + } + if (service == null) { + return getComponentServiceInterfaceContract(); + } + serviceInterfaceContract = getLeafContract(service).getInterfaceContract(); + if (serviceInterfaceContract == null) { + serviceInterfaceContract = getComponentServiceInterfaceContract(); + } + return serviceInterfaceContract; + } + + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + this.uri = in.readUTF(); + this.xml = in.readUTF(); + this.interfaceContractXML = in.readUTF(); +/* + this.wsdlCallback = in.readUTF(); +*/ + + } + + public void writeExternal(ObjectOutput out) throws IOException { + out.writeUTF(getURI()); + if (serializer == null && xml != null) { + out.writeUTF(xml); + } else { + if (serializer != null) { + out.writeUTF(serializer.write(this)); + } else { + throw new IllegalStateException("No serializer is configured"); + } + } + + if (interfaceContractXML == null) { + interfaceContractXML = getXMLFromTuscanyInterfaceContract(); + } + out.writeUTF(interfaceContractXML); + } + + public String getAsXML() { + if (xml == null) { + this.xml = serializer.write(this); + } + return xml; + } + + private String getXMLFromTuscanyInterfaceContract() throws IOException{ + String interfaceContract = null; + try { + InterfaceContractProcessor processor = new InterfaceContractProcessor(registry); + ProcessorContext context = new ProcessorContext(); + FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + XMLOutputFactory outputFactory = modelFactories.getFactory(XMLOutputFactory.class); + XMLStreamWriter writer = outputFactory.createXMLStreamWriter(bos); + processor.write(getComponentServiceInterfaceContract(), writer, context); + writer.close(); + interfaceContract = bos.toString(); + } catch (Exception ex){ + throw new IOException(ex); + } + //System.out.println("Generated IC XML: " + interfaceContract); + return interfaceContract; + } + + private InterfaceContract getTuscanyInterfaceContractFromXML() { + InterfaceContract interfaceContract = null; + //System.out.println("Reading IC XML: " + interfaceContractXML); + if (interfaceContractXML != null && interfaceContractXML.length() > 0){ + try { + FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class); + InterfaceContractProcessor processor = new InterfaceContractProcessor(registry); + ProcessorContext context = new ProcessorContext(); + ByteArrayInputStream bis = new ByteArrayInputStream(interfaceContractXML.getBytes()); + XMLInputFactory inputFactory = modelFactories.getFactory(XMLInputFactory.class); + XMLStreamReader reader = inputFactory.createXMLStreamReader(bis); + interfaceContract = processor.read(reader, context); + } catch (Exception ex){ + new ServiceRuntimeException(ex); + } + } + return interfaceContract; + } + + private String getWsdl() { + InterfaceContract ic = getComponentServiceInterfaceContract(); + if (ic == null || ic.getInterface() == null || !ic.getInterface().isRemotable()) { + return ""; + } + + WSDLInterfaceContract wsdlIC = null; + try { + wsdlIC = (WSDLInterfaceContract)getGeneratedWSDLContract(ic); + } catch (Exception ex){ + // ignore WSDL generation errors as the service interface may have + // types that can't be converted to XML easily + return ""; + } + + if (wsdlIC == null) { + return ""; + } + + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + + try { + // write out a flattened WSDL along with XSD + WSDLInterface wsdl = (WSDLInterface)wsdlIC.getInterface(); + WSDLDefinition wsdlDefinition = wsdl.getWsdlDefinition(); + writeWSDL(outStream, wsdlDefinition); + } catch (Exception e){ + throw new RuntimeException(e); + } + + String wsdlString = outStream.toString(); + + return wsdlString; + } + + private String getWsdlCallback() { + InterfaceContract ic = getComponentServiceInterfaceContract(); + if (ic == null || ic.getCallbackInterface() == null || !ic.getCallbackInterface().isRemotable()) { + return ""; + } + + WSDLInterfaceContract wsdlIC = null; + try { + wsdlIC = (WSDLInterfaceContract)getGeneratedWSDLContract(ic); + } catch (Exception ex){ + // ignore WSDL generation errors as the service interface may have + // types that can't be converted to XML easily + return ""; + } + + if (wsdlIC == null) { + return ""; + } + + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + + try { + // write out a flattened Callback WSDL along with XSD + WSDLInterface wsdl = (WSDLInterface)wsdlIC.getCallbackInterface(); + WSDLDefinition wsdlDefinition = wsdl.getWsdlDefinition(); + writeWSDL(outStream, wsdlDefinition); + } catch (Exception e){ + throw new RuntimeException(e); + } + + String wsdlString = outStream.toString(); + + return wsdlString; + } + + /** + * Write the WSDL followed by all it's XSD + * + * @param outStream + * @param wsdlDefinition + * @throws IOException + * @throws WSDLException + */ + private void writeWSDL(OutputStream outStream, WSDLDefinition wsdlDefinition) throws IOException, WSDLException { + Definition definition = wsdlDefinition.getDefinition(); + WSDLWriter writer = WSDLFactory.newInstance().newWSDLWriter(); + String baseURI = null; + if (wsdlDefinition.getLocation() != null) { + baseURI = wsdlDefinition.getLocation().toString(); + } else { + baseURI = "generated.wsdl"; + } + outStream.write(baseURI.getBytes()); + outStream.write(separator); + writer.writeWSDL(definition, outStream); + for (WSDLDefinition importedWSDLDefintion : wsdlDefinition.getImportedDefinitions()){ + outStream.write(separator); + baseURI = importedWSDLDefintion.getLocation().toString(); + outStream.write(baseURI.getBytes()); + outStream.write(separator); + writer.writeWSDL(importedWSDLDefintion.getDefinition(), outStream); + } +/* Exclude the XSD for the time being to see if we can get comparison working + * with the operation signatures but ignoring parameter types + for (XSDefinition xsdDefinition : wsdlDefinition.getXmlSchemas()){ + // we store a reference to the schema schema. We don't need to write that out. + if (!xsdDefinition.getNamespace().equals("http://www.w3.org/2001/XMLSchema") && + xsdDefinition.getSchema() != null){ + writeSchema(outStream, xsdDefinition.getSchema()); + } + } +*/ + } + + /** + * Write an XSD + * + * @param outStream + * @param schema + * @throws IOException + */ + private void writeSchema(OutputStream outStream, XmlSchema schema) throws IOException { + // TODO - this doesn't write schema in the non-namespace namespace + if (schema != null && +/* + schema.getTargetNamespace() != null && + !schema.getTargetNamespace().equals("http://www.w3.org/2001/XMLSchema") && +*/ + schema.getNamespaceContext() != null){ + outStream.write(separator); + String baseURI = schema.getSourceURI(); + outStream.write(baseURI.getBytes()); + outStream.write(separator); + schema.write(outStream); + + for (Iterator i = schema.getIncludes().getIterator(); i.hasNext();) { + XmlSchemaObject obj = (XmlSchemaObject)i.next(); + XmlSchema ext = null; + if (obj instanceof XmlSchemaInclude) { + ext = ((XmlSchemaInclude)obj).getSchema(); + } + if (obj instanceof XmlSchemaImport) { + ext = ((XmlSchemaImport)obj).getSchema(); + } + writeSchema(outStream, ext); + } + } + } + + private void setNormalizedWSDLContract() { + if (interfaceContractXML == null || interfaceContractXML.length() < 1) { + return; + } + InterfaceContract ic = getComponentServiceInterfaceContract(); + if (ic != null) { +/* + ic.setNormalizedWSDLContract(WSDLHelper.createWSDLInterfaceContract(registry, wsdl, wsdlCallback)); +*/ + ic.setNormalizedWSDLContract(getTuscanyInterfaceContractFromXML()); + } + } + + public InterfaceContract getGeneratedWSDLContract(InterfaceContract interfaceContract) { + + if ( interfaceContract.getNormalizedWSDLContract() == null){ + if (getComponentServiceInterfaceContract() instanceof JavaInterfaceContract){ + if (contractBuilder == null){ + throw new ServiceRuntimeException("Contract builder not found while calculating WSDL contract for " + this.toString()); + } + contractBuilder.build(interfaceContract, null); + } + } + + return interfaceContract.getNormalizedWSDLContract(); + } + + @Override + public RuntimeEndpoint getDelegateEndpoint() { + return delegateEndpoint; + } + + @Override + public void setDelegateEndpoint(RuntimeEndpoint delegateEndpoint) { + this.delegateEndpoint = delegateEndpoint; + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeEndpointReferenceImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeEndpointReferenceImpl.java new file mode 100644 index 0000000000..cfc997b261 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeEndpointReferenceImpl.java @@ -0,0 +1,840 @@ +/* + * 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.core.assembly.impl; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.lang.reflect.InvocationTargetException; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.ComponentReference; +import org.apache.tuscany.sca.assembly.ComponentService; +import org.apache.tuscany.sca.assembly.CompositeReference; +import org.apache.tuscany.sca.assembly.CompositeService; +import org.apache.tuscany.sca.assembly.Contract; +import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.assembly.builder.BindingBuilder; +import org.apache.tuscany.sca.assembly.builder.BuilderContext; +import org.apache.tuscany.sca.assembly.builder.BuilderExtensionPoint; +import org.apache.tuscany.sca.assembly.impl.EndpointReferenceImpl; +import org.apache.tuscany.sca.context.CompositeContext; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.ExtensionPointRegistryLocator; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +import org.apache.tuscany.sca.core.UtilityExtensionPoint; +import org.apache.tuscany.sca.core.assembly.RuntimeAssemblyFactory; +import org.apache.tuscany.sca.core.invocation.AsyncResponseService; +import org.apache.tuscany.sca.core.invocation.ExtensibleWireProcessor; +import org.apache.tuscany.sca.core.invocation.NonBlockingInterceptor; +import org.apache.tuscany.sca.core.invocation.RuntimeInvoker; +import org.apache.tuscany.sca.core.invocation.impl.InvocationChainImpl; +import org.apache.tuscany.sca.core.invocation.impl.PhaseManager; +import org.apache.tuscany.sca.interfacedef.Compatibility; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.interfacedef.InvalidInterfaceException; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceContract; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; +import org.apache.tuscany.sca.interfacedef.wsdl.WSDLInterfaceContract; +import org.apache.tuscany.sca.invocation.Interceptor; +import org.apache.tuscany.sca.invocation.InterceptorAsync; +import org.apache.tuscany.sca.invocation.InvocationChain; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.InvokerAsyncResponse; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.invocation.Phase; +import org.apache.tuscany.sca.monitor.MonitorFactory; +import org.apache.tuscany.sca.provider.BindingProviderFactory; +import org.apache.tuscany.sca.provider.EndpointReferenceProvider; +import org.apache.tuscany.sca.provider.ImplementationAsyncProvider; +import org.apache.tuscany.sca.provider.ImplementationProvider; +import org.apache.tuscany.sca.provider.PolicyProvider; +import org.apache.tuscany.sca.provider.PolicyProviderFactory; +import org.apache.tuscany.sca.provider.ProviderFactoryExtensionPoint; +import org.apache.tuscany.sca.provider.ReferenceBindingProvider; +import org.apache.tuscany.sca.runtime.DomainRegistryFactory; +import org.apache.tuscany.sca.runtime.EndpointReferenceBinder; +import org.apache.tuscany.sca.runtime.DomainRegistry; +import org.apache.tuscany.sca.runtime.EndpointSerializer; +import org.apache.tuscany.sca.runtime.ExtensibleDomainRegistryFactory; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeComponentReference; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; +import org.apache.tuscany.sca.runtime.RuntimeEndpointReference; +import org.apache.tuscany.sca.runtime.RuntimeWireProcessor; +import org.apache.tuscany.sca.runtime.RuntimeWireProcessorExtensionPoint; +import org.apache.tuscany.sca.work.WorkScheduler; +import org.oasisopen.sca.ServiceRuntimeException; + +/** + * Runtime model for Endpoint that supports java serialization + */ +public class RuntimeEndpointReferenceImpl extends EndpointReferenceImpl implements RuntimeEndpointReference, Externalizable { + private transient CompositeContext compositeContext; + private transient RuntimeWireProcessor wireProcessor; + private transient InterfaceContractMapper interfaceContractMapper; + private transient WorkScheduler workScheduler; + private transient PhaseManager phaseManager; + private transient MessageFactory messageFactory; + private transient RuntimeInvoker invoker; + private transient DomainRegistry domainRegistry; + + private transient List chains; + private transient Map invocationChainMap = + new ConcurrentHashMap(); + private transient InvocationChain bindingInvocationChain; + + private transient EndpointReferenceBinder eprBinder; + private transient ReferenceBindingProvider bindingProvider; + private transient ProviderFactoryExtensionPoint providerFactories; + private transient List policyProviders; + private transient EndpointSerializer serializer; + + protected InterfaceContract bindingInterfaceContract; + protected InterfaceContract referenceInterfaceContract; + + //protected InterfaceContract generatedReferenceWSDLInterfaceContract; + + private String xml; + + private boolean started; + + private RuntimeEndpointReference delegateEndpointReference; + private boolean bindingURIaltered; + + /** + * No-arg constructor for Java serilization + */ + public RuntimeEndpointReferenceImpl() { + super(null); + } + + public RuntimeEndpointReferenceImpl(ExtensionPointRegistry registry) { + super(registry); + } + + protected void copyFrom(RuntimeEndpointReferenceImpl copy) { + this.xml = copy.xml; + + this.component = copy.component; + this.reference = copy.reference; + this.interfaceContract = copy.interfaceContract; + this.referenceInterfaceContract = copy.referenceInterfaceContract; + this.callbackEndpoint = copy.callbackEndpoint; + this.targetEndpoint = copy.targetEndpoint; + + this.binding = copy.binding; + this.bindingInterfaceContract = copy.interfaceContract; + this.bindingInvocationChain = copy.bindingInvocationChain; + + this.requiredIntents = copy.requiredIntents; + this.policySets = copy.policySets; + + this.uri = copy.uri; + this.unresolved = copy.unresolved; + this.status = copy.status; + + this.chains = copy.chains; + this.invocationChainMap = copy.invocationChainMap; + this.bindingProvider = copy.bindingProvider; + this.policyProviders = copy.policyProviders; + + if (this.compositeContext == null && copy.compositeContext != null) { + bind(copy.compositeContext); + } + } + + public void bind(CompositeContext compositeContext) { + this.compositeContext = compositeContext; + bind(compositeContext.getExtensionPointRegistry(), compositeContext.getEndpointRegistry()); + } + + public void bind(ExtensionPointRegistry registry, DomainRegistry domainRegistry) { + if (compositeContext == null) { + compositeContext = new CompositeContext(registry, domainRegistry); + } + this.registry = registry; + this.domainRegistry = domainRegistry; + UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); + this.eprBinder = utilities.getUtility(EndpointReferenceBinder.class); + this.interfaceContractMapper = utilities.getUtility(InterfaceContractMapper.class); + this.workScheduler = utilities.getUtility(WorkScheduler.class); + this.wireProcessor = + new ExtensibleWireProcessor(registry.getExtensionPoint(RuntimeWireProcessorExtensionPoint.class)); + + this.messageFactory = registry.getExtensionPoint(FactoryExtensionPoint.class).getFactory(MessageFactory.class); + this.invoker = new RuntimeInvoker(registry, this); + + this.phaseManager = utilities.getUtility(PhaseManager.class); + this.serializer = utilities.getUtility(EndpointSerializer.class); + this.providerFactories = registry.getExtensionPoint(ProviderFactoryExtensionPoint.class); + + this.builders = registry.getExtensionPoint(BuilderExtensionPoint.class); + this.contractBuilder = builders.getContractBuilder(); + } + + public synchronized List getInvocationChains() { + if (chains == null) { + initInvocationChains(); + } + return chains; + } + + public synchronized InvocationChain getBindingInvocationChain() { + if (bindingInvocationChain == null) { + bindingInvocationChain = new InvocationChainImpl(null, null, true, phaseManager, isAsyncInvocation()); + initReferenceBindingInvocationChains(); + } + return bindingInvocationChain; + } + + public InvocationChain getInvocationChain(Operation operation) { + InvocationChain cached = invocationChainMap.get(operation); + if (cached == null) { + for (InvocationChain chain : getInvocationChains()) { + Operation op = chain.getSourceOperation(); + + // We used to check compatibility here but this is now validated when the + // chain is created. As the chain operations are the real interface types + // they may be incompatible just because they are described in different + // IDLs + if (operation.getName().equals(op.getName())) { + invocationChainMap.put(operation, chain); + return chain; + } + } + invocationChainMap.put(operation, null); + return null; + } else { + return cached; + } + } + + public Message invoke(Message msg) { + return invoker.invoke(msg); + } + + public Object invoke(Operation operation, Object[] args) throws InvocationTargetException { + return invoker.invoke(operation, args); + } + + public Message invoke(Operation operation, Message msg) { + return invoker.invoke(operation, msg); + } + + public void invokeAsync(Operation operation, Message msg){ + msg.setOperation(operation); + invoker.invokeAsync(msg); + } + + public void invokeAsync(Message msg){ + invoker.invokeAsync(msg); + } + + public void invokeAsyncResponse(Message msg){ + // If there is a Binding Chain, invoke it first... + InvocationChain chain = this.getBindingInvocationChain(); + if( chain != null ) { + Invoker tailInvoker = chain.getTailInvoker(); + if (tailInvoker != null) { + ((InvokerAsyncResponse)tailInvoker).invokeAsyncResponse(msg); + } // end if + } // end if + + chain = this.getInvocationChain(msg.getOperation()); + Invoker tailInvoker = chain.getTailInvoker(); + ((InvokerAsyncResponse)tailInvoker).invokeAsyncResponse(msg); + } // end method invokeAsyncResponse + + /** + * Navigate the component/componentType inheritence chain to find the leaf contract + * @param contract + * @return + */ + private Contract getLeafContract(Contract contract) { + Contract prev = null; + Contract current = contract; + while (current != null) { + prev = current; + if (current instanceof ComponentReference) { + current = ((ComponentReference)current).getReference(); + } else if (current instanceof CompositeReference) { + current = ((CompositeReference)current).getPromotedReferences().get(0); + } else if (current instanceof ComponentService) { + current = ((ComponentService)current).getService(); + } else if (current instanceof CompositeService) { + current = ((CompositeService)current).getPromotedService(); + } else { + break; + } + if (current == null) { + return prev; + } + } + return current; + } + + /** + * Initialize the invocation chains + */ + private void initInvocationChains() { + InterfaceContract sourceContract = getComponentTypeReferenceInterfaceContract(); + // TODO - EPR why is this looking at the component types. The endpoint reference should have the right interface contract by this time + //InterfaceContract sourceContract = getLeafInterfaceContract(endpointReference); + + // It's the reference wire + resolveEndpointReference(); + + InterfaceContract targetContract = getBindingInterfaceContract(); + // TODO - EPR why is this looking at the component types. The endpoint should have the right interface contract by this time + //InterfaceContract targetContract = getLeafInterfaceContract(endpoint); + + if (sourceContract == null && targetContract != null) { + // TODO: until the web component introspection is brought up + try { + sourceContract = (InterfaceContract)targetContract.clone(); + } catch (CloneNotSupportedException e) { + throw new IllegalStateException(e); + } + } + + validateReferenceInterfaceCompatibility(); + + List chainList = new ArrayList(); + if(sourceContract != null && targetContract != null) { + RuntimeComponentReference reference = (RuntimeComponentReference)getReference(); + for (Operation operation : sourceContract.getInterface().getOperations()) { + Operation targetOperation = interfaceContractMapper.map(targetContract.getInterface(), operation); + if (targetOperation == null) { + throw new ServiceRuntimeException("No matching operation for " + operation.getName() + + " is found in reference " + + getComponent().getURI() + + "#" + + reference.getName()); + } + InvocationChain chain = new InvocationChainImpl(operation, targetOperation, true, phaseManager, isAsyncInvocation()); + if (operation.isNonBlocking()) { + addNonBlockingInterceptor(chain); + } + chainList.add(chain); + addReferenceBindingInterceptor(chain, operation); + } + } + + // Set the chains until it's fully populated. If we initialize too early, any exception could + // leave this endpoint reference in a wrong state with an empty chain. + chains = chainList; + wireProcessor.process(this); + + // reset the binding uri altered flag + bindingURIaltered = false; + + if (isAsyncInvocation()){ + // Fix up all of the operation chain response paths to point back to the implementation provided + // async response handler + //ImplementationProvider implementationProvider = ((RuntimeComponent)getComponent()).getImplementationProvider(); + RuntimeComponentReference theReference = (RuntimeComponentReference)this.getReference(); + RuntimeComponent theComponent = theReference.getComponent(); + ImplementationProvider implementationProvider = theComponent.getImplementationProvider(); + if (implementationProvider instanceof ImplementationAsyncProvider){ + for (InvocationChain chain : getInvocationChains()){ + InvokerAsyncResponse asyncResponseInvoker = ((ImplementationAsyncProvider)implementationProvider).createAsyncResponseInvoker(chain.getSourceOperation()); + if (chain.getHeadInvoker() instanceof InterceptorAsync){ + ((InterceptorAsync)chain.getHeadInvoker()).setPrevious(asyncResponseInvoker); + } else { + //TODO - throw error once the old async code is removed + } // end if + } // end for + } // end if + } // end if + } // end method initInvocationChains + + /** + * Check that endpoint reference has compatible interface at the component and binding ends. + * The user can specify the interfaces at both ends so there is a danger that they won't be compatible. + * There is checking in the activator but of course endpoint references may not have a binding assigned + * until final resolution. + */ + public void validateReferenceInterfaceCompatibility() { + + InterfaceContract referenceContract = getComponentReferenceInterfaceContract(); + InterfaceContract bindingContract = getBindingInterfaceContract(); + + if ((referenceContract != null) && + (bindingContract != null)){ + + boolean bindingHasCallback = bindingContract.getCallbackInterface() != null; + + try { + // Use the normalized contract if the interface types are different or if + // a normalized contract has been previously generate, for example, by virtue + // of finding a JAXWS annotation on a Java class that references a WSDL file + if (referenceContract.getClass() != bindingContract.getClass() || + referenceContract.getNormalizedWSDLContract() != null || + bindingContract.getNormalizedWSDLContract() != null) { + interfaceContractMapper.checkCompatibility(getGeneratedWSDLContract(referenceContract), + getGeneratedWSDLContract(bindingContract), + Compatibility.SUBSET, + !bindingHasCallback, // ignore callbacks if binding doesn't have one + false); + } else { + interfaceContractMapper.checkCompatibility(referenceContract, + bindingContract, + Compatibility.SUBSET, + !bindingHasCallback, // ignore callbacks if binding doesn't have one + false); + } + } catch (Exception ex){ + throw new ServiceRuntimeException("Component " + + this.getComponent().getName() + + " Reference " + + getReference().getName() + + " interface is incompatible with the interface of the reference binding " + + getBinding().getName() + + " - " + + ex.getMessage() + + " - [" + this.toString() + "]"); + } + } + } + + /** + * This code used to be in the activator but has moved here as + * the endpoint reference may not now be resolved until the wire + * is first used + */ + private void resolveEndpointReference() { + resolve(); + + eprBinder.bindRunTime(domainRegistry, this); + + // start the binding provider + final ReferenceBindingProvider bindingProvider = getBindingProvider(); + + if (bindingProvider != null) { + // Allow bindings to add shutdown hooks. Requires RuntimePermission shutdownHooks in policy. + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + bindingProvider.start(); + return null; + } + }); + } + for (PolicyProvider policyProvider : getPolicyProviders()) { + policyProvider.start(); + } + + started = true; + + Contract ref = getReference(); + String refName = ref.getName(); + if (!refName.startsWith("$self$.") && !refName.startsWith("$sca.client$.") && !ref.isForCallback()) + compositeContext.getEndpointRegistry().addEndpointReference(this); + + // InterfaceContract bindingContract = getBindingInterfaceContract(); + // endpoint.setInterfaceContract(bindingContract); + } + + private void initReferenceBindingInvocationChains() { + + // add the binding interceptors to the reference binding wire + ReferenceBindingProvider provider = getBindingProvider(); + if ((provider != null) && (provider instanceof EndpointReferenceProvider)) { + ((EndpointReferenceProvider)provider).configure(); + } + + // add the policy interceptors to the service binding wire + // find out which policies are active + for (PolicyProvider p : getPolicyProviders()) { + Interceptor interceptor = p.createBindingInterceptor(); + if (interceptor != null) { + bindingInvocationChain.addInterceptor(interceptor); + } + } + } + + public void rebuild() { + // TODO - can we use the idea of setTarget to rebuild the wire? + // used at the moment by binding.sca when it resets the + // source interface contract for local wires + this.chains = null; + invocationChainMap.clear(); + + if (getStatus() == EndpointReference.Status.WIRED_TARGET_FOUND_AND_MATCHED){ + setStatus(EndpointReference.Status.NOT_CONFIGURED); + } + + // TODO - cheating here as I fixed the RuntimeComponentService code + // to call this when it resets the interface contract + //endpointReference.setInterfaceContract(epr.getInterfaceContract()); + } + + /** + * Add the interceptor for a reference binding + * + * @param reference + * @param binding + * @param chain + * @param operation + */ + private void addReferenceBindingInterceptor(InvocationChain chain, Operation operation) { + ReferenceBindingProvider provider = getBindingProvider(); + if (provider != null) { + Invoker invoker = provider.createInvoker(operation); + if (invoker != null) { + chain.addInvoker(invoker); + } + } + List pps = getPolicyProviders(); + if (pps != null) { + for (PolicyProvider p : pps) { + Interceptor interceptor = p.createInterceptor(operation); + if (interceptor != null) { + chain.addInterceptor(interceptor); + } + } + } + } + + /** + * Add a non-blocking interceptor if the reference binding needs it + * + * @param reference + * @param binding + * @param chain + */ + private void addNonBlockingInterceptor(InvocationChain chain) { + ReferenceBindingProvider provider = getBindingProvider(); + if (provider != null) { + boolean supportsOneWayInvocation = provider.supportsOneWayInvocation(); + if (!supportsOneWayInvocation) { + chain.addInterceptor(Phase.REFERENCE, new NonBlockingInterceptor(workScheduler)); + } + } + } + + /** + * @see java.lang.Object#clone() + */ + @Override + public Object clone() throws CloneNotSupportedException { + RuntimeEndpointReferenceImpl copy = (RuntimeEndpointReferenceImpl)super.clone(); + copy.invoker = new RuntimeInvoker(registry, copy); + return copy; + } + + public boolean isOutOfDate() { + resolve(); + return bindingURIaltered || eprBinder.isOutOfDate(domainRegistry, this); + } + + public synchronized ReferenceBindingProvider getBindingProvider() { + resolve(); + // For the case that binding.sca is implemented by another binding + if (binding == null) { + return null; + } + if (bindingProvider == null) { + BindingProviderFactory factory = + (BindingProviderFactory)providerFactories.getProviderFactory(getBinding().getClass()); + if (factory == null) { + throw new ServiceRuntimeException("No provider factory is registered for binding " + getBinding() + .getType()); + } + this.bindingProvider = factory.createReferenceBindingProvider(this); + } + return bindingProvider; + } + + public void setBindingProvider(ReferenceBindingProvider bindingProvider) { + this.bindingProvider = bindingProvider; + } + + public synchronized List getPolicyProviders() { + resolve(); + if (policyProviders == null) { + policyProviders = new ArrayList(); + for (PolicyProviderFactory factory : providerFactories.getPolicyProviderFactories()) { + PolicyProvider provider = factory.createReferencePolicyProvider(this); + if (provider != null) { + policyProviders.add(provider); + } + } + } + return policyProviders; + } + + public void unbind() { + bindingInvocationChain = null; + chains = null; + bindingProvider = null; + policyProviders = null; + invocationChainMap.clear(); + } + + public Contract getContract() { + return getReference(); + } + + public CompositeContext getCompositeContext() { + return compositeContext; + } + + public InterfaceContract getBindingInterfaceContract() { + resolve(); + if (bindingInterfaceContract != null) { + return bindingInterfaceContract; + } + ReferenceBindingProvider provider = getBindingProvider(); + if (provider != null) { + bindingInterfaceContract = provider.getBindingInterfaceContract(); + } + if (bindingInterfaceContract == null) { + bindingInterfaceContract = getComponentReferenceInterfaceContract(); + } + if (bindingInterfaceContract == null) { + bindingInterfaceContract = getComponentTypeReferenceInterfaceContract(); + } + return bindingInterfaceContract; + } + + public InterfaceContract getComponentTypeReferenceInterfaceContract() { + resolve(); + if (referenceInterfaceContract != null) { + return referenceInterfaceContract; + } + if (reference == null) { + return getComponentReferenceInterfaceContract(); + } + referenceInterfaceContract = getLeafContract(reference).getInterfaceContract(); + if (referenceInterfaceContract == null) { + referenceInterfaceContract = getComponentReferenceInterfaceContract(); + } + return referenceInterfaceContract; + } + + @Override + protected synchronized void resolve() { + if (xml != null && component == null) { + if (compositeContext == null) { + compositeContext = CompositeContext.getCurrentCompositeContext(); + if (compositeContext != null) { + bind(compositeContext); + } + } + if (serializer != null) { + RuntimeEndpointReferenceImpl epr = (RuntimeEndpointReferenceImpl)serializer.readEndpointReference(xml); + copyFrom(epr); + } else { + // In this case, we assume that we're running on a detached (non Tuscany) thread and + // as a result we need to connect back to the Tuscany environment... + ExtensionPointRegistry registry = ExtensionPointRegistryLocator.getExtensionPointRegistry(); + if( registry != null ) { + this.registry = registry; + UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); + this.serializer = utilities.getUtility(EndpointSerializer.class); + RuntimeEndpointReferenceImpl epr = (RuntimeEndpointReferenceImpl)serializer.readEndpointReference(xml); + // Find the actual Endpoint in the DomainRegistry + epr = findActualEPR( epr, registry ); + if( epr != null ){ + copyFrom( epr ); + } // end if + } // end if + } // end if + } + super.resolve(); + } // end method resolve + + /** + * Find the actual EndpointReference in the DomainRegistry which corresponds to the configuration described + * in a deserialized EndpointReference + * @param ep The deserialized endpointReference + * @param registry - the main extension point Registry + * @return the corresponding EndpointReference from the DomainRegistry, or null if no match can be found + */ + private RuntimeEndpointReferenceImpl findActualEPR(RuntimeEndpointReferenceImpl epr, + ExtensionPointRegistry registry) { + // Get the DomainRegistry + DomainRegistryFactory domainRegistryFactory = ExtensibleDomainRegistryFactory.getInstance(registry); + if( domainRegistryFactory == null ) return null; + + // TODO: For the moment, just use the first (and only!) DomainRegistry... + DomainRegistry domainRegistry = (DomainRegistry) domainRegistryFactory.getEndpointRegistries().toArray()[0]; + if( domainRegistry == null ) return null; + + for( EndpointReference epReference : domainRegistry.getEndpointReferences() ) { + // TODO: For the present, simply return the first matching endpointReference + if( epReference.getURI().equals(epr.getURI()) ) { + return (RuntimeEndpointReferenceImpl) epReference; + } // end if + } // end for + + return null; + } // end method findActualEPR + + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + this.uri = in.readUTF(); + this.xml = in.readUTF(); + } + + public void writeExternal(ObjectOutput out) throws IOException { + out.writeUTF(getURI()); + if (serializer == null && xml != null) { + out.writeUTF(xml); + } else { + if (serializer != null) { + out.writeUTF(serializer.write(this)); + } else { + throw new IllegalStateException("No serializer is configured"); + } + } + } + + public boolean isStarted() { + return started; + } + + public InterfaceContract getGeneratedWSDLContract(InterfaceContract interfaceContract) { + + if ( interfaceContract.getNormalizedWSDLContract() == null){ + if (getComponentReferenceInterfaceContract() instanceof JavaInterfaceContract){ + if (contractBuilder == null){ + throw new ServiceRuntimeException("Contract builder not found while calculating WSDL contract for " + this.toString()); + } + contractBuilder.build(interfaceContract, null); + } + } + + return interfaceContract.getNormalizedWSDLContract(); + } + + public void createAsyncCallbackEndpoint(){ + CompositeContext compositeContext = getCompositeContext(); + FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class); + RuntimeAssemblyFactory assemblyFactory = (RuntimeAssemblyFactory)modelFactories.getFactory(AssemblyFactory.class); + + RuntimeEndpoint endpoint = (RuntimeEndpoint)assemblyFactory.createEndpoint(); + endpoint.bind(compositeContext); + endpoint.setComponent(getComponent()); + + // Create pseudo-service + ComponentService service = assemblyFactory.createComponentService(); + JavaInterfaceFactory javaInterfaceFactory = + (JavaInterfaceFactory)modelFactories.getFactory(JavaInterfaceFactory.class); + JavaInterfaceContract interfaceContract = javaInterfaceFactory.createJavaInterfaceContract(); + try { + interfaceContract.setInterface(javaInterfaceFactory.createJavaInterface(AsyncResponseService.class)); + } catch (InvalidInterfaceException e1) { + // Nothing to do here - will not happen + } // end try + + service.setInterfaceContract(interfaceContract); + + String serviceName = getReference().getName() + "_asyncCallback"; + service.setName(serviceName); + service.getEndpoints().add(endpoint); + service.setForCallback(true); + endpoint.setService(service); + + // Set pseudo-service onto the component + getComponent().getServices().add(service); + + // if the reference has a WSDL contract reset the response endpoint to be WSDL also + InterfaceContract referenceInterfaceContract = getComponentTypeReferenceInterfaceContract(); + if (referenceInterfaceContract instanceof WSDLInterfaceContract){ + WSDLInterfaceContract wsdlInterfaceContract = (WSDLInterfaceContract)endpoint.getGeneratedWSDLContract(interfaceContract); + service.setInterfaceContract(wsdlInterfaceContract); + } + + // Create a binding + // Mike had to go via the XML but I don't remember why + Binding binding = null; + try { + binding = (Binding)getBinding().clone(); + } catch (Exception ex){ + // + } + String callbackURI = "/" + component.getName() + "/" + service.getName(); + binding.setURI(callbackURI); + + BuilderExtensionPoint builders = registry.getExtensionPoint(BuilderExtensionPoint.class); + BindingBuilder builder = builders.getBindingBuilder(binding.getType()); + if (builder != null) { + org.apache.tuscany.sca.assembly.builder.BuilderContext builderContext = new BuilderContext(registry); + builder.build(component, service, binding, builderContext, true); + } // end if + + endpoint.setBinding(binding); + + // Need to establish policies here (binding has some...) + endpoint.getRequiredIntents().addAll(getRequiredIntents()); + endpoint.getPolicySets().addAll(getPolicySets()); + String epURI = getComponent().getName() + "#service-binding(" + serviceName + "/" + serviceName + ")"; + endpoint.setURI(epURI); + endpoint.setUnresolved(false); + + setCallbackEndpoint(endpoint); + } + + @Override + public RuntimeEndpointReference getDelegateEndpointReference() { + return delegateEndpointReference; + } + + @Override + public void setDelegateEndpointReference(RuntimeEndpointReference delegateEndpointReference) { + this.delegateEndpointReference = delegateEndpointReference; + } + + /** + * Gets the async response invoker for an asynchronous invocation. + */ + public InvokerAsyncResponse getAsyncResponseInvoker(Operation op) { + InvocationChain chain = getInvocationChain(op); + Invoker headInvoker = chain.getHeadInvoker(); + if( headInvoker instanceof InterceptorAsync ) { + InvokerAsyncResponse responseInvoker = ((InterceptorAsync)headInvoker).getPrevious(); + return responseInvoker; + } + return null; + } + + public void setBindingURI(String uri) { + binding.setURI(uri); + bindingURIaltered = true; + BindingBuilder builder = builders.getBindingBuilder(binding.getType()); + if (builder != null) { + BuilderContext builderContext = new BuilderContext(null, null, null); + builder.build(component, reference, binding, builderContext, true); + } + } + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/WSDLHelper.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/WSDLHelper.java new file mode 100644 index 0000000000..c677b99b93 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/WSDLHelper.java @@ -0,0 +1,514 @@ +/* + * 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.core.assembly.impl; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.net.URI; +import java.net.URL; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.wsdl.Definition; +import javax.wsdl.PortType; +import javax.wsdl.Types; +import javax.wsdl.WSDLException; +import javax.wsdl.extensions.ExtensibilityElement; +import javax.wsdl.extensions.UnknownExtensibilityElement; +import javax.wsdl.extensions.schema.Schema; +import javax.wsdl.xml.WSDLLocator; +import javax.wsdl.xml.WSDLReader; + +import org.apache.tuscany.sca.contribution.Contribution; +import org.apache.tuscany.sca.contribution.ContributionFactory; +import org.apache.tuscany.sca.contribution.processor.ExtensibleURLArtifactProcessor; +import org.apache.tuscany.sca.contribution.processor.ProcessorContext; +import org.apache.tuscany.sca.contribution.processor.URLArtifactProcessorExtensionPoint; +import org.apache.tuscany.sca.contribution.resolver.ExtensibleModelResolver; +import org.apache.tuscany.sca.contribution.resolver.ModelResolver; +import org.apache.tuscany.sca.contribution.resolver.ModelResolverExtensionPoint; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +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.xsd.XSDFactory; +import org.apache.tuscany.sca.xsd.XSDefinition; +import org.apache.tuscany.sca.xsd.xml.XSDModelResolver; +import org.apache.ws.commons.schema.XmlSchema; +import org.apache.ws.commons.schema.XmlSchemaCollection; +import org.apache.ws.commons.schema.resolver.DefaultURIResolver; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.InputSource; + +public class WSDLHelper { + + /** + * This creates a WSDLInterfaceContract from a WSDL document + * TODO: Presently this writes the wsdl string to a temporary file which is then used by the Tuscany contribution + * code to turn the wsdl into the correctly populated Tuscany model objects. There must/should be a way to have + * that happen without needing the external file but i've not been able to find the correct configuration to + * get that to happen with all the schema objects created correctly. + */ +/* + public static WSDLInterfaceContract createWSDLInterfaceContractViaFile(ExtensionPointRegistry registry, String wsdl) { + File wsdlFile = null; + try { + + wsdlFile = writeToFile(wsdl); + System.out.println("wsdl: " + wsdlFile); + + FactoryExtensionPoint fep = registry.getExtensionPoint(FactoryExtensionPoint.class); + URLArtifactProcessorExtensionPoint apep = registry.getExtensionPoint(URLArtifactProcessorExtensionPoint.class); + ExtensibleURLArtifactProcessor aproc = new ExtensibleURLArtifactProcessor(apep); + ProcessorContext ctx = new ProcessorContext(); + + ContributionFactory cf = fep.getFactory(ContributionFactory.class); + final Contribution c = cf.createContribution(); + c.setURI("temp"); + c.setLocation(wsdlFile.toURI().toURL().toString()); + c.setModelResolver(new ExtensibleModelResolver(c, registry.getExtensionPoint(ModelResolverExtensionPoint.class), fep)); + + WSDLDefinition wd = aproc.read(null, new URI("temp.wsdl"), wsdlFile.toURI().toURL(), ctx, WSDLDefinition.class); + c.getModelResolver().addModel(wd, ctx); + c.getModelResolver().resolveModel(WSDLDefinition.class, wd, ctx); + PortType pt = (PortType)wd.getDefinition().getAllPortTypes().values().iterator().next(); + + WSDLFactory wsdlFactory = registry.getExtensionPoint(FactoryExtensionPoint.class).getFactory(WSDLFactory.class); + WSDLInterface nwi = wsdlFactory.createWSDLInterface(pt, wd, c.getModelResolver(), null); + nwi.setWsdlDefinition(wd); + WSDLInterfaceContract wsdlIC = wsdlFactory.createWSDLInterfaceContract(); + wsdlIC.setInterface(nwi); + + wsdlFile.delete(); + + return wsdlIC; + +// } catch (InvalidWSDLException e) { +// //* TODO: Also, this doesn't seem to work reliably and sometimes the schema objects don't get built correctly +// //* org.apache.tuscany.sca.interfacedef.wsdl.impl.InvalidWSDLException: Element cannot be resolved: {http://sample/}sayHello +// //* at org.apache.tuscany.sca.interfacedef.wsdl.impl.WSDLOperationIntrospectorImpl$WSDLPart.(WSDLOperationIntrospectorImpl.java:276) +// //* It seems like it works ok for me with IBM JDK but not with a Sun one +// // I'm still trying to track this down but committing like this to see if anyone has any ideas +// e.printStackTrace(); +// return null; + + } catch(Exception e) { + throw new RuntimeException(e); + } finally { + if (wsdlFile != null) { + wsdlFile.delete(); + } + } + } + + private static File writeToFile(String wsdl) throws FileNotFoundException, IOException { + File f = File.createTempFile("endpoint", ".wsdl"); + Writer out = new OutputStreamWriter(new FileOutputStream(f)); + try { + out.write(wsdl); + } + finally { + out.close(); + } + return f; + } +*/ + + /* + * A rework of the above code that + * + * 1 - doesn't use a intermediate file + * 2 - doesn't use the Tuscany contribution code + * 3 - takes care of imports/includes + * 4 - takes care of call and callback interfaces + * + * Re. point 1 - In theory it's neater but the Tuscany processors/resolvers don't know how to do this + * so there is quite a bit of code here. I don't really like it but we can sleep on it + * and look at how to integrate it into the runtime or even take a different approach to + * moving the interface about + */ + public static WSDLInterfaceContract createWSDLInterfaceContract(ExtensionPointRegistry registry, String wsdl, String wsdlCallback) { + FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class); + org.apache.tuscany.sca.interfacedef.wsdl.WSDLFactory wsdlFactory = modelFactories.getFactory(org.apache.tuscany.sca.interfacedef.wsdl.WSDLFactory.class); + + WSDLInterfaceContract wsdlInterfaceContract = wsdlFactory.createWSDLInterfaceContract(); + wsdlInterfaceContract.setInterface(createWSDLInterface(registry, wsdl)); + if (wsdlCallback != null && wsdlCallback.length() > 0){ + wsdlInterfaceContract.setCallbackInterface(createWSDLInterface(registry, wsdlCallback)); + } + + return wsdlInterfaceContract; + } + + /** + * Read a single WSDL interface and it's associated XSD from a string + * + * @param registry + * @param wsdl + * @return + */ + public static WSDLInterface createWSDLInterface(ExtensionPointRegistry registry, String wsdl) { + try { + // Read all the WSDL and XSD in from the wsdl string. The WSDL and XSD appear sequentially in + // the following format: + // + // filename + // _X_ + // wsdl xml + // _X_ + // xsd xml + // _X_ + // xsd xml + // + // So we need to read each WSDL and XSD separately and then fix up the includes/imports as appropriate + String xmlArray[] = wsdl.split("_X_"); + + String topWSDLLocation = null; + Map xmlMap = new HashMap(); + + for (int i = 0; i < xmlArray.length; i = i + 2){ + String location = xmlArray[i]; + String xml = xmlArray[i+1]; + // strip the file name out of the location + location = location.substring(location.lastIndexOf("/") + 1); + + if (location.endsWith(".wsdl")){ + xmlMap.put(location, + new WSDLInfo(xmlArray[i], + xml)); + + if (topWSDLLocation == null){ + topWSDLLocation = location; + } + } else { + xmlMap.put(location, + new XSDInfo(xmlArray[i], + xml)); + } + } + + FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class); + org.apache.tuscany.sca.interfacedef.wsdl.WSDLFactory wsdlFactory = modelFactories.getFactory(org.apache.tuscany.sca.interfacedef.wsdl.WSDLFactory.class); + XSDFactory xsdFactory = modelFactories.getFactory(XSDFactory.class); + XmlSchemaCollection schemaCollection = new XmlSchemaCollection(); + schemaCollection.setSchemaResolver(new XSDURIResolverImpl(xmlMap)); + ContributionFactory contributionFactory = modelFactories.getFactory(ContributionFactory.class); + final org.apache.tuscany.sca.contribution.Contribution contribution = contributionFactory.createContribution(); + ProcessorContext processorContext = new ProcessorContext(); + + ExtensibleModelResolver extensibleResolver = new ExtensibleModelResolver(contribution, registry.getExtensionPoint(ModelResolverExtensionPoint.class), modelFactories); + ModelResolver wsdlResolver = (ModelResolver)extensibleResolver.getModelResolverInstance(WSDLDefinition.class); + XSDModelResolver xsdResolver = (XSDModelResolver)extensibleResolver.getModelResolverInstance(XSDefinition.class); + contribution.setURI("temp"); + contribution.setLocation(topWSDLLocation); + contribution.setModelResolver(extensibleResolver); + + // read + for (XMLString xmlString : xmlMap.values()){ + if (xmlString instanceof WSDLInfo){ + WSDLReader reader; + try { + reader = AccessController.doPrivileged(new PrivilegedExceptionAction() { + public WSDLReader run() throws WSDLException { + return javax.wsdl.factory.WSDLFactory.newInstance().newWSDLReader(); + } + }); + } catch (PrivilegedActionException e){ + throw (WSDLException)e.getException(); + } + reader.setFeature("javax.wsdl.verbose", false); + reader.setFeature("javax.wsdl.importDocuments", true); + final WSDLLocatorImpl locator = new WSDLLocatorImpl(xmlString.getBaseURI(), xmlMap); + final WSDLReader freader = reader; + Definition readDefinition; + try { + readDefinition = AccessController.doPrivileged(new PrivilegedExceptionAction() { + public Definition run() throws WSDLException { + return freader.readWSDL(locator); + } + }); + } catch (PrivilegedActionException e){ + throw (WSDLException)e.getException(); + } + + WSDLDefinition wsdlDefinition = wsdlFactory.createWSDLDefinition(); + wsdlDefinition.setDefinition(readDefinition); + wsdlDefinition.setLocation(new URI(xmlString.getBaseURI())); + + ((WSDLInfo)xmlString).setWsdlDefintion(wsdlDefinition); + wsdlResolver.addModel(wsdlDefinition, processorContext); + + } else { + InputStream inputStream = new ByteArrayInputStream(xmlString.getXmlString().getBytes()); + InputSource inputSource = new InputSource(inputStream); + inputSource.setSystemId(xmlString.getBaseURI()); + XmlSchema schema = schemaCollection.read(inputSource, null); + inputStream.close(); + + XSDefinition xsdDefinition = xsdFactory.createXSDefinition(); + xsdDefinition.setSchema(schema); + + ((XSDInfo)xmlString).setXsdDefinition(xsdDefinition); + xsdResolver.addModel(xsdDefinition, processorContext); + } + } + + // resolve + for (XMLString xmlString : xmlMap.values()){ + if (xmlString instanceof WSDLInfo){ + WSDLDefinition wsdlDefinition = ((WSDLInfo)xmlString).getWsdlDefintion(); + + // link to imports + for (Map.Entry> entry : + ((Map>)wsdlDefinition.getDefinition().getImports()).entrySet()) { + for (javax.wsdl.Import imp : entry.getValue()) { + String wsdlName = imp.getDefinition().getDocumentBaseURI(); + WSDLInfo wsdlInfo = (WSDLInfo)xmlMap.get(getFilenameWithoutPath(wsdlName)); + wsdlDefinition.getImportedDefinitions().add(wsdlInfo.getWsdlDefintion()); + } + } + + // extract any in-line types in the Tuscany model + Types types = wsdlDefinition.getDefinition().getTypes(); + if ( types != null){ +/* read XSD from WSDL rather than from registry + for (int i=0; i < types.getExtensibilityElements().size(); i++){ + + String schemaName = xmlString.getBaseURI() + "#" + i++; + XSDInfo xsdInfo = (XSDInfo)xmlMap.get(getFilenameWithoutPath(schemaName)); + if (xsdInfo != null){ + wsdlDefinition.getXmlSchemas().add(xsdInfo.getXsdDefinition()); + } +*/ + int index = 0; + for (Object ext : types.getExtensibilityElements()) { + ExtensibilityElement extElement = (ExtensibilityElement)ext; + Element element = null; + if (extElement instanceof Schema) { + element = ((Schema)extElement).getElement(); + } + if (element != null) { + XSDefinition xsDefinition = xsdFactory.createXSDefinition(); + xsDefinition.setUnresolved(true); + xsDefinition.setNamespace(element.getAttribute("targetNamespace")); + xsDefinition.setDocument(element.getOwnerDocument()); + XmlSchema schema = schemaCollection.read(element, null); + xsDefinition.setSchema(schema); + xsDefinition.setLocation(URI.create(xmlString.getBaseURI() + "#" + index)); + wsdlDefinition.getXmlSchemas().add(xsDefinition); + index++; + } + } + } + } else { + // TODO + } + } + + WSDLInfo topWSDL = (WSDLInfo)xmlMap.get(topWSDLLocation); + WSDLDefinition topWSDLDefinition = topWSDL.getWsdlDefintion(); + + PortType portType = (PortType)topWSDLDefinition.getDefinition().getAllPortTypes().values().iterator().next(); + WSDLInterface readWSDLInterface = wsdlFactory.createWSDLInterface(portType, topWSDLDefinition, extensibleResolver, null); + + return readWSDLInterface; + } catch(Exception e) { + throw new RuntimeException(e); + } + } + + /* + * WSDL is provided in the following string form: + * + * _X_ + * the_original_path_to_a_wsdl_file + * _X_ + * the WSDL XML + * _X_ + * the_original_path_to_a_related_xsd_file + * _X_ + * the XSD XML + * etc. + * + * This structure, and the classes that specialize it, represent this format in memory + */ + private static class XMLString { + private String baseURI; + private String xmlString; + + public XMLString(String baseURI, String xmlString){ + this.baseURI = baseURI; + this.xmlString = xmlString; + } + + public String getBaseURI() { + return baseURI; + } + + public String getXmlString() { + return xmlString; + } + } + + private static class XSDInfo extends XMLString { + + XSDefinition xsdDefinition; + + public XSDInfo(String baseURI, String xmlString) { + super(baseURI, xmlString); + } + + public void setXsdDefinition(XSDefinition xsdDefinition) { + this.xsdDefinition = xsdDefinition; + } + + public XSDefinition getXsdDefinition() { + return xsdDefinition; + } + } + + private static class WSDLInfo extends XMLString { + + WSDLDefinition wsdlDefintion; + + public WSDLInfo(String baseURI, String xmlString) { + super(baseURI, xmlString); + } + + public void setWsdlDefintion(WSDLDefinition wsdlDefintion) { + this.wsdlDefintion = wsdlDefintion; + } + + public WSDLDefinition getWsdlDefintion() { + return wsdlDefintion; + } + } + + /* + * A WSDL locator used to find WSDL in memory based on the map + * of all WSDL/XSD that have been read from the input string + */ + private static class WSDLLocatorImpl implements WSDLLocator { + private Map xmlMap; + private String baseURI; + private String latestImportURI; + + public WSDLLocatorImpl(String baseURI, Map xmlMap) { + this.baseURI = baseURI; + this.xmlMap = xmlMap; + } + + public void close() { +/* + try { + inputStream.close(); + } catch (IOException e) { + // Ignore + } +*/ + } + + public InputSource getBaseInputSource() { + return getInputSource(getFilenameWithoutPath(baseURI), xmlMap); + } + + public String getBaseURI() { + return baseURI; + } + + public InputSource getImportInputSource(String parentLocation, String importLocation) { + latestImportURI = importLocation; + return getInputSource(getFilenameWithoutPath(importLocation), xmlMap); + } + + public String getLatestImportURI() { + return latestImportURI; + } + } + + /* + * A local URIResolver used to find XSD in memory based on the map + * of all WSDL/XSD that have been read from the input string + */ + private static class XSDURIResolverImpl extends DefaultURIResolver { + + private Map xmlMap; + + public XSDURIResolverImpl(Map xmlMap) { + this.xmlMap = xmlMap; + } + + @Override + protected URL getURL(URL contextURL, String spec) throws IOException { + return super.getURL(contextURL, spec); + } + @Override + public InputSource resolveEntity(String namespace, + String schemaLocation, + String baseUri) { + return getInputSource(getFilenameWithoutPath(schemaLocation), xmlMap); + } + } + + /* + * Retrieve the input source for the given URI + */ + private static InputSource getInputSource(String uri, Map xmlMap){ + String xmlString = xmlMap.get(uri).getXmlString(); + InputStream inputStream = new ByteArrayInputStream(xmlString.getBytes()); + InputSource inputSource = new InputSource(inputStream); + inputSource.setSystemId(uri); + return inputSource; + } + + /* + * Remove path from filename so that XSD/WSDL data can be found in memory + * rather than on the remote file system + */ + private static String getFilenameWithoutPath(String filename){ + // work out what the file name is that is being imported + // XSDs imports are written out by Tuscany with an relative web address such as + // /services/AccountService?xsd=wsdl-serialize.xsd + // for the time being just string the file name off the end. We are making + // assumption that the interface doesn't involve two files with the same + // name in different locations + int xsdIndex = filename.lastIndexOf("?xsd="); + int wsdlIndex = filename.lastIndexOf("/"); + if ( xsdIndex >= 0){ + return filename.substring(xsdIndex + 5); + } else { + return filename.substring(wsdlIndex + 1); + } + // What happens with generated WSDL? + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/context/DefaultComponentContextFactory.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/context/DefaultComponentContextFactory.java new file mode 100644 index 0000000000..d2528784fd --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/context/DefaultComponentContextFactory.java @@ -0,0 +1,72 @@ +/* + * 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.core.context; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.context.ComponentContextFactory; +import org.apache.tuscany.sca.context.CompositeContext; +import org.apache.tuscany.sca.context.ContextFactoryExtensionPoint; +import org.apache.tuscany.sca.context.PropertyValueFactory; +import org.apache.tuscany.sca.context.RequestContextFactory; +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.core.context.impl.ComponentContextImpl; +import org.apache.tuscany.sca.core.invocation.ExtensibleProxyFactory; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; +import org.apache.tuscany.sca.runtime.CompositeActivator; +import org.apache.tuscany.sca.runtime.EndpointReferenceBinder; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.oasisopen.sca.ComponentContext; + +/** + * @version $Rev$ $Date$ + */ +public class DefaultComponentContextFactory implements ComponentContextFactory { + private final ExtensionPointRegistry registry; + private AssemblyFactory assemblyFactory; + private JavaInterfaceFactory javaInterfaceFactory; + private CompositeActivator compositeActivator; + private RequestContextFactory requestContextFactory; + private PropertyValueFactory propertyFactory; + private EndpointReferenceBinder eprBinder; + private ExtensibleProxyFactory proxyFactory; + + public DefaultComponentContextFactory(ExtensionPointRegistry registry) { + this.registry = registry; + FactoryExtensionPoint factories = registry.getExtensionPoint(FactoryExtensionPoint.class); + UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); + this.assemblyFactory = factories.getFactory(AssemblyFactory.class); + this.javaInterfaceFactory = factories.getFactory(JavaInterfaceFactory.class); + this.compositeActivator = utilities.getUtility(CompositeActivator.class); + this.requestContextFactory = + registry.getExtensionPoint(ContextFactoryExtensionPoint.class).getFactory(RequestContextFactory.class); + this.propertyFactory = factories.getFactory(PropertyValueFactory.class); + this.eprBinder = utilities.getUtility(EndpointReferenceBinder.class); + this.proxyFactory = ExtensibleProxyFactory.getInstance(registry); + } + + public ComponentContext createComponentContext(CompositeContext compositeContext, RuntimeComponent component) { + return new ComponentContextImpl(registry, assemblyFactory, javaInterfaceFactory, compositeActivator, + requestContextFactory, propertyFactory, eprBinder, proxyFactory, + compositeContext, component); + } + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/context/DefaultRequestContextFactory.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/context/DefaultRequestContextFactory.java new file mode 100644 index 0000000000..ace4dc48e1 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/context/DefaultRequestContextFactory.java @@ -0,0 +1,40 @@ +/* + * 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.core.context; + +import org.apache.tuscany.sca.context.RequestContextFactory; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.context.impl.RequestContextImpl; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.oasisopen.sca.RequestContext; + +/** + * Default implementation of RequestContextFactory + */ +public class DefaultRequestContextFactory implements RequestContextFactory { + + public DefaultRequestContextFactory(ExtensionPointRegistry registry) { + } + + public RequestContext createRequestContext(RuntimeComponent component) { + return new RequestContextImpl(component); + } + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/context/ServiceReferenceExt.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/context/ServiceReferenceExt.java new file mode 100644 index 0000000000..5856ab114b --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/context/ServiceReferenceExt.java @@ -0,0 +1,41 @@ +/* + * 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.core.context; + +import java.io.Externalizable; + +import org.apache.tuscany.sca.runtime.RuntimeEndpointReference; +import org.apache.tuscany.sca.runtime.TuscanyServiceReference; + +/** + * Extended ServiceReference + */ +public interface ServiceReferenceExt extends TuscanyServiceReference, Externalizable { + + /** + * Return the EndpointReference that sits behind this service reference + * @return endpoint reference + */ + RuntimeEndpointReference getEndpointReference(); + + B getProxy(); + void setProxy(B proxy); + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/CallbackServiceReferenceImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/CallbackServiceReferenceImpl.java new file mode 100644 index 0000000000..4c206ec5db --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/CallbackServiceReferenceImpl.java @@ -0,0 +1,292 @@ +/* + * 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.core.context.impl; + +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.Endpoint; +import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.assembly.SCABinding; +import org.apache.tuscany.sca.assembly.builder.BindingBuilder; +import org.apache.tuscany.sca.assembly.builder.BuilderContext; +import org.apache.tuscany.sca.context.CompositeContext; +import org.apache.tuscany.sca.context.ThreadMessageContext; +import org.apache.tuscany.sca.core.invocation.CallbackHandler; +import org.apache.tuscany.sca.core.invocation.Constants; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; +import org.apache.tuscany.sca.runtime.RuntimeEndpointReference; +import org.oasisopen.sca.ServiceRuntimeException; + +/** + * Represent the reference to the callback service. This class basically wraps a Tuscany EndpointReference. + * The callback EPR is selected based on the are 3 basic scenarios we are trying to cater for + * + * A/ + * + * + * callbackEPRs) { + if(!callbackEPRs.isEmpty()) { + RuntimeEndpointReference epr = (RuntimeEndpointReference) callbackEPRs.get(0); + return epr.getCompositeContext(); + } + return null; + } + + @Override + protected B createProxy() throws Exception { + return proxyFactory.createCallbackProxy(this); + } + + public RuntimeEndpointReference getCallbackEPR() { + return callbackEPR; + } + + public Endpoint getResolvedEndpoint() { + return resolvedEndpoint; + } + + private RuntimeEndpointReference selectCallbackEPR(Message msgContext) { + + // look for callback binding with same name as service binding + Endpoint to = msgContext.getTo(); + if (to == null) { + //FIXME: need better exception + throw new ServiceRuntimeException("Destination for forward call is not available"); + } + for (EndpointReference epr : callbackEPRs) { + if (epr.getBinding().getName().equals(to.getBinding().getName())) { + return (RuntimeEndpointReference) epr; + } + } + + // if no match, look for callback binding with same type as service binding + for (EndpointReference epr : callbackEPRs) { + if (epr.getBinding().getType().equals(to.getBinding().getType())) { + return (RuntimeEndpointReference) epr; + } + } + + // no suitable callback wire was found + return null; + } + + private RuntimeEndpointReference setCallbackAddress(RuntimeEndpointReference endpointReference) { + try { + + RuntimeEndpointReference epr = endpointReference; + + if (callbackHandler.getCloneCallbackWire()){ + epr = (RuntimeEndpointReference)endpointReference.clone(); + } + + // TUSCANY-3932 + // If it's the default binding then we're going to look the callback endpoint + // up in the registry. Most remote protocols, which may be used as delegates + // for binding.sca, will expect to deal with absolute URLs so flip the + // callback endpoint back to force the lookup to happen + if (epr.getBinding().getType().equals(SCABinding.TYPE)){ + // A/ create a callback endpoint to allow the + // callback lookup to take place + epr.setStatus(EndpointReference.Status.WIRED_TARGET_NOT_FOUND); + + // if an endpoint it provided in the forward message use it or + // if not create one + if (resolvedEndpoint == null ){ + RuntimeEndpoint callbackEndpoint = (RuntimeEndpoint)assemblyFactory.createEndpoint(); + callbackEndpoint.setURI(callbackHandler.getCallbackTargetURI()); + callbackEndpoint.setUnresolved(true); + epr.setTargetEndpoint(callbackEndpoint); + } else { + epr.setTargetEndpoint(resolvedEndpoint); + } + } else { + // B/ and C/ assume that the callback EPR is already resolved + // and set the binding URI if one is provided with the + // forward message. Some bindings may want to do other + // things to determine the callback URI to the + // CallbackHandler will be sent in the callback message + // header. This is particularly true if the clone isn't + // called above because resetting the URI will not + // be thread safe. + epr.setStatus(EndpointReference.Status.RESOLVED_BINDING); + + if ( callbackHandler.getCallbackTargetURI() != null ){ + epr.getBinding().setURI(callbackHandler.getCallbackTargetURI()); + } else { + // do nothing and rely on whatever the user has configured + // in the SCDL + } + } + + return epr; + } catch (CloneNotSupportedException e) { + // will not happen + throw new ServiceRuntimeException(e); + } + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/ComponentContextImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/ComponentContextImpl.java new file mode 100644 index 0000000000..18587b2f6d --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/ComponentContextImpl.java @@ -0,0 +1,558 @@ +/* + * 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.core.context.impl; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.ComponentProperty; +import org.apache.tuscany.sca.assembly.ComponentReference; +import org.apache.tuscany.sca.assembly.ComponentService; +import org.apache.tuscany.sca.assembly.CompositeService; +import org.apache.tuscany.sca.assembly.Endpoint; +import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.assembly.Multiplicity; +import org.apache.tuscany.sca.assembly.SCABinding; +import org.apache.tuscany.sca.assembly.Service; +import org.apache.tuscany.sca.context.CompositeContext; +import org.apache.tuscany.sca.context.PropertyValueFactory; +import org.apache.tuscany.sca.context.RequestContextFactory; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.invocation.ProxyFactory; +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.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.runtime.CompositeActivator; +import org.apache.tuscany.sca.runtime.EndpointReferenceBinder; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeComponentContext; +import org.apache.tuscany.sca.runtime.RuntimeComponentReference; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; +import org.apache.tuscany.sca.runtime.RuntimeEndpointReference; +import org.apache.tuscany.sca.runtime.TuscanyServiceReference; +import org.oasisopen.sca.RequestContext; +import org.oasisopen.sca.ServiceReference; +import org.oasisopen.sca.ServiceRuntimeException; + +/** + * Implementation of ComponentContext that delegates to a ComponentContextProvider. + * + * @version $Rev$ $Date$ + */ +public class ComponentContextImpl implements RuntimeComponentContext { + private final RuntimeComponent component; + + private final CompositeContext compositeContext; + private final CompositeActivator compositeActivator; + private final RequestContextFactory requestContextFactory; + private final ProxyFactory proxyFactory; + private final AssemblyFactory assemblyFactory; + private final JavaInterfaceFactory javaInterfaceFactory; + private final PropertyValueFactory propertyFactory; + private final EndpointReferenceBinder eprBinder; + private final ExtensionPointRegistry registry; + + public ComponentContextImpl(ExtensionPointRegistry registry, + AssemblyFactory assemblyFactory, + JavaInterfaceFactory javaInterfaceFactory, + CompositeActivator compositeActivator, + RequestContextFactory requestContextFactory, + PropertyValueFactory propertyFactory, + EndpointReferenceBinder eprBinder, + ProxyFactory proxyFactory, + CompositeContext compositeContext, + RuntimeComponent component) { + this.registry = registry; + this.assemblyFactory = assemblyFactory; + this.javaInterfaceFactory = javaInterfaceFactory; + this.compositeActivator = compositeActivator; + this.requestContextFactory = requestContextFactory; + this.propertyFactory = propertyFactory; + this.eprBinder = eprBinder; + this.proxyFactory = proxyFactory; + this.compositeContext = compositeContext; + this.component = component; + } + + public String getURI() { + return component.getURI(); + } + + public ServiceReference cast(B target) throws IllegalArgumentException { + return proxyFactory.cast(target); + } + + public B getService(Class businessInterface, String referenceName) throws IllegalArgumentException { + B service = null; + + ServiceReference serviceRef = getServiceReference(businessInterface, referenceName); + if (serviceRef != null) { + service = serviceRef.getService(); + } + + return service; + } + + public TuscanyServiceReference getServiceReference(Class businessInterface, String referenceName) + throws IllegalArgumentException { + + for (ComponentReference ref : component.getReferences()) { + if (referenceName.equals(ref.getName())) { + Multiplicity multiplicity = ref.getMultiplicity(); + if (multiplicity == Multiplicity.ZERO_N || multiplicity == Multiplicity.ONE_N) { + throw new IllegalArgumentException("Reference " + referenceName + + " has multiplicity " + + multiplicity); + } + if (ref.getEndpointReferences().size() < 1) { + return null; + } + TuscanyServiceReference sr = + getServiceReference(businessInterface, (RuntimeEndpointReference)getEndpointReference(ref)); + if (sr == null) { + throw new IllegalArgumentException("Reference " + referenceName + " is null"); + } + return sr; + } + } + throw new IllegalArgumentException("[JCA80011] Reference not found: " + referenceName); + + } + + /** + * Select an endpoint reference from the component reference + * @param ref + * @return + */ + private EndpointReference getEndpointReference(ComponentReference ref) { + List eprs = ref.getEndpointReferences(); + if (eprs.size() == 1) { + // Return 1st one + return eprs.get(0); + } else { + for (EndpointReference epr : eprs) { + // Try to see if there is an EPR using binding.sca + if (epr.getBinding().getType().equals(SCABinding.TYPE)) { + return epr; + } + } + return eprs.get(0); + } + } + + /** + * Select an endpoint reference from the component reference + * @param ref + * @return + */ + private Endpoint getEndpoint(ComponentService service, String bindingName) { + if (bindingName == null) { + // The default binding name is the name of the promoted service + bindingName = getPromotedService(service).getName(); + } + Endpoint returnEp = null; + List eps = service.getEndpoints(); + for (Endpoint ep : eps) { + Binding binding = ep.getBinding(); + if (bindingName.equals(binding.getName()) || binding.getName() == null) { + returnEp = ep; + break; + } + } + //TUSCANY-3543 + if (returnEp == null) { + returnEp = eps.get(0); + } + + return returnEp; + } + + private ComponentService getPromotedService(ComponentService componentService) { + Service service = componentService.getService(); + if (service instanceof CompositeService) { + return getPromotedService(((CompositeService)service).getPromotedService()); + } else { + return componentService; + } + + } + + /** + * Gets the value for the specified property with the specified type. + * + * @param type The type of the property value we are getting + * @param propertyName The name of the property we are getting + * @param B The class of the property value we are getting + * + * @throws ServiceRuntimeException If a Property for the specified propertyName + * is not found + * + * @see #setPropertyValueFactory(PropertyValueFactory) + */ + public B getProperty(Class type, String propertyName) { + for (ComponentProperty p : component.getProperties()) { + if (propertyName.equals(p.getName())) { + return propertyFactory.createPropertyValue(p, type); + } + } + throw new IllegalArgumentException("Property not found: " + propertyName); + } + + /** + * @param component + */ + public static ComponentService getSingleService(Component component) { + ComponentService targetService; + List services = component.getServices(); + List regularServices = new ArrayList(); + for (ComponentService service : services) { + if (service.isForCallback()) { + continue; + } + String name = service.getName(); + if (!name.startsWith("$") || name.startsWith("$dynamic$")) { + regularServices.add(service); + } + } + if (regularServices.size() == 0) { + throw new ServiceRuntimeException("No service is declared on component " + component.getURI()); + } + if (regularServices.size() != 1) { + throw new ServiceRuntimeException("More than one service is declared on component " + component.getURI() + + ". Service name is required to get the service."); + } + targetService = regularServices.get(0); + return targetService; + } + + public ServiceReference createSelfReference(Class businessInterface) { + ComponentService service = getSingleService(component); + try { + return createSelfReference(businessInterface, service); + } catch (IllegalArgumentException iae) { + throw iae; + } catch (Exception e) { + throw new ServiceRuntimeException(e.getMessage(), e); + } + } + + public ServiceReference createSelfReference(Class businessInterface, String serviceName) { + if (serviceName == null) { + return createSelfReference(businessInterface); + } + try { + String bindingName = null; + int index = serviceName.indexOf('/'); + if (index != -1) { + bindingName = serviceName.substring(index + 1); + serviceName = serviceName.substring(0, index); + } + for (ComponentService service : component.getServices()) { + if (serviceName.equals(service.getName())) { + Endpoint endpoint = getEndpoint(service, bindingName); + if (endpoint == null) { + break; + } + return getServiceReference(businessInterface, (RuntimeEndpoint)endpoint); + } + } + throw new IllegalArgumentException("Service not found: " + serviceName); + } catch (IllegalArgumentException iae) { + throw iae; + } catch (ServiceRuntimeException e) { + throw e; + } catch (Exception e) { + throw new ServiceRuntimeException(e.getMessage(), e); + } + } + + /** + * @param + * @param businessInterface + * @param service + * @return + */ + public ServiceReference createSelfReference(Class businessInterface, ComponentService service) { + try { + RuntimeEndpointReference ref = + (RuntimeEndpointReference)createEndpointReference(component, service, null, businessInterface); + ref.setComponent(component); + return getServiceReference(businessInterface, ref); + } catch (IllegalArgumentException iae) { + throw iae; + } catch (Exception e) { + throw new ServiceRuntimeException(e); + } + } + + public RequestContext getRequestContext() { + if (requestContextFactory != null) { + return requestContextFactory.createRequestContext(component); + } else { + return new RequestContextImpl(component); + } + } + + /** + * @param businessInterface + * @param reference + * @return + * @throws CloneNotSupportedException + * @throws InvalidInterfaceException + */ + public TuscanyServiceReference getServiceReference(Class businessInterface, + RuntimeEndpointReference endpointReference) { + TuscanyServiceReference result = null; + + try { + InterfaceContract interfaceContract = endpointReference.getComponentTypeReferenceInterfaceContract(); + if (businessInterface == null) { + businessInterface = (Class)((JavaInterface)interfaceContract.getInterface()).getJavaClass(); + } + RuntimeComponentReference ref = (RuntimeComponentReference)endpointReference.getReference(); + InterfaceContract refInterfaceContract = getInterfaceContract(interfaceContract, businessInterface); + if (refInterfaceContract != null) { + if (refInterfaceContract != interfaceContract) { + ref = (RuntimeComponentReference)ref.clone(); + if (interfaceContract != null) { + ref.setInterfaceContract(interfaceContract); + } else { + ref.setInterfaceContract(refInterfaceContract); + } + } + + ref.setComponent(component); + result = + new ServiceReferenceImpl(businessInterface, endpointReference, component.getComponentContext() + .getCompositeContext()); + } + } catch (IllegalArgumentException iae) { + throw iae; + } catch (Exception e) { + throw new ServiceRuntimeException(e); + } + + return result; + } + + public ServiceReference getServiceReference(Class businessInterface, RuntimeEndpoint endpoint) { + try { + if (businessInterface == null) { + InterfaceContract contract = endpoint.getBindingInterfaceContract(); + if (contract.getInterface() instanceof JavaInterface) { + businessInterface = (Class)((JavaInterface)contract.getInterface()).getJavaClass(); + } else { + contract = endpoint.getComponentTypeServiceInterfaceContract(); + if (contract.getInterface() instanceof JavaInterface) { + businessInterface = (Class)((JavaInterface)contract.getInterface()).getJavaClass(); + } + } + } + RuntimeEndpointReference ref = + (RuntimeEndpointReference)createEndpointReference(endpoint, businessInterface); + ref.setComponent(component); + return new ServiceReferenceImpl(businessInterface, ref, compositeContext); + } catch (IllegalArgumentException iae) { + throw iae; + } catch (Exception e) { + throw new ServiceRuntimeException(e); + } + } + + /** + * Create a self-reference for a component service + * @param component + * @param service + * @throws CloneNotSupportedException + * @throws InvalidInterfaceException + */ + private EndpointReference createEndpointReference(Component component, + ComponentService service, + String bindingName, + Class businessInterface) throws CloneNotSupportedException, + InvalidInterfaceException { + + Endpoint endpoint = getEndpoint(service, bindingName); + return createEndpointReference(endpoint, businessInterface); + } + + private EndpointReference createEndpointReference(Endpoint endpoint, Class businessInterface) + throws CloneNotSupportedException, InvalidInterfaceException { + Component component = endpoint.getComponent(); + ComponentService service = endpoint.getService(); + ComponentReference componentReference = assemblyFactory.createComponentReference(); + componentReference.setName("$self$." + service.getName()); + + componentReference.setCallback(service.getCallback()); + componentReference.getTargets().add(service); + componentReference.getPolicySets().addAll(service.getPolicySets()); + componentReference.getRequiredIntents().addAll(service.getRequiredIntents()); + componentReference.getBindings().add(endpoint.getBinding()); + + // For the self-reference, allows pass by reference + componentReference.setAllowsPassByReference(true); + + InterfaceContract interfaceContract = service.getInterfaceContract(); + Service componentTypeService = service.getService(); + if (componentTypeService != null && componentTypeService.getInterfaceContract() != null) { + interfaceContract = componentTypeService.getInterfaceContract(); + } + interfaceContract = getInterfaceContract(interfaceContract, businessInterface); + componentReference.setInterfaceContract(interfaceContract); + componentReference.setMultiplicity(Multiplicity.ONE_ONE); + // component.getReferences().add(componentReference); + + // create endpoint reference + EndpointReference endpointReference = assemblyFactory.createEndpointReference(); + endpointReference.setComponent(component); + endpointReference.setReference(componentReference); + endpointReference.setBinding(endpoint.getBinding()); + endpointReference.setUnresolved(false); + endpointReference.setStatus(EndpointReference.Status.WIRED_TARGET_FOUND_READY_FOR_MATCHING); + + endpointReference.setTargetEndpoint(endpoint); + + componentReference.getEndpointReferences().add(endpointReference); + ((RuntimeComponentReference)componentReference).setComponent((RuntimeComponent)component); + ((RuntimeEndpointReference)endpointReference).bind(compositeContext); + + return endpointReference; + } + + /** + * @param interfaceContract + * @param businessInterface + * @return + * @throws CloneNotSupportedException + * @throws InvalidInterfaceException + */ + private InterfaceContract getInterfaceContract(InterfaceContract interfaceContract, Class businessInterface) + throws CloneNotSupportedException, InvalidInterfaceException { + if (businessInterface == null) { + return interfaceContract; + } + if (interfaceContract == null) { + JavaInterfaceContract ic = javaInterfaceFactory.createJavaInterfaceContract(); + ic.setInterface(javaInterfaceFactory.createJavaInterface(businessInterface)); + return ic; + } + boolean compatible = false; + if (interfaceContract != null && interfaceContract.getInterface() != null) { + Interface interfaze = interfaceContract.getInterface(); + if (interfaze instanceof JavaInterface) { + Class cls = ((JavaInterface)interfaze).getJavaClass(); + if (businessInterface.isAssignableFrom(cls)) { + compatible = true; + } + if (!compatible) { + InterfaceContract biContract = javaInterfaceFactory.createJavaInterfaceContract(); + JavaInterface callInterface = javaInterfaceFactory.createJavaInterface(businessInterface); + biContract.setInterface(callInterface); + if (callInterface.getCallbackClass() != null) { + biContract.setCallbackInterface(javaInterfaceFactory.createJavaInterface(callInterface + .getCallbackClass())); + } + InterfaceContractMapper ifcm = registry.getExtensionPoint(InterfaceContractMapper.class); + compatible = ifcm.isCompatibleSubset(biContract, interfaceContract); + // If the business interface class is not assignable from the service interface class but + // they are compatible, we need to return an InterfaceContract with the business interface + // class to store on the reference side. + if ( compatible ) { + return biContract; + } + } + + } + } + + if (!compatible) { + // JCA-9011 + throw new IllegalArgumentException("Business interface " + businessInterface.getName() + + " is not compatible with " + + interfaceContract.getInterface()); + } + + return interfaceContract; + } + + /* ******************** Contribution for issue TUSCANY-2281 ******************** */ + + /** + * @see ComponentContext#getServices(Class, String) + */ + public Collection getServices(Class businessInterface, String referenceName) { + ArrayList services = new ArrayList(); + Collection> serviceRefs = getServiceReferences(businessInterface, referenceName); + for (ServiceReference serviceRef : serviceRefs) { + services.add(serviceRef.getService()); + } + return services; + } + + /** + * @see ComponentContext#getServiceReferences(Class, String) + */ + public Collection> getServiceReferences(Class businessInterface, String referenceName) { + try { + for (ComponentReference ref : component.getReferences()) { + if (referenceName.equals(ref.getName())) { + if (ref.getMultiplicity() == Multiplicity.ONE_ONE) + throw new IllegalArgumentException("Reference " + referenceName + + " is not a valid argument for getServiceReferences because it has a multiplicity of 1..1"); + if (ref.getMultiplicity() == Multiplicity.ZERO_ONE) + throw new IllegalArgumentException("Reference " + referenceName + + " is not a valid argument for getServiceReferences because it has a multiplicity of 0..1"); + + ArrayList> serviceRefs = new ArrayList>(); + for (EndpointReference endpointReference : ref.getEndpointReferences()) { + RuntimeEndpointReference epr = (RuntimeEndpointReference)endpointReference; + serviceRefs.add(getServiceReference(businessInterface, epr)); + } + return serviceRefs; + } + } + throw new IllegalArgumentException("Reference not found: " + referenceName); + } catch (IllegalArgumentException iae) { + throw iae; + } catch (ServiceRuntimeException e) { + throw e; + } catch (Exception e) { + throw new ServiceRuntimeException(e.getMessage(), e); + } + } + + /* ******************** Contribution for issue TUSCANY-2281 ******************** */ + + public CompositeContext getCompositeContext() { + return compositeContext; + } + + public ExtensionPointRegistry getExtensionPointRegistry() { + return getCompositeContext().getExtensionPointRegistry(); + } + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/RequestContextImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/RequestContextImpl.java new file mode 100644 index 0000000000..6aaa6186b9 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/RequestContextImpl.java @@ -0,0 +1,126 @@ +/* + * 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.core.context.impl; + +import java.util.List; + +import javax.security.auth.Subject; + +import org.apache.tuscany.sca.assembly.Endpoint; +import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.context.ThreadMessageContext; +import org.apache.tuscany.sca.interfacedef.java.JavaInterface; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeComponentReference; +import org.apache.tuscany.sca.runtime.RuntimeComponentService; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; +import org.oasisopen.sca.RequestContext; +import org.oasisopen.sca.ServiceReference; + +/** + * @version $Rev$ $Date$ + */ +public class RequestContextImpl implements RequestContext { + + public RequestContextImpl(RuntimeComponent component) { + } + + public Subject getSecuritySubject() { + + Message msgContext = ThreadMessageContext.getMessageContext(); + + if (msgContext == null){ + // message in thread context could be null if the user has + // spun up a new thread inside their component implementation + return null; + } + + Subject subject = null; + for (Object header : msgContext.getHeaders().values()){ + if (header instanceof Subject){ + subject = (Subject)header; + break; + } + } + return subject; + } + + public String getServiceName() { + Message msgContext = ThreadMessageContext.getMessageContext(); + + if (msgContext != null && + msgContext.getTo() != null){ + return msgContext.getTo().getService().getName(); + } else { + // message in thread context could be null (or the default message where to == null) + // if the user has spun up a new thread inside their component implementation + return null; + } + } + + public ServiceReference getServiceReference() { + Message msgContext = ThreadMessageContext.getMessageContext(); + if (msgContext == null || + msgContext.getTo() == null){ + // message in thread context could be null (or the default message where to == null) + // if the user has spun up a new thread inside their component implementation + return null; + } + // FIXME: [rfeng] Is this the service reference matching the caller side? + RuntimeEndpoint to = (RuntimeEndpoint) msgContext.getTo(); + RuntimeComponent component = (RuntimeComponent) to.getComponent(); + + ServiceReference callableReference = component.getComponentContext().getServiceReference(null, to); + + return callableReference; + } + + public CB getCallback() { + ServiceReference cb = getCallbackReference(); + if (cb == null) { + return null; + } + return cb.getService(); + } + + @SuppressWarnings("unchecked") + public ServiceReference getCallbackReference() { + Message msgContext = ThreadMessageContext.getMessageContext(); + if (msgContext == null || + msgContext.getTo() == null){ + // message in thread context could be null (or the default message where to == null) + // if the user has spun up a new thread inside their component implementation + return null; + } + + Endpoint to = msgContext.getTo(); + RuntimeComponentService service = (RuntimeComponentService) to.getService(); + RuntimeComponentReference callbackReference = (RuntimeComponentReference)service.getCallbackReference(); + if (callbackReference == null) { + return null; + } + JavaInterface javaInterface = (JavaInterface) callbackReference.getInterfaceContract().getInterface(); + Class javaClass = (Class)javaInterface.getJavaClass(); + List wires = callbackReference.getEndpointReferences(); + ServiceReferenceImpl ref = new CallbackServiceReferenceImpl(javaClass, wires); + + return ref; + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/ServiceReferenceImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/ServiceReferenceImpl.java new file mode 100644 index 0000000000..6fa53dcea2 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/ServiceReferenceImpl.java @@ -0,0 +1,430 @@ +/* + * 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.core.context.impl; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.StringWriter; +import java.security.AccessController; +import java.security.PrivilegedAction; + +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.ComponentService; +import org.apache.tuscany.sca.assembly.CompositeService; +import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.assembly.Service; +import org.apache.tuscany.sca.assembly.builder.BindingBuilder; +import org.apache.tuscany.sca.assembly.builder.BuilderContext; +import org.apache.tuscany.sca.assembly.builder.BuilderExtensionPoint; +import org.apache.tuscany.sca.context.CompositeContext; +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.processor.StAXArtifactProcessorExtensionPoint; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +import org.apache.tuscany.sca.core.assembly.RuntimeAssemblyFactory; +import org.apache.tuscany.sca.core.assembly.impl.RuntimeEndpointReferenceImpl; +import org.apache.tuscany.sca.core.context.ServiceReferenceExt; +import org.apache.tuscany.sca.core.factory.ObjectCreationException; +import org.apache.tuscany.sca.core.invocation.ExtensibleProxyFactory; +import org.apache.tuscany.sca.core.invocation.ProxyFactory; +import org.apache.tuscany.sca.interfacedef.Interface; +import org.apache.tuscany.sca.interfacedef.InvalidInterfaceException; +import org.apache.tuscany.sca.interfacedef.java.JavaInterface; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; +import org.apache.tuscany.sca.runtime.Invocable; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeComponentReference; +import org.apache.tuscany.sca.runtime.RuntimeEndpointReference; +import org.oasisopen.sca.ServiceRuntimeException; + +/** + * Default implementation of a ServiceReference. + * + * @version $Rev$ $Date$ + * @param the type of the business interface + */ +public class ServiceReferenceImpl implements ServiceReferenceExt { + private static final long serialVersionUID = 6763709434194361540L; + + protected transient ProxyFactory proxyFactory; + protected transient Class businessInterface; + protected transient B proxy; + + protected Object callbackID; // The callbackID should be serializable + + protected transient RuntimeEndpointReference endpointReference; + +// protected String scdl; +// +// private transient XMLStreamReader xmlReader; + + protected transient CompositeContext compositeContext; + protected ExtensionPointRegistry registry; + protected FactoryExtensionPoint modelFactories; + protected RuntimeAssemblyFactory assemblyFactory; + protected StAXArtifactProcessorExtensionPoint staxProcessors; + protected StAXArtifactProcessor staxProcessor; + protected XMLInputFactory xmlInputFactory; + protected XMLOutputFactory xmlOutputFactory; + protected BuilderExtensionPoint builders; + + /* + * Public constructor for Externalizable serialization/deserialization + */ + public ServiceReferenceImpl() { + super(); + } + + public ServiceReferenceImpl(Class businessInterface, + Invocable endpointReference, + CompositeContext compositeContext) { + this.businessInterface = businessInterface; + this.endpointReference = (RuntimeEndpointReference) endpointReference; + if (compositeContext == null) { + compositeContext = endpointReference.getCompositeContext(); + } + bind(compositeContext); + } + + public ServiceReferenceImpl(Class businessInterface, + Invocable endpointReference) { + this(businessInterface, endpointReference, null); + } + + protected void bind(CompositeContext context) { + this.compositeContext = context; + this.registry = compositeContext.getExtensionPointRegistry(); + this.modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class); + this.assemblyFactory = (RuntimeAssemblyFactory)modelFactories.getFactory(AssemblyFactory.class); + this.xmlInputFactory = modelFactories.getFactory(XMLInputFactory.class); + this.xmlOutputFactory = modelFactories.getFactory(XMLOutputFactory.class); + this.staxProcessors = registry.getExtensionPoint(StAXArtifactProcessorExtensionPoint.class); + this.staxProcessor = staxProcessors.getProcessor(EndpointReference.class); + this.builders = registry.getExtensionPoint(BuilderExtensionPoint.class); + this.proxyFactory = ExtensibleProxyFactory.getInstance(registry); + } + + public RuntimeEndpointReference getEndpointReference() { + return endpointReference; + } + + public B getProxy() throws ObjectCreationException { + try { + if (proxy == null) { + proxy = createProxy(); + } + return proxy; + } catch (Exception e) { + throw new ObjectCreationException(e); + } + } + + public void setProxy(B proxy) { + this.proxy = proxy; + } + + protected B createProxy() throws Exception { + return proxyFactory.createProxy(this); + } + + public B getService() { + try { + resolve(); + return getProxy(); + } catch (Exception e) { + throw new ServiceRuntimeException(e); + } + } + + public Class getBusinessInterface() { + try { + resolve(); + return businessInterface; + } catch (Exception e) { + throw new ServiceRuntimeException(e); + } + } + + /** + * Follow a service promotion chain down to the inner most (non composite) + * component service. + * + * @param topCompositeService + * @return + */ + private ComponentService getPromotedComponentService(CompositeService compositeService) { + ComponentService componentService = compositeService.getPromotedService(); + if (componentService != null) { + Service service = componentService.getService(); + if (componentService.getName() != null && service instanceof CompositeService) { + + // Continue to follow the service promotion chain + return getPromotedComponentService((CompositeService)service); + + } else { + + // Found a non-composite service + return componentService; + } + } else { + + // No promoted service + return null; + } + } + + // ============ WRITE AND READ THE REFERENCE TO EXTERNAL XML ======================== + + /** + * write the reference to a stream + * + * @see java.io.Externalizable#writeExternal(java.io.ObjectOutput) + */ + public void writeExternal(ObjectOutput out) throws IOException { + out.writeObject(endpointReference); + /* + try { + String xml = null; + if (scdl == null) { + xml = toXMLString(); + } else { + xml = scdl; + } + + if (xml == null) { + out.writeBoolean(false); + } else { + out.writeBoolean(true); + out.writeUTF(xml); + } + } catch (Exception e) { + // e.printStackTrace(); + throw new IOException(e.toString()); + } + */ + } + + /** + * write the endpoint reference into an xml string + */ + public String toXMLString() throws IOException, XMLStreamException, ContributionWriteException { + StringWriter writer = new StringWriter(); + XMLStreamWriter streamWriter = xmlOutputFactory.createXMLStreamWriter(writer); + staxProcessor.write(endpointReference, streamWriter, new ProcessorContext(registry)); + return writer.toString(); + } + + /** + * Read the reference from a stream + * + * @see java.io.Externalizable#readExternal(java.io.ObjectInput) + */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + this.endpointReference = (RuntimeEndpointReference) in.readObject(); + // Force resolve + endpointReference.getComponent(); + bind(endpointReference.getCompositeContext()); + + RuntimeComponentReference reference = (RuntimeComponentReference)endpointReference.getReference(); + reference.setComponent((RuntimeComponent)endpointReference.getComponent()); + + Interface i = reference.getInterfaceContract().getInterface(); + if (i instanceof JavaInterface) { + JavaInterface javaInterface = (JavaInterface)i; + if (javaInterface.isUnresolved()) { + // Allow privileged access to get ClassLoader. Requires RuntimePermission in + // security policy. + ClassLoader classLoader = AccessController.doPrivileged(new PrivilegedAction() { + public ClassLoader run() { + return Thread.currentThread().getContextClassLoader(); + } + }); + + javaInterface.setJavaClass(classLoader.loadClass(javaInterface.getName())); + JavaInterfaceFactory javaInterfaceFactory = getJavaInterfaceFactory(compositeContext); + + try { + javaInterfaceFactory.createJavaInterface(javaInterface, javaInterface.getJavaClass()); + } catch (InvalidInterfaceException e) { + throw new ServiceRuntimeException(e); + } + //FIXME: If the interface needs XSDs to be loaded (e.g., for static SDO), + // this needs to be done here. We usually search for XSDs in the current + // contribution at resolve time. Is it possible to locate the current + // contribution at runtime? + } + this.businessInterface = (Class)javaInterface.getJavaClass(); + } + + Binding binding = endpointReference.getBinding(); + if (binding != null) { + BindingBuilder bindingBuilder = builders.getBindingBuilder(binding.getType()); + if (bindingBuilder != null) { + org.apache.tuscany.sca.assembly.builder.BuilderContext context = new BuilderContext(registry); + bindingBuilder.build(endpointReference.getComponent(), reference, endpointReference.getBinding(), context, false); + } + } + + this.proxyFactory = getProxyFactory(this.compositeContext); + + /* + endpointReference.bind(CompositeContext.getCurrentCompositeContext()); + endpointReference.rebuild(); + */ + /* + final boolean hasSCDL = in.readBoolean(); + if (hasSCDL) { + this.scdl = in.readUTF(); + } else { + this.scdl = null; + } + */ + } + + /** + * Read xml string into the endpoint reference + */ + /* + public void fromXMLString() throws IOException, XMLStreamException, ContributionReadException { + + XMLStreamReader streamReader = xmlReader; + + if (scdl != null) { + Reader reader = new StringReader(scdl); + + if (xmlInputFactory == null) { + // this is a reference being read from a external stream + // so set up enough of the reference in order to resolved the + // xml being read + bind(CompositeContext.getCurrentCompositeContext()); + } + + streamReader = xmlInputFactory.createXMLStreamReader(reader); + } + + endpointReference = (RuntimeEndpointReference) staxProcessor.read(streamReader, new ProcessorContext(registry)); + + // ok to GC + xmlReader = null; + scdl = null; + } + */ + + /** + * @throws IOException + */ + private synchronized void resolve() throws Exception { + /* + if ((scdl != null || xmlReader != null) && endpointReference == null) { + fromXMLString(); + + compositeContext.bindComponent((RuntimeComponent) endpointReference.getComponent()); + + RuntimeComponentReference reference = (RuntimeComponentReference)endpointReference.getReference(); + reference.setComponent((RuntimeComponent)endpointReference.getComponent()); + + ReferenceParameters parameters = null; + for (Object ext : reference.getExtensions()) { + if (ext instanceof ReferenceParameters) { + parameters = (ReferenceParameters)ext; + break; + } + } + + if (parameters != null) { + this.callbackID = parameters.getCallbackID(); + } + + Interface i = reference.getInterfaceContract().getInterface(); + if (i instanceof JavaInterface) { + JavaInterface javaInterface = (JavaInterface)i; + if (javaInterface.isUnresolved()) { + // Allow privileged access to get ClassLoader. Requires RuntimePermission in + // security policy. + ClassLoader classLoader = AccessController.doPrivileged(new PrivilegedAction() { + public ClassLoader run() { + return Thread.currentThread().getContextClassLoader(); + } + }); + + javaInterface.setJavaClass(classLoader.loadClass(javaInterface.getName())); + JavaInterfaceFactory javaInterfaceFactory = getJavaInterfaceFactory(compositeContext); + + javaInterfaceFactory.createJavaInterface(javaInterface, javaInterface.getJavaClass()); + //FIXME: If the interface needs XSDs to be loaded (e.g., for static SDO), + // this needs to be done here. We usually search for XSDs in the current + // contribution at resolve time. Is it possible to locate the current + // contribution at runtime? + } + this.businessInterface = (Class)javaInterface.getJavaClass(); + } + + Binding binding = endpointReference.getBinding(); + if (binding != null) { + BindingBuilder bindingBuilder = builders.getBindingBuilder(binding.getType()); + if (bindingBuilder != null) { + BuilderContext context = new BuilderContext(registry); + bindingBuilder.build(endpointReference.getComponent(), reference, endpointReference.getBinding(), context); + } + } + + this.proxyFactory = getProxyFactory(this.compositeContext); + } else if (compositeContext == null) { + this.compositeContext = CompositeContext.getCurrentCompositeContext(); + if (this.compositeContext != null) { + this.proxyFactory = getProxyFactory(this.compositeContext); + } + } + */ + } + + private JavaInterfaceFactory getJavaInterfaceFactory(CompositeContext compositeContext) { + ExtensionPointRegistry extensionPointRegistry = compositeContext.getExtensionPointRegistry(); + FactoryExtensionPoint factories = extensionPointRegistry.getExtensionPoint(FactoryExtensionPoint.class); + JavaInterfaceFactory javaInterfaceFactory = factories.getFactory(JavaInterfaceFactory.class); + return javaInterfaceFactory; + } + + private ProxyFactory getProxyFactory(CompositeContext compositeContext) { + ExtensionPointRegistry extensionPointRegistry = compositeContext.getExtensionPointRegistry(); + return ExtensibleProxyFactory.getInstance(extensionPointRegistry); + } + + // ================================================================================== + + /* + public XMLStreamReader getXMLReader() { + return xmlReader; + } + */ + + public void setBindingURI(String uri) { + ((RuntimeEndpointReferenceImpl)endpointReference).setBindingURI(uri); + } + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/factory/InstanceWrapper.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/factory/InstanceWrapper.java new file mode 100644 index 0000000000..4b563b0079 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/factory/InstanceWrapper.java @@ -0,0 +1,49 @@ +/* + * 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.core.factory; + +import org.apache.tuscany.sca.core.scope.TargetDestructionException; +import org.apache.tuscany.sca.core.scope.TargetInitializationException; + + +/** + * Provides lifecycle management for an implementation instance associated with + * a component for use by the component's associated {@link org.apache.tuscany.sca.core.scope.ScopeContainer} + * + * @version $Rev$ $Date$ + * @tuscany.spi.extension.asclient + */ +public interface InstanceWrapper { + + /** + * @return + */ + T getInstance(); + + /** + * @throws TargetInitializationException + */ + void start() throws TargetInitializationException; + + /** + * @throws TargetDestructionException + */ + void stop() throws TargetDestructionException; + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/factory/ObjectCreationException.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/factory/ObjectCreationException.java new file mode 100644 index 0000000000..820faf6259 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/factory/ObjectCreationException.java @@ -0,0 +1,48 @@ +/* + * 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.core.factory; + + +/** + * Denotes an error creating a new object instance + * + * @version $Rev$ $Date$ + * @tuscany.spi.extension.asclient + */ +public class ObjectCreationException extends RuntimeException { + private static final long serialVersionUID = -6423113430265944499L; + + public ObjectCreationException() { + super(); + } + + public ObjectCreationException(String message, Throwable cause) { + super(message, cause); + } + + public ObjectCreationException(String message) { + super(message); + } + + public ObjectCreationException(Throwable cause) { + super(cause); + } + +} + diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/factory/ObjectFactory.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/factory/ObjectFactory.java new file mode 100644 index 0000000000..db10b6cff2 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/factory/ObjectFactory.java @@ -0,0 +1,36 @@ +/* + * 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.core.factory; + +/** + * Implementations create new instances of a particular type + * + * @version $Rev$ $Date$ + * @tuscany.spi.extension.asclient + */ +public interface ObjectFactory { + + /** + * Return a instance of the type that this factory creates. + * + * @return a instance from this factory + */ + T getInstance() throws ObjectCreationException; + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/AsyncContext.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/AsyncContext.java new file mode 100644 index 0000000000..b91bfcca8e --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/AsyncContext.java @@ -0,0 +1,42 @@ +/* + * 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.core.invocation; + +/** + * Allows extensions to associate data with a client's async request. + */ +public interface AsyncContext { + + /** + * Looks up an attribute value by name. + * @param name The name of the attribute + * @return The value of the attribute + */ + public Object getAttribute(String name); + + /** + * Sets the value of an attribute. + * + * @param name The name of the attribute + * @param value + */ + public void setAttribute(String name, Object value); + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/AsyncFaultWrapper.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/AsyncFaultWrapper.java new file mode 100644 index 0000000000..b35d493d3c --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/AsyncFaultWrapper.java @@ -0,0 +1,107 @@ +/* + * 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.core.invocation; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +/** + * A class which is used to wrap an Exception of any type thrown by an asynchronous service operation and + * which is returned through a separate one-way message sent asynchronously from the server to the client. + * + */ +public class AsyncFaultWrapper { + + private String faultClassName = null; + private String faultMessage = null; + private AsyncFaultWrapper containedFault = null; + + + public AsyncFaultWrapper() { + super(); + } + + /** + * Constructor which creates an AsyncFaultWrapper which wraps the supplied Throwable + * @param e - a Throwable which is wrapped by this AsyncFaultWrapper + */ + public AsyncFaultWrapper( Throwable e ) { + super(); + storeFault( e ); + } + + /** + * Stores a given Throwable in this AsyncFaultWrapper + * If the supplied Throwable itself contains an embedded Throwable ("cause"), this is recursively + * wrapped by a nested AsyncFaultWrapper + * @param e - the Throwable + */ + public void storeFault( Throwable e ) { + setFaultClassName( e.getClass().getCanonicalName() ); + setFaultMessage( e.getMessage() ); + Throwable cause = e.getCause(); + if( cause != null ) setContainedFault( new AsyncFaultWrapper( cause ) ); + } + + /** + * Retrieves the Throwable wrapped by this AsyncFaultWrapper + * + * Note: When this method is invoked, the method attempts to instantiate an instance of the wrapped Throwable. + * It does this using the Thread Context Class Loader (TCCL) - the caller *MUST* ensure that the TCCL has access + * to the class of the wrapped Throwable and also to the classes of any nested Throwables. If this is not done, + * a ClassNotFound exception is thrown + * + * @return - the Throwable wrapped by this AsyncFaultWrapper - the Throwable will contain any nested Throwable(s) + * in its cause property + * @throws ClassNotFound exception, if the class of the wrapped Throwable is not accessible from the TCCL + */ + public Throwable retrieveFault( ) { + try { + ClassLoader tccl = Thread.currentThread().getContextClassLoader(); + Class faultClass = tccl.loadClass(faultClassName); + Class xclass = (Class) faultClass; + if( containedFault != null ) { + // If there is a nested fault, retrieve this recursively + Constructor cons = xclass.getConstructor(String.class, Throwable.class); + return (Throwable) cons.newInstance(faultMessage, getContainedFault().retrieveFault()); + } else { + try { + Constructor cons = xclass.getConstructor(String.class); + return (Throwable) cons.newInstance(faultMessage); + } catch (NoSuchMethodException e) { + Constructor cons = xclass.getConstructor(); + return (Throwable) cons.newInstance(); + } + } // end if + } catch (Exception e) { + return e; + } // end try + } // end method retrieveFault + + public void setFaultClassName( String name ) { this.faultClassName = name; } + public String getFaultClassName() { return this.faultClassName; } + + public String getFaultMessage() { return faultMessage; } + public void setFaultMessage(String faultMessage) { this.faultMessage = faultMessage; } + + public AsyncFaultWrapper getContainedFault() { return containedFault; } + public void setContainedFault(AsyncFaultWrapper containedFault) { this.containedFault = containedFault; } + +} // end class AsyncFaultWrapper diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/AsyncResponseException.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/AsyncResponseException.java new file mode 100644 index 0000000000..df90c3286d --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/AsyncResponseException.java @@ -0,0 +1,47 @@ +/* + * 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.core.invocation; + +/** + * An exception which is used to signal that a service has been invoked asynchronously + * and that the result will be sent separately + * + */ +public class AsyncResponseException extends RuntimeException { + + private static final long serialVersionUID = 457954562860541631L; + + public AsyncResponseException() { + super(); + } + + public AsyncResponseException(String arg0, Throwable arg1) { + super(arg0, arg1); + } + + public AsyncResponseException(String arg0) { + super(arg0); + } + + public AsyncResponseException(Throwable arg0) { + super(arg0); + } + +} // end class AsyncResponseException diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/AsyncResponseHandler.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/AsyncResponseHandler.java new file mode 100644 index 0000000000..306a141433 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/AsyncResponseHandler.java @@ -0,0 +1,58 @@ +/* + * 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.core.invocation; + +import org.oasisopen.sca.annotation.OneWay; +import org.oasisopen.sca.annotation.Remotable; + +/** + * An interface which describes a general response pattern for the asynchronous invocation of a service + * + * @param - the type of the non-fault response + */ +public interface AsyncResponseHandler extends AsyncResponseService { + + /** + * Async process completed with a wrapped Fault. Must only be invoked once + * + * @param e - the wrapper containing the Fault to send + * @throws IllegalStateException if either the setResponse method or the setFault method have been called previously + */ + @OneWay + public void setWrappedFault(AsyncFaultWrapper w); + + /** + * Async process completed with a Fault. Must only be invoked once. + * @param e - the Fault to send + * @throws IllegalStateException if either the setResponse method or the setFault method have been called previously + */ + @OneWay + public void setFault( Throwable e ); + + /** + * Async process completed with a response message. Must only be invoked once + * + * @throws IllegalStateException if either the setResponse method or the setFault method have been called previously + * @param res - the response message, which is of type V + */ + @OneWay + public void setResponse(V res); + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/AsyncResponseInvoker.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/AsyncResponseInvoker.java new file mode 100644 index 0000000000..1ebc9c633a --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/AsyncResponseInvoker.java @@ -0,0 +1,351 @@ +/* + * 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.core.invocation; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +import org.apache.tuscany.sca.assembly.Endpoint; +import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.context.CompositeContext; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.ExtensionPointRegistryLocator; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.invocation.InvokerAsyncResponse; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.provider.EndpointAsyncProvider; +import org.apache.tuscany.sca.runtime.DomainRegistryFactory; +import org.apache.tuscany.sca.runtime.DomainRegistry; +import org.apache.tuscany.sca.runtime.ExtensibleDomainRegistryFactory; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; +import org.apache.tuscany.sca.runtime.RuntimeEndpointReference; + +/** + * A class that wraps the mechanics for sending async responses + * and hides the decision about whether the response will be processed + * natively or non-natively + * + * This class is generic, based on the type of targetAddress information required by + * the Binding that creates it + */ +public class AsyncResponseInvoker implements InvokerAsyncResponse, Serializable { + + /** + * + */ + private static final long serialVersionUID = -7992598227671386588L; + + private transient RuntimeEndpoint requestEndpoint; + private transient RuntimeEndpointReference responseEndpointReference; + private T responseTargetAddress; + private String relatesToMsgID; + private String operationName; + private transient MessageFactory messageFactory; + private String bindingType = ""; + private boolean isNativeAsync; + + private String endpointURI; + private String endpointReferenceURI; + private String domainURI; + + private transient DomainRegistry domainRegistry; + private transient ExtensionPointRegistry registry; + + public AsyncResponseInvoker(RuntimeEndpoint requestEndpoint, + RuntimeEndpointReference responseEndpointReference, + T responseTargetAddress, String relatesToMsgID, + String operationName, MessageFactory messageFactory) { + super(); + this.requestEndpoint = requestEndpoint; + this.responseEndpointReference = responseEndpointReference; + this.responseTargetAddress = responseTargetAddress; + this.relatesToMsgID = relatesToMsgID; + this.operationName = operationName; + this.messageFactory = messageFactory; + + CompositeContext context = null; + if(requestEndpoint != null ) { + endpointURI = requestEndpoint.getURI(); + context = requestEndpoint.getCompositeContext(); + } // end if + if(responseEndpointReference != null ) { + endpointReferenceURI = responseEndpointReference.getURI(); + context = responseEndpointReference.getCompositeContext(); + } + + if( context != null ) { + domainURI = context.getDomainURI(); + registry = context.getExtensionPointRegistry(); + } // end if + + if ((requestEndpoint.getBindingProvider() instanceof EndpointAsyncProvider) && + (((EndpointAsyncProvider)requestEndpoint.getBindingProvider()).supportsNativeAsync())){ + isNativeAsync = true; + } else { + isNativeAsync = false; + } // end if + } // end constructor + + /** + * If you have a Tuscany message you can call this + */ + public void invokeAsyncResponse(Message responseMessage) { + responseMessage.getHeaders().put(Constants.ASYNC_RESPONSE_INVOKER, this); + responseMessage.getHeaders().put(Constants.RELATES_TO, relatesToMsgID); + + if (isNativeAsync){ + // process the response as a native async response + requestEndpoint.invokeAsyncResponse(responseMessage); + } else { + // process the response as a non-native async response + responseEndpointReference.invoke(responseMessage); + } + } // end method invokeAsyncReponse(Message) + + public T getResponseTargetAddress() { + return responseTargetAddress; + } + + public void setResponseTargetAddress(T responseTargetAddress) { + this.responseTargetAddress = responseTargetAddress; + } + + public String getRelatesToMsgID() { + return relatesToMsgID; + } + + public void setRelatesToMsgID(String relatesToMsgID) { + this.relatesToMsgID = relatesToMsgID; + } + + /** + * Invokes the async response where the parameter is Java bean(s) + * - this method creates a Tuscany message + * + * @param args the response data + * @param headers - any header + */ + public void invokeAsyncResponse(Object args, Map headers) { + + Message msg = messageFactory.createMessage(); + + msg.setOperation(getOperation( args )); + + // If this is not native async, then any Throwable is being passed as a parameter and + // requires wrapping + if( !isNativeAsync && args instanceof Throwable ) { + args = new AsyncFaultWrapper( (Throwable) args ); + } // end if + + // If this is not native async, then the message must contain an array of args since + // this is what is expected when invoking an EPR for the async response... + if( !isNativeAsync ) { + Object[] objs = new Object[1]; + objs[0] = args; + args = objs; + } // end if + + msg.setTo(requestEndpoint); + msg.setFrom(responseEndpointReference); + + if( headers != null ) { + msg.getHeaders().putAll(headers); + } + + if( args instanceof Throwable ) { + msg.setFaultBody(args); + } else { + msg.setBody(args); + } // end if + + invokeAsyncResponse(msg); + + } // end method invokeAsyncResponse(Object) + + private Operation getOperation( Object args ) { + if( isNativeAsync ) { + List ops = requestEndpoint.getService().getInterfaceContract().getInterface().getOperations(); + for (Operation op : ops) { + if( operationName.equals(op.getName()) ) return op; + } // end for + return null; + } else { + operationName = "setResponse"; + if( args instanceof Throwable ) { operationName = "setWrappedFault"; } + List ops = responseEndpointReference.getReference().getInterfaceContract().getInterface().getOperations(); + for (Operation op : ops) { + if( operationName.equals(op.getName()) ) return op; + } // end for + return null; + } // end if + } // end getOperation + + public void setBindingType(String bindingType) { + this.bindingType = bindingType; + } // end method setBindingType + + public String getBindingType() { + return bindingType; + } // end method getBindingType + + public RuntimeEndpoint getRequestEndpoint() { + return this.requestEndpoint; + } + + public RuntimeEndpointReference getResponseEndpointReference() { + return this.responseEndpointReference; + } + + public void setResponseEndpointReference( + RuntimeEndpointReference responseEndpointReference) { + this.responseEndpointReference = responseEndpointReference; + } + + @SuppressWarnings("unchecked") + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException + { + in.defaultReadObject(); + + requestEndpoint = retrieveEndpoint(endpointURI); + responseEndpointReference = retrieveEndpointReference(endpointReferenceURI); + + messageFactory = getMessageFactory(); + + if (responseTargetAddress instanceof EndpointReference){ + // fix the target as in this case it will be an EPR + EndpointReference epr = (EndpointReference)responseTargetAddress; + responseTargetAddress = (T)retrieveEndpointReference(epr.getURI()); + } // end if + } // end method readObject + + /** + * Gets a message factory + * @return + */ + private MessageFactory getMessageFactory() { + return registry.getExtensionPoint(FactoryExtensionPoint.class).getFactory(MessageFactory.class); + } // end method getMessageFactory + + /** + * Fetches the EndpointReference identified by an endpoint reference URI + * @param uri - the URI of the endpoint reference + * @return - the EndpointReference matching the supplied URI - null if no EPR is found which + * matches the URI + */ + private RuntimeEndpointReference retrieveEndpointReference(String uri) { + if( uri == null ) return null; + if( domainRegistry == null ) return null; + List refs = domainRegistry.findEndpointReferences( uri ); + // If there is more than EndpointReference with the uri... + if( refs.isEmpty() ) return null; + // TODO: what if there is more than 1 EPR with the given URI? + return (RuntimeEndpointReference) refs.get(0); + } // end method retrieveEndpointReference + + /** + * Fetches the Endpoint identified by an endpoint URI + * - the Endpoint is retrieved from the DomainRegistry + * @param uri - the URI of the Endpoint + * @return - the Endpoint corresponding to the URI, or null if no Endpoint is found which has the + * supplied URI + */ + private RuntimeEndpoint retrieveEndpoint(String uri) { + if( uri == null ) return null; + if( domainRegistry == null ) domainRegistry = getEndpointRegistry( uri ); + if( domainRegistry == null ) return null; + // TODO what if more than one Endpoint gets returned?? + return (RuntimeEndpoint) domainRegistry.findEndpoint(uri).get(0); + } // end method retrieveEndpoint + + /** + * Gets the DomainRegistry which contains an Endpoint with the supplied URI + * @param uri - The URI of an Endpoint + * @return - the DomainRegistry containing the Endpoint with the supplied URI - null if no + * such DomainRegistry can be found + */ + private DomainRegistry getEndpointRegistry(String uri) { + ExtensionPointRegistry registry = null; + DomainRegistry domainRegistry = null; + + CompositeContext context = CompositeContext.getCurrentCompositeContext(); + if( context == null && requestEndpoint != null ) context = requestEndpoint.getCompositeContext(); + if( context != null ) { + registry = context.getExtensionPointRegistry(); + domainRegistry = getEndpointRegistry( registry ); + if( domainRegistry != null ) { + this.registry = registry; + return domainRegistry; + } // end if + } // end if + + // Deal with the case where there is no context available + for(ExtensionPointRegistry r : ExtensionPointRegistryLocator.getExtensionPointRegistries()) { + registry = r; + if( registry != null ) { + // Find the actual Endpoint in the DomainRegistry + domainRegistry = getEndpointRegistry( registry ); + + if( domainRegistry != null ) { + for( Endpoint endpoint : domainRegistry.findEndpoint(uri) ) { + // TODO: For the present, simply return the first registry with a matching endpoint + this.registry = registry; + return domainRegistry; + } // end for + } // end if + } // end if + } // end for + + return null; + } // end method getEndpointRegistry + + /** + * Get the DomainRegistry + * @param registry - the ExtensionPoint registry + * @return the DomainRegistry - will be null if the DomainRegistry cannot be found + */ + private DomainRegistry getEndpointRegistry( ExtensionPointRegistry registry) { + DomainRegistryFactory domainRegistryFactory = ExtensibleDomainRegistryFactory.getInstance(registry); + + if( domainRegistryFactory == null ) return null; + + // Find the first endpoint registry that matches the domain name + if( domainURI != null ) { + for( DomainRegistry domainRegistry : domainRegistryFactory.getEndpointRegistries() ) { + if( domainURI.equals( domainRegistry.getDomainURI() ) ) return domainRegistry; + } // end for + } // end if + + // if there was no domainName to match, simply return the first DomainRegistry if there is one... + + if (domainRegistryFactory.getEndpointRegistries().size() > 0){ + DomainRegistry domainRegistry = (DomainRegistry) domainRegistryFactory.getEndpointRegistries().toArray()[0]; + return domainRegistry; + } else { + return null; + } + + } // end method + +} // end class diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/AsyncResponseService.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/AsyncResponseService.java new file mode 100644 index 0000000000..62d7f74505 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/AsyncResponseService.java @@ -0,0 +1,50 @@ +/* + * 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.core.invocation; + +import org.oasisopen.sca.annotation.OneWay; +import org.oasisopen.sca.annotation.Remotable; + +/** + * An interface which describes the client response service interface for a non-native binding + * performing an asynchronous invocation of a service + * + * @param - the type of the non-fault response + */ +@Remotable() +public interface AsyncResponseService { + + /** + * Async process completed with a wrapped Fault. Must only be invoked once + * @param e - the wrapper containing the Fault to send + * @throws IllegalStateException if either the setResponse method or the setFault method have been called previously + */ + @OneWay + public void setWrappedFault(AsyncFaultWrapper w); + + /** + * Async process completed with a response message. Must only be invoked once + * @throws IllegalStateException if either the setResponse method or the setFault method have been called previously + * @param res - the response message, which is of type V + */ + @OneWay + public void setResponse(V res); + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallableReferenceObjectFactory.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallableReferenceObjectFactory.java new file mode 100644 index 0000000000..400bb333fd --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallableReferenceObjectFactory.java @@ -0,0 +1,58 @@ +/* + * 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.core.invocation; + +import org.apache.tuscany.sca.core.factory.ObjectCreationException; +import org.apache.tuscany.sca.core.factory.ObjectFactory; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeEndpointReference; +import org.oasisopen.sca.ServiceReference; + +/** + * Uses a wire to return a CallableReference + * + * @version $Rev$ $Date$ + * @tuscany.spi.extension.asclient + */ +public class CallableReferenceObjectFactory implements ObjectFactory> { + private Class businessInterface; + private RuntimeEndpointReference endpointReference; + + /** + * Constructor. + * + * To support the @Reference protected CallableReference ref; + * + * @param businessInterface the interface to inject + * @param component the component defining the reference to be injected + * @param reference the reference to be injected + * @param binding the binding for the reference + */ + public CallableReferenceObjectFactory(Class businessInterface, + RuntimeEndpointReference endpointReference) { + this.businessInterface = businessInterface; + this.endpointReference = endpointReference; + } + + public ServiceReference getInstance() throws ObjectCreationException { + RuntimeComponent component = (RuntimeComponent) endpointReference.getComponent(); + return component.getComponentContext().getServiceReference(businessInterface, endpointReference); + } + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackHandler.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackHandler.java new file mode 100644 index 0000000000..bccce0d20a --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackHandler.java @@ -0,0 +1,53 @@ +/* + * 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.core.invocation; + +/** + * Models callback information arriving in the forward message + */ +public class CallbackHandler { + private String callbackTargetURI; + private boolean cloneCallbackWire = true; + + public CallbackHandler(String callbackTargetURI){ + setCallbackTargetURI(callbackTargetURI); + } + + public CallbackHandler(String callbackTargetURI, boolean cloneCallbackWire){ + setCallbackTargetURI(callbackTargetURI); + setCloneCallbackWire(cloneCallbackWire); + } + + public String getCallbackTargetURI() { + return callbackTargetURI; + } + + public boolean getCloneCallbackWire() { + return cloneCallbackWire; + } + + public void setCallbackTargetURI(String callbackTargetURI) { + this.callbackTargetURI = callbackTargetURI; + } + + public void setCloneCallbackWire(boolean cloneCallbackWire) { + this.cloneCallbackWire = cloneCallbackWire; + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackInterfaceInterceptor.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackInterfaceInterceptor.java new file mode 100644 index 0000000000..588eaa2d15 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackInterfaceInterceptor.java @@ -0,0 +1,60 @@ +/* + * 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.core.invocation; + +import org.apache.tuscany.sca.invocation.Interceptor; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.Message; + +/** + * An interceptor applied to the forward direction of a wire that ensures the callback target implements the required + * service contract. This is required as callback targets may be set dynamically by service implementations. + * + * @version $Rev$ $Date$ + */ +public class CallbackInterfaceInterceptor implements Interceptor { + private Invoker next; + + public CallbackInterfaceInterceptor() { + } + + public Message invoke(Message msg) { + + /* TODO - EPR - not required for OASIS + ReferenceParameters parameters = msg.getFrom().getReferenceParameters(); + if (parameters.getCallbackObjectID() != null || parameters.getCallbackReference() != msg.getFrom() + .getCallbackEndpoint()) { + */ + return next.invoke(msg); + /* + } else { + throw new NoRegisteredCallbackException("Callback target does not implement the callback interface"); + } + */ + } + + public void setNext(Invoker next) { + this.next = next; + } + + public Invoker getNext() { + return next; + } + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackReferenceObjectFactory.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackReferenceObjectFactory.java new file mode 100644 index 0000000000..a56983a5d3 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackReferenceObjectFactory.java @@ -0,0 +1,50 @@ +/* + * 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.core.invocation; + +import java.util.List; + +import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.core.context.impl.CallbackServiceReferenceImpl; +import org.apache.tuscany.sca.core.factory.ObjectCreationException; +import org.apache.tuscany.sca.core.factory.ObjectFactory; +import org.oasisopen.sca.ServiceReference; + +/** + * Uses a wire to return a CallableReference + * + * @version $Rev$ $Date$ + * @tuscany.spi.extension.asclient + */ +public class CallbackReferenceObjectFactory implements ObjectFactory> { + private Class businessInterface; + private ProxyFactory proxyFactory; + private List wires; + + public CallbackReferenceObjectFactory(Class interfaze, ProxyFactory proxyFactory, List wires) { + this.businessInterface = interfaze; + this.proxyFactory = proxyFactory; + this.wires = wires; + } + + public ServiceReference getInstance() throws ObjectCreationException { + return new CallbackServiceReferenceImpl(businessInterface, wires); + } + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackWireObjectFactory.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackWireObjectFactory.java new file mode 100644 index 0000000000..fff3727d87 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackWireObjectFactory.java @@ -0,0 +1,48 @@ +/* + * 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.core.invocation; + +import java.util.List; + +import org.apache.tuscany.sca.core.factory.ObjectCreationException; +import org.apache.tuscany.sca.core.factory.ObjectFactory; +import org.apache.tuscany.sca.runtime.Invocable; + +/** + * Returns proxy instance for a wire callback + * + * @version $Rev$ $Date$ + * @tuscany.spi.extension.asclient + */ +public class CallbackWireObjectFactory implements ObjectFactory { + private Class businessInterface; + private ProxyFactory proxyFactory; + private List wires; + + public CallbackWireObjectFactory(Class interfaze, ProxyFactory proxyFactory, List wires) { + this.businessInterface = interfaze; + this.proxyFactory = proxyFactory; + this.wires = wires; + } + + public B getInstance() throws ObjectCreationException { + return proxyFactory.createCallbackProxy(businessInterface, wires); + } + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CglibProxyFactory.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CglibProxyFactory.java new file mode 100644 index 0000000000..a597f8b1ee --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CglibProxyFactory.java @@ -0,0 +1,155 @@ +/* + * 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.core.invocation; + +import java.lang.reflect.Method; +import java.util.List; + +import net.sf.cglib.proxy.Callback; +import net.sf.cglib.proxy.Enhancer; +import net.sf.cglib.proxy.Factory; +import net.sf.cglib.proxy.MethodInterceptor; +import net.sf.cglib.proxy.MethodProxy; + +import org.apache.tuscany.sca.core.context.ServiceReferenceExt; +import org.apache.tuscany.sca.core.context.impl.ServiceReferenceImpl; +import org.apache.tuscany.sca.core.invocation.impl.JDKCallbackInvocationHandler; +import org.apache.tuscany.sca.core.invocation.impl.JDKInvocationHandler; +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.runtime.Invocable; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; +import org.oasisopen.sca.ServiceReference; + +/** + * The implementation of a wire service that uses cglib dynamic proxies + * + * @version $Rev$ $Date$ + * @tuscany.spi.extension.asclient + */ +public class CglibProxyFactory implements ProxyFactory { + private MessageFactory messageFactory; + + public CglibProxyFactory(MessageFactory messageFactory, InterfaceContractMapper mapper) { + this.messageFactory = messageFactory; + + } + + public T createProxy(final Class interfaze, Invocable invocable) throws ProxyCreationException { + if (invocable instanceof RuntimeEndpoint) { + Enhancer enhancer = new Enhancer(); + enhancer.setSuperclass(interfaze); + enhancer.setCallback(new CglibMethodInterceptor(interfaze, invocable)); + Object proxy = enhancer.create(); + return interfaze.cast(proxy); + } + ServiceReference serviceReference = new ServiceReferenceImpl(interfaze, invocable, null); + return createProxy(serviceReference); + } + + /** + * create the proxy with cglib. use the same JDKInvocationHandler as + * JDKProxyService. + */ + public T createProxy(ServiceReference callableReference) throws ProxyCreationException { + Enhancer enhancer = new Enhancer(); + Class interfaze = callableReference.getBusinessInterface(); + enhancer.setSuperclass(interfaze); + enhancer.setCallback(new CglibMethodInterceptor(callableReference)); + Object proxy = enhancer.create(); + ((ServiceReferenceImpl)callableReference).setProxy(proxy); + return interfaze.cast(proxy); + } + + /** + * create the callback proxy with cglib. use the same + * JDKCallbackInvocationHandler as JDKProxyService. + */ + public T createCallbackProxy(Class interfaze, final List wires) throws ProxyCreationException { + ServiceReferenceImpl callbackReference = new ServiceReferenceImpl(interfaze, wires.get(0), null); + return callbackReference != null ? createCallbackProxy(callbackReference) : null; + } + + /** + * create the callback proxy with cglib. use the same + * JDKCallbackInvocationHandler as JDKProxyService. + */ + public T createCallbackProxy(ServiceReference callbackReference) throws ProxyCreationException { + Enhancer enhancer = new Enhancer(); + Class interfaze = callbackReference.getBusinessInterface(); + enhancer.setSuperclass(interfaze); + enhancer.setCallback(new CglibMethodInterceptor(callbackReference)); + Object object = enhancer.create(); + T proxy = interfaze.cast(object); + ((ServiceReferenceExt)callbackReference).setProxy(proxy); + return proxy; + } + + @SuppressWarnings("unchecked") + public > R cast(B target) throws IllegalArgumentException { + if (isProxyClass(target.getClass())) { + Factory factory = (Factory)target; + Callback[] callbacks = factory.getCallbacks(); + if (callbacks.length != 1 || !(callbacks[0] instanceof CglibMethodInterceptor)) { + throw new IllegalArgumentException("The object is not a known proxy."); + } + CglibMethodInterceptor interceptor = (CglibMethodInterceptor)callbacks[0]; + return (R)interceptor.invocationHandler.getCallableReference(); + } else { + throw new IllegalArgumentException("The object is not a known proxy."); + } + } + + /** + * @see org.apache.tuscany.sca.core.invocation.ProxyFactory#isProxyClass(java.lang.Class) + */ + public boolean isProxyClass(Class clazz) { + return Factory.class.isAssignableFrom(clazz); + } + + private class CglibMethodInterceptor implements MethodInterceptor { + private JDKInvocationHandler invocationHandler; + + public CglibMethodInterceptor(ServiceReference callableReference) { + invocationHandler = new JDKInvocationHandler(messageFactory, callableReference); + } + + public CglibMethodInterceptor(Class interfaze, Invocable invocable) { + invocationHandler = new JDKInvocationHandler(messageFactory, interfaze, invocable); + } + + public CglibMethodInterceptor(ServiceReferenceImpl callbackReference) { + invocationHandler = new JDKCallbackInvocationHandler(messageFactory, callbackReference); + } + + /** + * @see net.sf.cglib.proxy.MethodInterceptor#intercept(java.lang.Object, java.lang.reflect.Method, java.lang.Object[], net.sf.cglib.proxy.MethodProxy) + */ + public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { + Object result = invocationHandler.invoke(proxy, method, args); + return result; + } + + } + + public void removeProxiesForContribution(ClassLoader contributionClassloader){ + // do nothing, no cache to clear + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/Constants.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/Constants.java new file mode 100644 index 0000000000..00c650ada6 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/Constants.java @@ -0,0 +1,38 @@ +/* + * 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.core.invocation; + +/** + * Constants used during invocation in the runtime + * + */ +public interface Constants { + public static final String MESSAGE_ID = "MESSAGE_ID"; + public static final String RELATES_TO = "RELATES_TO"; + public static final String ASYNC_RESPONSE_INVOKER = "ASYNC_RESPONSE_INVOKER"; + public static final String ASYNC_CALLBACK = "ASYNC_CALLBACK"; + public static final String CALLBACK = "CALLBACK"; + + /** + * If you've set the TCCL in your binding impl according to OASIS rules you can prevent + * the implementation provider from repeating the process by including this header + */ + public static final String SUPPRESS_TCCL_SWAP = "SUPPRESS_TCCL_SWAP"; +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/DefaultProxyFactoryExtensionPoint.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/DefaultProxyFactoryExtensionPoint.java new file mode 100644 index 0000000000..03505da302 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/DefaultProxyFactoryExtensionPoint.java @@ -0,0 +1,95 @@ +/* + * 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.core.invocation; + +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +import org.apache.tuscany.sca.core.LifeCycleListener; +import org.apache.tuscany.sca.core.UtilityExtensionPoint; +import org.apache.tuscany.sca.core.invocation.impl.JDKProxyFactory; +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.invocation.MessageFactory; + +/** + * Default implementation of a ProxyFactoryExtensionPoint. + * + * @version $Rev$ $Date$ + */ +public class DefaultProxyFactoryExtensionPoint implements ProxyFactoryExtensionPoint, LifeCycleListener { + private InterfaceContractMapper interfaceContractMapper; + private MessageFactory messageFactory; + + private ProxyFactory interfaceFactory; + private ProxyFactory classFactory; + + public DefaultProxyFactoryExtensionPoint(ExtensionPointRegistry registry) { + UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); + this.interfaceContractMapper = utilities.getUtility(InterfaceContractMapper.class); + + FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class); + this.messageFactory = modelFactories.getFactory(MessageFactory.class); + + interfaceFactory = new JDKProxyFactory(registry, messageFactory, interfaceContractMapper); + } + + // public DefaultProxyFactoryExtensionPoint(MessageFactory messageFactory, InterfaceContractMapper mapper) { + // this.interfaceContractMapper = mapper; + // this.messageFactory = messageFactory; + // interfaceFactory = new JDKProxyFactory(null, messageFactory, mapper); + // } + + public ProxyFactory getClassProxyFactory() { + return classFactory; + } + + public ProxyFactory getInterfaceProxyFactory() { + return interfaceFactory; + } + + public void setClassProxyFactory(ProxyFactory factory) { + this.classFactory = factory; + + } + + public void setInterfaceProxyFactory(ProxyFactory factory) { + this.interfaceFactory = factory; + + } + + public void start() { + if (interfaceFactory instanceof LifeCycleListener) { + ((LifeCycleListener)interfaceFactory).start(); + } + if (classFactory instanceof LifeCycleListener) { + ((LifeCycleListener)classFactory).start(); + } + } + + public void stop() { + if (interfaceFactory instanceof LifeCycleListener) { + ((LifeCycleListener)interfaceFactory).stop(); + } + if (classFactory instanceof LifeCycleListener) { + ((LifeCycleListener)classFactory).stop(); + } + + } + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ExtensibleProxyFactory.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ExtensibleProxyFactory.java new file mode 100644 index 0000000000..3cb9445d2d --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ExtensibleProxyFactory.java @@ -0,0 +1,128 @@ +/* + * 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.core.invocation; + +import java.util.List; + +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.UtilityExtensionPoint; +import org.apache.tuscany.sca.runtime.Invocable; +import org.oasisopen.sca.ServiceReference; + +/** + * An extensible proxy factory. + * + * @version $Rev$ $Date$ + * @tuscany.spi.extension.asclient + */ +public class ExtensibleProxyFactory implements ProxyFactory { + + private ProxyFactoryExtensionPoint proxyFactories; + + public ExtensibleProxyFactory(ProxyFactoryExtensionPoint proxyFactories) { + this.proxyFactories = proxyFactories; + } + + public ExtensibleProxyFactory(ExtensionPointRegistry registry) { + this.proxyFactories = registry.getExtensionPoint(ProxyFactoryExtensionPoint.class); + } + + public static ExtensibleProxyFactory getInstance(ExtensionPointRegistry registry) { + UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); + return utilities.getUtility(ExtensibleProxyFactory.class); + } + + /** + * @see org.apache.tuscany.sca.core.invocation.ProxyFactory#cast(java.lang.Object) + */ + @SuppressWarnings("unchecked") + public > R cast(B target) throws IllegalArgumentException { + ProxyFactory interfaceFactory = proxyFactories.getInterfaceProxyFactory(); + ProxyFactory classFactory = proxyFactories.getClassProxyFactory(); + if (interfaceFactory.isProxyClass(target.getClass())) { + return (R)interfaceFactory.cast(target); + } else if (classFactory != null && classFactory.isProxyClass(target.getClass())) { + return (R)classFactory.cast(target); + } else { + throw new IllegalArgumentException("The target is not a callable proxy"); + } + } + + /** + * @see org.apache.tuscany.sca.core.invocation.ProxyFactory#createCallbackProxy(java.lang.Class, + * java.util.List) + */ + public T createCallbackProxy(Class interfaze, List wires) throws ProxyCreationException { + ProxyFactory interfaceFactory = proxyFactories.getInterfaceProxyFactory(); + ProxyFactory classFactory = proxyFactories.getClassProxyFactory(); + if (interfaze.isInterface()) { + return interfaceFactory.createCallbackProxy(interfaze, wires); + } else { + return classFactory.createCallbackProxy(interfaze, wires); + } + } + + public T createProxy(ServiceReference callableReference) throws ProxyCreationException { + ProxyFactory interfaceFactory = proxyFactories.getInterfaceProxyFactory(); + ProxyFactory classFactory = proxyFactories.getClassProxyFactory(); + if (callableReference.getBusinessInterface().isInterface()) { + return interfaceFactory.createProxy(callableReference); + } else { + return classFactory.createProxy(callableReference); + } + } + + public T createCallbackProxy(ServiceReference callbackReference) throws ProxyCreationException { + ProxyFactory interfaceFactory = proxyFactories.getInterfaceProxyFactory(); + ProxyFactory classFactory = proxyFactories.getClassProxyFactory(); + if (callbackReference.getBusinessInterface().isInterface()) { + return interfaceFactory.createCallbackProxy(callbackReference); + } else { + return classFactory.createCallbackProxy(callbackReference); + } + } + + /** + * @see org.apache.tuscany.sca.core.invocation.ProxyFactory#createProxy(java.lang.Class, + * org.apache.tuscany.sca.runtime.Invocable) + */ + public T createProxy(Class interfaze, Invocable wire) throws ProxyCreationException { + ProxyFactory interfaceFactory = proxyFactories.getInterfaceProxyFactory(); + ProxyFactory classFactory = proxyFactories.getClassProxyFactory(); + if (interfaze.isInterface()) { + return interfaceFactory.createProxy(interfaze, wire); + } else { + return classFactory.createProxy(interfaze, wire); + } + } + + /** + * @see org.apache.tuscany.sca.core.invocation.ProxyFactory#isProxyClass(java.lang.Class) + */ + public boolean isProxyClass(Class clazz) { + ProxyFactory interfaceFactory = proxyFactories.getInterfaceProxyFactory(); + ProxyFactory classFactory = proxyFactories.getClassProxyFactory(); + return interfaceFactory.isProxyClass(clazz) || (classFactory != null && classFactory.isProxyClass(clazz)); + } + + public void removeProxiesForContribution(ClassLoader contributionClassloader){ + // do nothing, no cache to clear + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ExtensibleWireProcessor.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ExtensibleWireProcessor.java new file mode 100644 index 0000000000..08019ec3e2 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ExtensibleWireProcessor.java @@ -0,0 +1,51 @@ +/* + * 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.core.invocation; + +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; +import org.apache.tuscany.sca.runtime.RuntimeEndpointReference; +import org.apache.tuscany.sca.runtime.RuntimeWireProcessor; +import org.apache.tuscany.sca.runtime.RuntimeWireProcessorExtensionPoint; + +/** + * The default implementation of an extensible WireProcessor + * + * @version $Rev$ $Date$ + */ +public class ExtensibleWireProcessor implements RuntimeWireProcessor { + + private RuntimeWireProcessorExtensionPoint processors; + + public ExtensibleWireProcessor(RuntimeWireProcessorExtensionPoint processors) { + this.processors = processors; + } + + public void process(RuntimeEndpoint endpoint) { + for (RuntimeWireProcessor processor : processors.getWireProcessors()) { + processor.process(endpoint); + } + } + + public void process(RuntimeEndpointReference endpointReference) { + for (RuntimeWireProcessor processor : processors.getWireProcessors()) { + processor.process(endpointReference); + } + } + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/InterceptorAsyncImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/InterceptorAsyncImpl.java new file mode 100644 index 0000000000..265311fe6b --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/InterceptorAsyncImpl.java @@ -0,0 +1,111 @@ +/* + * 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.core.invocation; + + +import org.apache.tuscany.sca.invocation.InterceptorAsync; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.InvokerAsyncRequest; +import org.apache.tuscany.sca.invocation.InvokerAsyncResponse; +import org.apache.tuscany.sca.invocation.Message; + +/** + * A base class that holds the mechanics for representing + * chained interceptors and for driving processing up and + * down the chain. + * + */ +public abstract class InterceptorAsyncImpl implements InterceptorAsync { + + protected Invoker next; + protected InvokerAsyncResponse previous; + + public Invoker getNext() { + return (Invoker)next; + } + + public void setNext(Invoker next) { + this.next = next; + } + + public InvokerAsyncResponse getPrevious() { + return previous; + } + + public void setPrevious(InvokerAsyncResponse previous) { + this.previous = previous; + } + + public Message invoke(Message msg) { + msg = processRequest(msg); + Message resultMsg = getNext().invoke(msg); + resultMsg = processResponse(resultMsg); + return resultMsg; + } + + public void invokeAsyncRequest(Message msg) throws Throwable { + try{ + msg = processRequest(msg); + InvokerAsyncRequest theNext = (InvokerAsyncRequest)getNext(); + if( theNext != null ) theNext.invokeAsyncRequest(msg); + postProcessRequest(msg); + } catch (Throwable e) { + postProcessRequest(msg, e); + } // end try + } // end method invokeAsyncRequest + + public void invokeAsyncResponse(Message msg) { + msg = processResponse(msg); + InvokerAsyncResponse thePrevious = (InvokerAsyncResponse)getPrevious(); + if (thePrevious != null ) thePrevious.invokeAsyncResponse(msg); + } // end method invokeAsyncResponse + + /** + * Basic null version of postProcessRequest - subclasses should override for any required + * real processing + */ + public Message postProcessRequest(Message msg) { + // Default processing is to do nothing + return msg; + } // end method postProcessRequest + + /** + * Basic null version of postProcessRequest - subclasses should override for any required + * real processing + * @throws Throwable + */ + public Message postProcessRequest(Message msg, Throwable e) throws Throwable { + // Default processing is to rethrow the exception + throw e; + } // end method postProcessRequest + + + /** + * A testing method while I use the local SCA binding wire to look + * at how the async response path works. This allows me to detect the + * point where the reference wire turns into the service with in the + * optimized case + * + * @return + */ + public boolean isLocalSCABIndingInvoker() { + return false; + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/JDKAsyncResponseInvoker.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/JDKAsyncResponseInvoker.java new file mode 100644 index 0000000000..60958ed6f9 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/JDKAsyncResponseInvoker.java @@ -0,0 +1,40 @@ +/* + * 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.core.invocation; + +import org.apache.tuscany.sca.invocation.InvokerAsyncResponse; + +public interface JDKAsyncResponseInvoker extends InvokerAsyncResponse { + + /** + * Registers an Async response, which provides an ID which identifies a given response + * and an object which can handle the response + * @param id - the ID + * @param responseHandler - the response handler object + */ + public void registerAsyncResponse( String id, Object responseHandler ); + + /** + * Returns the registered async response for a given ID + * @param id - the ID + * @return responseHandler - the response handler object + */ + public Object getAsyncResponse( String id ); + +} // end interface JDKAsyncResponseInvoker diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/NonBlockingInterceptor.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/NonBlockingInterceptor.java new file mode 100644 index 0000000000..7108728206 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/NonBlockingInterceptor.java @@ -0,0 +1,197 @@ +/* + * 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.core.invocation; + +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.apache.tuscany.sca.assembly.Endpoint; +import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.context.ThreadMessageContext; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.invocation.Interceptor; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.work.WorkScheduler; +import org.oasisopen.sca.ServiceRuntimeException; + +/** + * Adds non-blocking behavior to an invocation chain + * + * @version $Rev$ $Date$ + */ +public class NonBlockingInterceptor extends InterceptorAsyncImpl { + + private static final Message RESPONSE = new ImmutableMessage(); + + /** + * The JDK logger that will be used to log messages. + */ + private static final Logger LOGGER = Logger.getLogger(NonBlockingInterceptor.class.getName()); + + private WorkScheduler workScheduler; + + public NonBlockingInterceptor(WorkScheduler workScheduler) { + this.workScheduler = workScheduler; + } + + public NonBlockingInterceptor(WorkScheduler workScheduler, Interceptor next) { + this.workScheduler = workScheduler; + this.next = next; + } + + /** + * Sets desired workScheduler to NonBlockingInterceptor. This is a useful function for the extension framework + * to set desired workmanager on the InvocationChain, other than default workmanager which is set per Tuscany runtime. + * Using this function, extension framework can set desired workmanager on InvocationChain during post wire processing. + * @param workScheduler workScheduler which contains workmanager + */ + public void setWorkScheduler(WorkScheduler workScheduler){ + this.workScheduler = workScheduler; + } + + /** + * For request/response messages use the workScheduler to break the connection between + * requests and the void response + */ + @Override + public Message invoke(final Message msg) { + // Schedule the invocation of the next interceptor in a new Work instance + try { + workScheduler.scheduleWork(new Runnable() { + public void run() { + Message context = ThreadMessageContext.setMessageContext(msg); + try { + Message response = null; + + Throwable ex = null; + try { + response = next.invoke(msg); + } catch (Throwable t) { + ex = t; + } + + // Tuscany-2225 - Did the @OneWay method complete successfully? + // (i.e. no exceptions) + if (response != null && response.isFault()) { + // The @OneWay method threw an Exception. Lets log it and + // then pass it on to the WorkScheduler so it can notify any + // listeners + ex = (Throwable)response.getBody(); + } + if (ex != null) { + LOGGER.log(Level.SEVERE, "Exception from @OneWay invocation", ex); + throw new ServiceRuntimeException("Exception from @OneWay invocation", ex); + } + } finally { + ThreadMessageContext.setMessageContext(context); + } + } + }); + } catch (Exception e) { + throw new ServiceRuntimeException(e); + } + return RESPONSE; + } + + /** + * For forward async responses we just pass the message along + * as this is naturally one way + */ + public Message processRequest(Message msg) { + return msg; + } + + /** + * This should never be called as a one way message won't + * expect a response + */ + public Message processResponse(Message msg) { + return null; + } + + /** + * A dummy message passed back on an invocation + */ + private static class ImmutableMessage implements Message { + + public T getBody() { + return null; + } + + public void setBody(Object body) { + if (body != null) { + throw new UnsupportedOperationException(); + } + } + + public Object getMessageID() { + return null; + } + + public void setMessageID(Object messageId) { + throw new UnsupportedOperationException(); + } + + public boolean isFault() { + return false; + } + + public void setFaultBody(Object fault) { + throw new UnsupportedOperationException(); + } + + public EndpointReference getFrom() { + return null; + } + + public Endpoint getTo() { + return null; + } + + public void setFrom(EndpointReference from) { + throw new UnsupportedOperationException(); + } + + public void setTo(Endpoint to) { + throw new UnsupportedOperationException(); + } + + public Operation getOperation() { + return null; + } + + public void setOperation(Operation op) { + throw new UnsupportedOperationException(); + } + + public Map getHeaders() { + return null; + } + public T getBindingContext() { + return null; + } + + public void setBindingContext(T bindingContext) { + } + } + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyCreationException.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyCreationException.java new file mode 100644 index 0000000000..0b36b178f3 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyCreationException.java @@ -0,0 +1,48 @@ +/* + * 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.core.invocation; + +import org.apache.tuscany.sca.core.factory.ObjectCreationException; + + +/** + * Denotes an error creating a proxy + * + * @version $Rev$ $Date$ + */ +public class ProxyCreationException extends ObjectCreationException { + private static final long serialVersionUID = 8002454344828513781L; + + public ProxyCreationException() { + super(); + } + + public ProxyCreationException(String message, Throwable cause) { + super(message, cause); + } + + public ProxyCreationException(String message) { + super(message); + } + + public ProxyCreationException(Throwable cause) { + super(cause); + } + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyFactory.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyFactory.java new file mode 100644 index 0000000000..8d9612315a --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyFactory.java @@ -0,0 +1,96 @@ +/* + * 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.core.invocation; + +import java.util.List; + +import org.apache.tuscany.sca.runtime.Invocable; +import org.oasisopen.sca.ServiceReference; + +/** + * Creates proxies that implement Java interfaces and invocation handlers for fronting wires + * + * @version $Rev$ $Date$ + * @tuscany.spi.extension.asclient + */ + +public interface ProxyFactory { + + /** + * Creates a Java proxy for the given wire + * + * @param interfaze the interface the proxy implements + * @param invocable the wire to proxy + * @return the proxy + * @throws ProxyCreationException + */ + T createProxy(Class interfaze, Invocable invocable) throws ProxyCreationException; + + /** + * Creates a Java proxy for the given CallableReference + * + * @param callableReference The CallableReference + * @return the proxy + * @throws ProxyCreationException + */ + T createProxy(ServiceReference callableReference) throws ProxyCreationException; + + /** + * Creates a Java proxy for the service contract callback + * + * @param interfaze the interface the proxy should implement + * @return the proxy + * @throws ProxyCreationException + */ + T createCallbackProxy(Class interfaze, List invocables) throws ProxyCreationException; + + /** + * Creates a Java proxy for the given callback reference + * + * @param callableReference The CallableReference + * @return the proxy + * @throws ProxyCreationException + */ + T createCallbackProxy(ServiceReference callbackReference) throws ProxyCreationException; + + /** + * Cast a proxy to a CallableReference. + * + * @param target a proxy generated by this implementation + * @return a CallableReference (or subclass) equivalent to this proxy + * @throws IllegalArgumentException if the object supplied is not a proxy + */ + > R cast(B target) throws IllegalArgumentException; + + /** + * Test if a given class is a generated proxy class by this factory + * @param clazz A java class or interface + * @return true if the class is a generated proxy class by this factory + */ + boolean isProxyClass(Class clazz); + + /** + * Allow cached proxies to be removed when a contribution is removed. The proxy + * cache holds the application interface so will pin the contribution classloader + * + * @param contributionClassloader the classloader of the contribution being removed + */ + void removeProxiesForContribution(ClassLoader contributionClassloader); + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyFactoryExtensionPoint.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyFactoryExtensionPoint.java new file mode 100644 index 0000000000..3e0bd7cb17 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyFactoryExtensionPoint.java @@ -0,0 +1,54 @@ +/* + * 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.core.invocation; + + +/** + * The extension point to plug in proxy factories + * @version $Rev$ $Date$ + * @tuscany.spi.extension.asclient + */ +public interface ProxyFactoryExtensionPoint { + + /** + * Get the proxy factory for java interfaces + * @return + */ + ProxyFactory getInterfaceProxyFactory(); + + /** + * Get the proxy factory for java classes + * @return + */ + ProxyFactory getClassProxyFactory(); + + /** + * Set the proxy factory for java interfaces + * @param factory + */ + void setInterfaceProxyFactory(ProxyFactory factory); + + /** + * Set the proxy factory for java classes + * @param factory + */ + void setClassProxyFactory(ProxyFactory factory); + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/RuntimeInvoker.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/RuntimeInvoker.java new file mode 100644 index 0000000000..8f093d62ed --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/RuntimeInvoker.java @@ -0,0 +1,210 @@ +/* + * 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.core.invocation; + +import java.lang.reflect.InvocationTargetException; +import java.util.UUID; +import java.util.concurrent.ExecutorService; + +import org.apache.tuscany.sca.assembly.Endpoint; +import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.context.ThreadMessageContext; +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.Operation; +import org.apache.tuscany.sca.invocation.InvocationChain; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.InvokerAsyncRequest; +import org.apache.tuscany.sca.invocation.InvokerAsyncResponse; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.runtime.Invocable; +import org.apache.tuscany.sca.runtime.RuntimeEndpointReference; +import org.apache.tuscany.sca.work.WorkScheduler; +import org.oasisopen.sca.ServiceRuntimeException; + +/** + * Invoker for a endpoint or endpoint reference + * @version $Rev$ $Date$ + */ +public class RuntimeInvoker implements Invoker, InvokerAsyncRequest { + protected ExtensionPointRegistry registry; + protected MessageFactory messageFactory; + protected Invocable invocable; + + // Run async service invocations using a ThreadPoolExecutor + private ExecutorService theExecutor; + + public RuntimeInvoker(ExtensionPointRegistry registry, Invocable invocable) { + this.registry = registry; + this.messageFactory = registry.getExtensionPoint(FactoryExtensionPoint.class).getFactory(MessageFactory.class); + this.invocable = invocable; + + UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); + WorkScheduler scheduler = utilities.getUtility(WorkScheduler.class); + theExecutor = scheduler.getExecutorService(); + } + + public Message invokeBinding(Message msg) { + Message context = ThreadMessageContext.setMessageContext(msg); + try { + return invocable.getBindingInvocationChain().getHeadInvoker().invoke(msg); + } finally { + ThreadMessageContext.setMessageContext(context); + } + } // end method invokeBinding + + /** + * Async Invoke of the Binding Chain + * @param msg - the message to use in the invocation + */ + public void invokeBindingAsync(Message msg) { + Message context = ThreadMessageContext.setMessageContext(msg); + try { + ((InvokerAsyncRequest)invocable.getBindingInvocationChain().getHeadInvoker()).invokeAsyncRequest(msg); + } catch (Throwable t ) { + // TODO - consider what best to do with exception + t.printStackTrace(); + } finally { + ThreadMessageContext.setMessageContext(context); + } // end try + } // end method invokeBindingAsync + + public Message invoke(Message msg) { + return invoke(msg.getOperation(), msg); + } + + public Object invoke(Operation operation, Object[] args) throws InvocationTargetException { + Message msg = messageFactory.createMessage(); + msg.setBody(args); + Message resp = invoke(operation, msg); + Object body = resp.getBody(); + if (resp.isFault()) { + throw new InvocationTargetException((Throwable)body); + } + return body; + } + + + public Message invoke(Operation operation, Message msg) { + InvocationChain chain = invocable.getInvocationChain(operation); + return invoke(chain, msg); + } + + public Message invoke(InvocationChain chain, Message msg) { + + if (invocable instanceof Endpoint) { + msg.setTo((Endpoint)invocable); + } else if (invocable instanceof EndpointReference) { + msg.setFrom((EndpointReference)invocable); + } + + Invoker headInvoker = chain.getHeadInvoker(); + Operation operation = chain.getTargetOperation(); + msg.setOperation(operation); + + Message msgContext = ThreadMessageContext.setMessageContext(msg); + try { + return headInvoker.invoke(msg); + } finally { + ThreadMessageContext.setMessageContext(msgContext); + } + } + + /** + * Initiate the sending of the forward part of an asynchronous + * exchange along the request part of the wire. + * + * @param msg the request message + */ + public void invokeAsync(Message msg) { + if (invocable instanceof Endpoint) { + Endpoint ep = (Endpoint)invocable; + msg.setTo(ep); + if (!ep.isAsyncInvocation()){ + throw new ServiceRuntimeException("Calling invokeAsync on a non-async endpoint - " + + ep); + } + } else if (invocable instanceof EndpointReference) { + RuntimeEndpointReference epr = (RuntimeEndpointReference)invocable; + if (!epr.isAsyncInvocation()){ + throw new ServiceRuntimeException("Calling invokeAsync on a non-async endpoint reference - " + + epr); + } + if (epr.isOutOfDate()) { + epr.rebuild(); + } + msg.setFrom(epr); + msg.setTo(epr.getTargetEndpoint()); + } + + Operation operation = msg.getOperation(); + InvocationChain chain = invocable.getInvocationChain(operation); + + if (chain == null) { + throw new IllegalArgumentException("No matching operation is found: " + operation.getName()); + } + + // create an async message ID if there isn't one there already + if (!msg.getHeaders().containsKey(Constants.MESSAGE_ID)){ + msg.getHeaders().put(Constants.MESSAGE_ID, UUID.randomUUID().toString());UUID.randomUUID().toString(); + } + + // Perform the async invocation + Invoker headInvoker = chain.getHeadInvoker(); + + Message msgContext = ThreadMessageContext.setMessageContext(msg); + try { + try { + ((InvokerAsyncRequest)headInvoker).invokeAsyncRequest(msg); + } catch (ServiceRuntimeException ex) { + throw ex; + } catch (Throwable ex) { + // temporary fix to swallow the dummy exception that's + // thrown back to get past the response chain processing. + if (!(ex instanceof AsyncResponseException)){ + throw new ServiceRuntimeException(ex); + } + } + } finally { + ThreadMessageContext.setMessageContext(msgContext); + } + + return; + } + + /** + * Initiate the sending of the response part of an asynchronous + * exchange along the response part of the wire. + * + * @param msg the response message + */ + public void invokeAsyncResponse(Message msg) { + InvocationChain chain = invocable.getInvocationChain(msg.getOperation()); + Invoker tailInvoker = chain.getTailInvoker(); + ((InvokerAsyncResponse)tailInvoker).invokeAsyncResponse(msg); + } // end method invokeAsyncResponse + + @Override + public void invokeAsyncRequest(Message msg) throws Throwable { + invokeAsync(msg); + } // end method invokeAsyncRequest +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/WireObjectFactory.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/WireObjectFactory.java new file mode 100644 index 0000000000..489d06a3e1 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/WireObjectFactory.java @@ -0,0 +1,56 @@ +/* + * 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.core.invocation; + +import org.apache.tuscany.sca.core.context.impl.ServiceReferenceImpl; +import org.apache.tuscany.sca.core.factory.ObjectCreationException; +import org.apache.tuscany.sca.core.factory.ObjectFactory; +import org.apache.tuscany.sca.core.invocation.impl.NoMethodForOperationException; +import org.apache.tuscany.sca.runtime.Invocable; + +/** + * Uses a wire to return an object instance + * + * @version $Rev$ $Date$ + * @tuscany.spi.extension.asclient + */ +public class WireObjectFactory implements ObjectFactory { + private Class interfaze; + private Invocable wire; + private ProxyFactory proxyService; + + /** + * Constructor. + * + * @param interfaze the interface to inject on the client + * @param wire the backing wire + * @param proxyService the wire service to create the proxy + * @throws NoMethodForOperationException + */ + public WireObjectFactory(Class interfaze, Invocable wire, ProxyFactory proxyService) { + this.interfaze = interfaze; + this.wire = wire; + this.proxyService = proxyService; + } + + public T getInstance() throws ObjectCreationException { + return new ServiceReferenceImpl(interfaze, wire, null).getProxy(); + } + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/AsyncInvocationFutureImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/AsyncInvocationFutureImpl.java new file mode 100644 index 0000000000..66b9516738 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/AsyncInvocationFutureImpl.java @@ -0,0 +1,285 @@ +/* + * 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.core.invocation.impl; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import javax.xml.ws.AsyncHandler; +import javax.xml.ws.Response; + +import org.apache.tuscany.sca.core.invocation.AsyncContext; +import org.apache.tuscany.sca.core.invocation.AsyncFaultWrapper; +import org.apache.tuscany.sca.core.invocation.AsyncResponseHandler; + +/** + * A class which provides an Implementation of a Future and Response for use with the JAXWS defined client + * asynchronous APIs. + * + * This implementation class provides the interfaces for use by the client code, but also provides methods for the + * Tuscany system code to set the result of the asynchronous service invocation, both Regular and Fault responses. + * + * This class is constructed to be fully thread-safe + * + * @param - this is the type of the response message from the invoked service. + */ +public class AsyncInvocationFutureImpl implements Future, Response, AsyncContext, AsyncResponseHandler { + + // Lock for handling the completion of this Future + private final Lock lock = new ReentrantLock(); + private final Condition isDone = lock.newCondition(); + + // The result + private volatile V response = null; + private volatile Throwable fault = null; + + private String uniqueID = UUID.randomUUID().toString(); + + private Class businessInterface = null; + private AsyncHandler callback; + + private Map attributes = new HashMap(); + + protected AsyncInvocationFutureImpl() { + super(); + } // end constructor + + /** + * Public constructor for AsyncInvocationFutureImpl - newInstance is necessary in order to enable the Type variable + * to be set for the class instances + * @param - the type of the response from the asynchronously invoked service + * @param type - the type of the AsyncInvocationFutureImpl expressed as a parameter + * @param classLoader - the classloader used for the business interface to which this Future applies + * @return - an instance of AsyncInvocationFutureImpl + */ + public static AsyncInvocationFutureImpl newInstance( Class type, Class businessInterface ) { + AsyncInvocationFutureImpl future = new AsyncInvocationFutureImpl(); + future.setBusinessInterface( businessInterface ); + return future; + } + + /** + * Cancels the asynchronous process + * - not possible in this version, so always returns false + */ + public boolean cancel(boolean mayInterruptIfRunning) { + return false; + } + + /** + * Gets the response value returned by the asynchronous process + * - waits forever + * @return - the response value of type V + * @throws InterruptedException if the get() method was interrupted while waiting for the async process to finish + * @throws ExecutionException if the async process threw an exception - the exception thrown is nested + */ + public V get() throws InterruptedException, ExecutionException { + try { + V response = get(Long.MAX_VALUE, TimeUnit.SECONDS); + return response; + } catch (TimeoutException t) { + throw new InterruptedException("Timed out waiting for Future to complete"); + } // end try + } // end method get() + + /** + * Gets the response value returned by the asynchronous process + * @return - the response value of type V + * @throws InterruptedException if the get() method was interrupted while waiting for the async process to finish + * @throws ExecutionException if the async process threw an exception - the exception thrown is nested + * @throws TimeoutException if the get() method timed out waiting for the async process to finish + */ + public V get(long timeout, TimeUnit unit) throws InterruptedException, + ExecutionException, TimeoutException { + lock.lock(); + try { + // wait for result to be available + if( notSetYet() ) isDone.await( timeout, unit); + if( response != null ) return response; + if( fault != null ) throw new ExecutionException( fault ); + throw new TimeoutException("get on this Future timed out"); + } finally { + lock.unlock(); + } // end try + + } // end method get(long timeout, TimeUnit unit) + + /** + * Indicates if the asynchronous process has been cancelled + * - not possible in this version so always returns false + */ + public boolean isCancelled() { + return false; + } + + /** + * Indicates if the asynchronous process is completed + * @return - true if the process is completed, false otherwise + */ + public boolean isDone() { + lock.lock(); + try { + return !notSetYet(); + } finally { + lock.unlock(); + } // end try + } // end method isDone + + /** + * Async process completed with a Fault. Must only be invoked once. + * @param e - the Fault to send + * @throws IllegalStateException if either the setResponse method or the setFault method have been called previously + */ + public void setFault( Throwable e ) { + lock.lock(); + try { + if( notSetYet() ) { + fault = e; + isDone.signalAll(); + } else { + throw new IllegalStateException("setResponse() or setFault() has been called previously"); + } // end if + } finally { + lock.unlock(); + } // end try + if (callback != null) { + callback.handleResponse(this); + } + } // end method setFault( Throwable ) + + /** + * Async process completed with a wrapped Fault. Must only be invoked once. + * @param w - the wrapped Fault to send + * @throws IllegalStateException if either the setResponse method or the setFault method have been called previously + */ + public void setWrappedFault(AsyncFaultWrapper w) { + + ClassLoader tccl = Thread.currentThread().getContextClassLoader(); + Throwable e; + try { + // Set the TCCL to the classloader of the business interface + Thread.currentThread().setContextClassLoader(this.getBusinessInterface().getClassLoader()); + e = w.retrieveFault(); + } finally { + Thread.currentThread().setContextClassLoader(tccl); + } // end try + + if( e == null ) throw new IllegalArgumentException("AsyncFaultWrapper did not return an Exception"); + setFault( e ); + + } // end method setFault( AsyncFaultWrapper ) + + /** + * Async process completed with a response message. Must only be invoked once + * @throws IllegalStateException if either the setResponse method or the setFault method have been called previously + * @param res - the response message, which is of type V + */ + public void setResponse(V res) { + + lock.lock(); + try { + if( notSetYet() ) { + response = res; + isDone.signalAll(); + } else { + throw new IllegalStateException("setResponse() or setFault() has been called previously"); + } + } finally { + lock.unlock(); + } // end try + if (callback != null) { + callback.handleResponse(this); + } + + } // end method setResponse + + /** + * Gets the unique ID of this future as a String + */ + public String getUniqueID() { return uniqueID; } + + /** + * Indicates that setting a response value is OK - can only set the response value or fault once + * @return - true if it is OK to set the response, false otherwise + */ + private boolean notSetYet() { + return ( response == null && fault == null ); + } + + /** + * Returns the JAXWS context for the response + * @return - a Map containing the context + */ + public Map getContext() { + // Intentionally returns null + return null; + } + + /** + * Gets the business interface to which this Future relates + * @return the business interface + */ + public Class getBusinessInterface() { + return businessInterface; + } + + /** + * Sets the business interface to which this Future relates + * @param classLoader - the classloader of the business interface + */ + public void setBusinessInterface(Class businessInterface) { + this.businessInterface = businessInterface; + } + + /** + * Sets the callback handler, when the client uses the async callback method + * @param callback - the client's callback object + */ + public void setCallback(AsyncHandler callback) { + this.callback = callback; + } + + /** + * Look up an attribute value by name. + * @param name The name of the attribute + * @return The value of the attribute + */ + public Object getAttribute(String name) { + return attributes.get(name); + } + + /** + * Set the value of an attribute. Allows extensions to associate other data with an async response. + * @param name The name of the attribute + * @param value + */ + public void setAttribute(String name, Object value) { + attributes.put(name, value); + } + +} // end class AsyncInvocationFutureImpl diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/AsyncJDKInvocationHandler.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/AsyncJDKInvocationHandler.java new file mode 100644 index 0000000000..dc5738af96 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/AsyncJDKInvocationHandler.java @@ -0,0 +1,740 @@ +/* + * 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.core.invocation.impl; + +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.io.StringReader; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.transform.stream.StreamSource; +import javax.xml.ws.AsyncHandler; +import javax.xml.ws.Response; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.ComponentService; +import org.apache.tuscany.sca.assembly.Endpoint; +import org.apache.tuscany.sca.assembly.Implementation; +import org.apache.tuscany.sca.assembly.Service; +import org.apache.tuscany.sca.assembly.builder.BindingBuilder; +import org.apache.tuscany.sca.assembly.builder.BuilderContext; +import org.apache.tuscany.sca.assembly.builder.BuilderExtensionPoint; +import org.apache.tuscany.sca.assembly.xml.Constants; +import org.apache.tuscany.sca.context.CompositeContext; +import org.apache.tuscany.sca.context.ThreadMessageContext; +import org.apache.tuscany.sca.contribution.processor.ContributionReadException; +import org.apache.tuscany.sca.contribution.processor.ProcessorContext; +import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor; +import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessorExtensionPoint; +import org.apache.tuscany.sca.contribution.processor.ValidatingXMLInputFactory; +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.core.assembly.RuntimeAssemblyFactory; +import org.apache.tuscany.sca.core.invocation.AsyncFaultWrapper; +import org.apache.tuscany.sca.core.invocation.AsyncResponseException; +import org.apache.tuscany.sca.core.invocation.AsyncResponseService; +import org.apache.tuscany.sca.core.invocation.JDKAsyncResponseInvoker; +import org.apache.tuscany.sca.interfacedef.InvalidInterfaceException; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceContract; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; +import org.apache.tuscany.sca.interfacedef.util.FaultException; +import org.apache.tuscany.sca.interfacedef.util.WrapperInfo; +import org.apache.tuscany.sca.invocation.InterceptorAsync; +import org.apache.tuscany.sca.invocation.InvocationChain; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.InvokerAsyncResponse; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.policy.Intent; +import org.apache.tuscany.sca.provider.EndpointReferenceAsyncProvider; +import org.apache.tuscany.sca.provider.PolicyProvider; +import org.apache.tuscany.sca.provider.ReferenceBindingProvider; +import org.apache.tuscany.sca.provider.ServiceBindingProvider; +import org.apache.tuscany.sca.runtime.Invocable; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; +import org.apache.tuscany.sca.runtime.RuntimeEndpointReference; +import org.apache.tuscany.sca.work.WorkScheduler; +import org.oasisopen.sca.ServiceReference; +import org.oasisopen.sca.ServiceRuntimeException; + +/** + * An InvocationHandler which deals with JAXWS-defined asynchronous client Java API method calls + * + * 2 asynchronous mappings exist for any given synchronous service operation, as shown in this example: + * public interface StockQuote { + * float getPrice(String ticker); + * Response getPriceAsync(String ticker); + * Future getPriceAsync(String ticker, AsyncHandler handler); + * } + * + * - the second method is called the "polling method", since the returned Response object permits + * the client to poll to see if the async call has completed + * - the third method is called the "async callback method", since in this case the client application can specify + * a callback operation that is automatically called when the async call completes + */ +public class AsyncJDKInvocationHandler extends JDKInvocationHandler { + + private static final long serialVersionUID = 1L; + + // Run the async service invocations using a WorkScheduler + private WorkScheduler scheduler; + + public AsyncJDKInvocationHandler(ExtensionPointRegistry registry, + MessageFactory messageFactory, + ServiceReference callableReference ) { + super(messageFactory, callableReference); + initWorkScheduler(registry); + } + + public AsyncJDKInvocationHandler(ExtensionPointRegistry registry, + MessageFactory messageFactory, + Class businessInterface, + Invocable source ) { + super(messageFactory, businessInterface, source); + initWorkScheduler(registry); + } + + private final void initWorkScheduler(ExtensionPointRegistry registry) { + UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); + scheduler = utilities.getUtility(WorkScheduler.class); + } // end method initWorkScheduler + + /** + * Perform the invocation of the operation + * - provides support for all 3 forms of client method: synchronous, polling and async callback + */ + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + + if (Object.class == method.getDeclaringClass()) { + return invokeObjectMethod(method, args); + } + + // force the bind of the reference so that we can look at the + // target contract to see if it's asynchronous + source.getInvocationChains(); + + if (isAsyncCallback(method)) { + return doInvokeAsyncCallback(proxy, method, args); + } else if (isAsyncPoll(method)) { + return doInvokeAsyncPoll(proxy, method, args, null); + } else { + // Regular synchronous method call + return doInvokeSync(proxy, method, args); + } + } + + /** + * Indicates if a supplied method has the form of an async callback method + * @param method - the method + * @return - true if the method has the form of an async callback + */ + protected boolean isAsyncCallback(Method method) { + if (method.getName().endsWith("Async") && (method.getReturnType() == Future.class)) { + if (method.getParameterTypes().length > 0) { + return method.getParameterTypes()[method.getParameterTypes().length - 1] == AsyncHandler.class; + } + } + return false; + } + + /** + * Indicates is a supplied method has the form of an async polling method + * @param method - the method + * @return - true if the method has the form of an async polling method + */ + protected boolean isAsyncPoll(Method method) { + return method.getName().endsWith("Async") && (method.getReturnType() == Response.class); + } + + /** + * Invoke an async polling method + * @param proxy - the reference proxy + * @param asyncMethod - the async method to invoke + * @param args - array of input arguments to the method + * @return - the Response object that is returned to the client application, typed by the + * type of the response + */ + @SuppressWarnings("unchecked") + protected Response doInvokeAsyncPoll(Object proxy, Method asyncMethod, Object[] args, AsyncHandler callback) { + Method method = getNonAsyncMethod(asyncMethod); + Class returnType = method.getReturnType(); + // Allocate the Future / Response object - note: Response is a subclass of Future + AsyncInvocationFutureImpl future = AsyncInvocationFutureImpl.newInstance(returnType, businessInterface); + if (callback != null) + future.setCallback(callback); + try { + invokeAsync(proxy, method, args, future, asyncMethod); + } catch (Throwable t) { + // invokeAsync schedules a separate Runnable to run the request. Any exception caught here + // is a runtime exception, not an application exception. + if (!(t instanceof ServiceRuntimeException)) { + t = new ServiceRuntimeException("Received Throwable: " + t.getClass().getName() + + " when invoking: " + + asyncMethod.getName(), t); + } + future.setFault(t); + } // end try + return future; + } // end method doInvokeAsyncPoll + + /** + * Provide a synchronous invocation of a service operation that is either synchronous or asynchronous + * @return + */ + protected Object doInvokeSync(Object proxy, Method method, Object[] args) throws Throwable { + if (isAsyncInvocation(source)) { + // Target service is asynchronous + Class returnType = method.getReturnType(); + AsyncInvocationFutureImpl future = + AsyncInvocationFutureImpl.newInstance(returnType, businessInterface); + invokeAsync(proxy, method, args, future, method); + // Wait for some maximum time for the result - 120 seconds here + // Really, if the service is async, the client should use async client methods to invoke the service + // - and be prepared to wait a *really* long time + Object response = null; + try { + response = future.get(120, TimeUnit.SECONDS); + } catch (ExecutionException ex) { + throw ex.getCause(); + } + return response; + } else { + // Target service is not asynchronous, so perform sync invocation + return super.invoke(proxy, method, args); + } // end if + } // end method doInvokeSync + + /** + * Invoke an async callback method - note that this form of the async client API has as its final parameter + * an AsyncHandler method, used for callbacks to the client code + * @param proxy - the reference proxy + * @param asyncMethod - the async method to invoke + * @param args - array of input arguments to the method + * @return - the Future object that is returned to the client application, typed by the type of + * the response + */ + @SuppressWarnings("unchecked") + private Object doInvokeAsyncCallback(final Object proxy, final Method asyncMethod, final Object[] args) + throws Exception { + + AsyncHandler callback = (AsyncHandler)args[args.length - 1]; + Response response = doInvokeAsyncPoll(proxy, asyncMethod, Arrays.copyOf(args, args.length - 1), callback); + return response; + + } // end method doInvokeAsyncCallback + + /** + * Invoke the target (synchronous) method asynchronously + * @param proxy - the reference proxy object + * @param method - the method to invoke + * @param args - arguments for the call + * @param future - Future for handling the response + * @return - returns the response from the invocation + * @throws Throwable - if an exception is thrown during the invocation + */ + @SuppressWarnings("unchecked") + private void invokeAsync(Object proxy, + Method method, + Object[] args, + AsyncInvocationFutureImpl future, + Method asyncMethod) throws Throwable { + if (source == null) { + throw new ServiceRuntimeException("No runtime source is available"); + } + + if (source instanceof RuntimeEndpointReference) { + RuntimeEndpointReference epr = (RuntimeEndpointReference)source; + if (epr.isOutOfDate()) { + epr.rebuild(); + chains.clear(); + } + } // end if + + InvocationChain chain = getInvocationChain(method, source); + + if (chain == null) { + throw new IllegalArgumentException("No matching operation is found: " + method); + } + + // Organize for an async service + RuntimeEndpoint theEndpoint = getAsyncCallback(source); + boolean isAsyncService = false; + if (theEndpoint != null) { + // ... the service is asynchronous but binding does not support async natively ... + attachFuture(theEndpoint, future); + } // end if + + if( isAsyncInvocation((RuntimeEndpointReference)source ) ) { + isAsyncService = true; + // Get hold of the JavaAsyncResponseHandler from the chain dealing with the async response + Invoker theInvoker = chain.getHeadInvoker(); + if( theInvoker instanceof InterceptorAsync ) { + InvokerAsyncResponse responseInvoker = ((InterceptorAsync)theInvoker).getPrevious(); + if( responseInvoker instanceof JDKAsyncResponseInvoker ) { + // Register the future as the response object with its ID + ((JDKAsyncResponseInvoker)responseInvoker).registerAsyncResponse(future.getUniqueID(), future); + } // end if + } // end if + } // end if + + // Perform the invocations on separate thread... + scheduler.scheduleWork(new SeparateThreadInvoker(chain, args, source, future, asyncMethod, isAsyncService)); + + return; + } // end method invokeAsync + + /** + * An inner class which acts as a runnable task for invoking services asynchronously on threads that are separate from + * those used to execute operations of components + * + * This supports both synchronous services and asynchronous services + */ + private class SeparateThreadInvoker implements Runnable { + + private AsyncInvocationFutureImpl future; + private Method asyncMethod; + private InvocationChain chain; + private Object[] args; + private Invocable invocable; + private boolean isAsyncService; + + public SeparateThreadInvoker(InvocationChain chain, + Object[] args, + Invocable invocable, + AsyncInvocationFutureImpl future, + Method asyncMethod, + boolean isAsyncService) { + super(); + this.chain = chain; + this.asyncMethod = asyncMethod; + this.args = args; + this.invocable = invocable; + this.future = future; + this.isAsyncService = isAsyncService; + } // end constructor + + public void run() { + Object result; + + try { + if (isAsyncService) { + if( supportsNativeAsync(invocable) ) { + // Binding supports native async invocations + invokeAsync(chain, args, invocable, future.getUniqueID()); + } else { + // Binding does not support native async invocations + invoke(asyncMethod, chain, args, invocable, future.getUniqueID()); + } // end if + // The result is returned asynchronously via the future... + } else { + // ... the service is synchronous ... + result = invoke(asyncMethod, chain, args, invocable); + Type type = null; + if (asyncMethod.getReturnType() == Future.class) { + // For callback async method, where a Future is returned + Type[] types = asyncMethod.getGenericParameterTypes(); + if (types.length > 0 && asyncMethod.getParameterTypes()[types.length - 1] == AsyncHandler.class) { + // Last parameter is AsyncHandler + type = types[types.length - 1]; + } // end if + } else if (asyncMethod.getReturnType() == Response.class) { + // For the polling method, Response + type = asyncMethod.getGenericReturnType(); + } // end if + if (type instanceof ParameterizedType) { + // Check if the parameterized type of Response is a doc-lit-wrapper class + Class wrapperClass = (Class)((ParameterizedType)type).getActualTypeArguments()[0]; + WrapperInfo wrapperInfo = chain.getSourceOperation().getOutputWrapper(); + if (wrapperInfo != null && wrapperInfo.getWrapperClass() == wrapperClass) { + Object wrapper = wrapperClass.newInstance(); + // Find the 1st matching property + for (PropertyDescriptor p : Introspector.getBeanInfo(wrapperClass).getPropertyDescriptors()) { + if (p.getWriteMethod() == null) { + // There is a "class" property ... + continue; + } // end if + if (p.getWriteMethod().getParameterTypes()[0].isInstance(result)) { + p.getWriteMethod().invoke(wrapper, result); + result = wrapper; + break; + } // end if + } // end for + } // end if + } // end if + future.setResponse(result); + } // end if + } catch (ServiceRuntimeException s) { + Throwable e = s.getCause(); + if (e != null && e instanceof FaultException) { + if ("AsyncResponse".equals(e.getMessage())) { + // Do nothing... + } else { + future.setFault(s); + } // end if + } // end if + else { + future.setFault(s); + } + } catch (AsyncResponseException ar) { + // This exception is received in the case where the Binding does not support async invocation + // natively - the initial invocation is effectively synchronous with this exception thrown to + // indicate that the service received the request but will send the response separately - do nothing + } catch (Throwable t) { + //System.out.println("Async invoke got exception: " + t.toString()); + // If we invoked a sync service, this might be an application exception. + // The databinding ensured the exception is type-compatible with the application. + future.setFault(t); + } // end try + + } // end method run + + } // end class SeparateThreadInvoker + + /** + * Attaches a future to the callback endpoint - so that the Future is triggered when a response is + * received from the asynchronous service invocation associated with the Future + * @param endpoint - the async callback endpoint + * @param future - the async invocation future to attach + */ + private void attachFuture(RuntimeEndpoint endpoint, AsyncInvocationFutureImpl future) { + Implementation impl = endpoint.getComponent().getImplementation(); + AsyncResponseHandlerImpl asyncHandler = (AsyncResponseHandlerImpl)impl; + asyncHandler.addFuture(future); + } // end method attachFuture + + /** + * Perform an async invocation on the reference + * @param chain - the chain + * @param args - parameters for the invocation + * @param invocable - the reference + * @param msgID - a message ID + */ + public void invokeAsync(InvocationChain chain, Object[] args, Invocable invocable, String msgID) { + Message msg = messageFactory.createMessage(); + if (invocable instanceof RuntimeEndpointReference) { + msg.setFrom((RuntimeEndpointReference)invocable); + } // end if + if (target != null) { + msg.setTo(target); + } else if (source instanceof RuntimeEndpointReference) { + msg.setTo(((RuntimeEndpointReference)invocable).getTargetEndpoint()); + } // end if + + Operation operation = chain.getTargetOperation(); + msg.setOperation(operation); + msg.setBody(args); + + Message msgContext = ThreadMessageContext.getMessageContext(); + + // Deal with header information that needs to be copied from the message context to the new message... + transferMessageHeaders( msg, msgContext); + + ThreadMessageContext.setMessageContext(msg); + + // If there is a supplied message ID, place its value into the Message Header under "MESSAGE_ID" + if( msgID != null ){ + msg.getHeaders().put("MESSAGE_ID", msgID); + } // end if + + try { + // Invoke the reference + invocable.invokeAsync(msg); + return; + } finally { + ThreadMessageContext.setMessageContext(msgContext); + } // end try + } // end method invokeAsync + + /** + * Get the async callback endpoint - if not already created, create and start it + * @param source - the RuntimeEndpointReference which needs an async callback endpoint + * @param future + * @return - the RuntimeEndpoint of the async callback + */ + private RuntimeEndpoint getAsyncCallback(Invocable source) { + if (!(source instanceof RuntimeEndpointReference)) + return null; + RuntimeEndpointReference epr = (RuntimeEndpointReference)source; + if (!isAsyncInvocation(epr)) return null; + + // Check to see if the binding supports async invocation natively + ReferenceBindingProvider eprProvider = epr.getBindingProvider(); + if( eprProvider instanceof EndpointReferenceAsyncProvider) { + if( ((EndpointReferenceAsyncProvider)eprProvider).supportsNativeAsync() ) return null; + } // end if + + RuntimeEndpoint endpoint; + synchronized (epr) { + endpoint = (RuntimeEndpoint)epr.getCallbackEndpoint(); + // If the async callback endpoint is already created, return it... + if (endpoint != null) + return endpoint; + // Create the endpoint for the async callback + endpoint = createAsyncCallbackEndpoint(epr); + epr.setCallbackEndpoint(endpoint); + } // end synchronized + + // Activate the new callback endpoint + startEndpoint(epr.getCompositeContext(), endpoint); + endpoint.getInvocationChains(); + + return endpoint; + } // end method setupAsyncCallback + + /** + * Start the callback endpoint + * @param compositeContext - the composite context + * @param ep - the endpoint to start + */ + private void startEndpoint(CompositeContext compositeContext, RuntimeEndpoint ep) { + for (PolicyProvider policyProvider : ep.getPolicyProviders()) { + policyProvider.start(); + } // end for + + final ServiceBindingProvider bindingProvider = ep.getBindingProvider(); + if (bindingProvider != null) { + // Allow bindings to add shutdown hooks. Requires RuntimePermission shutdownHooks in policy. + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + bindingProvider.start(); + return null; + } + }); + compositeContext.getEndpointRegistry().addEndpoint(ep); + } + } // end method startEndpoint + + /** + * Create the async callback endpoint for a reference that is going to invoke an asyncInvocation service + * @param epr - the RuntimeEndpointReference for which the callback is created + * @return - a RuntimeEndpoint representing the callback endpoint + */ + private RuntimeEndpoint createAsyncCallbackEndpoint(RuntimeEndpointReference epr) { + CompositeContext compositeContext = epr.getCompositeContext(); + RuntimeAssemblyFactory assemblyFactory = getAssemblyFactory(compositeContext); + RuntimeEndpoint endpoint = (RuntimeEndpoint)assemblyFactory.createEndpoint(); + endpoint.bind(compositeContext); + + // Create a pseudo-component and pseudo-service + // - need to end with a chain with an invoker into the AsyncCallbackHandler class + RuntimeComponent fakeComponent = null; + try { + fakeComponent = (RuntimeComponent)epr.getComponent().clone(); + applyImplementation(fakeComponent); + } catch (CloneNotSupportedException e2) { + // will not happen + } // end try + endpoint.setComponent(fakeComponent); + + // Create pseudo-service + ComponentService service = assemblyFactory.createComponentService(); + ExtensionPointRegistry registry = compositeContext.getExtensionPointRegistry(); + FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class); + JavaInterfaceFactory javaInterfaceFactory = + (JavaInterfaceFactory)modelFactories.getFactory(JavaInterfaceFactory.class); + JavaInterfaceContract interfaceContract = javaInterfaceFactory.createJavaInterfaceContract(); + try { + interfaceContract.setInterface(javaInterfaceFactory.createJavaInterface(AsyncResponseService.class)); + } catch (InvalidInterfaceException e1) { + // Nothing to do here - will not happen + } // end try + service.setInterfaceContract(interfaceContract); + String serviceName = epr.getReference().getName() + "_asyncCallback"; + service.setName(serviceName); + // MJE 06/12/2010 - fixup for JMS binding code which looks at the implementation service + // as well as the component service... + // Create a pseudo implementation service... + Service implService = assemblyFactory.createService(); + implService.setName(serviceName); + implService.setInterfaceContract(interfaceContract); + service.setService(implService); + // + endpoint.setService(service); + // Set pseudo-service onto the pseudo-component + List services = fakeComponent.getServices(); + services.clear(); + services.add(service); + + // Create a binding + Binding binding = createMatchingBinding(epr.getBinding(), fakeComponent, service, registry); + endpoint.setBinding(binding); + + // Need to establish policies here (binding has some...) + endpoint.getRequiredIntents().addAll(epr.getRequiredIntents()); + endpoint.getPolicySets().addAll(epr.getPolicySets()); + String epURI = epr.getComponent().getName() + "#service-binding(" + serviceName + "/" + serviceName + ")"; + endpoint.setURI(epURI); + endpoint.setUnresolved(false); + return endpoint; + } + + /** + * Create a matching binding to a supplied binding + * - the matching binding has the same binding type, but is for the supplied component and service + * @param matchBinding - the binding to match + * @param component - the component + * @param service - the service + * @param registry - registry for extensions + * @return - the matching binding, or null if it could not be created + */ + @SuppressWarnings("unchecked") + private Binding createMatchingBinding(Binding matchBinding, + RuntimeComponent component, + ComponentService service, + ExtensionPointRegistry registry) { + // Since there is no simple way to obtain a Factory for a binding where the type is not known ahead of + // time, the process followed here is to generate the XML element from the binding type QName + // and then read the XML using the processor for that XML... + QName bindingName = matchBinding.getType(); + String bindingXML = + ""; + + StAXArtifactProcessorExtensionPoint processors = + registry.getExtensionPoint(StAXArtifactProcessorExtensionPoint.class); + StAXArtifactProcessor processor = (StAXArtifactProcessor)processors.getProcessor(bindingName); + + FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class); + ValidatingXMLInputFactory inputFactory = modelFactories.getFactory(ValidatingXMLInputFactory.class); + StreamSource source = new StreamSource(new StringReader(bindingXML)); + + ProcessorContext context = new ProcessorContext(); + try { + XMLStreamReader reader = inputFactory.createXMLStreamReader(source); + reader.next(); + Binding newBinding = (Binding)processor.read(reader, context); + + // Create a URI address for the callback based on the Component_Name/Reference_Name pattern + String callbackURI = "/" + component.getName() + "/" + service.getName(); + newBinding.setURI(callbackURI); + + BuilderExtensionPoint builders = registry.getExtensionPoint(BuilderExtensionPoint.class); + BindingBuilder builder = builders.getBindingBuilder(newBinding.getType()); + if (builder != null) { + org.apache.tuscany.sca.assembly.builder.BuilderContext builderContext = new BuilderContext(registry); + builder.build(component, service, newBinding, builderContext, true); + } // end if + + return newBinding; + } catch (ContributionReadException e) { + e.printStackTrace(); + } catch (XMLStreamException e) { + e.printStackTrace(); + } + + return null; + } // end method createMatchingBinding + + /** + * Gets a RuntimeAssemblyFactory from the CompositeContext + * @param compositeContext + * @return the RuntimeAssemblyFactory + */ + private RuntimeAssemblyFactory getAssemblyFactory(CompositeContext compositeContext) { + ExtensionPointRegistry registry = compositeContext.getExtensionPointRegistry(); + FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class); + return (RuntimeAssemblyFactory)modelFactories.getFactory(AssemblyFactory.class); + } // end method RuntimeAssemblyFactory + + /** + * Applies an AsyncResponseHandlerImpl as the implementation of a RuntimeComponent + * - the AsyncResponseHandlerImpl acts as both the implementation class and the implementation provider... + * @param component - the component + */ + private void applyImplementation(RuntimeComponent component) { + AsyncResponseHandlerImpl asyncHandler = new AsyncResponseHandlerImpl(); + component.setImplementation(asyncHandler); + component.setImplementationProvider(asyncHandler); + return; + } // end method getImplementationProvider + + private static QName ASYNC_INVOKE = new QName(Constants.SCA11_NS, "asyncInvocation"); + + /** + * Determines if the service invocation is asynchronous + * @param source - the EPR involved in the invocation + * @return - true if the invocation is async + */ + private boolean isAsyncInvocation(Invocable source) { + if (!(source instanceof RuntimeEndpointReference)) + return false; + RuntimeEndpointReference epr = (RuntimeEndpointReference)source; + // First check is to see if the EPR itself has the asyncInvocation intent marked + for (Intent intent : epr.getRequiredIntents()) { + if (intent.getName().equals(ASYNC_INVOKE)) + return true; + } // end for + + // Second check is to see if the target service has the asyncInvocation intent marked + Endpoint ep = epr.getTargetEndpoint(); + for (Intent intent : ep.getRequiredIntents()) { + if (intent.getName().equals(ASYNC_INVOKE)) + return true; + } // end for + return false; + } // end isAsyncInvocation + + private boolean supportsNativeAsync(Invocable source) { + if (!(source instanceof RuntimeEndpointReference)) + return false; + RuntimeEndpointReference epr = (RuntimeEndpointReference)source; + + // TODO - need to update this once BindingProvider interface is refactored to contain + // supportsNativeAsync directly... + ReferenceBindingProvider provider = epr.getBindingProvider(); + if( provider instanceof EndpointReferenceAsyncProvider ) { + return ((EndpointReferenceAsyncProvider)provider).supportsNativeAsync(); + } else { + return false; + } // end if + } // end method supportsNativeAsync + + /** + * Return the synchronous method that is the equivalent of an async method + * @param asyncMethod - the async method + * @return - the equivalent synchronous method + */ + protected Method getNonAsyncMethod(Method asyncMethod) { + String methodName = asyncMethod.getName().substring(0, asyncMethod.getName().length() - 5); + for (Method m : businessInterface.getMethods()) { + if (methodName.equals(m.getName())) { + return m; + } + } + throw new IllegalStateException("No synchronous method matching async method " + asyncMethod.getName()); + } // end method getNonAsyncMethod +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/AsyncResponse.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/AsyncResponse.java new file mode 100644 index 0000000000..7b459f3e7d --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/AsyncResponse.java @@ -0,0 +1,68 @@ +/* + * 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.core.invocation.impl; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import javax.xml.ws.Response; + +public class AsyncResponse implements Response { + + private Object response; + private boolean isException; + + public AsyncResponse(Object response, boolean isException) { + this.response = response; + this.isException = isException; + } + + public Map getContext() { + return new HashMap(); + } + + public boolean cancel(boolean mayInterruptIfRunning) { + return false; + } + + public Object get() throws InterruptedException, ExecutionException { + if (isException) { + throw new ExecutionException((Throwable)response); + } else { + return response; + } + } + + public Object get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + return get(); + } + + public boolean isCancelled() { + return false; + } + + public boolean isDone() { + return true; + } + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/AsyncResponseHandlerImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/AsyncResponseHandlerImpl.java new file mode 100644 index 0000000000..9de1809200 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/AsyncResponseHandlerImpl.java @@ -0,0 +1,197 @@ +/* + * 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.core.invocation.impl; + +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.assembly.Implementation; +import org.apache.tuscany.sca.assembly.Property; +import org.apache.tuscany.sca.assembly.Reference; +import org.apache.tuscany.sca.assembly.Service; +import org.apache.tuscany.sca.core.invocation.AsyncFaultWrapper; +import org.apache.tuscany.sca.core.invocation.AsyncResponseHandler; +import org.apache.tuscany.sca.core.invocation.Constants; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.policy.ExtensionType; +import org.apache.tuscany.sca.policy.Intent; +import org.apache.tuscany.sca.policy.PolicySet; +import org.apache.tuscany.sca.provider.ImplementationProvider; +import org.apache.tuscany.sca.runtime.RuntimeComponentService; + +/** + * A class intended to form the final link in the chain calling into a Future which represents + * the response to an asynchronous service invocation + * + * Most methods are dummies, required to fulfil the contracts for ImplementationProvider, Implementation + * and Invoker, since this class collapses together the functions of these separate interfaces, due to its + * specialized nature, where most of the function will never be used. + * + * The class acts as the implementation object that terminates the chain - and also as the provider of the implementation. + * The class accepts Future objects which represent individual invocations of forward operations on the async service + * and expects that the responses it handles as invocations will carry the unique ID of one of the Future objects in the + * message header. On receipt of each message, the class seeks out the Future with that unique ID and completes the future + * either with a response message or with a Fault. + * + * @param + */ +public class AsyncResponseHandlerImpl implements AsyncResponseHandler, + ImplementationProvider, Implementation, Invoker { + + private ConcurrentHashMap< String, AsyncInvocationFutureImpl > table = + new ConcurrentHashMap< String, AsyncInvocationFutureImpl >(); + + /** + * This class is its own invoker... + */ + public Invoker createInvoker(RuntimeComponentService service, + Operation operation) { + return this; + } + + /** + * Add a future to this response handler + * @param future - the future + */ + public void addFuture( AsyncInvocationFutureImpl future ) { + // The Future is stored in the table indexed by its unique ID + table.put(future.getUniqueID(), future); + } // end method addFuture + + public boolean supportsOneWayInvocation() { + return true; + } + + public void start() {} + + public void stop() {} + + public List getOperations() { + return null; + } + + public QName getType() { + return null; + } + + public List getProperties() { + return null; + } + + public Property getProperty(String name) { + return null; + } + + public Reference getReference(String name) { + return null; + } + + public List getReferences() { + return null; + } + + public Service getService(String name) { + return null; + } + + public List getServices() { + return null; + } + + public String getURI() { + return null; + } + + public void setURI(String uri) {} + + public boolean isUnresolved() { + return false; + } + + public void setUnresolved(boolean unresolved) {} + + public ExtensionType getExtensionType() { + return null; + } + + public List getPolicySets() { + return null; + } + + public List getRequiredIntents() { + return null; + } + + public void setExtensionType(ExtensionType type) {} + + public void setWrappedFault(AsyncFaultWrapper e) {} + + public void setFault(Throwable e) {} + + public void setResponse(V res) { } + + /** + * Method which is the termination for the invocation chain from the callback endpoint + * @param msg - the Tuscany message containing the response from the async service invocation + * which is either the Response message or an exception of some kind + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public Message invoke(Message msg) { + // Get the unique ID from the RELATES_TO message header + String idValue = (String)msg.getHeaders().get(Constants.RELATES_TO); + + if( idValue == null ) { + System.out.println( "Async message ID not found "); + } else { + // Fetch the Future with that Unique ID + AsyncInvocationFutureImpl future = table.get(idValue); + if( future == null ) { + System.out.println("Future not found for id: " + idValue); + } else { + // Complete the Future with a Response message + Object payload = msg.getBody(); + Object response; + if( payload == null ) { + System.out.println("Returned response message was null"); + } else { + if (payload.getClass().isArray()) { + response = ((Object[])payload)[0]; + } else { + response = payload; + } // end if + if( response.getClass().equals(AsyncFaultWrapper.class)) { + future.setWrappedFault((AsyncFaultWrapper) response ); + } else { + future.setResponse(response); + } // end if + } // end if + } // end if + } // end if + + // Prepare an empty response message + msg.setBody(null); + return msg; + } // end method invoke + +} // end class diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/InvocationChainImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/InvocationChainImpl.java new file mode 100644 index 0000000000..0e4d4344d2 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/InvocationChainImpl.java @@ -0,0 +1,313 @@ +/* + * 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.core.invocation.impl; + +import java.util.ArrayList; +import java.util.List; +import java.util.ListIterator; + +import org.apache.tuscany.sca.core.invocation.InterceptorAsyncImpl; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.invocation.DataExchangeSemantics; +import org.apache.tuscany.sca.invocation.Interceptor; +import org.apache.tuscany.sca.invocation.InterceptorAsync; +import org.apache.tuscany.sca.invocation.InvocationChain; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.InvokerAsyncRequest; +import org.apache.tuscany.sca.invocation.InvokerAsyncResponse; +import org.apache.tuscany.sca.invocation.Phase; +import org.apache.tuscany.sca.invocation.PhasedInterceptor; + +/** + * Default implementation of an invocation chain + * + * @version $Rev$ $Date$ + */ +public class InvocationChainImpl implements InvocationChain { + private Operation sourceOperation; + private Operation targetOperation; + private List nodes = new ArrayList(); + + private final PhaseManager phaseManager; + private boolean forReference; + private boolean allowsPassByReference; + private boolean isAsyncInvocation; + + public InvocationChainImpl(Operation sourceOperation, Operation targetOperation, boolean forReference, PhaseManager phaseManager, boolean isAsyncInvocation) { + this.targetOperation = targetOperation; + this.sourceOperation = sourceOperation; + this.forReference = forReference; + this.phaseManager = phaseManager; + this.isAsyncInvocation = isAsyncInvocation; + } + + public Operation getTargetOperation() { + return targetOperation; + } + + public void setTargetOperation(Operation operation) { + this.targetOperation = operation; + } + + public void addInterceptor(Interceptor interceptor) { + if (interceptor instanceof PhasedInterceptor) { + PhasedInterceptor pi = (PhasedInterceptor)interceptor; + if (pi.getPhase() != null) { + addInvoker(pi.getPhase(), pi); + return; + } + } + String phase = forReference ? Phase.REFERENCE : Phase.SERVICE; + addInterceptor(phase, interceptor); + } // end method addInterceptor + + public void addInvoker(Invoker invoker) { + if (invoker instanceof PhasedInterceptor) { + PhasedInterceptor pi = (PhasedInterceptor)invoker; + if (pi.getPhase() != null) { + addInvoker(pi.getPhase(), pi); + return; + } + } + String phase = forReference ? Phase.REFERENCE_BINDING : Phase.IMPLEMENTATION; + addInvoker(phase, invoker); + } + + public Invoker getHeadInvoker() { + return nodes.isEmpty() ? null : nodes.get(0).getInvoker(); + } + + public Invoker getTailInvoker() { + int nodeCount = nodes.size(); + if( nodeCount > 0 ) { + return nodes.get( nodeCount - 1).getInvoker(); + } // end if + + return null; + } // end method getTailInvoker + + public Invoker getHeadInvoker(String phase) { + int index = phaseManager.getAllPhases().indexOf(phase); + if (index == -1) { + throw new IllegalArgumentException("Invalid phase name: " + phase); + } + for (Node node : nodes) { + if (index <= node.getPhaseIndex()) { + return node.getInvoker(); + } + } + return null; + } + + /** + * @return the sourceOperation + */ + public Operation getSourceOperation() { + return sourceOperation; + } + + /** + * @param sourceOperation the sourceOperation to set + */ + public void setSourceOperation(Operation sourceOperation) { + this.sourceOperation = sourceOperation; + } + + public void addInterceptor(String phase, Interceptor interceptor) { + addInvoker(phase, interceptor); + } + + private void addInvoker(String phase, Invoker invoker) { + if (isAsyncInvocation && + !(invoker instanceof InvokerAsyncRequest) && + !(invoker instanceof InvokerAsyncResponse) ){ + // TODO - should raise an error but don't want to break + // the existing non-native async support +/* + throw new IllegalArgumentException("Trying to add synchronous invoker " + + invoker.getClass().getName() + + " to asynchronous chain"); +*/ + } + + int index = phaseManager.getAllPhases().indexOf(phase); + if (index == -1) { + throw new IllegalArgumentException("Invalid phase name: " + phase); + } + Node node = new Node(index, invoker); + ListIterator li = nodes.listIterator(); + Node before = null, after = null; + boolean found = false; + while (li.hasNext()) { + before = after; + after = li.next(); + if (after.getPhaseIndex() > index) { + // Move back + li.previous(); + li.add(node); + found = true; + break; + } + } + if (!found) { + // Add to the end + nodes.add(node); + before = after; + after = null; + } + + // Relink the interceptors + if (before != null) { + if (before.getInvoker() instanceof Interceptor) { + ((Interceptor)before.getInvoker()).setNext(invoker); + if ((invoker instanceof InterceptorAsync) && + (before.getInvoker() instanceof InvokerAsyncResponse)) { + ((InterceptorAsync) invoker).setPrevious((InvokerAsyncResponse)before.getInvoker()); + } + } + } + if (after != null) { + if (invoker instanceof Interceptor) { + ((Interceptor)invoker).setNext(after.getInvoker()); + if ((after.getInvoker() instanceof InterceptorAsync) && + (invoker instanceof InvokerAsyncResponse)){ + ((InterceptorAsync) after.getInvoker()).setPrevious((InvokerAsyncResponse)invoker); + } + } + } + + } + + public boolean allowsPassByReference() { + if (allowsPassByReference) { + // No need to check the invokers + return true; + } + // Check if any of the invokers allows pass-by-reference + boolean allowsPBR = false; + for (Node i : nodes) { + if (i.getInvoker() instanceof DataExchangeSemantics) { + if (((DataExchangeSemantics)i.getInvoker()).allowsPassByReference()) { + allowsPBR = true; + break; + } + } + } + return allowsPBR; + } + + public void setAllowsPassByReference(boolean allowsPBR) { + this.allowsPassByReference = allowsPBR; + } + + private static class Node { + private int phaseIndex; + private Invoker invoker; + + public Node(int phaseIndex, Invoker invoker) { + super(); + this.phaseIndex = phaseIndex; + this.invoker = invoker; + } + + public int getPhaseIndex() { + return phaseIndex; + } + + public Invoker getInvoker() { + return invoker; + } + + @Override + public String toString() { + return "(" + phaseIndex + ")" + invoker; + } + } + + public boolean isAsyncInvocation() { + return isAsyncInvocation; + } + + public void addHeadInterceptor(Interceptor interceptor) { + String phase = forReference ? Phase.REFERENCE : Phase.SERVICE_BINDING; + if (interceptor instanceof PhasedInterceptor) { + PhasedInterceptor pi = (PhasedInterceptor)interceptor; + if (pi.getPhase() != null) { + phase = pi.getPhase(); + } // end if + } // end if + + addHeadInterceptor(phase, interceptor); + } // end method addHeadInterceptor + + public void addHeadInterceptor(String phase, Interceptor interceptor) { + // TODO Auto-generated method stub + Invoker invoker = (Invoker)interceptor; + + int index = phaseManager.getAllPhases().indexOf(phase); + if (index == -1) { + throw new IllegalArgumentException("Invalid phase name: " + phase); + } // end if + Node node = new Node(index, invoker); + + ListIterator li = nodes.listIterator(); + Node before = null, after = null; + boolean found = false; + while (li.hasNext()) { + before = after; + after = li.next(); + // Look for the first node with a phase index equal to or greater than the one provided + if (after.getPhaseIndex() >= index) { + // Move back + li.previous(); + li.add(node); + found = true; + break; + } + } + if (!found) { + // Add to the end + nodes.add(node); + before = after; + after = null; + } + + // Relink the interceptors + if (before != null) { + if (before.getInvoker() instanceof Interceptor) { + ((Interceptor)before.getInvoker()).setNext(invoker); + if ((invoker instanceof InterceptorAsync) && + (before.getInvoker() instanceof InvokerAsyncResponse)) { + ((InterceptorAsync) invoker).setPrevious((InvokerAsyncResponse)before.getInvoker()); + } + } + } + if (after != null) { + if (invoker instanceof Interceptor) { + ((Interceptor)invoker).setNext(after.getInvoker()); + if ((after.getInvoker() instanceof InterceptorAsync) && + (invoker instanceof InvokerAsyncResponse)){ + ((InterceptorAsync) after.getInvoker()).setPrevious((InvokerAsyncResponse)invoker); + } + } + } + + } // end method addHeadInterceptor + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/JDKCallbackInvocationHandler.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/JDKCallbackInvocationHandler.java new file mode 100644 index 0000000000..bde3e92c27 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/JDKCallbackInvocationHandler.java @@ -0,0 +1,153 @@ +/* + * 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.core.invocation.impl; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.apache.tuscany.sca.context.ThreadMessageContext; +import org.apache.tuscany.sca.core.context.impl.CallbackServiceReferenceImpl; +import org.apache.tuscany.sca.core.invocation.Constants; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.invocation.InvocationChain; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.runtime.Invocable; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; +import org.apache.tuscany.sca.runtime.RuntimeEndpointReference; +import org.oasisopen.sca.ServiceReference; +import org.oasisopen.sca.ServiceRuntimeException; + +/** + * Responsible for dispatching to a callback through a wire.

TODO cache + * target invoker + * + * @version $Rev$ $Date$ + */ +public class JDKCallbackInvocationHandler extends JDKInvocationHandler { + private static final long serialVersionUID = -3350283555825935609L; + + public JDKCallbackInvocationHandler(MessageFactory messageFactory, ServiceReference ref) { + super(messageFactory, ref); + this.fixedWire = false; + } + + @Override + @SuppressWarnings( {"unchecked", "rawtypes"}) + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + + if (Object.class == method.getDeclaringClass()) { + return invokeObjectMethod(method, args); + } + + // obtain a dedicated wire to be used for this callback invocation + RuntimeEndpointReference wire = ((CallbackServiceReferenceImpl)callableReference).getCallbackEPR(); + if (wire == null) { + //FIXME: need better exception + throw new ServiceRuntimeException("No callback wire found"); + } + + setEndpoint(((CallbackServiceReferenceImpl)callableReference).getResolvedEndpoint()); + + InvocationChain chain = getInvocationChain(method, wire); + if (chain == null) { + throw new IllegalArgumentException("No matching operation is found: " + method); + } + + try { + String msgID = ((CallbackServiceReferenceImpl)callableReference).getMsgID(); + return invoke(method, chain, args, wire, msgID ); + } catch (InvocationTargetException e) { + Throwable t = e.getCause(); + throw t; + } finally { + // allow the cloned wire to be reused by subsequent callbacks + } + } + + /** + * Invoke the chain + * @param chain - the chain + * @param args - arguments to the invocation as an array of Objects + * @param source - the Endpoint or EndpointReference to which the chain relates + * @param msgID - ID of the message to which this invovation is a callback - ID ends up in "RELATES_TO" header + * @return - the Response message from the invocation + * @throws Throwable - if any exception occurs during the invocation + */ + @Override + protected Object invoke(Method method, InvocationChain chain, Object[] args, Invocable source, String msgID) + throws Throwable { + Message msg = messageFactory.createMessage(); + if (source instanceof RuntimeEndpointReference) { + msg.setFrom((RuntimeEndpointReference)source); + } + if (target != null) { + msg.setTo(target); + } else { + if (source instanceof RuntimeEndpointReference) { + msg.setTo(((RuntimeEndpointReference)source).getTargetEndpoint()); + } + } + + msg.getHeaders().put(Constants.CALLBACK, ((CallbackServiceReferenceImpl)callableReference).getCallbackHandler()); + + Invoker headInvoker = chain.getHeadInvoker(); + + Operation operation = null; + if(source instanceof RuntimeEndpoint) { + for (InvocationChain c : source.getInvocationChains()) { + Operation op = c.getTargetOperation(); + if (method.getName().equals(op.getName())) { + operation = op; + break; + } + } + } else { + operation = chain.getTargetOperation(); + } + msg.setOperation(operation); + msg.setBody(args); + + Message msgContext = ThreadMessageContext.getMessageContext(); + + // Deal with header information that needs to be copied from the message context to the new message... + transferMessageHeaders( msg, msgContext); + + ThreadMessageContext.setMessageContext(msg); + + // If there is a supplied message ID, place its value into the Message Header under "RELATES_TO" + if( msgID != null ){ + msg.getHeaders().put(Constants.RELATES_TO, msgID); + } // end if + + try { + // dispatch the source down the chain and get the response + Message resp = headInvoker.invoke(msg); + Object body = resp.getBody(); + if (resp.isFault()) { + throw (Throwable)body; + } + return body; + } finally { + ThreadMessageContext.setMessageContext(msgContext); + } + } // end method invoke + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/JDKInvocationHandler.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/JDKInvocationHandler.java new file mode 100644 index 0000000000..827008dc73 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/JDKInvocationHandler.java @@ -0,0 +1,436 @@ +/* + * 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.core.invocation.impl; + +import java.io.Serializable; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.ws.Holder; + +import org.apache.tuscany.sca.assembly.Endpoint; +import org.apache.tuscany.sca.context.ThreadMessageContext; +import org.apache.tuscany.sca.core.context.ServiceReferenceExt; +import org.apache.tuscany.sca.interfacedef.DataType; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.interfacedef.ParameterMode; +import org.apache.tuscany.sca.interfacedef.java.JavaOperation; +import org.apache.tuscany.sca.invocation.InvocationChain; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.runtime.Invocable; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; +import org.apache.tuscany.sca.runtime.RuntimeEndpointReference; +import org.oasisopen.sca.ServiceReference; +import org.oasisopen.sca.ServiceRuntimeException; + +/** + * @version $Rev$ $Date$ + */ +public class JDKInvocationHandler implements InvocationHandler, Serializable { + private static final long serialVersionUID = -3366410500152201371L; + + protected MessageFactory messageFactory; + protected Endpoint target; + protected Invocable source; + protected ServiceReferenceExt callableReference; + protected Class businessInterface; + + protected boolean fixedWire = true; + + protected transient Map chains = new IdentityHashMap(); + + public JDKInvocationHandler(MessageFactory messageFactory, Class businessInterface, Invocable source) { + this.messageFactory = messageFactory; + this.source = source; + this.businessInterface = businessInterface; + } + + public JDKInvocationHandler(MessageFactory messageFactory, ServiceReference callableReference) { + this.messageFactory = messageFactory; + this.callableReference = (ServiceReferenceExt)callableReference; + if (callableReference != null) { + this.businessInterface = callableReference.getBusinessInterface(); + this.source = (RuntimeEndpointReference) this.callableReference.getEndpointReference(); + } + } + + + public Class getBusinessInterface() { + return businessInterface; + } + + protected Object getCallbackID() { + return null; + } + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if (Object.class == method.getDeclaringClass()) { + return invokeObjectMethod(method, args); + } + if (source == null) { + throw new ServiceRuntimeException("No runtime source is available"); + } + + if (source instanceof RuntimeEndpointReference) { + RuntimeEndpointReference epr = (RuntimeEndpointReference)source; + if (epr.isOutOfDate()) { + epr.rebuild(); + chains.clear(); + } + } + + InvocationChain chain = getInvocationChain(method, source); + + if (chain == null) { + throw new IllegalArgumentException("No matching operation is found: " + method); + } + + // Holder pattern. Items stored in a Holder are promoted to T. + // After the invoke, the returned data are placed back in Holder. + Object [] promotedArgs = promoteHolderArgs( args ); + + // Strip out OUT-only arguments. Not too sure if the presence + // of a sourceOperation is exactly the right check to use to + // know whether or not to do this, but will assume it is until + // learning otherwise. + Operation sourceOp = chain.getSourceOperation(); + if (sourceOp != null) { + promotedArgs = removeOutOnlyArgs(sourceOp, promotedArgs ); + } + + Object result = invoke(method, chain, promotedArgs, source); + + // TODO - Based on the code in JavaInterfaceIntrospectorImpl, it seems there are + // some cases involving generics that we're not taking into account. + boolean voidReturnType = (void.class == method.getReturnType() ? true : false); + + // Returned Holder data are placed back in Holder. + boolean holderPattern = false; + Class [] parameters = method.getParameterTypes(); + if ( parameters != null ) { + int resultIdx = (voidReturnType ? 0 : 1); + for ( int i = 0; i < parameters.length; i++ ) { + Class parameterType = parameters[ i ]; + if ( isHolder( parameterType ) ) { + holderPattern = true; + // Pop results and place in holder (demote). + Holder holder = (Holder) args[ i ]; + + Object[] results = (Object[])result; + if ( result != null ) { + holder.value = results[resultIdx++]; + } + } + } + } + if (holderPattern && result != null) { + if (voidReturnType) { + return null; + } else { + return ((Object[])result)[0]; + } + } else { + return result; + } + } + + /** + * Handle the methods on the Object.class + * @param method + * @param args + */ + protected Object invokeObjectMethod(Method method, Object[] args) throws Throwable { + String name = method.getName(); + if ("toString".equals(name)) { + return "[Proxy - " + toString() + "]"; + } else if ("equals".equals(name)) { + Object obj = args[0]; + if (obj == null) { + return false; + } + if (!Proxy.isProxyClass(obj.getClass())) { + return false; + } + return equals(Proxy.getInvocationHandler(obj)); + } else if ("hashCode".equals(name)) { + return hashCode(); + } else { + return method.invoke(this); + } + } + + /** + * Determines if the given operation matches the given method + * + * @return true if the operation matches, false if does not + */ + // FIXME: Should it be in the InterfaceContractMapper? + @SuppressWarnings("unchecked") + private static boolean match(Operation operation, Method method) { + if (operation instanceof JavaOperation) { + JavaOperation javaOp = (JavaOperation)operation; + Method m = javaOp.getJavaMethod(); + if (!method.getName().equals(m.getName())) { + return false; + } + if (method.equals(m)) { + return true; + } + } else { + if (!method.getName().equals(operation.getName())) { + return false; + } + } + + // For remotable interface, operation is not overloaded. + if (operation.getInterface().isRemotable()) { + return true; + } + + Class[] params = method.getParameterTypes(); + + DataType> inputType = null; + if (operation.isInputWrapperStyle()) { + inputType = operation.getInputWrapper().getUnwrappedType(); + } else { + inputType = operation.getInputType(); + } + List types = inputType.getLogical(); + boolean matched = true; + if (types.size() == params.length && method.getName().equals(operation.getName())) { + for (int i = 0; i < params.length; i++) { + Class clazz = params[i]; + Class type = types.get(i).getPhysical(); + // Object.class.isAssignableFrom(int.class) returns false + if (type != Object.class && (!type.isAssignableFrom(clazz))) { + matched = false; + } + } + } else { + matched = false; + } + return matched; + + } + + protected synchronized InvocationChain getInvocationChain(Method method, Invocable source) { + if (source instanceof RuntimeEndpoint) { + // [rfeng] Start with the binding invocation chain + return source.getBindingInvocationChain(); + } + if (fixedWire && chains.containsKey(method)) { + return chains.get(method); + } + InvocationChain found = null; + for (InvocationChain chain : source.getInvocationChains()) { + Operation operation = chain.getSourceOperation(); + if (operation.isDynamic()) { + operation.setName(method.getName()); + found = chain; + break; + } else if (match(operation, method)) { + found = chain; + break; + } + } + if (fixedWire) { + chains.put(method, found); + } + return found; + } + + protected void setEndpoint(Endpoint endpoint) { + this.target = endpoint; + } + + protected Object invoke(Method method, InvocationChain chain, Object[] args, Invocable source) + throws Throwable { + return invoke( method, chain, args, source, null ); + } + + /** + * Invoke the chain + * @param chain - the chain + * @param args - arguments to the invocation as an array of Objects + * @param source - the Endpoint or EndpointReference to which the chain relates + * @param msgID - an ID for the message being sent, may be null + * @return - the Response message from the invocation + * @throws Throwable - if any exception occurs during the invocation + */ + protected Object invoke(Method method, InvocationChain chain, Object[] args, Invocable source, String msgID) + throws Throwable { + Message msg = messageFactory.createMessage(); + if (source instanceof RuntimeEndpointReference) { + msg.setFrom((RuntimeEndpointReference)source); + } + if (target != null) { + msg.setTo(target); + } else { + if (source instanceof RuntimeEndpointReference) { + msg.setTo(((RuntimeEndpointReference)source).getTargetEndpoint()); + } + } + Invoker headInvoker = chain.getHeadInvoker(); + Operation operation = null; + if(source instanceof RuntimeEndpoint) { + // [rfeng] We cannot use the targetOperation from the binding invocation chain. + // For each method, we need to find the matching operation so that we can set the operation on to the message + for (InvocationChain c : source.getInvocationChains()) { + Operation op = c.getTargetOperation(); + if (method.getName().equals(op.getName())) { + operation = op; + break; + } + } + } else { + operation = chain.getTargetOperation(); + } + msg.setOperation(operation); + msg.setBody(args); + + Message msgContext = ThreadMessageContext.getMessageContext(); + + // Deal with header information that needs to be copied from the message context to the new message... + transferMessageHeaders( msg, msgContext); + + ThreadMessageContext.setMessageContext(msg); + + // If there is a supplied message ID, place its value into the Message Header under "MESSAGE_ID" + if( msgID != null ){ + msg.getHeaders().put("MESSAGE_ID", msgID); + } // end if + + try { + // dispatch the source down the chain and get the response + Message resp = headInvoker.invoke(msg); + Object body = resp.getBody(); + if (resp.isFault()) { + throw (Throwable)body; + } + return body; + } finally { + ThreadMessageContext.setMessageContext(msgContext); + } + } + + /** + * Transfer relevant header information from the old message (incoming) to the new message (outgoing) + * @param newMsg + * @param oldMsg + */ + protected void transferMessageHeaders( Message newMsg, Message oldMsg ) { + if( oldMsg == null ) return; + // For the present, simply copy all the headers + if( !oldMsg.getHeaders().isEmpty() ) newMsg.getHeaders().putAll( oldMsg.getHeaders() ); + } // end transferMessageHeaders + + /** + * @return the callableReference + */ + public ServiceReference getCallableReference() { + return callableReference; + } + + /** + * @param callableReference the callableReference to set + */ + public void setCallableReference(ServiceReference callableReference) { + this.callableReference = (ServiceReferenceExt)callableReference; + } + + /** + * Creates a copy of arguments. Holder values are promoted to T. + * Note. It is essential that arg Holders not be destroyed here. + * PromotedArgs should not destroy holders. They are used on response return. + * @param args containing Holders and other objects. + * @return Object [] + */ + protected static Object [] promoteHolderArgs( Object [] args ) { + if ( args == null ) + return args; + Object [] promotedArgs = new Object[ args.length ]; + + for ( int i = 0; i < args.length; i++ ) { + Object argument = args[ i ]; + if ( argument != null ) { + if ( isHolder( argument ) ) { + promotedArgs[ i ] = ((Holder)argument).value; + } else { + promotedArgs[ i ] = args[ i ]; + } + + } + } + return promotedArgs; + } + + /** + * Given an argument array, filters out (removes) OUT-only parameters + * @param sourceOp + * @return array of filtered arguments + */ + Object[] removeOutOnlyArgs(Operation sourceOp, Object[] args) { + if ( args == null ) + return args; + ArrayList retValList = new ArrayList(); + List parmList = sourceOp.getParameterModes(); + for (int i = 0; i < args.length; i++) { + if (parmList.get(i) != ParameterMode.OUT) { + retValList.add(args[i]); + } + } + return retValList.toArray(); + } + + /** + * Given a Class, tells if it is a Holder by comparing to "javax.xml.ws.Holder" + * @param testClass + * @return boolean whether class is Holder type. + */ + protected static boolean isHolder( Class testClass ) { + if ( testClass.getName().startsWith( "javax.xml.ws.Holder" )) { + return true; + } + return false; + } + + + /** + * Given an Object, tells if it is a Holder by comparing to "javax.xml.ws.Holder" + * @param testClass + * @return boolean stating whether Object is a Holder type. + * @author DOB + */ + protected static boolean isHolder( Object object ) { + String objectName = object.getClass().getName(); + if ( object instanceof javax.xml.ws.Holder ) { + return true; + } + return false; + } + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/JDKProxyFactory.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/JDKProxyFactory.java new file mode 100644 index 0000000000..7163357042 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/JDKProxyFactory.java @@ -0,0 +1,248 @@ +/* + * 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.core.invocation.impl; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Future; + +import javax.xml.bind.JAXBContext; +import javax.xml.ws.AsyncHandler; +import javax.xml.ws.Response; + +import org.apache.tuscany.sca.common.java.collection.LRUCache; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.LifeCycleListener; +import org.apache.tuscany.sca.core.context.ServiceReferenceExt; +import org.apache.tuscany.sca.core.context.impl.CallbackServiceReferenceImpl; +import org.apache.tuscany.sca.core.context.impl.ServiceReferenceImpl; +import org.apache.tuscany.sca.core.invocation.ProxyCreationException; +import org.apache.tuscany.sca.core.invocation.ProxyFactory; +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.runtime.Invocable; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; +import org.oasisopen.sca.ServiceReference; +import org.oasisopen.sca.ServiceRuntimeException; + +/** + * the default implementation of a wire service that uses JDK dynamic proxies + * + * @version $Rev$ $Date$ + */ +public class JDKProxyFactory implements ProxyFactory, LifeCycleListener { + protected ExtensionPointRegistry registry; + protected InterfaceContractMapper contractMapper; + private MessageFactory messageFactory; + + public JDKProxyFactory(ExtensionPointRegistry registry, + MessageFactory messageFactory, + InterfaceContractMapper mapper) { + this.registry = registry; + this.contractMapper = mapper; + this.messageFactory = messageFactory; + } + + /** + * The original createProxy method assumes that the proxy doesn't want to + * share conversation state so sets the conversation object to null + */ + public T createProxy(final Class interfaze, Invocable invocable) throws ProxyCreationException { + if (invocable instanceof RuntimeEndpoint) { + InvocationHandler handler; + // TUSCANY-3659 - Always install a asynch handler regardless of whether ref is sync or async + // needs tidying + // if (isAsync(interfaze)) { + handler = new AsyncJDKInvocationHandler(registry, messageFactory, interfaze, invocable); + // } else { + // handler = new JDKInvocationHandler(messageFactory, interfaze, invocable); + // } + // Allow privileged access to class loader. Requires RuntimePermission in security policy. + ClassLoader cl = AccessController.doPrivileged(new PrivilegedAction() { + public ClassLoader run() { + return interfaze.getClassLoader(); + } + }); + T proxy = interfaze.cast(newProxyInstance(cl, new Class[] {interfaze}, handler)); + return proxy; + } + ServiceReference serviceReference = new ServiceReferenceImpl(interfaze, invocable, null); + return createProxy(serviceReference); + } + + public T createProxy(ServiceReference callableReference) throws ProxyCreationException { + assert callableReference != null; + final Class interfaze = callableReference.getBusinessInterface(); + InvocationHandler handler; + // TUSCANY-3659 - Always install a asynch handler regardless of whether ref is sync or async + // needs tidying + // if (isAsync(interfaze)) { + handler = new AsyncJDKInvocationHandler(registry, messageFactory, callableReference); + // } else { + // handler = new JDKInvocationHandler(messageFactory, callableReference); + // } + // Allow privileged access to class loader. Requires RuntimePermission in security policy. + ClassLoader cl = AccessController.doPrivileged(new PrivilegedAction() { + public ClassLoader run() { + return interfaze.getClassLoader(); + } + }); + T proxy = interfaze.cast(newProxyInstance(cl, new Class[] {interfaze}, handler)); + ((ServiceReferenceExt)callableReference).setProxy(proxy); + return proxy; + } + + private boolean isAsync(Class interfaze) { + for (Method method : interfaze.getMethods()) { + if (method.getName().endsWith("Async")) { + if (method.getReturnType().isAssignableFrom(Future.class)) { + if (method.getParameterTypes().length > 0) { + if (method.getParameterTypes()[method.getParameterTypes().length - 1] + .isAssignableFrom(AsyncHandler.class)) { + return true; + } + } + } + if (method.getReturnType().isAssignableFrom(Response.class)) { + return true; + } + } + } + return false; + } + + public T createCallbackProxy(Class interfaze, List wires) throws ProxyCreationException { + ServiceReferenceImpl callbackReference = null; + try { + callbackReference = new CallbackServiceReferenceImpl(interfaze, wires); + } catch (ServiceRuntimeException e) { + // [rfeng] In case that the call is not from a bidirectional interface, the field should be injected with null + callbackReference = null; + } + return callbackReference != null ? createCallbackProxy(callbackReference) : null; + } + + public T createCallbackProxy(ServiceReference callbackReference) throws ProxyCreationException { + assert callbackReference != null; + final Class interfaze = callbackReference.getBusinessInterface(); + InvocationHandler handler = new JDKCallbackInvocationHandler(messageFactory, callbackReference); + ClassLoader cl = AccessController.doPrivileged(new PrivilegedAction() { + public ClassLoader run() { + return interfaze.getClassLoader(); + } + }); + T proxy = interfaze.cast(newProxyInstance(cl, new Class[] {interfaze}, handler)); + ((ServiceReferenceExt)callbackReference).setProxy(proxy); + return proxy; + } + + public > R cast(B target) throws IllegalArgumentException { + InvocationHandler handler = Proxy.getInvocationHandler(target); + if (handler instanceof JDKInvocationHandler) { + return (R)((JDKInvocationHandler)handler).getCallableReference(); + } else { + throw new IllegalArgumentException("The object is not a known proxy."); + } + } + + /** + * @see org.apache.tuscany.sca.core.invocation.ProxyFactory#isProxyClass(java.lang.Class) + */ + public boolean isProxyClass(Class clazz) { + return Proxy.isProxyClass(clazz); + } + + // This is a cache containing the proxy class constructor for each business interface. + // This improves performance compared to calling Proxy.newProxyInstance() + // every time that a proxy is needed. + private final LRUCache, Constructor> cache = new LRUCache, Constructor>(512); + + public Object newProxyInstance(ClassLoader classloader, Class interfaces[], InvocationHandler invocationhandler) + throws IllegalArgumentException { + if (interfaces.length > 1) { + // We only cache the proxy constructors with one single interface which the case in SCA where + // one reference can have one interface + return Proxy.newProxyInstance(classloader, interfaces, invocationhandler); + } + try { + if (invocationhandler == null) + throw new NullPointerException("InvocationHandler is null"); + // Lookup cached constructor. aclass[0] is the reference's business interface. + Constructor proxyCTOR; + synchronized (cache) { + proxyCTOR = cache.get(interfaces[0]); + } + if (proxyCTOR == null) { + Class proxyClass = Proxy.getProxyClass(classloader, interfaces); + proxyCTOR = proxyClass.getConstructor(InvocationHandler.class); + synchronized (cache) { + cache.put(interfaces[0], proxyCTOR); + } + } + return proxyCTOR.newInstance(invocationhandler); + } catch (Throwable e) { + throw new IllegalArgumentException(e); + } + } + + public void start() { + } + + public void stop() { + cache.clear(); + } + + public void removeProxiesForContribution(ClassLoader contributionClassloader){ + try { + synchronized(cache) { + Set> objSet = cache.keySet(); + List> toRemove = new ArrayList>(); + Iterator> i = objSet.iterator(); + loop: + while(i.hasNext()) { + Class cls = i.next(); + ClassLoader cl = cls.getClassLoader(); + while (cl != null){ + if (cl == contributionClassloader){ + toRemove.add(cls); + break loop; + } + // take account of generated classes + cl = cl.getParent(); + } + } + for (Class cls : toRemove){ + cache.remove(cls); + } + } + } catch(Exception e) { + throw new ServiceRuntimeException(e); + } + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/MessageFactoryImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/MessageFactoryImpl.java new file mode 100644 index 0000000000..6f3e947631 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/MessageFactoryImpl.java @@ -0,0 +1,43 @@ +/* + * 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.core.invocation.impl; + +import java.io.Serializable; + +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.invocation.MessageFactory; + +/** + * Implementation of MessageFactory. + * + * @version $Rev$ $Date$ + */ +public class MessageFactoryImpl implements MessageFactory, Serializable { + + /** + * + */ + private static final long serialVersionUID = -2112289169275106977L; + + public Message createMessage() { + return new MessageImpl(); + } + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/MessageImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/MessageImpl.java new file mode 100644 index 0000000000..cc8cb48cc5 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/MessageImpl.java @@ -0,0 +1,114 @@ +/* + * 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.core.invocation.impl; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.tuscany.sca.assembly.Endpoint; +import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.invocation.Message; + +/** + * The default implementation of a message flowed through a wire during an invocation + * + * @version $Rev $Date$ + */ +public class MessageImpl implements Message { + private Map headers = new HashMap(); + private Object body; + private Object messageID; + private boolean isFault; + private Operation operation; + + private EndpointReference from; + private Endpoint to; + + private Object bindingContext; + + public MessageImpl() { + this.from = null; + this.to = null; + } + + @SuppressWarnings("unchecked") + public T getBody() { + return (T)body; + } + + public void setBody(T body) { + this.isFault = false; + this.body = body; + } + + public Object getMessageID() { + return messageID; + } + + public void setMessageID(Object messageId) { + this.messageID = messageId; + } + + public boolean isFault() { + return isFault; + } + + public void setFaultBody(Object fault) { + this.isFault = true; + this.body = fault; + } + + public EndpointReference getFrom() { + return from; + } + + public void setFrom(EndpointReference from) { + this.from = from; + } + + public Endpoint getTo() { + return to; + } + + public void setTo(Endpoint to) { + this.to = to; + } + + public Operation getOperation() { + return operation; + } + + public void setOperation(Operation op) { + this.operation = op; + } + + public Map getHeaders() { + return headers; + } + + @SuppressWarnings("unchecked") + public T getBindingContext() { + return (T)bindingContext; + } + + public void setBindingContext(T bindingContext) { + this.bindingContext = bindingContext; + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/NoMethodForOperationException.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/NoMethodForOperationException.java new file mode 100644 index 0000000000..45f4bf52bf --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/NoMethodForOperationException.java @@ -0,0 +1,45 @@ +/* + * 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.core.invocation.impl; + +import org.apache.tuscany.sca.core.invocation.ProxyCreationException; + + +/** + * Thrown when an {@link org.apache.tuscany.sca.core.factory.model.Operation} cannot be mapped to a method on an interface + * @version $Rev$ $Date$ + */ +public class NoMethodForOperationException extends ProxyCreationException { + private static final long serialVersionUID = 5116536602309483679L; + + public NoMethodForOperationException() { + } + + public NoMethodForOperationException(String message) { + super(message); + } + + public NoMethodForOperationException(String message, Throwable cause) { + super(message, cause); + } + + public NoMethodForOperationException(Throwable cause) { + super(cause); + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/PhaseManager.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/PhaseManager.java new file mode 100644 index 0000000000..85ef79b5d7 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/PhaseManager.java @@ -0,0 +1,313 @@ +/* + * 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.core.invocation.impl; + +import static org.apache.tuscany.sca.invocation.Phase.IMPLEMENTATION; +import static org.apache.tuscany.sca.invocation.Phase.IMPLEMENTATION_POLICY; +import static org.apache.tuscany.sca.invocation.Phase.REFERENCE; +import static org.apache.tuscany.sca.invocation.Phase.REFERENCE_BINDING; +import static org.apache.tuscany.sca.invocation.Phase.REFERENCE_BINDING_POLICY; +import static org.apache.tuscany.sca.invocation.Phase.REFERENCE_BINDING_TRANSPORT; +import static org.apache.tuscany.sca.invocation.Phase.REFERENCE_BINDING_WIREFORMAT; +import static org.apache.tuscany.sca.invocation.Phase.REFERENCE_INTERFACE; +import static org.apache.tuscany.sca.invocation.Phase.REFERENCE_POLICY; +import static org.apache.tuscany.sca.invocation.Phase.SERVICE; +import static org.apache.tuscany.sca.invocation.Phase.SERVICE_BINDING; +import static org.apache.tuscany.sca.invocation.Phase.SERVICE_BINDING_OPERATION_SELECTOR; +import static org.apache.tuscany.sca.invocation.Phase.SERVICE_BINDING_POLICY; +import static org.apache.tuscany.sca.invocation.Phase.SERVICE_BINDING_TRANSPORT; +import static org.apache.tuscany.sca.invocation.Phase.SERVICE_BINDING_WIREFORMAT; +import static org.apache.tuscany.sca.invocation.Phase.SERVICE_INTERFACE; +import static org.apache.tuscany.sca.invocation.Phase.SERVICE_POLICY; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.apache.tuscany.sca.core.DefaultExtensionPointRegistry; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.UtilityExtensionPoint; +import org.apache.tuscany.sca.extensibility.ServiceDeclaration; +import org.apache.tuscany.sca.invocation.Phase; +import org.oasisopen.sca.ServiceRuntimeException; + +/** + * @version $Rev$ $Date$ + */ +public class PhaseManager { + private static final Logger log = Logger.getLogger(PhaseManager.class.getName()); + + public static final String STAGE_REFERENCE = "reference"; + public static final String STAGE_REFERENCE_BINDING = "reference.binding"; + public static final String STAGE_SERVICE_BINDING = "service.binding"; + public static final String STAGE_SERVICE = "service"; + public static final String STAGE_IMPLEMENTATION = "implementation"; + + private static final String[] SYSTEM_REFERENCE_PHASES = + {REFERENCE, REFERENCE_POLICY, REFERENCE_INTERFACE, REFERENCE_BINDING}; + + private static final String[] SYSTEM_REFERENCE_BINDING_PHASES = + {REFERENCE_BINDING_WIREFORMAT, REFERENCE_BINDING_POLICY, REFERENCE_BINDING_TRANSPORT}; + + private static final String[] SYSTEM_SERVICE_BINDING_PHASES = + {SERVICE_BINDING_TRANSPORT, SERVICE_BINDING_OPERATION_SELECTOR, SERVICE_BINDING_WIREFORMAT, SERVICE_BINDING_POLICY}; + + private static final String[] SYSTEM_SERVICE_PHASES = + {SERVICE_BINDING, SERVICE_INTERFACE, SERVICE_POLICY, SERVICE}; + + private static final String[] SYSTEM_IMPLEMENTATION_PHASES = {IMPLEMENTATION_POLICY, IMPLEMENTATION}; + + private ExtensionPointRegistry registry; + private String pattern = Phase.class.getName(); + private Map stages; + private List phases; + + public class Stage { + private String name; + private PhaseSorter sorter = new PhaseSorter(); + private Set firstSet = new HashSet(); + private Set lastSet = new HashSet(); + private List phases = new ArrayList(); + + public Stage(String name) { + super(); + this.name = name; + } + + public String getName() { + return name; + } + + public PhaseSorter getSorter() { + return sorter; + } + + public Set getFirstSet() { + return firstSet; + } + + public Set getLastSet() { + return lastSet; + } + + public List getPhases() { + return phases; + } + + @Override + public String toString() { + return name + phases; + } + } + + /** + * @param registry + */ + public PhaseManager(ExtensionPointRegistry registry) { + super(); + this.registry = registry; + } + + public static PhaseManager getInstance(ExtensionPointRegistry registry) { + UtilityExtensionPoint utilityExtensionPoint = registry.getExtensionPoint(UtilityExtensionPoint.class); + return utilityExtensionPoint.getUtility(PhaseManager.class); + } + + // For unit test purpose + PhaseManager(String pattern) { + super(); + this.pattern = pattern; + this.registry = new DefaultExtensionPointRegistry(); + } + + private List getPhases(String stage) { + Stage s = getStages().get(stage); + return s == null ? null : s.getPhases(); + } + + public List getReferencePhases() { + return getPhases(STAGE_REFERENCE); + } + + public List getServicePhases() { + return getPhases(STAGE_SERVICE); + } + + public List getReferenceBindingPhases() { + return getPhases(STAGE_REFERENCE_BINDING); + } + + public List getServiceBindingPhases() { + return getPhases(STAGE_SERVICE_BINDING); + } + + public List getImplementationPhases() { + return getPhases(STAGE_IMPLEMENTATION); + } + + public synchronized List getAllPhases() { + if (phases == null) { + phases = new ArrayList(); + phases.addAll(getReferencePhases()); + phases.addAll(getReferenceBindingPhases()); + phases.addAll(getServiceBindingPhases()); + phases.addAll(getServicePhases()); + phases.addAll(getImplementationPhases()); + } + return phases; + } + + public synchronized Map getStages() { + if (stages != null) { + return stages; + } + init(); + + Collection services; + try { + services = registry.getServiceDiscovery().getServiceDeclarations(pattern); + } catch (IOException e) { + throw new ServiceRuntimeException(e); + } + + for (ServiceDeclaration d : services) { + if (log.isLoggable(Level.FINE)) { + log.fine(d.getLocation() + ": " + d.getAttributes()); + } + String name = d.getAttributes().get("name"); + if (name == null) { + throw new ServiceRuntimeException("Required attribute 'name' is missing."); + } + String stageName = d.getAttributes().get("stage"); + if (stageName == null) { + throw new ServiceRuntimeException("Required attribute 'stage' is missing."); + } + Stage stage = stages.get(stageName); + if (stage == null) { + throw new ServiceRuntimeException("Invalid stage: " + stageName); + } + PhaseSorter graph = stage.getSorter(); + Set firstSet = stage.getFirstSet(), lastSet = stage.getLastSet(); + + String before = d.getAttributes().get("before"); + String after = d.getAttributes().get("after"); + if (before != null) { + StringTokenizer tokenizer = new StringTokenizer(before); + while (tokenizer.hasMoreTokens()) { + String p = tokenizer.nextToken(); + if (!"*".equals(p)) { + graph.addEdge(name, p); + } else { + firstSet.add(name); + } + } + } + if (after != null) { + StringTokenizer tokenizer = new StringTokenizer(after); + while (tokenizer.hasMoreTokens()) { + String p = tokenizer.nextToken(); + if (!"*".equals(p)) { + graph.addEdge(p, name); + } else { + lastSet.add(name); + } + } + } + graph.addVertext(name); + if(firstSet.size()>1) { + log.warning("More than one phases are declared to be first: "+firstSet); + } + for (String s : firstSet) { + for (String v : new HashSet(graph.getVertices().keySet())) { + if (!firstSet.contains(v)) { + graph.addEdge(s, v); + } + } + } + if(lastSet.size()>1) { + log.warning("More than one phases are declared to be the last: "+lastSet); + } + for (String s : lastSet) { + for (String v : new HashSet(graph.getVertices().keySet())) { + if (!lastSet.contains(v)) { + graph.addEdge(v, s); + } + } + } + + } + + for (Stage s : stages.values()) { + List phases = s.getSorter().topologicalSort(false); + s.getPhases().clear(); + s.getPhases().addAll(phases); + } + if (log.isLoggable(Level.FINE)) { + log.fine("Stages: " + stages); + } + return stages; + } + + private void init() { + stages = new HashMap(); + + Stage referenceStage = new Stage(STAGE_REFERENCE); + for (int i = 1; i < SYSTEM_REFERENCE_PHASES.length; i++) { + referenceStage.getSorter().addEdge(SYSTEM_REFERENCE_PHASES[i - 1], SYSTEM_REFERENCE_PHASES[i]); + } + referenceStage.getLastSet().add(REFERENCE_BINDING); + stages.put(referenceStage.getName(), referenceStage); + + Stage referenceBindingStage = new Stage(STAGE_REFERENCE_BINDING); + for (int i = 1; i < SYSTEM_REFERENCE_BINDING_PHASES.length; i++) { + referenceBindingStage.getSorter().addEdge(SYSTEM_REFERENCE_BINDING_PHASES[i - 1], SYSTEM_REFERENCE_BINDING_PHASES[i]); + } + stages.put(referenceBindingStage.getName(), referenceBindingStage); + + Stage serviceBindingStage = new Stage(STAGE_SERVICE_BINDING); + for (int i = 1; i < SYSTEM_SERVICE_BINDING_PHASES.length; i++) { + serviceBindingStage.getSorter().addEdge(SYSTEM_SERVICE_BINDING_PHASES[i - 1], SYSTEM_SERVICE_BINDING_PHASES[i]); + } + stages.put(serviceBindingStage.getName(), serviceBindingStage); + + + Stage serviceStage = new Stage(STAGE_SERVICE); + for (int i = 1; i < SYSTEM_SERVICE_PHASES.length; i++) { + serviceStage.getSorter().addEdge(SYSTEM_SERVICE_PHASES[i - 1], SYSTEM_SERVICE_PHASES[i]); + } + stages.put(serviceStage.getName(), serviceStage); + + Stage implementationStage = new Stage(STAGE_IMPLEMENTATION); + for (int i = 1; i < SYSTEM_IMPLEMENTATION_PHASES.length; i++) { + implementationStage.getSorter().addEdge(SYSTEM_IMPLEMENTATION_PHASES[i - 1], + SYSTEM_IMPLEMENTATION_PHASES[i]); + } + implementationStage.getLastSet().add(IMPLEMENTATION); + stages.put(implementationStage.getName(), implementationStage); + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/PhaseSorter.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/PhaseSorter.java new file mode 100644 index 0000000000..175f3463ad --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/PhaseSorter.java @@ -0,0 +1,236 @@ +/* + * 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.core.invocation.impl; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Directed, weighted graph + * + * @param The type of vertex object + * @param The type of edge object + * + * @version $Rev$ $Date$ + */ +public class PhaseSorter implements Cloneable { + private final Map vertices = new HashMap(); + + /** + * Vertex of a graph + */ + public final class Vertex { + private V value; + + // TODO: Do we want to support multiple edges for a vertex pair? If so, + // we should use a List instead of Map + private Map outEdges = new HashMap(); + private Map inEdges = new HashMap(); + + private Vertex(V value) { + this.value = value; + } + + @Override + public String toString() { + return "(" + value + ")"; + } + + public V getValue() { + return value; + } + + public Map getOutEdges() { + return outEdges; + } + + public Map getInEdges() { + return inEdges; + } + + } + + /** + * An Edge connects two vertices in one direction + */ + public final class Edge { + private Vertex sourceVertex; + + private Vertex targetVertex; + + public Edge(Vertex source, Vertex target) { + this.sourceVertex = source; + this.targetVertex = target; + } + + @Override + public String toString() { + return sourceVertex + "->" + targetVertex; + } + + public Vertex getTargetVertex() { + return targetVertex; + } + + public void setTargetVertex(Vertex vertex) { + this.targetVertex = vertex; + } + + public Vertex getSourceVertex() { + return sourceVertex; + } + + public void setSourceVertex(Vertex sourceVertex) { + this.sourceVertex = sourceVertex; + } + } + + public void addEdge(V source, V target) { + Vertex s = getVertex(source); + if (s == null) { + s = new Vertex(source); + vertices.put(source, s); + } + Vertex t = getVertex(target); + if (t == null) { + t = new Vertex(target); + vertices.put(target, t); + } + Edge edge = new Edge(s, t); + s.outEdges.put(t, edge); + t.inEdges.put(s, edge); + } + + public void addVertext(V source) { + Vertex s = getVertex(source); + if (s == null) { + s = new Vertex(source); + vertices.put(source, s); + } + } + + public Vertex getVertex(V source) { + Vertex s = vertices.get(source); + return s; + } + + public boolean removeEdge(V source, V target) { + Vertex s = getVertex(source); + if (s == null) { + return false; + } + + Vertex t = getVertex(target); + if (t == null) { + return false; + } + + return s.outEdges.remove(t) != null && t.inEdges.remove(s) != null; + + } + + public void removeEdge(Edge edge) { + edge.sourceVertex.outEdges.remove(edge.targetVertex); + edge.targetVertex.inEdges.remove(edge.sourceVertex); + } + + public void removeVertex(Vertex vertex) { + vertices.remove(vertex.getValue()); + for (Edge e : new ArrayList(vertex.outEdges.values())) { + removeEdge(e); + } + for (Edge e : new ArrayList(vertex.inEdges.values())) { + removeEdge(e); + } + } + + public Edge getEdge(Vertex source, Vertex target) { + return source.outEdges.get(target); + } + + public Edge getEdge(V source, V target) { + Vertex sv = getVertex(source); + if (sv == null) { + return null; + } + Vertex tv = getVertex(target); + if (tv == null) { + return null; + } + return getEdge(getVertex(source), getVertex(target)); + } + + @Override + public String toString() { + StringBuffer sb = new StringBuffer(); + for (Vertex v : vertices.values()) { + sb.append(v.outEdges.values()).append("\n"); + } + return sb.toString(); + } + + public Map getVertices() { + return vertices; + } + + public void addGraph(PhaseSorter otherGraph) { + for (Vertex v : otherGraph.vertices.values()) { + for (Edge e : v.outEdges.values()) { + addEdge(e.sourceVertex.value, e.targetVertex.value); + } + } + } + + private Vertex getFirst() { + for (Vertex v : vertices.values()) { + if (v.inEdges.isEmpty()) { + return v; + } + } + if (!vertices.isEmpty()) { + throw new IllegalArgumentException("Circular ordering has been detected: " + toString()); + } else { + return null; + } + } + + public List topologicalSort(boolean readOnly) { + PhaseSorter graph = (!readOnly) ? this : (PhaseSorter)clone(); + List list = new ArrayList(); + while (true) { + Vertex v = graph.getFirst(); + if (v == null) { + break; + } + list.add(v.getValue()); + graph.removeVertex(v); + } + + return list; + } + + @Override + public Object clone() { + PhaseSorter copy = new PhaseSorter(); + copy.addGraph(this); + return copy; + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/runtime/impl/EndpointReferenceBinderImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/runtime/impl/EndpointReferenceBinderImpl.java new file mode 100644 index 0000000000..395d154779 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/runtime/impl/EndpointReferenceBinderImpl.java @@ -0,0 +1,1206 @@ +/* + * 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.core.runtime.impl; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.logging.Logger; + +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Base; +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.Callback; +import org.apache.tuscany.sca.assembly.ComponentReference; +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.Multiplicity; +import org.apache.tuscany.sca.assembly.SCABinding; +import org.apache.tuscany.sca.assembly.builder.BindingBuilder; +import org.apache.tuscany.sca.assembly.builder.BuilderContext; +import org.apache.tuscany.sca.assembly.builder.BuilderExtensionPoint; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilder; +import org.apache.tuscany.sca.assembly.builder.PolicyBuilder; +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.core.assembly.impl.RuntimeEndpointImpl; +import org.apache.tuscany.sca.core.assembly.impl.RuntimeEndpointReferenceImpl; +import org.apache.tuscany.sca.definitions.Definitions; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.interfacedef.impl.TuscanyInterfaceContractImpl; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceContract; +import org.apache.tuscany.sca.interfacedef.util.Audit; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.monitor.MonitorFactory; +import org.apache.tuscany.sca.policy.BindingType; +import org.apache.tuscany.sca.policy.ExtensionType; +import org.apache.tuscany.sca.policy.Intent; +import org.apache.tuscany.sca.policy.IntentMap; +import org.apache.tuscany.sca.policy.PolicySet; +import org.apache.tuscany.sca.policy.Qualifier; +import org.apache.tuscany.sca.provider.EndpointReferenceAsyncProvider; +import org.apache.tuscany.sca.provider.ReferenceBindingProvider; +import org.apache.tuscany.sca.runtime.CompositeActivator; +import org.apache.tuscany.sca.runtime.DomainRegistry; +import org.apache.tuscany.sca.runtime.EndpointReferenceBinder; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; +import org.apache.tuscany.sca.runtime.RuntimeEndpointReference; +import org.apache.tuscany.sca.runtime.UnknownEndpointHandler; +import org.oasisopen.sca.ServiceRuntimeException; + +/** + * A builder that takes endpoint references and resolves them. It either finds local + * service endpoints if they are available or asks the domain. The main function here + * is to perform binding and policy matching. + * + * This is a separate from the builders so that the mechanism for reference/service matching + * can be used at runtime as well as build time and can also be replaced independently + * + * @version $Rev$ $Date$ + */ +public class EndpointReferenceBinderImpl implements EndpointReferenceBinder { + private static final Logger logger = Logger.getLogger(EndpointReferenceBinderImpl.class.getName()); + + protected ExtensionPointRegistry extensionPoints; + protected AssemblyFactory assemblyFactory; + protected InterfaceContractMapper interfaceContractMapper; + protected BuilderExtensionPoint builders; + protected CompositeActivator compositeActivator; + protected Monitor monitor; + protected UnknownEndpointHandler unknownEndpointHandler; + protected CompositeBuilder policyAppliesToBuilder; + + + public EndpointReferenceBinderImpl(ExtensionPointRegistry extensionPoints) { + this.extensionPoints = extensionPoints; + + FactoryExtensionPoint factories = extensionPoints.getExtensionPoint(FactoryExtensionPoint.class); + this.assemblyFactory = factories.getFactory(AssemblyFactory.class); + + UtilityExtensionPoint utils = extensionPoints.getExtensionPoint(UtilityExtensionPoint.class); + this.interfaceContractMapper = utils.getUtility(InterfaceContractMapper.class); + + MonitorFactory monitorFactory = utils.getUtility(MonitorFactory.class); + monitor = monitorFactory.createMonitor(); + + this.unknownEndpointHandler = utils.getUtility(UnknownEndpointHandler.class); + + this.builders = extensionPoints.getExtensionPoint(BuilderExtensionPoint.class); + + this.compositeActivator = extensionPoints.getExtensionPoint(CompositeActivator.class); + } + + /** + * Bind a single endpoint reference at build time. Here we only expect the + * registry to have a record of local endpoints + * + * @param domainRegistry + * @param endpointReference + */ + public void bindBuildTime(DomainRegistry domainRegistry, + EndpointReference endpointReference, + BuilderContext builderContext) { + bind(domainRegistry, endpointReference, builderContext, false); + } + + /** + * Bind a single endpoint reference at run time. Here we expect the + * registry to be populated with endpoints from across the domain + * + * @param domainRegistry + * @param endpointReference + */ + public void bindRunTime(DomainRegistry domainRegistry, + EndpointReference endpointReference) { + bind(domainRegistry, endpointReference, null, true); + } + + /** + * Bind a reference to a service endpoint + * + * @param domainRegistry + * @param endpointReference + * @param runtime set true if called from the runtime + */ + public void bind(DomainRegistry domainRegistry, + EndpointReference endpointReference, + BuilderContext builderContext, + boolean runtime){ + + logger.fine("Binding " + endpointReference.toString()); + + Audit matchAudit = new Audit(); + + // This logic does post build autowire matching but isn't actually used at the moment + // as problems with dependencies mean we still do this during build + if (endpointReference.getStatus() == EndpointReference.Status.AUTOWIRE_PLACEHOLDER){ + + // do autowire matching + // will only be called at build time at the moment + Multiplicity multiplicity = endpointReference.getReference().getMultiplicity(); + for (Endpoint endpoint : domainRegistry.getEndpoints()){ +// if (endpoint is in the same composite as endpoint reference){ + if ((multiplicity == Multiplicity.ZERO_ONE || + multiplicity == Multiplicity.ONE_ONE) && + (endpointReference.getReference().getEndpointReferences().size() > 1)) { + break; + } + + // Prevent autowire connecting to self + if (endpointReference.getComponent() == + endpoint.getComponent()) { + continue; + } + + if (haveMatchingPolicy(endpointReference, endpoint, matchAudit, builderContext) && + haveMatchingInterfaceContracts(endpointReference, endpoint, matchAudit)){ + // matching service so find if this reference already has + // an endpoint reference for this endpoint + Endpoint autowireEndpoint = null; + + for (EndpointReference epr : endpointReference.getReference().getEndpointReferences()){ + if (epr.getTargetEndpoint() == endpoint){ + autowireEndpoint = endpoint; + break; + } + } + + if (autowireEndpoint == null){ + // create new EPR for autowire + EndpointReference autowireEndpointRefrence = null; + try { + autowireEndpointRefrence = (EndpointReference)endpointReference.clone(); + } catch (Exception ex){ + // won't happen as clone is supported + } + + autowireEndpointRefrence.setTargetEndpoint(endpoint); + autowireEndpointRefrence.setBinding(endpoint.getBinding()); + autowireEndpointRefrence.setStatus(EndpointReference.Status.WIRED_TARGET_FOUND_AND_MATCHED); + endpointReference.getReference().getEndpointReferences().add(autowireEndpointRefrence); + } + } +// } + } + + if (multiplicity == Multiplicity.ONE_N || multiplicity == Multiplicity.ONE_ONE) { + if (endpointReference.getReference().getEndpointReferences().size() == 1) { + Monitor.error(monitor, + this, + "endpoint-validation-messages", + "NoComponentReferenceTarget", + endpointReference.getReference().getName()); + //throw new ServiceRuntimeException("Unable to bind " + + // monitor.getLastProblem().toString()); + } + } + + setSingleAutoWireTarget(endpointReference.getReference()); + + } else if ( endpointReference.getStatus() == EndpointReference.Status.WIRED_TARGET_FOUND_AND_MATCHED|| + endpointReference.getStatus() == EndpointReference.Status.RESOLVED_BINDING ) { + // The endpoint reference is already resolved to either + // a service endpoint local to this composite or it has + // a remote binding. Just make sure the binding is built + build(endpointReference); + + // still need to check that the callback endpoint is set correctly + if (hasCallback(endpointReference) && + (endpointReference.getCallbackEndpoint() == null + || endpointReference.getCallbackEndpoint().isUnresolved())) { + selectCallbackEndpoint(endpointReference, + endpointReference.getReference().getCallbackService(), + matchAudit, + builderContext, + runtime); + } + } else if (endpointReference.getStatus() == EndpointReference.Status.WIRED_TARGET_FOUND_READY_FOR_MATCHING ){ + // The endpoint reference is already resolved to either + // a service endpoint but no binding was specified in the + // target URL and/or the policies have yet to be matched. + // Used when $self references are resolved + + selectForwardEndpoint(endpointReference, + endpointReference.getTargetEndpoint().getService().getEndpoints(), + matchAudit, + builderContext, + runtime); + + if (hasCallback(endpointReference)){ + selectCallbackEndpoint(endpointReference, + endpointReference.getReference().getCallbackService(), + matchAudit, + builderContext, + runtime); + } + } else if (endpointReference.getStatus() == EndpointReference.Status.WIRED_TARGET_IN_BINDING_URI || + endpointReference.getStatus() == EndpointReference.Status.WIRED_TARGET_NOT_FOUND || + endpointReference.getStatus() == EndpointReference.Status.NOT_CONFIGURED){ + // The reference is not yet matched to a service + + // find the service in the endpoint registry + List endpoints = domainRegistry.findEndpoint(endpointReference); + + if (endpoints.size() > 0){ + selectForwardEndpoint(endpointReference, + endpoints, + matchAudit, + builderContext, + runtime); + + // If the reference was matched try to match the callback + if (endpointReference.getStatus().equals(EndpointReference.Status.WIRED_TARGET_FOUND_AND_MATCHED) && + hasCallback(endpointReference)){ + selectCallbackEndpoint(endpointReference, + endpointReference.getReference().getCallbackService(), + matchAudit, + builderContext, + runtime); + } + } else if (runtime) { + // tweak to test if this could be a resolved binding. This is the back end of the test + // in the builder that pulls the URI out of the binding if there are no targets + // on the reference. have to wait until here to see if the binding uri matches any + // available services. If not we assume here that it's a resolved binding + if (endpointReference.getStatus() == EndpointReference.Status.WIRED_TARGET_IN_BINDING_URI){ + endpointReference.getTargetEndpoint().setBinding(endpointReference.getBinding()); + endpointReference.setStatus(EndpointReference.Status.RESOLVED_BINDING); + } else { + processUnknownEndpoint(endpointReference, matchAudit); + + if (!endpointReference.getStatus().equals(EndpointReference.Status.WIRED_TARGET_FOUND_AND_MATCHED)){ + Monitor.error(monitor, + this, + "endpoint-validation-messages", + "NoEndpointsFound", + endpointReference.toString()); + throw new ServiceRuntimeException(monitor.getMessageString(EndpointReferenceBinderImpl.class.getName(), + "endpoint-validation-messages", + "UnableToBind") + + " " + + monitor.getLastProblem().toString()); + } + } + } else { + // it's build time so just give the UnknownEndpoint code a chance + // without regard for the result + processUnknownEndpoint(endpointReference, matchAudit); + } + } + + logger.fine(matchAudit.toString()); + + if (endpointReference.getStatus() != EndpointReference.Status.WIRED_TARGET_FOUND_AND_MATCHED && + endpointReference.getStatus() != EndpointReference.Status.RESOLVED_BINDING){ + + if (runtime){ + Monitor.error(monitor, + this, + "endpoint-validation-messages", + "EndpointReferenceCantBeMatched", + endpointReference.toString(), + matchAudit); + throw new ServiceRuntimeException(monitor.getMessageString(EndpointReferenceBinderImpl.class.getName(), + "endpoint-validation-messages", + "UnableToBind") + + " " + + monitor.getLastProblem().toString()); + } else { + Monitor.warning(monitor, + this, + "endpoint-validation-messages", + "ComponentReferenceTargetNotFound", + endpointReference.toString()); + return; + } + + + } + + // [rfeng] Setup the target endpoint if the reference uses an explicit binding + if (endpointReference.getTargetEndpoint().getBinding() == null) { + endpointReference.getTargetEndpoint().setBinding(endpointReference.getBinding()); + } + + // Now the endpoint reference is resolved check that the binding interfaces contract + // and the reference contract are compatible + try { + ((RuntimeEndpointReference)endpointReference).validateReferenceInterfaceCompatibility(); + } catch (ServiceRuntimeException ex) { + // don't re-throw this exception at build time just record the + // error. If it's thrown here is messes up the order in which + // build time errors are reported and that in turn messes + // up the output of the compliance tests. + if (runtime){ + throw ex; + } else { + Monitor.error(monitor, + this, + "endpoint-validation-messages", + "EndpointReferenceCantBeMatched", + endpointReference.toString(), + ex.getMessage()); + } + } + + // TUSCANY-3783 + // if the reference is an async reference and the binding doesn't support + // async natively fluff up the response service/endpoint + ReferenceBindingProvider referenceBindingProvider = ((RuntimeEndpointReference)endpointReference).getBindingProvider(); + if ( referenceBindingProvider instanceof EndpointReferenceAsyncProvider && + !((EndpointReferenceAsyncProvider)referenceBindingProvider).supportsNativeAsync() && + endpointReference.isAsyncInvocation() && + endpointReference.getCallbackEndpoint() == null) { + ((RuntimeEndpointReference)endpointReference).createAsyncCallbackEndpoint(); + } + + // System.out.println("MATCH AUDIT:" + matchAudit.toString()); + } + + private void processUnknownEndpoint(EndpointReference endpointReference, Audit matchAudit){ + Binding b = null; + if (unknownEndpointHandler != null) { + b = unknownEndpointHandler.handleUnknownEndpoint(endpointReference); + } + if (b != null) { + Endpoint matchedEndpoint = new RuntimeEndpointImpl(extensionPoints); + matchedEndpoint.setBinding(b); + matchedEndpoint.setRemote(true); + endpointReference.setTargetEndpoint(matchedEndpoint); + endpointReference.setBinding(b); + endpointReference.setUnresolved(false); + endpointReference.setStatus(EndpointReference.Status.WIRED_TARGET_FOUND_AND_MATCHED); + matchAudit.append("Match because the UnknownEndpointHandler provided a binding: " + b.getType() + " uri: " + b.getURI()); + matchAudit.appendSeperator(); + } + } + + /** + * Returns true if the reference has a callback + */ + private boolean hasCallback(EndpointReference endpointReference){ + if (endpointReference.getReference().getInterfaceContract() == null || + endpointReference.getReference().getInterfaceContract().getCallbackInterface() == null || + endpointReference.getReference().getName().startsWith("$self$.")){ + return false; + } else { + return true; + } + } + + /** + * Selects a forward endpoint from a list of possible candidates + * + * @param endpointReference + * @param endpoints + */ + private void selectForwardEndpoint(EndpointReference endpointReference, List endpoints, Audit matchAudit, BuilderContext builderContext, boolean runtime) { + + Endpoint matchedEndpoint = null; + + if (endpointReference.getReference().getName().startsWith("$self$.")){ + // just select the first one and don't do any policy matching + if (endpointReference.getTargetEndpoint() != null && !endpointReference.getTargetEndpoint().isUnresolved()) { + matchedEndpoint = endpointReference.getTargetEndpoint(); + } else { + matchedEndpoint = endpoints.get(0); + } + } else { + // find the endpoints that match this endpoint reference + List matchedEndpoints = new ArrayList(); + + for (Endpoint endpoint : endpoints){ + if (haveMatchingPolicy(endpointReference, endpoint, matchAudit, builderContext) && + haveMatchingInterfaceContracts(endpointReference, endpoint, matchAudit)){ + matchedEndpoints.add(endpoint); + } + } + + // TUSCANY-4005 - raise an error if a reference target that only specifies the + // component name matches more than one component service + if (endpointReference.getTargetEndpoint().getService() == null && + endpointReference.getTargetEndpoint().getBinding() == null && + matchedEndpoints.size() > 1 ) { + + String serviceName = null; + for (Endpoint endpoint : matchedEndpoints){ + // ignore service names called "default" as these indicate dynamic services + // created for the likes of implementation.python + if (serviceName == null && + !endpoint.getService().getName().equals("default")){ + serviceName = endpoint.getService().getName(); + } + + if (serviceName != null && + !endpoint.getService().getName().equals("default") && + !endpoint.getService().getName().equals(serviceName)){ + if (runtime){ + Monitor.error(monitor, + this, + "endpoint-validation-messages", + "TooManyTargetServices", + endpointReference.toString(), + endpointReference.getTargetEndpoint().toString(), + matchAudit); + throw new ServiceRuntimeException("Unable to bind " + + monitor.getLastProblem().toString()); + } else { + Monitor.warning(monitor, + this, + "endpoint-validation-messages", + "TooManyTargetServices", + endpointReference.toString(), + endpointReference.getTargetEndpoint().toString()); + return; + } + } + } + } + + // TUSCANY-3941 check for the case where the user has provided a + // binding.sca at the reference and make sure we pick + // a binding.sca at the service regardless of how many + // other bindings are provided + if (endpointReference.getBinding() != null && + endpointReference.getBinding() instanceof SCABinding ){ + for (Endpoint endpoint : matchedEndpoints){ + if (endpoint.getBinding() instanceof SCABinding){ + matchedEndpoint = endpoint; + break; + } + } + } + + if (matchedEndpoint == null) { + // just take the first matched endpoint from the list + if (matchedEndpoints.size() > 0){ + matchedEndpoint = matchedEndpoints.get(0); + } + } + } + + if (matchedEndpoint == null){ + return; + } else { + endpointReference.setTargetEndpoint(matchedEndpoint); + Binding binding = matchedEndpoint.getBinding(); + try { + endpointReference.setBinding((Binding)binding.clone()); + } catch (CloneNotSupportedException e) { + // shouldn't happen + throw new RuntimeException(e); + } + // TUSCANY-3873 - add policy from the service + // we don't care about intents at this stage + endpointReference.getPolicySets().addAll(matchedEndpoint.getPolicySets()); + + // TODO - we need to re-run the appliesTo processing here but there is some question about what + // appliesTo means. It's also difficult to get to the PolicyAppliesToBuilder from here and + // need a new EntensionInterface to support access. So for now I'm just cheating and looking to + // see if the XPath expression contains the binding type as a string while we discuss appliesTo + List psToRemove = new ArrayList(); + + for (PolicySet ps : endpointReference.getPolicySets() ) { + if (!ps.getAppliesTo().contains(endpointReference.getBinding().getType().getLocalPart())){ + psToRemove.add(ps); + } + } + + endpointReference.getPolicySets().removeAll(psToRemove); + + build(endpointReference); + endpointReference.setStatus(EndpointReference.Status.WIRED_TARGET_FOUND_AND_MATCHED); + endpointReference.setUnresolved(false); + } + + } + + private void build(EndpointReference endpointReference) { + BindingBuilder builder = builders.getBindingBuilder(endpointReference.getBinding().getType()); + if (builder != null) { + builder.build(endpointReference.getComponent(), + endpointReference.getReference(), + endpointReference.getBinding(), + new BuilderContext(extensionPoints), + false); + } + } + + /** + * This code is very similar to the code in EnpointReferenceBuilder.fixUpCallbackLinks() + * but here we are selecting endpoint/endpoint references at runtime. + * + * To recap the general model is as follows: + * + * Forward EPR -----------> Forward EP (target EP) + * | | + * \/ \/ + * Callback EP <------------ Callback EPR + * + * The question then becomes how to construct this model given that + * target resolution can happen at runtime and EPR and EP can be + * distributed across the domain. + * + * The forward link is resolved by searching in the registry for an EP + * that matches the EPR. + * + * At build time we've made the assumption that, if the user configures + * a callback binding at all, they will choose the same binding as the + * forward call (TODO - this may be a bold assumption). So here we just + * assume that the callback endpoint that is set on the reference + * at build time matches. This may not be true if the callback bindings + * are configured differently on the reference and service. + * + * @param endpointReference + * @param endpoints + */ + private void selectCallbackEndpoint(EndpointReference endpointReference, ComponentService callbackService, Audit matchAudit, BuilderContext builderContext, boolean runtime) { + + // A simplifying assumption here is that the user will only specify a callback binding + // of the same type as the forward binding in order to specify further configuration + // We can then assume that if there is no callback endpoint that matches already then we have + // picked up binding config from the service and we can create a callback endpoint to match + + // So having said this we look in three places for the callback binding. + // 1/ in callback endpoints at the reference + // - will find it here if the user has manually configured a callback binding at the reference + // 2/ in the service callback structure + // - will find it here if the user has manually configured a callback binding at the service + // 3/ in the service callback reference structure + // - will find it here if the system has constructed the callback binding based on the forward binding + // + // 2 and 3 are conflated in the distributed case as be write any derived callback bindings out into the + // callback structure as the endpoint is serialized across the domain + + RuntimeEndpoint callbackEndpoint = null; + + // 1/ look in callback endpoints at the reference + // - exploiting the assumption that the user will specific callback bindings of + // the same type as the forward binding + match1: + for(Endpoint loopCallbackEndpoint : callbackService.getEndpoints()){ + if(loopCallbackEndpoint.getBinding().getType().equals(endpointReference.getBinding().getType())){ + callbackEndpoint = (RuntimeEndpoint)loopCallbackEndpoint; + break match1; + } + } + + // if no callback endpoint was found then create a new callback endpoint + if (callbackEndpoint == null ){ + callbackEndpoint = (RuntimeEndpoint)assemblyFactory.createEndpoint(); + callbackEndpoint.setComponent(endpointReference.getComponent()); + callbackEndpoint.setService(callbackService); + + Binding forwardBinding = endpointReference.getBinding(); + Binding callbackBinding = null; + + // 2/ look in the service callback structure + Callback serviceCallback = endpointReference.getTargetEndpoint().getService().getCallback(); + + if (serviceCallback != null){ + for(Binding loopCallbackBinding : serviceCallback.getBindings()){ + if(loopCallbackBinding.getType().equals(endpointReference.getBinding().getType())){ + callbackBinding = loopCallbackBinding; + break; + } + } + } + + // 3/ look in the service endpoint callback reference structure + ComponentReference callbackReference = endpointReference.getTargetEndpoint().getService().getCallbackReference(); + + if (callbackReference != null){ + for (EndpointReference loopEndpointReference : callbackReference.getEndpointReferences()){ + if (loopEndpointReference.getBinding().getType().equals(endpointReference.getBinding().getType())){ + callbackBinding = loopEndpointReference.getBinding(); + break; + } + } + } + + // if all else fails clone the forward binding + // TODO - do we ever get here? + if (callbackBinding == null){ + try { + callbackBinding = (Binding)forwardBinding.clone(); + } catch (CloneNotSupportedException ex){ + } + } + + // get the callback binding URI by looking at the SCA binding + // that will have been added at build time + callbackBinding.setURI(null); + for (Endpoint endpoint : callbackService.getEndpoints()){ + if (endpoint.getBinding().getType().equals(SCABinding.TYPE)){ + callbackBinding.setURI(endpoint.getBinding().getURI()); + } + } + + callbackEndpoint.setBinding(callbackBinding); + callbackService.getBindings().add(callbackBinding); + + callbackEndpoint.setUnresolved(false); + callbackService.getEndpoints().add(callbackEndpoint); + + // build it + build(callbackEndpoint); + + // Only activate the callback endpoint if the bind is being done at runtime + // and hence everything else is running. If it's build time then the + // endpoint will be activated at the same time as all the other endpoints + if (runtime) { + // activate it + compositeActivator.activate(((RuntimeEndpointReferenceImpl)endpointReference).getCompositeContext(), + callbackEndpoint); + + // start it + compositeActivator.start(((RuntimeEndpointReferenceImpl)endpointReference).getCompositeContext(), + callbackEndpoint); + } + } + + // finally set the callback endpoint into the forward reference + endpointReference.setCallbackEndpoint(callbackEndpoint); + } + + private void build(Endpoint endpoint) { + + BindingBuilder builder = builders.getBindingBuilder(endpoint.getBinding().getType()); + if (builder != null) { + builder.build(endpoint.getComponent(), + endpoint.getService(), + endpoint.getBinding(), + new BuilderContext(extensionPoints), + true); + } + } + + /** + * Determine if endpoint reference and endpoint policies match. We know by this stage + * that + * - a given policy set will only contain expressions from a single language + * - a given endpoint or endpoint reference's policy sets will only contain + * expressions from a single language + * + * Matching algorithm (read from the top down): + * - FAIL if there are intents that are mutually exclusive between reference and service + * - PASS if there are no intents or policies present at reference and service + * - FAIL if there are unresolved intents (intents with no policy set) at the reference (service should have been checked previously) + * the wrinkle here is that we need to adopt policy from the service if the reference doesn't define a binding + * - PASS if there are no policies at reference and service (now we know all intents are resolved) + * - FAIL if there are some policies on one side but not on the other + * - PASS if the QName of the policy sets on each side match + * - FAIL if the policy languages on both sides are different + * - Perform policy specific match + * + */ + private boolean haveMatchingPolicy(EndpointReference endpointReference, Endpoint endpoint, Audit matchAudit, BuilderContext builderContext){ + matchAudit.append("Match policy of " + endpointReference.toString() + " to " + endpoint.toString() + " "); + + if (!endpoint.getSpecVersion().equals(Base.SCA11_NS)){ + // the thing we need to check here is asyncInvocation as only OASIS supports that + if (endpointReference.isAsyncInvocation()){ + // this definitely won't mactch anything but OASIS so fail + matchAudit.append("No match because the endpoint reference is configured for asyncInvocation " + + "and the target endpoint is not an OASIS endpoint, specVersion = " + + endpoint.getSpecVersion()); + matchAudit.appendSeperator(); + return false; + } else { + // Assume it matches as we don't know how to do policy + // matching with anything but OASIS endpoints + matchAudit.append("Match because the target endpoint is not an OASIS endpoint, specVersion = " + + endpoint.getSpecVersion()); + matchAudit.appendSeperator(); + return true; + } + } + + List referencePolicySets = new ArrayList(); + Binding binding = null; + + if (endpointReference.getBinding() == null){ + binding = endpoint.getBinding(); + } else { + binding = endpointReference.getBinding(); + } + + // if there are any intents that are mutually exclusive between + // service and reference then they don't match + for (Intent eprIntent : endpointReference.getRequiredIntents()){ + for (Intent epIntent : endpoint.getRequiredIntents()){ + if (eprIntent.getExcludedIntents().contains(epIntent) || + epIntent.getExcludedIntents().contains(eprIntent) || + checkQualifiedMutualExclusion(eprIntent.getExcludedIntents(), epIntent) || + checkQualifiedMutualExclusion(epIntent.getExcludedIntents(), eprIntent)){ + matchAudit.append("No match because the following intents are mutually exclusive " + + eprIntent.toString() + + " " + + epIntent.toString() + + " "); + matchAudit.appendSeperator(); + return false; + } + } + } + + // Find the set of policy sets from this reference. This includes + // the policy sets that are specific to the service binding and + // any policy sets that are not binding specific + for (PolicySet policySet : endpointReference.getPolicySets()){ + PolicyBuilder policyBuilder = null; + + if (policySet.getPolicies().size() > 0){ + QName policyType = policySet.getPolicies().get(0).getName(); + policyBuilder = builders.getPolicyBuilder(policyType); + } + + if ((policyBuilder == null) || + (policyBuilder != null && policyBuilder.getSupportedBindings() == null) || + (policyBuilder != null && policyBuilder.getSupportedBindings().contains(binding.getType()))){ + referencePolicySets.add(policySet); + } + } + + // if there are no policy sets on the reference take the policy sets from the + // service binding we are matching against + if (referencePolicySets.isEmpty()) { + for (PolicySet policySet : endpoint.getPolicySets()){ + PolicyBuilder policyBuilder = null; + + if (policySet.getPolicies().size() > 0){ + QName policyType = policySet.getPolicies().get(0).getName(); + policyBuilder = builders.getPolicyBuilder(policyType); + } + + if ((policyBuilder == null) || + (policyBuilder != null && policyBuilder.getSupportedBindings() == null) || + (policyBuilder != null && policyBuilder.getSupportedBindings().contains(binding.getType()))){ + referencePolicySets.add(policySet); + } + } + } + + // the "appliesTo" algorithm to remove any policy sets that + // don't apply to the service binding will already have been + // run during the build phase + + // Determine if there are any reference policies + boolean noEndpointReferencePolicies = true; + + for (PolicySet policySet : referencePolicySets){ + if (policySet.getPolicies().size() > 0){ + noEndpointReferencePolicies = false; + break; + } + } + + // Determine of there are any service policies + boolean noEndpointPolicies = true; + + for (PolicySet policySet : endpoint.getPolicySets()){ + if (policySet.getPolicies().size() > 0){ + noEndpointPolicies = false; + break; + } + } + + // if no policy sets or intents are present then they match + if ((endpointReference.getRequiredIntents().size() == 0) && + (endpoint.getRequiredIntents().size() == 0) && + (noEndpointReferencePolicies) && + (noEndpointPolicies)) { + matchAudit.append("Match because there are no intents or policies "); + matchAudit.appendSeperator(); + return true; + } + + // check that the intents on the reference side are resolved + // can't do this until this point as the service binding + // may come into play. Intents may be satisfied by the default + // or optional intents that the binding type provides. Failing + // this they must be satisfied by reference policy sets + // Failing this the intent is unresolved and the reference and + // service don't match + + // TODO - seems that we should do this loop on a binding by binding basis + // rather than each time we do matching + BindingType bindingType = null; + + Definitions systemDefinitions = null; + if (builderContext != null){ + systemDefinitions = builderContext.getDefinitions(); + } else { + systemDefinitions = ((RuntimeEndpoint)endpoint).getCompositeContext().getSystemDefinitions(); + } + + bindingType = systemDefinitions.getBindingType(binding.getType()); + + // Before we start examining intents, remove any whose constrained + // types don't include the binding type + removeConstrainedIntents(endpointReference, bindingType); + + List eprIntents = new ArrayList(); + List eprMayProvideInterationIntents = new ArrayList(); + eprIntents.addAll(endpointReference.getRequiredIntents()); + + // first check the binding type + for (Intent intent : endpointReference.getRequiredIntents()){ + if (bindingType != null && + bindingType.getAlwaysProvidedIntents().contains(intent)){ + eprIntents.remove(intent); + } else if (bindingType != null && + bindingType.getMayProvidedIntents().contains(intent)){ + eprIntents.remove(intent); + if (intent.getType().equals(Intent.Type.interaction)){ + eprMayProvideInterationIntents.add(intent); + } + } else { + // TODO - this code also appears in the ComponentPolicyBuilder + // so should rationalize + loop: for (PolicySet policySet : referencePolicySets){ + if (policySet.getProvidedIntents().contains(intent)){ + eprIntents.remove(intent); + break; + } + + for (Intent psProvidedIntent : policySet.getProvidedIntents()){ + if (isQualifiedBy(psProvidedIntent, intent)){ + eprIntents.remove(intent); + break loop; + } + } + + for (IntentMap map : policySet.getIntentMaps()) { + for (Qualifier q : map.getQualifiers()) { + if (intent.equals(q.getIntent())) { + eprIntents.remove(intent); + break loop; + } + } + } + } + } + } + + // if there are unresolved intents the service and reference don't match + if (eprIntents.size() > 0){ + matchAudit.append("No match because there are unresolved intents " + eprIntents.toString() + " "); + matchAudit.appendSeperator(); + return false; + } + + // TUSCANY-3959 - something that's not explicitly stated in the spec. mayProvides intents don't + // lead to policy sets as the binding natively implements the intent. So + // we need to check that these intents match explicitly between reference and service + // sides + if (eprMayProvideInterationIntents.size() > 0){ + for (Intent eprIntent : eprMayProvideInterationIntents){ + boolean match = false; + for (Intent epIntent : endpoint.getRequiredIntents()){ + if (epIntent.equals(eprIntent)){ + match = true; + break; + } + } + + if (!match){ + matchAudit.append("No match because the reference has a mayProvide intent that the service doesn't have " + eprIntent.getName()); + matchAudit.appendSeperator(); + return false; + } + } + } + + // if there are no policies on epr or ep side then + // they match + if (noEndpointPolicies && noEndpointReferencePolicies){ + matchAudit.append("Match because the intents are resolved and there are no policy sets "); + matchAudit.appendSeperator(); + return true; + } + + // if there are some policies on one side and not the other then + // the don't match + if (noEndpointPolicies && !noEndpointReferencePolicies) { + matchAudit.append("No match because there are policy sets at the endpoint reference but not at the endpoint "); + matchAudit.appendSeperator(); + return false; + } + + if (!noEndpointPolicies && noEndpointReferencePolicies){ + matchAudit.append("No match because there are policy sets at the endpoint but not at the endpoint reference "); + matchAudit.appendSeperator(); + return false; + } + + // If policy set QNames from epr and er match exactly then the reference and + // service policies are compatible + Set referencePolicySet = new HashSet(referencePolicySets); + Set servicePolicySet = new HashSet(endpoint.getPolicySets()); + if(referencePolicySet.equals(servicePolicySet)){ + matchAudit.append("Match because the policy sets on both sides are eactly the same "); + matchAudit.appendSeperator(); + return true; + } + + // if policy set language at ep and epr are not the same then there is no + // match. We get the policy language by looking at the first expression + // of the first policy set. By this stage we know that all the policy sets + // in an endpoint or endpoint reference will use a single language and we know + // that there is at least one policy set with at least one policy + QName eprLanguage = null; + + for (PolicySet policySet : referencePolicySets){ + if (policySet.getPolicies().size() > 0){ + eprLanguage = policySet.getPolicies().get(0).getName(); + break; + } + } + + QName epLanguage = null; + + for (PolicySet policySet : endpoint.getPolicySets()){ + if (policySet.getPolicies().size() > 0){ + epLanguage = policySet.getPolicies().get(0).getName(); + break; + } + } + + if(!eprLanguage.getNamespaceURI().equals(epLanguage.getNamespaceURI())){ + matchAudit.append("No match because the policy sets on either side have policies in differnt languages " + + eprLanguage + + " and " + + epLanguage + + " "); + matchAudit.appendSeperator(); + return false; + } + + // now do a policy specific language match + PolicyBuilder builder = builders.getPolicyBuilder(eprLanguage); + boolean match = false; + + // switch the derived list of policy sets into the reference + // it will be left there if there is a match + List originalPolicySets = endpointReference.getPolicySets(); + endpointReference.getPolicySets().clear(); + endpointReference.getPolicySets().addAll(referencePolicySets); + + if (builder != null) { + if (builderContext == null){ + builderContext = new BuilderContext(monitor); + } + + match = builder.build(endpointReference, endpoint, builderContext); + } + + if (!match){ + matchAudit.append("No match because the language specific matching failed "); + matchAudit.appendSeperator(); + endpointReference.getPolicySets().clear(); + endpointReference.getPolicySets().addAll(originalPolicySets); + } else { + matchAudit.append("Match because the language specific matching succeeded "); + matchAudit.appendSeperator(); + } + + return match; + } + + // Copied from ComponentPolicyBuilder, should probably be refactored + protected void removeConstrainedIntents(EndpointReference subject, BindingType bindingType) { + List intents = subject.getRequiredIntents(); + + // Remove the intents whose @contrains do not include the current element + if(bindingType != null){ + List copy = new ArrayList(intents); + for (Intent i : copy) { + List constrainedTypes = i.getConstrainedTypes(); + if (( constrainedTypes.size() == 0 ) && ( i.getQualifiableIntent() != null ) ) + constrainedTypes = i.getQualifiableIntent().getConstrainedTypes(); + + if (constrainedTypes.size() > 0){ + boolean constraintFound = false; + for (ExtensionType constrainedType : constrainedTypes){ + if (constrainedType.getType().equals(bindingType.getType()) || + constrainedType.getType().equals(bindingType.getBaseType())){ + constraintFound = true; + break; + } + } + if(!constraintFound){ + intents.remove(i); + } + } + } + } + } + + + protected boolean isQualifiedBy(Intent qualifiableIntent, Intent qualifiedIntent){ + if (qualifiedIntent.getQualifiableIntent() == qualifiableIntent){ + return true; + } else { + return false; + } + } + + protected boolean checkQualifiedMutualExclusion(List excludedIntentList, Intent intent){ + for (Intent excludedIntent : excludedIntentList){ + if (intent.getQualifiableIntent() != null && + excludedIntent != null && + intent.getQualifiableIntent().equals(excludedIntent)){ + return true; + } + } + return false; + } + + /** + * Determine if endpoint reference and endpoint interface contracts match + */ + private boolean haveMatchingInterfaceContracts(EndpointReference endpointReference, Endpoint endpoint, Audit matchAudit){ + matchAudit.append("Match interface of " + endpointReference.toString() + " to " + endpoint.toString() + " "); + + InterfaceContract endpointReferenceContract = endpointReference.getReference().getInterfaceContract(); + InterfaceContract endpointContract = endpoint.getComponentServiceInterfaceContract(); + + if (endpointReferenceContract == null){ + matchAudit.append("Match because there is no interface contract on the reference "); + matchAudit.appendSeperator(); + return true; + } + + if (!endpoint.getSpecVersion().equals(Base.SCA11_NS)){ + // Assume it matches as we don't know how to do interface + // matching with anything but OASIS endpoint + matchAudit.append("Match because the target endpoint is not an OASIS endpoint, specVersion = " + + endpoint.getSpecVersion()); + matchAudit.appendSeperator(); + return true; + } + +/* For testing this code turns off remote interface matching completely + if (endpoint.isRemote()){ + matchAudit.append("Match because endpoint is remote"); + matchAudit.appendSeperator(); + return true; + } +*/ + + // If the remote interface was not retrieved successfully from the registry for whatever reason + // then assume the interfaces match and leave the checking until runtime. We looking for an interface + // with no operations defined to tell us this. + if ((endpointContract.getInterface().getOperations().size() == 0 && + endpointContract.getNormalizedWSDLContract() == null) || + (endpointContract.getNormalizedWSDLContract() != null && + endpointContract.getNormalizedWSDLContract().getInterface().getOperations().size() == 0)){ + matchAudit.append("Match because the endpoint is remote and we don't have a copy of it's interface contract "); + matchAudit.appendSeperator(); + return true; + } + + // TUSCANY-4033 + // Detect the case where the interfaces are both Java but the Endpoint is remote in which case + // we have to match the local Java interface with the remote Tuscany interface. But we can do this + // without running WSDLGen + if (endpointReferenceContract.getClass() == endpointContract.getClass() && + endpointReferenceContract instanceof JavaInterfaceContract && + endpointContract.getNormalizedWSDLContract() != null && + endpointContract.getNormalizedWSDLContract() instanceof TuscanyInterfaceContractImpl){ + // use the TuscanyInterfaceContractImpl to compare against the Java contract + endpointContract = endpointContract.getNormalizedWSDLContract(); + } else if (endpointReferenceContract.getClass() != endpointContract.getClass() || + endpointReferenceContract.getNormalizedWSDLContract() != null || + endpointContract.getNormalizedWSDLContract() != null) { + // If the contracts are not of the same type use normailized interfaces + endpointReferenceContract = ((RuntimeEndpointReference)endpointReference).getGeneratedWSDLContract(endpointReferenceContract); + endpointContract = ((RuntimeEndpoint)endpoint).getGeneratedWSDLContract(endpointContract); + } + + boolean match = false; + match = interfaceContractMapper.isCompatibleSubset(endpointReferenceContract, + endpointContract, + matchAudit); + + if (!match){ + matchAudit.append("Match failed because the interface contract mapper failed "); + } else { + matchAudit.append("Match because the interface contract mapper succeeded "); + } + + matchAudit.appendSeperator(); + + return match; + } + + /** + * Checks to see if the registry has been updated since the reference was last matched + * + * @return true is the registry has changed + */ + public boolean isOutOfDate(DomainRegistry domainRegistry, EndpointReference endpointReference) { + Endpoint te = endpointReference.getTargetEndpoint(); + if (te != null && !te.isUnresolved() + && te.getURI() != null + && endpointReference.getStatus() != EndpointReference.Status.RESOLVED_BINDING) { + return domainRegistry.isOutOfDate(endpointReference); + } + return false; + } + + /** + * ASM_5021: where a of a has @autowire=true + * and where the has a child element which + * declares a single target service, the reference is wired only to + * the single service identified by the element + */ + private void setSingleAutoWireTarget(ComponentReference reference) { + if (reference.getEndpointReferences().size() > 1 && reference.getBindings() != null + && reference.getBindings().size() == 1) { + String uri = reference.getBindings().get(0).getURI(); + if (uri != null) { + if (uri.indexOf('/') > -1) { + // TODO: must be a way to avoid this fiddling + int i = uri.indexOf('/'); + String c = uri.substring(0, i); + String s = uri.substring(i + 1); + uri = c + "#service(" + s + ")"; + } + for (EndpointReference er : reference.getEndpointReferences()) { + if (er.getTargetEndpoint() != null && uri.equals(er.getTargetEndpoint().getURI())) { + reference.getEndpointReferences().clear(); + reference.getEndpointReferences().add(er); + return; + } + } + } + } + } + + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/runtime/impl/RuntimePropertiesImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/runtime/impl/RuntimePropertiesImpl.java new file mode 100644 index 0000000000..cd8bc936af --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/runtime/impl/RuntimePropertiesImpl.java @@ -0,0 +1,38 @@ +/* + * 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.core.runtime.impl; + +import java.util.Properties; + +import org.apache.tuscany.sca.runtime.RuntimeProperties; + +public class RuntimePropertiesImpl implements RuntimeProperties { + + private Properties properties = new Properties(); + + public Properties getProperties() { + return properties; + } + + public void setProperties(Properties properties) { + this.properties = properties; + } + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/AbstractScopeContainer.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/AbstractScopeContainer.java new file mode 100644 index 0000000000..a1bb91faec --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/AbstractScopeContainer.java @@ -0,0 +1,181 @@ +/* + * 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.core.scope; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.tuscany.sca.core.factory.InstanceWrapper; +import org.apache.tuscany.sca.provider.ImplementationProvider; +import org.apache.tuscany.sca.runtime.RuntimeComponent; + +/** + * Implements functionality common to scope contexts. + * + * @version $Rev$ $Date$ + */ +public abstract class AbstractScopeContainer implements ScopeContainer { + protected Map> wrappers = new ConcurrentHashMap>(); + protected final Scope scope; + + protected RuntimeComponent component; + protected volatile int lifecycleState = UNINITIALIZED; + + private static String scopeStateStrings[] = {"CONFIG_ERROR", + "UNINITIALIZED", + "INITIALIZING", + "INITIALIZED", + "NOT USED", + "RUNNING", + "STOPPING", + "STOPPED", + "ERROR"}; + + public AbstractScopeContainer(Scope scope, RuntimeComponent component) { + this.scope = scope; + this.component = component; + } + + protected void checkInit() { + if (getLifecycleState() != RUNNING) { + throw new IllegalStateException("Scope container not running. Current state is [" + + scopeStateStrings[getLifecycleState() + 1] + + "]"); + } + } + + /** + * Creates a new physical instance of a component, wrapped in an + * InstanceWrapper. + * + * @param component the component whose instance should be created + * @return a wrapped instance that has been injected but not yet started + * @throws TargetResolutionException if there was a problem creating the + * instance + */ + protected InstanceWrapper createInstanceWrapper() throws TargetResolutionException { + ImplementationProvider implementationProvider = component.getImplementationProvider(); + if (implementationProvider instanceof ScopedImplementationProvider) { + return ((ScopedImplementationProvider)implementationProvider).createInstanceWrapper(); + } + return null; + } + + public InstanceWrapper getAssociatedWrapper(KEY contextId) throws TargetResolutionException { + return getWrapper(contextId); // TODO: what is this method supposed to do diff than getWrapper? + } + + public Scope getScope() { + return scope; + } + + public InstanceWrapper getWrapper(KEY contextId) throws TargetResolutionException { + return wrappers.get(contextId); + } + + public void addWrapperReference(KEY existingContextId, KEY newContextId) + throws TargetResolutionException { + // do nothing here. the conversational scope container implements this + } + + public void registerWrapper(InstanceWrapper wrapper, KEY contextId) throws TargetResolutionException { + // do nothing here. the conversational scope container implements this + } + + protected boolean isEagerInit() { + ImplementationProvider implementationProvider = ((RuntimeComponent)component).getImplementationProvider(); + if (implementationProvider instanceof ScopedImplementationProvider) { + return ((ScopedImplementationProvider)implementationProvider).isEagerInit(); + } + return false; + } + + public void returnWrapper(InstanceWrapper wrapper, KEY contextId) throws TargetDestructionException { + } + + /** + * Default implementation of remove which does nothing + * + * @param contextId the identifier of the context to remove. + */ + public void remove(KEY contextId) + throws TargetDestructionException { + } + + public synchronized void start() { + int lifecycleState = getLifecycleState(); + if (lifecycleState != UNINITIALIZED && lifecycleState != STOPPED) { + throw new IllegalStateException("Scope must be in UNINITIALIZED or STOPPED state but the current state is [" + + scopeStateStrings[lifecycleState + 1] + + "]. Did you try to start the same node twice?"); + } + setLifecycleState(RUNNING); + } + + public void startContext(KEY contextId) { + if(isEagerInit()) { + try { + getWrapper(contextId); + } catch (TargetResolutionException e) { + // + } + } + } + + public synchronized void stop() { + int lifecycleState = getLifecycleState(); + if (lifecycleState != RUNNING) { + throw new IllegalStateException("Scope in wrong state. Current state is [" + + scopeStateStrings[lifecycleState + 1] + + "]"); + } + setLifecycleState(STOPPED); + } + + public void stopContext(KEY contextId) { + wrappers.remove(contextId); + } + + @Override + public String toString() { + return "In state [" + scopeStateStrings[lifecycleState + 1] + ']'; + } + + public RuntimeComponent getComponent() { + return component; + } + + public void setComponent(RuntimeComponent component) { + this.component = component; + } + + public int getLifecycleState() { + return lifecycleState; + } + + /** + * Set the current state of the Lifecycle. + * + * @param lifecycleState the new state + */ + protected void setLifecycleState(int lifecycleState) { + this.lifecycleState = lifecycleState; + } + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/DefaultScopeRegistry.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/DefaultScopeRegistry.java new file mode 100644 index 0000000000..2ea724ccf6 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/DefaultScopeRegistry.java @@ -0,0 +1,40 @@ +/* + * 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.core.scope; + +import org.apache.tuscany.sca.core.scope.impl.CompositeScopeContainerFactory; +import org.apache.tuscany.sca.core.scope.impl.ScopeRegistryImpl; +import org.apache.tuscany.sca.core.scope.impl.StatelessScopeContainerFactory; + +/** + * A default scope registry implementation. + * + * @version $Rev$ $Date$ + */ +public class DefaultScopeRegistry extends ScopeRegistryImpl implements ScopeRegistry { + + public DefaultScopeRegistry() { + ScopeContainerFactory[] factories = + new ScopeContainerFactory[] {new CompositeScopeContainerFactory(), new StatelessScopeContainerFactory()}; + for (ScopeContainerFactory f : factories) { + register(f); + } + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/Scope.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/Scope.java new file mode 100644 index 0000000000..35da433af0 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/Scope.java @@ -0,0 +1,63 @@ +/* + * 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.core.scope; + +/** + * The default implementation scopes supported by assemblies. + * + * @version $Rev$ $Date$ + * @tuscany.spi.extension.asclient + */ +public class Scope { + public static final Scope STATELESS = new Scope("STATELESS"); + public static final Scope COMPOSITE = new Scope("COMPOSITE"); + public static final Scope INVALID = new Scope("INVALID"); + + private String scope; + + public Scope(String scope) { + this.scope = scope.toUpperCase().intern(); + } + + public String getScope() { + return scope; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final Scope scope1 = (Scope) o; + return !(scope != null ? scope != scope1.scope.intern() : scope1.scope != null); + } + + @Override + public int hashCode() { + return scope != null ? scope.hashCode() : 0; + } + + @Override + public String toString() { + return scope; + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopeContainer.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopeContainer.java new file mode 100644 index 0000000000..7d34a0144b --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopeContainer.java @@ -0,0 +1,160 @@ +/* + * 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.core.scope; + +import org.apache.tuscany.sca.core.factory.InstanceWrapper; +import org.apache.tuscany.sca.runtime.RuntimeComponent; + + +/** + * Manages the lifecycle and visibility of instances associated with a an {@link RuntimeComponent}. + * + * @version $Rev$ $Date$ + * @param the type of IDs that this container uses to identify its contexts. + * For example, for COMPOSITE scope this could be the URI of the composite component, + * or for HTTP Session scope it might be the HTTP session ID. + * + * @tuscany.spi.extension.asclient + */ +public interface ScopeContainer { + + /** + * Returns the Scope that this container supports. + * + * @return the Scope that this container supports + */ + Scope getScope(); + + /** + * Start a new context with the supplied ID. + * + * @param contextId an ID that uniquely identifies the context. + */ + void startContext(KEY contextId); + + /** + * Stop the context with the supplied ID. + * + * @param contextId an ID that uniquely identifies the context. + */ + void stopContext(KEY contextId); + + /** + * Returns an instance wrapper associated with the current scope context, creating one if necessary + * @param contextId the id for the scope context + * + * @return the wrapper for the target instance + * @throws TargetResolutionException if there was a problem instantiating the target instance + */ + InstanceWrapper getWrapper(KEY contextId) throws TargetResolutionException; + + /** + * Allows a component to be registered against more than one context id. This is required in the + * case of stateful callbacks where we want to identify the originating client component instance + * as the callback target but we don't want to reuse the clients original conversation id + * + * @param existingContextId an id that identifies an existing component instance + * @param newContextId a new id against which this component will also be registered + * @throws TargetResolutionException + */ + void addWrapperReference(KEY existingContextId, KEY newContextId) + throws TargetResolutionException; + + /** + * Register an existing instance against a context id. This is needed + * for a stateful callback where the service reference for the forward call + * contains a callback object that is not a service reference. + * + * @param wrapper the instance wrapper for the instance to be registered + * @param contextId the id for the scope context + * @throws TargetResolutionException + */ + void registerWrapper(InstanceWrapper wrapper, KEY contextId) + throws TargetResolutionException; + + /** + * Returns an implementation instance associated with the current scope context. + * If no instance is found, a {@link TargetNotFoundException} is thrown. + * @param contextId the id for the scope context + * + * @return the wrapper for the target instance + * @throws TargetResolutionException if there was a problem instantiating the target instance + */ + InstanceWrapper getAssociatedWrapper(KEY contextId) + throws TargetResolutionException; + + /** + * Return a wrapper after use (for example, after invoking the instance). + * @param wrapper the wrapper for the target instance being returned + * @param contextId the id for the scope context + * + * @throws TargetDestructionException if there was a problem returning the target instance + */ + void returnWrapper(InstanceWrapper wrapper, KEY contextId) + throws TargetDestructionException; + + /** + * Removes an identified component implementation instance associated with the current + * context from persistent storage + * + * @param contextId the identifier of the context to remove. + */ + void remove(KEY contextId) + throws TargetDestructionException; + + /* A configuration error state */ + int CONFIG_ERROR = -1; + /* Has not been initialized */ + int UNINITIALIZED = 0; + /* In the process of being configured and initialized */ + int INITIALIZING = 1; + /* Instantiated and configured */ + int INITIALIZED = 2; + /* Configured and initialized */ + int RUNNING = 4; + /* In the process of being shutdown */ + int STOPPING = 5; + /* Has been shutdown and removed from the composite */ + int STOPPED = 6; + /* In an error state */ + int ERROR = 7; + + /** + * Returns the lifecycle state + * + * @see #UNINITIALIZED + * @see #INITIALIZING + * @see #INITIALIZED + * @see #RUNNING + * @see #STOPPING + * @see #STOPPED + */ + int getLifecycleState(); + + /** + * Starts the Lifecycle. + */ + void start(); + + /** + * Stops the Lifecycle. + */ + void stop(); + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopeContainerFactory.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopeContainerFactory.java new file mode 100644 index 0000000000..b19c14b3e0 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopeContainerFactory.java @@ -0,0 +1,32 @@ +/* + * 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.core.scope; + +import org.apache.tuscany.sca.runtime.RuntimeComponent; + +/** + * Factory to create ScopeContainer for components + * + * @version $Rev$ $Date$ + */ +public interface ScopeContainerFactory { + ScopeContainer createScopeContainer(RuntimeComponent component); + Scope getScope(); +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopeRegistry.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopeRegistry.java new file mode 100644 index 0000000000..842ed4c547 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopeRegistry.java @@ -0,0 +1,43 @@ +/* + * 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.core.scope; + +import org.apache.tuscany.sca.runtime.RuntimeComponent; + + +/** + * Manages {@link ScopeContainer}s in the runtime + * + * @version $Rev$ $Date$ + */ +public interface ScopeRegistry { + + /** + * Returns the scope container for the given scope or null if one not found + * + * @param scope the scope + * @return the scope container for the given scope or null if one not found + */ + ScopeContainer getScopeContainer(RuntimeComponent component); + + /** + * @param factory + */ + void register(ScopeContainerFactory factory); +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopedImplementationProvider.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopedImplementationProvider.java new file mode 100644 index 0000000000..ee55917f2f --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopedImplementationProvider.java @@ -0,0 +1,56 @@ +/* + * 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.core.scope; + +import org.apache.tuscany.sca.core.factory.InstanceWrapper; +import org.apache.tuscany.sca.provider.ImplementationProvider; + +/** + * A component implementation can implement this interface to provide scope + * management for the components + * + * @version $Rev$ $Date$ + * @tuscany.spi.extension.inheritfrom + */ +public interface ScopedImplementationProvider extends ImplementationProvider { + /** + * Get the scope for the component implementation + * + * @return The scope for the component implementation, if null is returned, + * STATELESS will be used + */ + Scope getScope(); + + /** + * Indicate if the component needs to be eagerly initialized + * + * @return true if the component is marked to be eagerly initialized, false + * otherwise + */ + boolean isEagerInit(); + + /** + * Create a wrapper for the component instance for the scope management + * + * @return A wrapper for the component instance + */ + InstanceWrapper createInstanceWrapper(); + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopedRuntimeComponent.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopedRuntimeComponent.java new file mode 100644 index 0000000000..98c5f84c71 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopedRuntimeComponent.java @@ -0,0 +1,41 @@ +/* + * 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.core.scope; + +import org.apache.tuscany.sca.runtime.RuntimeComponent; + +/** + * Scoped runtime component + * + * @version $Rev$ $Date$ + * @tuscany.spi.extension.asclient + */ +public interface ScopedRuntimeComponent extends RuntimeComponent { + /** + * Set the associated scope container + * @param scopeContainer + */ + void setScopeContainer(ScopeContainer scopeContainer); + /** + * Get the assoicated scope container + * @return + */ + ScopeContainer getScopeContainer(); +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetDestructionException.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetDestructionException.java new file mode 100644 index 0000000000..5c85fead2c --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetDestructionException.java @@ -0,0 +1,45 @@ +/* + * 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.core.scope; + +/** + * Denotes an error destroying a target + * + * @version $Rev$ $Date$ + * @tuscany.spi.extension.asclient + */ +public class TargetDestructionException extends TargetResolutionException { + private static final long serialVersionUID = -6126684147851674709L; + + public TargetDestructionException() { + super(); + } + + public TargetDestructionException(String message, Throwable cause) { + super(message, cause); + } + + public TargetDestructionException(String message) { + super(message); + } + + public TargetDestructionException(Throwable cause) { + super(cause); + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetInitializationException.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetInitializationException.java new file mode 100644 index 0000000000..89ddd7e538 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetInitializationException.java @@ -0,0 +1,45 @@ +/* + * 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.core.scope; + +/** + * Denotes an error initializing a target + * + * @version $Rev$ $Date$ + * @tuscany.spi.extension.asclient + */ +public class TargetInitializationException extends TargetResolutionException { + private static final long serialVersionUID = -6228778208649752698L; + + public TargetInitializationException() { + super(); + } + + public TargetInitializationException(String message, Throwable cause) { + super(message, cause); + } + + public TargetInitializationException(String message) { + super(message); + } + + public TargetInitializationException(Throwable cause) { + super(cause); + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetNotFoundException.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetNotFoundException.java new file mode 100644 index 0000000000..bb46a2499b --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetNotFoundException.java @@ -0,0 +1,44 @@ +/* + * 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.core.scope; + +/** + * Thrown when a target of an operation cannot be found + * + * @version $Rev$ $Date$ + */ +public class TargetNotFoundException extends TargetResolutionException { + private static final long serialVersionUID = 5541830480658471186L; + + public TargetNotFoundException() { + super(); + } + + public TargetNotFoundException(String message, Throwable cause) { + super(message, cause); + } + + public TargetNotFoundException(String message) { + super(message); + } + + public TargetNotFoundException(Throwable cause) { + super(cause); + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetResolutionException.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetResolutionException.java new file mode 100644 index 0000000000..17afd36219 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetResolutionException.java @@ -0,0 +1,45 @@ +/* + * 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.core.scope; + +/** + * Denotes an error retrieving a target instance + * + * @version $Rev$ $Date$ + * @tuscany.spi.extension.asclient + */ +public class TargetResolutionException extends Exception { + private static final long serialVersionUID = 2912513650522019405L; + + public TargetResolutionException() { + super(); + } + + public TargetResolutionException(String message, Throwable cause) { + super(message, cause); + } + + public TargetResolutionException(String message) { + super(message); + } + + public TargetResolutionException(Throwable cause) { + super(cause); + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/impl/CompositeScopeContainer.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/impl/CompositeScopeContainer.java new file mode 100644 index 0000000000..efe7c94b54 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/impl/CompositeScopeContainer.java @@ -0,0 +1,89 @@ +/* + * 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.core.scope.impl; + +import org.apache.tuscany.sca.core.factory.InstanceWrapper; +import org.apache.tuscany.sca.core.scope.AbstractScopeContainer; +import org.apache.tuscany.sca.core.scope.Scope; +import org.apache.tuscany.sca.core.scope.TargetDestructionException; +import org.apache.tuscany.sca.core.scope.TargetNotFoundException; +import org.apache.tuscany.sca.core.scope.TargetResolutionException; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.oasisopen.sca.ServiceUnavailableException; + +/** + * A scope context which manages atomic component instances keyed by composite + * + * @version $Rev$ $Date$ + */ +public class CompositeScopeContainer extends AbstractScopeContainer { + private InstanceWrapper wrapper; + + public CompositeScopeContainer(RuntimeComponent component) { + super(Scope.COMPOSITE, component); + } + + @Override + public synchronized void stop() { + super.stop(); + if (wrapper != null) { + try { + wrapper.stop(); + } catch (TargetDestructionException e) { + wrapper = null; + throw new IllegalStateException(e); + } + } + wrapper = null; + } + + @Override + public synchronized InstanceWrapper getWrapper(KEY contextId) throws TargetResolutionException { + if (wrapper == null) { + try { + wrapper = createInstanceWrapper(); + wrapper.start(); + } catch (Exception e) { + wrapper = null; + throw new ServiceUnavailableException(e); + } + } + return wrapper; + } + + @Override + public InstanceWrapper getAssociatedWrapper(KEY contextId) throws TargetResolutionException { + if (wrapper == null) { + throw new TargetNotFoundException(component.getURI()); + } + return wrapper; + } + + @Override + public synchronized void start() { + super.start(); + if (isEagerInit()) { + try { + getWrapper(null); + } catch (TargetResolutionException e) { + throw new IllegalStateException(e); + } + } + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/impl/CompositeScopeContainerFactory.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/impl/CompositeScopeContainerFactory.java new file mode 100644 index 0000000000..f61e70a598 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/impl/CompositeScopeContainerFactory.java @@ -0,0 +1,40 @@ +/* + * 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.core.scope.impl; + +import org.apache.tuscany.sca.core.scope.Scope; +import org.apache.tuscany.sca.core.scope.ScopeContainer; +import org.apache.tuscany.sca.core.scope.ScopeContainerFactory; +import org.apache.tuscany.sca.runtime.RuntimeComponent; + +/** + * @version $Rev$ $Date$ + */ +public class CompositeScopeContainerFactory implements ScopeContainerFactory { + + public ScopeContainer createScopeContainer(RuntimeComponent component) { + return new CompositeScopeContainer(component); + } + + public Scope getScope() { + return Scope.COMPOSITE; + } + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/impl/ScopeRegistryImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/impl/ScopeRegistryImpl.java new file mode 100644 index 0000000000..9884c5f053 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/impl/ScopeRegistryImpl.java @@ -0,0 +1,70 @@ +/* + * 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.core.scope.impl; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.tuscany.sca.core.scope.Scope; +import org.apache.tuscany.sca.core.scope.ScopeContainer; +import org.apache.tuscany.sca.core.scope.ScopeContainerFactory; +import org.apache.tuscany.sca.core.scope.ScopeRegistry; +import org.apache.tuscany.sca.core.scope.ScopedImplementationProvider; +import org.apache.tuscany.sca.core.scope.ScopedRuntimeComponent; +import org.apache.tuscany.sca.provider.ImplementationProvider; +import org.apache.tuscany.sca.runtime.RuntimeComponent; + +/** + * The default implementation of a scope registry + * + * @version $Rev$ $Date$ + */ +public class ScopeRegistryImpl implements ScopeRegistry { + private final Map scopeCache = new ConcurrentHashMap(); + + public void register(ScopeContainerFactory factory) { + scopeCache.put(factory.getScope(), factory); + } + + public ScopeContainer getScopeContainer(RuntimeComponent runtimeComponent) { + if (!(runtimeComponent instanceof ScopedRuntimeComponent)) { + return null; + } + ScopedRuntimeComponent component = (ScopedRuntimeComponent)runtimeComponent; + if (component.getScopeContainer() != null) { + return component.getScopeContainer(); + } + ImplementationProvider implementationProvider = component.getImplementationProvider(); + if (implementationProvider instanceof ScopedImplementationProvider) { + ScopedImplementationProvider provider = (ScopedImplementationProvider)implementationProvider; + Scope scope = provider.getScope(); + if (scope == null) { + scope = Scope.STATELESS; + } else if (scope.equals(Scope.INVALID)) { + return null; + } + ScopeContainerFactory factory = scopeCache.get(scope); + ScopeContainer container = factory.createScopeContainer(component); + component.setScopeContainer(container); + return container; + } + return null; + } + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/impl/StatelessScopeContainer.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/impl/StatelessScopeContainer.java new file mode 100644 index 0000000000..1235fd2a67 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/impl/StatelessScopeContainer.java @@ -0,0 +1,61 @@ +/* + * 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.core.scope.impl; + +import org.apache.tuscany.sca.core.factory.InstanceWrapper; +import org.apache.tuscany.sca.core.scope.AbstractScopeContainer; +import org.apache.tuscany.sca.core.scope.Scope; +import org.apache.tuscany.sca.core.scope.TargetDestructionException; +import org.apache.tuscany.sca.core.scope.TargetResolutionException; +import org.apache.tuscany.sca.runtime.RuntimeComponent; + +/** + * A scope context which manages stateless atomic component instances in a non-pooled fashion. + * + * @version $Rev$ $Date$ + */ +public class StatelessScopeContainer extends AbstractScopeContainer { + + public StatelessScopeContainer(RuntimeComponent component) { + super(Scope.STATELESS, component); + } + + @Override + public InstanceWrapper getWrapper(KEY contextId) throws TargetResolutionException { + if (lifecycleState != RUNNING) { + throw new TargetResolutionException("scope container not running, lifecycleState=" + lifecycleState); + } + InstanceWrapper ctx = createInstanceWrapper(); + ctx.start(); + return ctx; + } + + @Override + public InstanceWrapper getAssociatedWrapper(KEY contextId) + throws TargetResolutionException { + return getWrapper(contextId); + } + + @Override + public void returnWrapper(InstanceWrapper wrapper, KEY contextId) + throws TargetDestructionException { + wrapper.stop(); + } + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/impl/StatelessScopeContainerFactory.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/impl/StatelessScopeContainerFactory.java new file mode 100644 index 0000000000..5bf20a6a5f --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/impl/StatelessScopeContainerFactory.java @@ -0,0 +1,40 @@ +/* + * 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.core.scope.impl; + +import org.apache.tuscany.sca.core.scope.Scope; +import org.apache.tuscany.sca.core.scope.ScopeContainer; +import org.apache.tuscany.sca.core.scope.ScopeContainerFactory; +import org.apache.tuscany.sca.runtime.RuntimeComponent; + +/** + * @version $Rev$ $Date$ + */ +public class StatelessScopeContainerFactory implements ScopeContainerFactory { + + public ScopeContainer createScopeContainer(RuntimeComponent component) { + return new StatelessScopeContainer(component); + } + + public Scope getScope() { + return Scope.STATELESS; + } + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/DefaultWorkScheduler.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/DefaultWorkScheduler.java new file mode 100644 index 0000000000..dd4abf0cd2 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/DefaultWorkScheduler.java @@ -0,0 +1,210 @@ +/* + * 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.core.work.impl; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Map; +import java.util.concurrent.ExecutorService; + +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.LifeCycleListener; +import org.apache.tuscany.sca.work.NotificationListener; +import org.apache.tuscany.sca.work.WorkScheduler; +import org.apache.tuscany.sca.work.WorkSchedulerException; + +/** + * A work scheduler implementation based on a JSR 237 work manager. + *

+ *

+ * This needs a JSR 237 work manager implementation available for scheduling work. Instances can be configured with a + * work manager implementation that is injected in. It is the responsibility of the runtime environment to make a work + * manager implementation available. For example, if the managed environment supports work manager the runtime can use + * the appropriate lookup mechanism to inject the work manager implementation.

+ * + * @version $Rev$ $Date$ + */ +public class DefaultWorkScheduler implements WorkScheduler, LifeCycleListener { + + /** + * Underlying JSR-237 work manager + */ + private ThreadPoolWorkManager jsr237WorkManager; + private int maxThreads = 0; + + /** + * Initializes the JSR 237 work manager. + * + * @param jsr237WorkManager JSR 237 work manager. + */ + public DefaultWorkScheduler(ExtensionPointRegistry registry, Map attributes) { + if (attributes != null) { + String value = attributes.get("maxThreads"); + if (value != null) { + maxThreads = Integer.parseInt(value.trim()); + } + } + } + + private synchronized ThreadPoolWorkManager getWorkManager() { + if (jsr237WorkManager != null) { + return jsr237WorkManager; + } +// try { +// InitialContext ctx = new InitialContext(); +// jsr237WorkManager = (ThreadPoolWorkManager)ctx.lookup("java:comp/env/wm/TuscanyWorkManager"); +// } catch (Throwable e) { +// // ignore +// } + if (jsr237WorkManager == null) { + jsr237WorkManager = new ThreadPoolWorkManager(maxThreads); + } + return jsr237WorkManager; + } + + /** + * Schedules a unit of work for future execution. The notification listener is used to register interest in + * callbacks regarding the status of the work. + * + * @param work The unit of work that needs to be asynchronously executed. + */ + public void scheduleWork(T work) { + scheduleWork(work, null); + } + + /** + * Schedules a unit of work for future execution. The notification listener is used to register interest in + * callbacks regarding the status of the work. + * + * @param work The unit of work that needs to be asynchronously executed. + * @param listener Notification listener for callbacks. + */ + public void scheduleWork(T work, NotificationListener listener) { + + if (work == null) { + throw new IllegalArgumentException("Work cannot be null"); + } + + Work jsr237Work = new Work(work); + try { + if (listener == null) { + getWorkManager().schedule(jsr237Work); + } else { + Jsr237WorkListener jsr237WorkListener = new Jsr237WorkListener(listener, work); + getWorkManager().schedule(jsr237Work, jsr237WorkListener); + } + } catch (IllegalArgumentException ex) { + if (listener != null) { + listener.workRejected(work); + } else { + throw new WorkSchedulerException(ex); + } + } catch (Exception ex) { + throw new WorkSchedulerException(ex); + } + + } + + public void start() { + } + + public void stop() { + if (jsr237WorkManager instanceof ThreadPoolWorkManager) { + // Allow privileged access to modify threads. Requires RuntimePermission in security + // policy. + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + ((ThreadPoolWorkManager)jsr237WorkManager).destroy(); + return null; + } + }); + } + } + + /* + * WorkListener for keeping track of work status callbacks. + * + */ + private class Jsr237WorkListener implements WorkListener { + + // Notification listener + private NotificationListener listener; + + // Work + private T work; + + /* + * Initializes the notification listener. + */ + public Jsr237WorkListener(NotificationListener listener, T work) { + this.listener = listener; + this.work = work; + } + + /* + * Callback when the work is accepted. + */ + public void workAccepted(WorkEvent workEvent) { + T work = getWork(); + listener.workAccepted(work); + } + + /* + * Callback when the work is rejected. + */ + public void workRejected(WorkEvent workEvent) { + T work = getWork(); + listener.workRejected(work); + } + + /* + * Callback when the work is started. + */ + public void workStarted(WorkEvent workEvent) { + T work = getWork(); + listener.workStarted(work); + } + + /* + * Callback when the work is completed. + */ + public void workCompleted(WorkEvent workEvent) { + T work = getWork(); + Exception exception = workEvent.getException(); + if (exception != null) { + listener.workFailed(work, exception); + } else { + listener.workCompleted(work); + } + } + + /* + * Gets the underlying work from the work event. + */ + private T getWork() { + return work; + } + + } + + @Override + public ExecutorService getExecutorService() { + return getWorkManager().getExecutorService(); + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/ThreadPoolWorkManager.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/ThreadPoolWorkManager.java new file mode 100644 index 0000000000..7e116655e1 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/ThreadPoolWorkManager.java @@ -0,0 +1,232 @@ +/* + * 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.core.work.impl; + +import java.util.Collection; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ThreadFactory; + +import org.apache.tuscany.sca.work.WorkSchedulerException; + +/** + * A thread-pool based implementation for the JSR-237 work manager. + *

+ *

+ * This implementation supports only local work. + *

+ * TODO Elaborate the implementation.

+ * + * @version $Rev$ $Date$ + */ +public class ThreadPoolWorkManager { + + // Map of work items currently handled by the work manager + private Map workItems = new ConcurrentHashMap(); + + // Thread-pool + protected ExecutorService executor; + + /** + * Initializes the thread-pool. + * + * @param threadPoolSize Thread-pool size. If the size <1, then a cached pool is created + */ + public ThreadPoolWorkManager(int threadPoolSize) { + ThreadFactory factory = new ThreadFactory() { + public Thread newThread(Runnable r) { + Thread thread = new Thread(r); + thread.setDaemon(true); + return thread; + } + }; + if (threadPoolSize <= 0) { + + // Creates a new Executor, use a custom ThreadFactory that + // creates daemon threads. + executor = Executors.newCachedThreadPool(factory); + } else { + executor = Executors.newFixedThreadPool(threadPoolSize, factory); + } + } + + /** + * Schedules a unit of work asynchronously. + * + * @param work Work that needs to be scheduled. + * @return Work Work item representing the asynchronous work + */ + public WorkItem schedule(Work work) throws IllegalArgumentException { + return schedule(work, null); + } + + /** + * Schedules a unit of work asynchronously. + * + * @param work Work that needs to be scheduled. + * @param workListener Work listener for callbacks. + * @return Work Work item representing the asynchronous work + */ + public WorkItem schedule(Work work, WorkListener workListener) throws IllegalArgumentException { + + WorkItem workItem = new WorkItem(UUID.randomUUID().toString(), work); + if (workListener != null) { + workItems.put(workItem, workListener); + } + workAccepted(workItem, work); + if (scheduleWork(work, workItem)) { + return workItem; + } else { + workItem.setStatus(WorkEvent.WORK_REJECTED); + if (workListener != null) { + workListener.workRejected(new WorkEvent(workItem)); + } + throw new IllegalArgumentException("Unable to schedule work"); + } + } + + /** + * Wait for all the specified units of work to finish. + * + * @param works Units of the work that need to finish. + * @param timeout Timeout for waiting for the units of work to finish. + */ + public boolean waitForAll(Collection works, long timeout) { + throw new UnsupportedOperationException("waitForAll not supported"); + } + + /** + * Wait for any of the specified units of work to finish. + * + * @param works Units of the work that need to finish. + * @param timeout Timeout for waiting for the units of work to finish. + */ + public Collection waitForAny(Collection works, long timeout) { + throw new UnsupportedOperationException("waitForAny not supported"); + } + + /** + * Method provided for subclasses to indicate a work acceptance. + * + * @param workItem Work item representing the work that was accepted. + * @param work Work that was accepted. + */ + private void workAccepted(final WorkItem workItem, final Work work) { + WorkListener listener = workItems.get(workItem); + if (listener != null) { + workItem.setStatus(WorkEvent.WORK_ACCEPTED); + WorkEvent event = new WorkEvent(workItem); + listener.workAccepted(event); + } + } + + /* + * Method to indicate a work start. + */ + private void workStarted(final WorkItem workItem, final Work work) { + WorkListener listener = workItems.get(workItem); + if (listener != null) { + workItem.setStatus(WorkEvent.WORK_STARTED); + WorkEvent event = new WorkEvent(workItem); + listener.workStarted(event); + } + } + + /* + * Method to indicate a work completion. + */ + private void workCompleted(final WorkItem workItem, final Work work) { + workCompleted(workItem, work, null); + } + + /* + * Method to indicate a work completion. + */ + private void workCompleted(final WorkItem workItem, final Work work, final WorkSchedulerException exception) { + WorkListener listener = workItems.get(workItem); + if (listener != null) { + workItem.setStatus(WorkEvent.WORK_COMPLETED); + workItem.setResult(work); + workItem.setException(exception); + WorkEvent event = new WorkEvent(workItem); + listener.workCompleted(event); + workItems.remove(workItem); + } + } + + /* + * Schedules the work using the ThreadPool. + */ + private boolean scheduleWork(final Work work, final WorkItem workItem) { + try { + executor.execute(new DecoratingWork(workItem, work)); + return true; + } catch (RejectedExecutionException ex) { + return false; + } + } + + /* + * Class that decorates the original worker so that it can get callbacks when work is done. + */ + private final class DecoratingWork implements Runnable { + + // Work item for this work. + private WorkItem workItem; + + // The original work. + private Work decoratedWork; + + /* + * Initializes the work item and underlying work. + */ + private DecoratingWork(final WorkItem workItem, final Work decoratedWork) { + this.workItem = workItem; + this.decoratedWork = decoratedWork; + } + + /* + * Overrides the run method. + */ + public void run() { + workStarted(workItem, decoratedWork); + try { + decoratedWork.run(); + workCompleted(workItem, decoratedWork); + } catch (Throwable th) { + workCompleted(workItem, decoratedWork, new WorkSchedulerException(th.getMessage(), th)); + } + } + + } + + public void destroy() { + executor.shutdown(); + } + + public ExecutorService getExecutorService() { + return executor; + } + +} + diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/Work.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/Work.java new file mode 100644 index 0000000000..ca06d0e854 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/Work.java @@ -0,0 +1,65 @@ +/* + * 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.core.work.impl; + +/** + * JCA work wrapper. + * + * @version $Rev$ $Date$ + */ +public class Work { + + // Work that is being executed. + private T work; + + /* + * Initializes the work instance. + */ + public Work(T work) { + this.work = work; + } + + /* + * Returns the completed work. + */ + public T getWork() { + return work; + } + + /* + * Release the work. + */ + public void release() { + } + + /* + * Work attributes are not daemon. + */ + public boolean isDaemon() { + return false; + } + + /* + * Runs the work. + */ + public void run() { + work.run(); + } +} \ No newline at end of file diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/WorkEvent.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/WorkEvent.java new file mode 100644 index 0000000000..4580011806 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/WorkEvent.java @@ -0,0 +1,80 @@ +/* + * 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.core.work.impl; + +import org.apache.tuscany.sca.work.WorkSchedulerException; + + + +/** + * Default immutable implementation of the WorkEvent class. + * + * @version $Rev$ $Date$ + */ +class WorkEvent { + + public static final int WORK_ACCEPTED = 1; + public static final int WORK_REJECTED = 2; + public static final int WORK_STARTED = 3; + public static final int WORK_COMPLETED = 4; + + // Work item for this event + private WorkItem workItem; + + // Exception if something has gone wrong + private WorkSchedulerException exception; + + /** + * Instantiates the event. + * + * @param workItem Work item for this event. + */ + public WorkEvent(final WorkItem workItem) { + this.workItem = workItem; + this.exception = workItem.getException(); + } + + /** + * Returns the work type based on whether the work was accepted, started, + * rejected or completed. + * + * @return Work type. + */ + public int getType() { + return workItem.getStatus(); + } + + /** + * Returns the work item associated with this work type. + * + * @return Work item. + */ + public WorkItem getWorkItem() { + return workItem; + } + + /** + * Returns the exception if the work completed with an exception. + * + * @return Work exception. + */ + public WorkSchedulerException getException() { + return exception; + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/WorkItem.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/WorkItem.java new file mode 100644 index 0000000000..0fc104d0fc --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/WorkItem.java @@ -0,0 +1,167 @@ +/* + * 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.core.work.impl; + +import org.apache.tuscany.sca.work.WorkSchedulerException; + +/** + * An identity based immutable implementation of the WorkItem + * interface. + * + * @version $Rev$ $Date$ + */ +class WorkItem { + + // Id scoped for the VM + private String id; + + // Status + private int status = -1; + + // Result + private Work result; + + // Original work + private Work originalWork; + + // Exception + private WorkSchedulerException exception; + + /** + * Instantiates an id for this item. + * + * @param id of this work event. + */ + protected WorkItem(final String id, final Work orginalWork) { + this.id = id; + this.originalWork = orginalWork; + } + + /** + * Returns the id. + * + * @return Id of this item. + */ + public String getId() { + return id; + } + + /** + * Returns the original work. + * + * @return Original work. + */ + public Work getOriginalWork() { + return originalWork; + } + + /** + * Returns the work result if the work completed. + * + * @return Work. + * @throws WorkException If the work completed with an exception. + */ + public Work getResult() { + return result; + } + + /** + * Sets the result. + * + * @param result Result. + */ + protected void setResult(final Work result) { + this.result = result; + } + + /** + * Returns the exception if work completed with an exception. + * + * @return Work exception. + */ + protected WorkSchedulerException getException() { + return exception; + } + + /** + * Sets the exception. + * + * @param exception Exception. + */ + protected void setException(final WorkSchedulerException exception) { + this.exception = exception; + } + + /** + * Returns the work type based on whether the work was accepted, started, + * rejected or completed. + * + * @return Work status. + */ + public int getStatus() { + return status; + } + + /** + * Sets the status. + * + * @param status Status. + */ + protected void setStatus(final int status) { + this.status = status; + } + + /** + * @see Object#hashCode() + */ + @Override + public int hashCode() { + return id.hashCode(); + } + + /** + * Indicates whether some other object is "equal to" this one. + * + * @param obj Object to be compared. + * @return true if this object is the same as the obj argument; false + * otherwise.. + */ + @Override + public boolean equals(final Object obj) { + return (obj != null) && (obj.getClass() == WorkItem.class) && ((WorkItem) obj).id.equals(id); + } + + /** + * Compares this object with the specified object for order. Returns a + * negative integer, zero, or a positive integer as this object is less + * than, equal to, or greater than the specified object. + * + * @param o Object to be compared. + * @return A negative integer, zero, or a positive integer as this object + * is less than, equal to, or greater than the specified object. + * @throws ClassCastException needs better documentation. + */ + public int compareTo(final Object o) { + if (o.getClass() != WorkItem.class) { + throw new ClassCastException(o.getClass().getName()); + } else { + return ((WorkItem) o).getId().compareTo(getId()); + } + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/WorkListener.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/WorkListener.java new file mode 100644 index 0000000000..38bbaeebe0 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/WorkListener.java @@ -0,0 +1,32 @@ +/* + * 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.core.work.impl; + +public interface WorkListener { + + long IMMEDIATE = 0; + long INDEFINITE = java.lang.Long.MAX_VALUE; + + void workAccepted(WorkEvent event); + void workCompleted(WorkEvent event); + void workRejected(WorkEvent event); + void workStarted(WorkEvent event); + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.assembly.AssemblyFactory b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.assembly.AssemblyFactory new file mode 100644 index 0000000000..e8ee318b6c --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.assembly.AssemblyFactory @@ -0,0 +1,18 @@ +# 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. +# Set the ranking to be greater than the DefaultAssemblyFactory +org.apache.tuscany.sca.core.assembly.RuntimeAssemblyFactory;ranking=100 diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.context.ComponentContextFactory b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.context.ComponentContextFactory new file mode 100644 index 0000000000..51ed2449fb --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.context.ComponentContextFactory @@ -0,0 +1,17 @@ +# 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. +org.apache.tuscany.sca.core.context.DefaultComponentContextFactory diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.context.RequestContextFactory b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.context.RequestContextFactory new file mode 100644 index 0000000000..70b17a2f00 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.context.RequestContextFactory @@ -0,0 +1,17 @@ +# 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. +org.apache.tuscany.sca.core.context.DefaultRequestContextFactory diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor new file mode 100644 index 0000000000..94c83ceeab --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor @@ -0,0 +1,20 @@ +# 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. + +# Implementation class for the artifact processor extension +org.apache.tuscany.sca.core.assembly.impl.ReferenceParameterProcessor;qname=http://tuscany.apache.org/xmlns/sca/1.1#referenceParameters,model=org.apache.tuscany.sca.runtime.ReferenceParameters + diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.core.invocation.ProxyFactoryExtensionPoint b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.core.invocation.ProxyFactoryExtensionPoint new file mode 100644 index 0000000000..c6567aa904 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.core.invocation.ProxyFactoryExtensionPoint @@ -0,0 +1,19 @@ +# 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. + +org.apache.tuscany.sca.core.invocation.DefaultProxyFactoryExtensionPoint + diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.core.scope.ScopeRegistry b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.core.scope.ScopeRegistry new file mode 100644 index 0000000000..2aa000efc0 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.core.scope.ScopeRegistry @@ -0,0 +1,19 @@ +# 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. + +org.apache.tuscany.sca.core.scope.DefaultScopeRegistry + diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.invocation.MessageFactory b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.invocation.MessageFactory new file mode 100644 index 0000000000..a21b75b570 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.invocation.MessageFactory @@ -0,0 +1,19 @@ +# 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. + +org.apache.tuscany.sca.core.invocation.impl.MessageFactoryImpl + diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.runtime.CompositeActivator b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.runtime.CompositeActivator new file mode 100644 index 0000000000..0182f52086 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.runtime.CompositeActivator @@ -0,0 +1,19 @@ +# 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. + +org.apache.tuscany.sca.core.assembly.impl.CompositeActivatorImpl + diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.runtime.DomainRegistryFactory b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.runtime.DomainRegistryFactory new file mode 100644 index 0000000000..6a01eac2df --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.runtime.DomainRegistryFactory @@ -0,0 +1,17 @@ +# 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. +org.apache.tuscany.sca.core.assembly.impl.LocalDomainRegistryFactory;ranking=10 diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.runtime.EndpointReferenceBinder b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.runtime.EndpointReferenceBinder new file mode 100644 index 0000000000..61edf5111e --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.runtime.EndpointReferenceBinder @@ -0,0 +1,18 @@ +# 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. +org.apache.tuscany.sca.core.runtime.impl.EndpointReferenceBinderImpl + diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.runtime.EndpointSerializer b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.runtime.EndpointSerializer new file mode 100644 index 0000000000..fb951e75d5 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.runtime.EndpointSerializer @@ -0,0 +1,17 @@ +# 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. +org.apache.tuscany.sca.core.assembly.impl.EndpointSerializerImpl diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.runtime.RuntimeProperties b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.runtime.RuntimeProperties new file mode 100644 index 0000000000..66e0277d59 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.runtime.RuntimeProperties @@ -0,0 +1,18 @@ +# 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. +org.apache.tuscany.sca.core.runtime.impl.RuntimePropertiesImpl + diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.work.WorkScheduler b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.work.WorkScheduler new file mode 100644 index 0000000000..90e887739a --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/META-INF/services/org.apache.tuscany.sca.work.WorkScheduler @@ -0,0 +1,17 @@ +# 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. +org.apache.tuscany.sca.core.work.impl.DefaultWorkScheduler;maxThreads=0 diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/core-messages.properties b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/core-messages.properties new file mode 100644 index 0000000000..f6346b885f --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/core-messages.properties @@ -0,0 +1,21 @@ +# +# 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. +# +# +StopException = Exception during stop processing +StartException = Exception during start processing \ No newline at end of file diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/endpoint-validation-messages.properties b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/endpoint-validation-messages.properties new file mode 100644 index 0000000000..121baddf5c --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/main/resources/endpoint-validation-messages.properties @@ -0,0 +1,26 @@ +# +# +# 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. +# +# +NoEndpointsFound = No endpoints found in the domain that match the reference {0} +EndpointReferenceCantBeMatched = Unable to match the endpoint reference {0} with the policy of the service to which it refers, matching process was {1} +# Single quote (we'll) needs to be escaped as we''ll +ComponentReferenceTargetNotFound = Component reference target not found at deployment time, it might be a remote service elsewhere in the SCA Domain so we''ll try and resolve it again at runtime: {0} +TooManyTargetServices = [ASM60048] A component reference {0} with only the target component service name specified {1} matches more than one service +UnableToBind = Unable to bind \ No newline at end of file diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/invocation/impl/InvocationChainImplTestCase.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/invocation/impl/InvocationChainImplTestCase.java new file mode 100644 index 0000000000..38306317b4 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/invocation/impl/InvocationChainImplTestCase.java @@ -0,0 +1,93 @@ +/* + * 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.core.invocation.impl; + +import static org.junit.Assert.assertEquals; + +import org.apache.tuscany.sca.core.DefaultExtensionPointRegistry; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.interfacedef.impl.OperationImpl; +import org.apache.tuscany.sca.invocation.Interceptor; +import org.apache.tuscany.sca.invocation.InvocationChain; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.invocation.Phase; +import org.junit.Test; + +/** + * @version $Rev$ $Date$ + */ +public class InvocationChainImplTestCase { + + @Test + public void testInsertAtEnd() throws Exception { + Operation op = newOperation("foo"); + InvocationChain chain = new InvocationChainImpl(op, op, true, new PhaseManager(new DefaultExtensionPointRegistry()), false); + Interceptor inter2 = new MockInterceptor(); + Interceptor inter1 = new MockInterceptor(); + chain.addInterceptor(inter1); + chain.addInterceptor(inter2); + Interceptor head = (Interceptor)chain.getHeadInvoker(); + assertEquals(inter1, head); + assertEquals(inter2, head.getNext()); + } + + @Test + public void testAddByPhase() throws Exception { + Operation op = newOperation("foo"); + InvocationChain chain = new InvocationChainImpl(op, op, false, new PhaseManager(new DefaultExtensionPointRegistry()), false); + Interceptor inter1 = new MockInterceptor(); + Interceptor inter2 = new MockInterceptor(); + Interceptor inter3 = new MockInterceptor(); + Interceptor inter4 = new MockInterceptor(); + chain.addInterceptor(inter3); // SERVICE + chain.addInterceptor(Phase.IMPLEMENTATION_POLICY, inter4); + chain.addInterceptor(Phase.SERVICE_POLICY, inter2); + chain.addInterceptor(Phase.SERVICE_BINDING, inter1); + Interceptor head = (Interceptor)chain.getHeadInvoker(); + assertEquals(inter1, head); + assertEquals(inter2, inter1.getNext()); + assertEquals(inter3, inter2.getNext()); + assertEquals(inter4, inter3.getNext()); + } + + private class MockInterceptor implements Interceptor { + + private Invoker next; + + public Message invoke(Message msg) { + return null; + } + + public void setNext(Invoker next) { + this.next = next; + } + + public Invoker getNext() { + return next; + } + + } + + private static Operation newOperation(String name) { + Operation operation = new OperationImpl(); + operation.setName(name); + return operation; + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/invocation/impl/PhaseManagerTestCase.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/invocation/impl/PhaseManagerTestCase.java new file mode 100644 index 0000000000..8fcead004d --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/invocation/impl/PhaseManagerTestCase.java @@ -0,0 +1,50 @@ +/* + * 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.core.invocation.impl; + +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; + +/** + * @version $Rev$ $Date$ + */ +public class PhaseManagerTestCase { + + @Test + public void testDiscovery() { + PhaseManager pm = new PhaseManager("org.apache.tuscany.sca.invocation.PhaseTest"); + List phases = pm.getAllPhases(); + System.out.println(phases.size()); + System.out.println(phases); + // Assert.assertEquals(15, phases.size()); + Assert.assertEquals("reference.first", phases.get(0)); + + int rt = phases.indexOf("reference.transaction"); + Assert.assertTrue(rt > phases.indexOf("reference.interface")); + + int st = phases.indexOf("service.transaction"); + Assert.assertTrue(st > phases.indexOf("service.binding")); + + int it = phases.indexOf("implementation.transaction"); + Assert.assertTrue(it < phases.indexOf("implementation.policy")); + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/invocation/impl/PhaseSorterTestCase.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/invocation/impl/PhaseSorterTestCase.java new file mode 100644 index 0000000000..c268e133e4 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/invocation/impl/PhaseSorterTestCase.java @@ -0,0 +1,67 @@ +/* + * 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.core.invocation.impl; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.Arrays; +import java.util.List; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class PhaseSorterTestCase { + private PhaseSorter graph; + + @Before + public void setUp() throws Exception { + graph = new PhaseSorter(); + } + + @Test + public void testSort() { + graph.addEdge("a", "b"); + graph.addEdge("a", "c"); + graph.addEdge("c", "d"); + graph.addEdge("b", "c"); + List order = graph.topologicalSort(true); + assertEquals(Arrays.asList("a", "b", "c", "d"), order); + assertTrue(!graph.getVertices().isEmpty()); + + graph.addEdge("d", "a"); + try { + order = graph.topologicalSort(true); + assertTrue("Should have failed", false); + } catch (IllegalArgumentException e) { + assertTrue(true); + } + + graph.removeEdge("d", "a"); + order = graph.topologicalSort(false); + assertEquals(Arrays.asList("a", "b", "c", "d"), order); + assertTrue(graph.getVertices().isEmpty()); + } + + @After + public void tearDown() throws Exception { + } + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/work/impl/FailingWork.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/work/impl/FailingWork.java new file mode 100644 index 0000000000..16ca5fd00e --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/work/impl/FailingWork.java @@ -0,0 +1,54 @@ +/* + * 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.core.work.impl; + + + +/** + * Simple Work item that will throw an exception + * + * @version $Rev$ $Date$ + */ +public class FailingWork extends Work { + + public FailingWork() { + super(null); + } + + /** + * {@inheritDoc} + */ + public boolean isDaemon() { + return false; + } + + /** + * {@inheritDoc} + */ + public void release() { + } + + /** + * Throws an IllegalArgumentException + */ + public void run() { + System.out.println("Starting " + this + " and throwing an Exception"); + throw new IllegalArgumentException("Sample exception from " + this); + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/work/impl/JSR237MyFailingRunnable.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/work/impl/JSR237MyFailingRunnable.java new file mode 100644 index 0000000000..2d791e5012 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/work/impl/JSR237MyFailingRunnable.java @@ -0,0 +1,43 @@ +/* + * 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.core.work.impl; + +/** + * Simple Runnable that throws an IllegalArgumentException + * + * @version $Rev$ $Date$ + */ +public class JSR237MyFailingRunnable extends JSR237MyRunnable { + + /** + * Constructor + */ + public JSR237MyFailingRunnable() { + super(-1); + } + + /** + * Sleeps for a period of time defined by sleepTime + */ + @Override + public void run() { + System.out.println("Starting " + this + " and throwing an Exception"); + throw new IllegalArgumentException("Sample exception from " + this); + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/work/impl/JSR237MyRunnable.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/work/impl/JSR237MyRunnable.java new file mode 100644 index 0000000000..c0183b6f9b --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/work/impl/JSR237MyRunnable.java @@ -0,0 +1,71 @@ +/* + * 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.core.work.impl; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Simple Runnable that is used for testing Jsr237WorkScheduler + * + * @version $Rev$ $Date$ + */ +public class JSR237MyRunnable implements Runnable { + + /** + * Count of workAccepted() method calls + */ + private AtomicInteger runCompletedCount = new AtomicInteger(); + + /** + * The amount of time to sleep in the Run loop + */ + private final long sleepTime; + + /** + * Constructor + * + * @param sleepTime The amount of time to sleep (in milliseconds) in the run() method + */ + public JSR237MyRunnable(long sleepTime) { + this.sleepTime = sleepTime; + } + + /** + * Sleeps for a period of time defined by sleepTime + */ + public void run() { + System.out.println("Starting " + this); + try { + Thread.sleep(sleepTime); + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println("Done " + this); + runCompletedCount.incrementAndGet(); + } + + /** + * Returns the number of completed calls to run() + * + * @return The number of completed calls to run() + */ + public int getRunCompletedCount() { + return runCompletedCount.get(); + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/work/impl/JSR237MyRunnerListener.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/work/impl/JSR237MyRunnerListener.java new file mode 100644 index 0000000000..307f24aca7 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/work/impl/JSR237MyRunnerListener.java @@ -0,0 +1,154 @@ +/* + * 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.core.work.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.tuscany.sca.work.NotificationListener; + +/** + * Simple NotificationListener that is used for testing Jsr237WorkScheduler + * + * @version $Rev$ $Date$ + */ +public class JSR237MyRunnerListener implements NotificationListener { + + /** + * Count of workAccepted() method calls + */ + private AtomicInteger workAcceptedCallCount = new AtomicInteger(); + + /** + * Count of workStarted() method calls + */ + private AtomicInteger workStartedCallCount = new AtomicInteger(); + + /** + * Count of workCompleted() method calls + */ + private AtomicInteger workCompletedCallCount = new AtomicInteger(); + + /** + * Count of workFailed() method calls + */ + private AtomicInteger workFailedCallCount = new AtomicInteger(); + + /** + * Count of workRejected() method calls + */ + private AtomicInteger workRejectedCallCount = new AtomicInteger(); + + /** + * List of all exceptions thrown by Work items + */ + private List workExceptions = Collections.synchronizedList(new ArrayList()); + + /** + * {@inheritDoc} + */ + public void workAccepted(JSR237MyRunnable work) { + workAcceptedCallCount.incrementAndGet(); + } + + /** + * {@inheritDoc} + */ + public void workCompleted(JSR237MyRunnable work) { + workCompletedCallCount.incrementAndGet(); + } + + /** + * {@inheritDoc} + */ + public void workFailed(JSR237MyRunnable work, Throwable error) { + workExceptions.add(error); + workFailedCallCount.incrementAndGet(); + } + + /** + * {@inheritDoc} + */ + public void workRejected(JSR237MyRunnable work) { + workRejectedCallCount.incrementAndGet(); + } + + /** + * {@inheritDoc} + */ + public void workStarted(JSR237MyRunnable work) { + workStartedCallCount.incrementAndGet(); + } + + /** + * Returns the number of calls to workAccepted() + * + * @return The number of calls to workAccepted() + */ + public int getWorkAcceptedCallCount() { + return workAcceptedCallCount.get(); + } + + /** + * Returns the number of calls to workStarted() + * + * @return The number of calls to workStarted() + */ + public int getWorkStartedCallCount() { + return workStartedCallCount.get(); + } + + /** + * Returns the number of calls to workCompleted() + * + * @return The number of calls to workCompleted() + */ + public int getWorkCompletedCallCount() { + return workCompletedCallCount.get(); + } + + /** + * Returns the number of calls to workFailed() + * + * @return The number of calls to workFailed() + */ + public int getWorkFailedCallCount() { + return workFailedCallCount.get(); + } + + /** + * Returns the number of calls to workRejected() + * + * @return The number of calls to workRejected() + */ + public int getWorkRejectedCallCount() { + return workRejectedCallCount.get(); + } + + /** + * Returns a List of all exceptions that are thrown by the Work items + * + * @return A List of all exceptions that are thrown by the Work items + */ + public List getWorkExceptions() { + return Collections.unmodifiableList(workExceptions); + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/work/impl/Jsr237WorkSchedulerTestCase.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/work/impl/Jsr237WorkSchedulerTestCase.java new file mode 100644 index 0000000000..4ec0f55867 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/work/impl/Jsr237WorkSchedulerTestCase.java @@ -0,0 +1,240 @@ +/* + * 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.core.work.impl; + +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * Test case for Jsr237WorkScheduler + * + * @version $Rev$ $Date$ + */ +public class Jsr237WorkSchedulerTestCase { + + /** + * Wait up to 20 seconds for the Work units to complete + */ + private static final long WAIT_TIMEOUT = 20000; + + /** + * This is the shared instance of the ThreadPoolWorkManager used by the tests + */ + private static DefaultWorkScheduler workSchedular = null; + + /** + * Setup the Jsr237WorkScheduler + */ + @BeforeClass + public static void setup() { + workSchedular = new DefaultWorkScheduler(null, null); + } + + /** + * Make sure that the Jsr237WorkScheduler is stopped after running the tests + */ + @AfterClass + public static void destroy() { + if (workSchedular != null) { + workSchedular.stop(); + } + } + + /** + * Tests running a single fast job on the Jsr237WorkScheduler + */ + @Test + public void testSingleFastJob() { + // Create the work and register it + JSR237MyRunnable fast = new JSR237MyRunnable(10); + JSR237MyRunnerListener listener = new JSR237MyRunnerListener(); + workSchedular.scheduleWork(fast, listener); + + // Wait for the 1 job to complete + waitForWorkToComplete(listener, 1); + + // Test that the job completed successfully. + Assert.assertEquals(1, listener.getWorkAcceptedCallCount()); + Assert.assertEquals(0, listener.getWorkRejectedCallCount()); + Assert.assertEquals(1, listener.getWorkStartedCallCount()); + Assert.assertEquals(1, listener.getWorkCompletedCallCount()); + Assert.assertEquals(0, listener.getWorkExceptions().size()); + } + + /** + * Tests running a single job that fails on the Jsr237WorkScheduler + */ + @Test + public void testSingleFailingJob() { + // Create the work and register it + JSR237MyFailingRunnable fail = new JSR237MyFailingRunnable(); + JSR237MyRunnerListener listener = new JSR237MyRunnerListener(); + workSchedular.scheduleWork(fail, listener); + + // Wait for the 1 job to complete + waitForWorkToComplete(listener, 1); + + // Test that the job completed successfully. + Assert.assertEquals(1, listener.getWorkAcceptedCallCount()); + Assert.assertEquals(0, listener.getWorkRejectedCallCount()); + Assert.assertEquals(1, listener.getWorkStartedCallCount()); + Assert.assertEquals(0, listener.getWorkCompletedCallCount()); + Assert.assertEquals(1, listener.getWorkFailedCallCount()); + Assert.assertEquals(1, listener.getWorkExceptions().size()); + } + + /** + * Tests running a mixture of fast and slow jobs on the Jsr237WorkScheduler + */ + @Test + public void testMultipleJobs() { + // Create the work and register it + JSR237MyRunnable fast1 = new JSR237MyRunnable(5); + JSR237MyRunnable fast2 = new JSR237MyRunnable(10); + JSR237MyRunnable fast3 = new JSR237MyRunnable(20); + JSR237MyRunnable slow1= new JSR237MyRunnable(200); + JSR237MyRunnable slow2 = new JSR237MyRunnable(200); + JSR237MyRunnerListener listener = new JSR237MyRunnerListener(); + workSchedular.scheduleWork(fast1, listener); + workSchedular.scheduleWork(fast2, listener); + workSchedular.scheduleWork(fast3, listener); + workSchedular.scheduleWork(slow1, listener); + workSchedular.scheduleWork(slow2, listener); + + // Wait for the 5 jobs to complete + waitForWorkToComplete(listener, 5); + + // Test that the job completed successfully. + Assert.assertEquals(5, listener.getWorkAcceptedCallCount()); + Assert.assertEquals(0, listener.getWorkRejectedCallCount()); + Assert.assertEquals(5, listener.getWorkStartedCallCount()); + Assert.assertEquals(5, listener.getWorkCompletedCallCount()); + Assert.assertEquals(0, listener.getWorkExceptions().size()); + } + + /** + * Tests running a mixture of fast and slow jobs some of which fail on the + * Jsr237WorkScheduler + */ + @Test + public void testMultipleJobsSomeFail() { + // Create the work and register it + JSR237MyRunnable fast1 = new JSR237MyRunnable(5); + JSR237MyRunnable fast2 = new JSR237MyRunnable(10); + JSR237MyRunnable fast3 = new JSR237MyRunnable(20); + JSR237MyRunnable slow1= new JSR237MyRunnable(200); + JSR237MyRunnable slow2 = new JSR237MyRunnable(200); + JSR237MyFailingRunnable fail1 = new JSR237MyFailingRunnable(); + JSR237MyFailingRunnable fail2 = new JSR237MyFailingRunnable(); + JSR237MyRunnerListener listener = new JSR237MyRunnerListener(); + workSchedular.scheduleWork(fast1, listener); + workSchedular.scheduleWork(fast2, listener); + workSchedular.scheduleWork(fail1, listener); + workSchedular.scheduleWork(fast3, listener); + workSchedular.scheduleWork(slow1, listener); + workSchedular.scheduleWork(fail2, listener); + workSchedular.scheduleWork(slow2, listener); + + // Wait for the 7 jobs to complete + waitForWorkToComplete(listener, 7); + + // Test that the job completed successfully. + Assert.assertEquals(7, listener.getWorkAcceptedCallCount()); + Assert.assertEquals(0, listener.getWorkRejectedCallCount()); + Assert.assertEquals(7, listener.getWorkStartedCallCount()); + Assert.assertEquals(5, listener.getWorkCompletedCallCount()); + Assert.assertEquals(2, listener.getWorkFailedCallCount()); + Assert.assertEquals(2, listener.getWorkExceptions().size()); + } + + /** + * Tests running a single job that has no listener + */ + @Test + public void testSingleFastJobWithNoListener() { + // Create the work and register it + JSR237MyRunnable fast = new JSR237MyRunnable(10); + workSchedular.scheduleWork(fast); + + // Wait for the job to complete + long startTime = System.currentTimeMillis(); + while (true) { + int completedCount = fast.getRunCompletedCount(); + if (completedCount == 1) { + break; + } + + if (System.currentTimeMillis() - startTime > WAIT_TIMEOUT) { + Assert.fail("Only " + completedCount + " work items completed before timeout"); + return; + } + + // Lets wait for the job to complete + try { + Thread.sleep(25); + } catch (InterruptedException ex) { + Assert.fail("Unexpected exception: " + ex); + } + } + } + + /** + * Tests scheduling a null as the work item + */ + @Test + public void testNullWork() { + try { + workSchedular.scheduleWork(null); + Assert.fail("Should have thrown IllegalArgumentException "); + } catch (IllegalArgumentException ex) { + // As expected + Assert.assertTrue(ex.toString().indexOf("null") != -1); + } + } + + /** + * Waits for the specified number of jobs to complete or the timeout to fire. + * + * @param listener The listener to use to track Work unit completion + * @param completedWorkItemsToWaitFor The number of Work items to complete + */ + private void waitForWorkToComplete(JSR237MyRunnerListener listener, int completedWorkItemsToWaitFor) { + long startTime = System.currentTimeMillis(); + while (true) { + int completedCount = listener.getWorkCompletedCallCount() + listener.getWorkFailedCallCount(); + if (completedCount == completedWorkItemsToWaitFor) { + return; + } + + if (System.currentTimeMillis() - startTime > WAIT_TIMEOUT) { + Assert.fail("Only " + completedCount + " work items completed before timeout"); + return; + } + + // Lets wait for more jobs to complete + try { + Thread.sleep(25); + } catch (InterruptedException ex) { + Assert.fail("Unexpected exception: " + ex); + } + } + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/work/impl/TestWorkListener.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/work/impl/TestWorkListener.java new file mode 100644 index 0000000000..a452d6f371 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/work/impl/TestWorkListener.java @@ -0,0 +1,153 @@ +/* + * 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.core.work.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.tuscany.sca.work.WorkSchedulerException; +import org.junit.Assert; + +/** + * A simple WorkListener that tracks invocations to it. + * + * @version $Rev$ $Date$ + */ +public class TestWorkListener implements WorkListener { + + /** + * Count of workAccepted() method calls + */ + private AtomicInteger workAcceptedCallCount = new AtomicInteger(); + + /** + * Count of workStarted() method calls + */ + private AtomicInteger workStartedCallCount = new AtomicInteger(); + + /** + * Count of workCompleted() method calls + */ + private AtomicInteger workCompletedCallCount = new AtomicInteger(); + + /** + * Count of workRejected() method calls + */ + private AtomicInteger workRejectedCallCount = new AtomicInteger(); + + /** + * List of all exceptions thrown by Work items + */ + private List workExceptions = Collections.synchronizedList(new ArrayList()); + + /** + * {@inheritDoc} + */ + public void workAccepted(WorkEvent work) { + workAcceptedCallCount.incrementAndGet(); + + // Validate the WorkEvent + Assert.assertNotNull(work.getWorkItem()); + Assert.assertEquals(WorkEvent.WORK_ACCEPTED, work.getType()); + } + + /** + * {@inheritDoc} + */ + public void workStarted(WorkEvent work) { + workStartedCallCount.incrementAndGet(); + + // Validate the WorkEvent + Assert.assertNotNull(work.getWorkItem()); + Assert.assertEquals(WorkEvent.WORK_STARTED, work.getType()); + } + + /** + * {@inheritDoc} + */ + public void workCompleted(WorkEvent work) { + if (work.getException() != null) { + workExceptions.add(work.getException()); + } + + // Validate the WorkEvent + Assert.assertNotNull(work.getWorkItem()); + Assert.assertEquals(WorkEvent.WORK_COMPLETED, work.getType()); + + workCompletedCallCount.incrementAndGet(); + } + + /** + * {@inheritDoc} + */ + public void workRejected(WorkEvent work) { + workRejectedCallCount.incrementAndGet(); + + // Validate the WorkEvent + Assert.assertNotNull(work.getWorkItem()); + Assert.assertEquals(WorkEvent.WORK_REJECTED, work.getType()); + } + + /** + * Returns the number of calls to workAccepted() + * + * @return The number of calls to workAccepted() + */ + public int getWorkAcceptedCallCount() { + return workAcceptedCallCount.get(); + } + + /** + * Returns the number of calls to workStarted() + * + * @return The number of calls to workStarted() + */ + public int getWorkStartedCallCount() { + return workStartedCallCount.get(); + } + + /** + * Returns the number of calls to workCompleted() + * + * @return The number of calls to workCompleted() + */ + public int getWorkCompletedCallCount() { + return workCompletedCallCount.get(); + } + + /** + * Returns the number of calls to workRejected() + * + * @return The number of calls to workRejected() + */ + public int getWorkRejectedCallCount() { + return workRejectedCallCount.get(); + } + + /** + * Returns a List of all exceptions that are thrown by the Work items + * + * @return A List of all exceptions that are thrown by the Work items + */ + public List getWorkExceptions() { + return Collections.unmodifiableList(workExceptions); + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/work/impl/ThreadPoolWorkManagerTestCase.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/work/impl/ThreadPoolWorkManagerTestCase.java new file mode 100644 index 0000000000..122609d7e6 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/work/impl/ThreadPoolWorkManagerTestCase.java @@ -0,0 +1,227 @@ +/* + * 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.core.work.impl; + +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * This test case will test the ThreadPoolWorkManager + * + * @version $Rev$ $Date$ + */ +public class ThreadPoolWorkManagerTestCase { + + /** + * Wait up to 20 seconds for the Work units to complete + */ + private static final long WAIT_TIMEOUT = 20000; + + /** + * This is the shared instance of the ThreadPoolWorkManager used by the tests + */ + private static ThreadPoolWorkManager workManager = null; + + /** + * Setup the ThreadPoolWorkManager + */ + @BeforeClass + public static void setup() { + workManager = new ThreadPoolWorkManager(10); + } + + /** + * Make sure that the ThreadPoolWorkManager is stopped after running the tests + */ + @AfterClass + public static void destroy() { + if (workManager != null) { + workManager.destroy(); + } + } + + /** + * Tests running a single fast job on the ThreadPoolWorkManager + */ + @Test + public void testSingleFastJob() { + // Create the work and register it + TimeDelayWork fast = new TimeDelayWork(10); + TestWorkListener listener = new TestWorkListener(); + workManager.schedule(fast, listener); + + // Wait for the 1 job to complete + waitForWorkToComplete(listener, 1); + + // Test that the job completed successfully. + Assert.assertEquals(1, listener.getWorkAcceptedCallCount()); + Assert.assertEquals(0, listener.getWorkRejectedCallCount()); + Assert.assertEquals(1, listener.getWorkStartedCallCount()); + Assert.assertEquals(1, listener.getWorkCompletedCallCount()); + Assert.assertEquals(0, listener.getWorkExceptions().size()); + } + + /** + * Tests running a single job that fails on the ThreadPoolWorkManager + */ + @Test + public void testSingleFailingJob() { + // Create the work and register it + FailingWork fail = new FailingWork(); + TestWorkListener listener = new TestWorkListener(); + workManager.schedule(fail, listener); + + // Wait for the 1 job to complete + waitForWorkToComplete(listener, 1); + + // Test that the job completed successfully. + Assert.assertEquals(1, listener.getWorkAcceptedCallCount()); + Assert.assertEquals(0, listener.getWorkRejectedCallCount()); + Assert.assertEquals(1, listener.getWorkStartedCallCount()); + Assert.assertEquals(1, listener.getWorkCompletedCallCount()); + Assert.assertEquals(1, listener.getWorkExceptions().size()); + } + + /** + * Tests running a mixture of fast and slow jobs on the ThreadPoolWorkManager + */ + @Test + public void testMultipleJobs() { + // Create the work and register it + TimeDelayWork fast1 = new TimeDelayWork(5); + TimeDelayWork fast2 = new TimeDelayWork(10); + TimeDelayWork fast3 = new TimeDelayWork(20); + TimeDelayWork slow1= new TimeDelayWork(200); + TimeDelayWork slow2 = new TimeDelayWork(200); + TestWorkListener listener = new TestWorkListener(); + workManager.schedule(fast1, listener); + workManager.schedule(fast2, listener); + workManager.schedule(fast3, listener); + workManager.schedule(slow1, listener); + workManager.schedule(slow2, listener); + + // Wait for the 5 jobs to complete + waitForWorkToComplete(listener, 5); + + // Test that the job completed successfully. + Assert.assertEquals(5, listener.getWorkAcceptedCallCount()); + Assert.assertEquals(0, listener.getWorkRejectedCallCount()); + Assert.assertEquals(5, listener.getWorkStartedCallCount()); + Assert.assertEquals(5, listener.getWorkCompletedCallCount()); + Assert.assertEquals(0, listener.getWorkExceptions().size()); + } + + /** + * Tests running a mixture of fast and slow jobs some of which fail on the + * ThreadPoolWorkManager + */ + @Test + public void testMultipleJobsSomeFail() { + // Create the work and register it + TimeDelayWork fast1 = new TimeDelayWork(5); + TimeDelayWork fast2 = new TimeDelayWork(10); + TimeDelayWork fast3 = new TimeDelayWork(20); + TimeDelayWork slow1= new TimeDelayWork(200); + TimeDelayWork slow2 = new TimeDelayWork(200); + FailingWork fail1 = new FailingWork(); + FailingWork fail2 = new FailingWork(); + TestWorkListener listener = new TestWorkListener(); + workManager.schedule(fast1, listener); + workManager.schedule(fast2, listener); + workManager.schedule(fail1, listener); + workManager.schedule(fast3, listener); + workManager.schedule(slow1, listener); + workManager.schedule(fail2, listener); + workManager.schedule(slow2, listener); + + // Wait for the 7 jobs to complete + waitForWorkToComplete(listener, 7); + + // Test that the job completed successfully. + Assert.assertEquals(7, listener.getWorkAcceptedCallCount()); + Assert.assertEquals(0, listener.getWorkRejectedCallCount()); + Assert.assertEquals(7, listener.getWorkStartedCallCount()); + Assert.assertEquals(7, listener.getWorkCompletedCallCount()); + Assert.assertEquals(2, listener.getWorkExceptions().size()); + } + + /** + * Tests running a single job that has no listener + */ + @Test + public void testSingleFastJobWithNoListener() { + // Create the work and register it + TimeDelayWork fast = new TimeDelayWork(10); + workManager.schedule(fast); + + // Wait for the job to complete + long startTime = System.currentTimeMillis(); + while (true) { + int completedCount = fast.getRunCompletedCount(); + if (completedCount == 1) { + break; + } + + if (System.currentTimeMillis() - startTime > WAIT_TIMEOUT) { + Assert.fail("Only " + completedCount + " work items completed before timeout"); + return; + } + + // Lets wait for the job to complete + try { + Thread.sleep(25); + } catch (InterruptedException ex) { + Assert.fail("Unexpected exception: " + ex); + } + } + + // Make sure we have got one completed run + Assert.assertEquals(1, fast.getRunCompletedCount()); + } + + /** + * Waits for the specified number of jobs to complete or the timeout to fire. + * + * @param listener The listener to use to track Work unit completion + * @param completedWorkItemsToWaitFor The number of Work items to complete + */ + private void waitForWorkToComplete(TestWorkListener listener, int completedWorkItemsToWaitFor) { + long startTime = System.currentTimeMillis(); + while (true) { + int completedCount = listener.getWorkCompletedCallCount(); + if (completedCount == completedWorkItemsToWaitFor) { + return; + } + + if (System.currentTimeMillis() - startTime > WAIT_TIMEOUT) { + Assert.fail("Only " + completedCount + " work items completed before timeout"); + return; + } + + // Lets wait for more jobs to complete + try { + Thread.sleep(25); + } catch (InterruptedException ex) { + Assert.fail("Unexpected exception: " + ex); + } + } + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/work/impl/TimeDelayWork.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/work/impl/TimeDelayWork.java new file mode 100644 index 0000000000..f6435659ef --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/core/work/impl/TimeDelayWork.java @@ -0,0 +1,86 @@ +/* + * 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.core.work.impl; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Simple Work item that will sleep in the run() method for the specified + * period of time + * + * @version $Rev$ $Date$ + */ +public class TimeDelayWork extends Work { + + /** + * Count of completed run() method calls + */ + private AtomicInteger runCompletedCount = new AtomicInteger(); + + /** + * The amount of time to sleep in the Run loop + */ + private final long sleepTime; + + /** + * Constructor + * + * @param sleepTime The amount of time to sleep (in milliseconds) in the run() method + */ + public TimeDelayWork(long sleepTime) { + super(null); + this.sleepTime = sleepTime; + } + + /** + * {@inheritDoc} + */ + public boolean isDaemon() { + return false; + } + + /** + * {@inheritDoc} + */ + public void release() { + } + + /** + * Sleeps for a period of time defined by sleepTime + */ + public void run() { + System.out.println("Starting " + this); + try { + Thread.sleep(sleepTime); + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println("Done " + this); + runCompletedCount.incrementAndGet(); + } + + /** + * Returns the number of completed calls to run() + * + * @return The number of completed calls to run() + */ + public int getRunCompletedCount() { + return runCompletedCount.get(); + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/scope/ScopeTestCase.java b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/scope/ScopeTestCase.java new file mode 100644 index 0000000000..ca7bf9b3d7 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/java/org/apache/tuscany/sca/scope/ScopeTestCase.java @@ -0,0 +1,66 @@ +/* + * 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.scope; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.apache.tuscany.sca.core.scope.Scope; +import org.junit.Test; +/** + * @version $Rev$ $Date$ + */ +public class ScopeTestCase { + + @Test + public void testEquals() throws Exception { + Scope scope = new Scope("COMPOSITE"); + assertTrue(scope.equals(Scope.COMPOSITE)); + } + + @Test + public void testEqualsNew() throws Exception { + Scope foo = new Scope("foo"); + Scope foo2 = new Scope("FOO"); + assertTrue(foo.equals(foo2)); + } + + @Test + public void testNotEquals() throws Exception { + Scope foo = new Scope("BAR"); + Scope foo2 = new Scope("FOO"); + assertFalse(foo.equals(foo2)); + } + + @Test + public void testNotEqualsDifferent() throws Exception { + Scope foo = new Scope("FOO"); + assertFalse(foo.equals(new Bar("FOO"))); + } + + public class Bar { + String scope; + + public Bar(String scope) { + this.scope = scope; + } + } + + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/resources/META-INF/services/org.apache.tuscany.sca.invocation.PhaseTest b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/resources/META-INF/services/org.apache.tuscany.sca.invocation.PhaseTest new file mode 100644 index 0000000000..ad23df3761 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/core/src/test/resources/META-INF/services/org.apache.tuscany.sca.invocation.PhaseTest @@ -0,0 +1,24 @@ +# 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. + +name=implementation.last, stage=implementation, after=* +name=reference.first, stage=reference, before=* +name=reference.transaction, stage=reference, after=reference.interface +name=reference.binding.header, stage=reference.binding, after=reference.binding.transport +name=service.binding.header, stage=service.binding, after=service.binding.transport +name=service.transaction, stage=service, after=service.binding, before=component.service +name=implementation.transaction, stage=implementation, before=implementation.policy -- cgit v1.2.3