diff options
Diffstat (limited to 'branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca')
72 files changed, 9946 insertions, 0 deletions
diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/RuntimeAssemblyFactory.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/RuntimeAssemblyFactory.java new file mode 100644 index 0000000000..8c84a9e399 --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/RuntimeAssemblyFactory.java @@ -0,0 +1,74 @@ +/* + * 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$ + */ +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/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/CompositeActivatorImpl.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/CompositeActivatorImpl.java new file mode 100644 index 0000000000..1c4ded13fc --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/CompositeActivatorImpl.java @@ -0,0 +1,846 @@ +/* + * 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.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +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.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.Reference; +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.FactoryExtensionPoint; +import org.apache.tuscany.sca.core.UtilityExtensionPoint; +import org.apache.tuscany.sca.core.invocation.ExtensibleWireProcessor; +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.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.provider.BindingProviderFactory; +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.ServiceBindingProvider; +import org.apache.tuscany.sca.runtime.ActivationException; +import org.apache.tuscany.sca.runtime.CompositeActivator; +import org.apache.tuscany.sca.runtime.EndpointRegistry; +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.RuntimeWire; +import org.apache.tuscany.sca.runtime.RuntimeWireProcessor; +import org.apache.tuscany.sca.runtime.RuntimeWireProcessorExtensionPoint; +import org.apache.tuscany.sca.work.WorkScheduler; + +/** + * @version $Rev$ $Date$ + */ +public class CompositeActivatorImpl implements CompositeActivator { + final Logger logger = Logger.getLogger(CompositeActivatorImpl.class.getName()); + + private final ExtensionPointRegistry extensionPoints; + private final AssemblyFactory assemblyFactory; + private final MessageFactory messageFactory; + private final InterfaceContractMapper interfaceContractMapper; + private final ScopeRegistry scopeRegistry; + private final WorkScheduler workScheduler; + private final RuntimeWireProcessor wireProcessor; + private final ProviderFactoryExtensionPoint providerFactories; + + public CompositeActivatorImpl(ExtensionPointRegistry extensionPoints) { + this.extensionPoints = extensionPoints; + UtilityExtensionPoint utilities = extensionPoints.getExtensionPoint(UtilityExtensionPoint.class); + FactoryExtensionPoint factories = extensionPoints.getExtensionPoint(FactoryExtensionPoint.class); + this.assemblyFactory = factories.getFactory(AssemblyFactory.class); + this.messageFactory = factories.getFactory(MessageFactory.class); + this.interfaceContractMapper = utilities.getUtility(InterfaceContractMapper.class); + this.scopeRegistry = utilities.getUtility(ScopeRegistry.class); + this.workScheduler = utilities.getUtility(WorkScheduler.class); + this.wireProcessor = new ExtensibleWireProcessor(extensionPoints.getExtensionPoint(RuntimeWireProcessorExtensionPoint.class)); + this.providerFactories = extensionPoints.getExtensionPoint(ProviderFactoryExtensionPoint.class); + } + + //========================================================================= + // 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; + } + + /* TODO - EPR - activate services at all levels as promoted endpoin references are maintained + * on the higher level services + if (service.getService() instanceof CompositeService) { + return; + } + */ + + if (logger.isLoggable(Level.FINE)) { + logger.fine("Activating component service: " + component.getURI() + "#" + service.getName()); + } + + for (Endpoint endpoint : service.getEndpoints()) { + addServiceBindingProvider(endpoint, component, service, endpoint.getBinding()); + } + addServiceWires(compositeContext, component, service); + } + + public void deactivate(RuntimeComponent component, RuntimeComponentService service) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Deactivating component service: " + component.getURI() + "#" + service.getName()); + } + removeServiceWires(service); + for (Binding binding : service.getBindings()) { + removeServiceBindingProvider(component, service, binding); + } + } + + private ServiceBindingProvider addServiceBindingProvider( + Endpoint endpoint, + RuntimeComponent component, RuntimeComponentService service, + Binding binding) { + BindingProviderFactory providerFactory = (BindingProviderFactory) providerFactories + .getProviderFactory(binding.getClass()); + if (providerFactory != null) { + @SuppressWarnings("unchecked") + ServiceBindingProvider bindingProvider = providerFactory + .createServiceBindingProvider(endpoint); + if (bindingProvider != null) { + ((RuntimeComponentService) service).setBindingProvider(binding, + bindingProvider); + } + for (PolicyProviderFactory f : providerFactories.getPolicyProviderFactories()) { + PolicyProvider policyProvider = f.createServicePolicyProvider(endpoint); + if (policyProvider != null) { + service.addPolicyProvider(binding, policyProvider); + } + } + return bindingProvider; + } else { + throw new IllegalStateException( + "Provider factory not found for binding: " + + binding.getType()); + } + } + + private void removeServiceBindingProvider(RuntimeComponent component, + RuntimeComponentService service, Binding binding) { + service.setBindingProvider(binding, null); + for (Binding b : service.getBindings()) { + List<PolicyProvider> pps = service.getPolicyProviders(b); + if (pps != null) { + pps.clear(); + } + } + } + + private void addServiceWires(CompositeContext compositeContext, Component serviceComponent, ComponentService service) { + if (!(service instanceof RuntimeComponentService)) { + return; + } + + RuntimeComponentService runtimeService = (RuntimeComponentService)service; + + // Add a wire for each service Endpoint + for ( Endpoint endpoint : runtimeService.getEndpoints()){ + + // fluff up a fake endpoint reference as we are on the service side + // so we need to represent the reference that will call us + EndpointReference endpointReference = assemblyFactory.createEndpointReference(); + endpointReference.setBinding(endpoint.getBinding()); + endpointReference.setTargetEndpoint(endpoint); + endpointReference.setStatus(EndpointReference.WIRED_TARGET_FOUND_AND_MATCHED); + + // 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)); + endpointReference.setInterfaceContract(getServiceBindingInterfaceContract(service, endpoint.getBinding())); + + // create the wire + RuntimeWire wire = new RuntimeWireImpl(compositeContext, + false, + endpointReference, + endpoint, + interfaceContractMapper, + workScheduler, + wireProcessor, + messageFactory); + + // TODO - EPR - TUSCANY-3187 - keep and eye on this as to code + // has been reported to be working without this fix in some + // environments + //runtimeService.getRuntimeWires().add(wire); + ((RuntimeComponentService)endpoint.getService()).getRuntimeWires().add(wire); + } + } + + private void removeServiceWires(ComponentService service) { + if (!(service instanceof RuntimeComponentService)) { + return; + } + RuntimeComponentService runtimeService = (RuntimeComponentService)service; + runtimeService.getRuntimeWires().clear(); + } + + private InterfaceContract getServiceBindingInterfaceContract(ComponentService service, Binding binding) { + InterfaceContract interfaceContract = service.getInterfaceContract(); + + ServiceBindingProvider provider = ((RuntimeComponentService)service).getBindingProvider(binding); + if (provider != null) { + InterfaceContract bindingContract = provider.getBindingInterfaceContract(); + if (bindingContract != null) { + interfaceContract = bindingContract; + } + } + return interfaceContract.makeUnidirectional(false); + } + + // 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); + + // TODO reference wires are added at component start for some reason + } + + public void deactivate(RuntimeComponent component, RuntimeComponentReference reference) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Deactivating component reference: " + component.getURI() + "#" + reference.getName()); + } + removeReferenceWires(reference); + for (EndpointReference endpointReference : reference.getEndpointReferences()) { + if (endpointReference.getBinding() != null){ + removeReferenceBindingProvider(component, reference, endpointReference.getBinding()); + } + } + } +/* + private ReferenceBindingProvider addReferenceBindingProvider( + RuntimeComponent component, RuntimeComponentReference reference, + Binding binding) { + BindingProviderFactory providerFactory = (BindingProviderFactory) providerFactories + .getProviderFactory(binding.getClass()); + if (providerFactory != null) { + @SuppressWarnings("unchecked") + ReferenceBindingProvider bindingProvider = providerFactory + .createReferenceBindingProvider( + (RuntimeComponent) component, + (RuntimeComponentReference) reference, binding); + if (bindingProvider != null) { + ((RuntimeComponentReference) reference).setBindingProvider( + binding, bindingProvider); + } + for (PolicyProviderFactory f : providerFactories + .getPolicyProviderFactories()) { + PolicyProvider policyProvider = f + .createReferencePolicyProvider(component, reference, + binding); + if (policyProvider != null) { + reference.addPolicyProvider(binding, policyProvider); + } + } + + return bindingProvider; + } else { + throw new IllegalStateException( + "Provider factory not found for binding: " + + binding.getClass().getType()); + } + } +*/ + private void removeReferenceBindingProvider(RuntimeComponent component, + RuntimeComponentReference reference, Binding binding) { + reference.setBindingProvider(binding, null); + for (Binding b : reference.getBindings()) { + List<PolicyProvider> pps = reference.getPolicyProviders(b); + if (pps != null) { + pps.clear(); + } + } + } + + private void removeReferenceWires(ComponentReference reference) { + if (!(reference instanceof RuntimeComponentReference)) { + return; + } + + // TODO - EPR what is this all about? + // [rfeng] Comment out the following statements to avoid the on-demand activation + // RuntimeComponentReference runtimeRef = (RuntimeComponentReference)reference; + // runtimeRef.getRuntimeWires().clear(); + } + + //========================================================================= + // 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); + } + } + + 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); + + // Reference bindings aren't started until the wire is first used + + for (ComponentService service : component.getServices()) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Starting component service: " + component.getURI() + "#" + service.getName()); + } + RuntimeComponentService runtimeService = (RuntimeComponentService)service; + for (Endpoint endpoint : service.getEndpoints()) { + // FIXME: Should the policy providers be started before the endpoint is started? + for (PolicyProvider policyProvider : runtimeService.getPolicyProviders(endpoint.getBinding())) { + policyProvider.start(); + } + + final ServiceBindingProvider bindingProvider = runtimeService.getBindingProvider(endpoint.getBinding()); + if (bindingProvider != null) { + // bindingProvider.start(); + // Allow bindings to add shutdown hooks. Requires RuntimePermission shutdownHooks in policy. + AccessController.doPrivileged(new PrivilegedAction<Object>() { + public Object run() { + bindingProvider.start(); + return null; + } + }); + compositeContext.getEndpointRegistry().addEndpoint(endpoint); + } + } + } + + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + start(compositeContext, (Composite)implementation); + } else { + for (PolicyProvider policyProvider : runtimeComponent.getPolicyProviders()) { + policyProvider.start(); + } + ImplementationProvider implementationProvider = runtimeComponent.getImplementationProvider(); + if (implementationProvider != null) { + implementationProvider.start(); + } + } + + if (component instanceof ScopedRuntimeComponent) { + ScopedRuntimeComponent scopedRuntimeComponent = (ScopedRuntimeComponent)component; + if (scopedRuntimeComponent.getScopeContainer() != null) { + scopedRuntimeComponent.getScopeContainer().start(); + } + } + + runtimeComponent.setStarted(true); + } + + 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()) { + compositeContext.getEndpointRegistry().removeEndpoint(endpoint); + final ServiceBindingProvider bindingProvider = ((RuntimeComponentService)service).getBindingProvider(endpoint.getBinding()); + if (bindingProvider != null) { + // Allow bindings to read properties. Requires PropertyPermission read in security policy. + AccessController.doPrivileged(new PrivilegedAction<Object>() { + public Object run() { + bindingProvider.stop(); + return null; + } + }); + } + for (PolicyProvider policyProvider : ((RuntimeComponentService)service).getPolicyProviders(endpoint + .getBinding())) { + policyProvider.stop(); + } + } + } + for (ComponentReference reference : component.getReferences()) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Stopping component reference: " + component.getURI() + "#" + reference.getName()); + } + RuntimeComponentReference runtimeRef = ((RuntimeComponentReference)reference); + + for (EndpointReference endpointReference : reference.getEndpointReferences()) { + compositeContext.getEndpointRegistry().removeEndpointReference(endpointReference); + final ReferenceBindingProvider bindingProvider = runtimeRef.getBindingProvider(endpointReference.getBinding()); + if (bindingProvider != null) { + // Allow bindings to read properties. Requires PropertyPermission read in security policy. + AccessController.doPrivileged(new PrivilegedAction<Object>() { + public Object run() { + bindingProvider.stop(); + return null; + } + }); + } + for (PolicyProvider policyProvider : ((RuntimeComponentReference)reference) + .getPolicyProviders(endpointReference.getBinding())) { + policyProvider.stop(); + } + + } + } + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + stop(compositeContext, (Composite)implementation); + } else { + final ImplementationProvider implementationProvider = ((RuntimeComponent)component).getImplementationProvider(); + if (implementationProvider != null) { + // Allow bindings to read properties. Requires PropertyPermission read in security policy. + AccessController.doPrivileged(new PrivilegedAction<Object>() { + public Object run() { + implementationProvider.stop(); + return null; + } + }); + } + for (PolicyProvider policyProvider : ((RuntimeComponent)component).getPolicyProviders()) { + policyProvider.stop(); + } + } + + if (component instanceof ScopedRuntimeComponent) { + ScopedRuntimeComponent runtimeComponent = (ScopedRuntimeComponent)component; + if (runtimeComponent.getScopeContainer() != null && + runtimeComponent.getScopeContainer().getLifecycleState() != ScopeContainer.STOPPED) { + runtimeComponent.getScopeContainer().stop(); + } + } + + ((RuntimeComponent)component).setStarted(false); + } + + // Service start/stop + + // TODO - EPR done as part of the component start above + + // Reference start/stop + // Used by component context start + // TODO - EPR I don't know why reference wires don't get added until component start + + public void start(CompositeContext compositeContext, RuntimeComponent component, RuntimeComponentReference componentReference) { + synchronized (componentReference) { + + if (!(componentReference instanceof RuntimeComponentReference)) { + return; + } + + /* The way it was + // create a wire for each endpoint reference. An endpoint reference says that a + // target has been specified and hence the reference has been wired in some way. + // The service may not have been found yet, depending on the way the composite + // is deployed, but it is expected to be found. In the case where the reference + // is unwired (a target has not been specified) there will be no endpoint + // reference and this will lead to null being injected + for (EndpointReference2 endpointReference : componentReference.getEndpointReferences()){ + + // if there is a binding an endpoint has been found for the endpoint reference + if (endpointReference.getBinding() != null){ + + // add the binding provider. This is apparently a repeat + // of previous configuration as self references are created + // on the fly and miss the previous point where providers are added + RuntimeComponentReference runtimeRef = (RuntimeComponentReference)componentReference; + + if (runtimeRef.getBindingProvider(endpointReference.getBinding()) == null) { + addReferenceBindingProvider(component, componentReference, endpointReference.getBinding()); + } + + // start the binding provider + final ReferenceBindingProvider bindingProvider = runtimeRef.getBindingProvider(endpointReference.getBinding()); + + if (bindingProvider != null) { + // Allow bindings to add shutdown hooks. Requires RuntimePermission shutdownHooks in policy. + AccessController.doPrivileged(new PrivilegedAction<Object>() { + public Object run() { + bindingProvider.start(); + return null; + } + }); + } + + // add the wire + addReferenceWire(component, componentReference, endpointReference); + } + } + */ + + // create a wire for each endpoint reference. An endpoint reference says either that + // - a target has been specified and hence the reference has been wired in some way. + // - an unwired binding ha been specified + // and endpoint reference representing a wired reference may not at this point + // be resolved (the service to which it points may not be present in the + // current composite). Endpoint reference resolution takes place when the wire + // is first used (when the chains are created) + for (EndpointReference endpointReference : componentReference.getEndpointReferences()){ + addReferenceWire(compositeContext, component, componentReference, endpointReference); + component.getComponentContext().getCompositeContext().getEndpointRegistry().addEndpointReference(endpointReference); + } + + } + } + + 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); + RuntimeComponent runtimeComponent = (RuntimeComponent) component; + EndpointRegistry endpointRegistry = runtimeComponent.getComponentContext().getCompositeContext().getEndpointRegistry(); + for ( EndpointReference endpointReference : runtimeRef.getEndpointReferences()){ + endpointRegistry.removeEndpointReference(endpointReference); + ReferenceBindingProvider bindingProvider = runtimeRef.getBindingProvider(endpointReference.getBinding()); + if (bindingProvider != null) { + bindingProvider.stop(); + } + for (PolicyProvider policyProvider : ((RuntimeComponentReference)reference) + .getPolicyProviders(endpointReference.getBinding())) { + policyProvider.stop(); + } + } + } + + private void addReferenceWire(CompositeContext compositeContext, Component component, ComponentReference reference, EndpointReference endpointReference) { + RuntimeComponentReference runtimeRef = (RuntimeComponentReference)reference; + + // Use the interface contract of the reference on the component type and if there + // isn't one then use the one from the reference itself + Reference componentTypeRef = reference.getReference(); + + InterfaceContract sourceContract; + if (componentTypeRef == null || componentTypeRef.getInterfaceContract() == null) { + sourceContract = reference.getInterfaceContract(); + } else { + sourceContract = componentTypeRef.getInterfaceContract(); + } + + // 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 = endpointReference.getTargetEndpoint().getInterfaceContract(); + reference.setInterfaceContract(sourceContract); + } + + endpointReference.setInterfaceContract(sourceContract.makeUnidirectional(false)); + +/* TODO - EPR should have been done previously during matching + ComponentService callbackService = reference.getCallbackService(); + if (callbackService != null) { + // select a reference callback binding to pass with invocations on this wire + Binding callbackBinding = null; + for (Binding binding : callbackService.getBindings()) { + // first look for a callback binding whose name matches the reference binding name + if (refBinding.getName().startsWith(binding.getName())) { + callbackBinding = binding; + break; + } + } + // if no callback binding found, try again based on reference binding type + if (callbackBinding == null) { + callbackBinding = callbackService.getBinding(refBinding.getClass()); + } + InterfaceContract callbackContract = callbackService.getInterfaceContract(); + EndpointReference callbackEndpoint = + new EndpointReferenceImpl((RuntimeComponent)refComponent, callbackService, callbackBinding, + callbackContract); + wireSource.setCallbackEndpoint(callbackEndpoint); + } +*/ + +/* TODO - EPR can't do this until the binding matches the EPR + InterfaceContract bindingContract = getInterfaceContract(reference, endpointReference.getBinding()); + Endpoint2 endpoint = endpointReference.getTargetEndpoint(); + endpoint.setInterfaceContract(bindingContract); +*/ + +/* TODO - EPR review in the light of new matching code + // TUSCANY-2029 - We should use the URI of the serviceBinding because the target may be a Component in a + // nested composite. + if (serviceBinding != null) { + wireTarget.setURI(serviceBinding.getURI()); + } +*/ + + // create the wire + // null endpoint passed in here as the endpoint reference may + // not be resolved yet + RuntimeWire wire = new RuntimeWireImpl(compositeContext, + true, + endpointReference, + null, + interfaceContractMapper, + workScheduler, + wireProcessor, + messageFactory); + runtimeRef.getRuntimeWires().add(wire); + + } + + private InterfaceContract getInterfaceContract(ComponentReference reference, Binding binding) { + InterfaceContract interfaceContract = reference.getInterfaceContract(); + ReferenceBindingProvider provider = ((RuntimeComponentReference)reference).getBindingProvider(binding); + if (provider != null) { + InterfaceContract bindingContract = provider.getBindingInterfaceContract(); + if (bindingContract != null) { + interfaceContract = bindingContract; + } + } + return interfaceContract.makeUnidirectional(false); + } + + + /* TODO - EPR - Resolved via registry now + public Component resolve(String componentURI) { + for (Composite composite : domainComposite.getIncludes()) { + Component component = resolve(composite, componentURI); + if (component != null) { + return component; + } + } + return null; + } + + + public Component resolve(Composite composite, String componentURI) { + for (Component component : composite.getComponents()) { + String uri = component.getURI(); + if (uri.equals(componentURI)) { + return component; + } + if (componentURI.startsWith(uri)) { + Implementation implementation = component.getImplementation(); + if (!(implementation instanceof Composite)) { + return null; + } + return resolve((Composite)implementation, componentURI); + } + } + return null; + } + */ +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/EndpointRegistryImpl.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/EndpointRegistryImpl.java new file mode 100644 index 0000000000..2ad61963e0 --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/EndpointRegistryImpl.java @@ -0,0 +1,208 @@ +/* + * 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.Iterator; +import java.util.List; +import java.util.logging.Logger; + +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.LifeCycleListener; +import org.apache.tuscany.sca.runtime.EndpointListener; +import org.apache.tuscany.sca.runtime.EndpointRegistry; + +/** + * A EndpointRegistry implementation that sees registrations from the same JVM + */ +public class EndpointRegistryImpl implements EndpointRegistry, LifeCycleListener { + private final Logger logger = Logger.getLogger(EndpointRegistryImpl.class.getName()); + + private List<Endpoint> endpoints = new ArrayList<Endpoint>(); + private List<EndpointReference> endpointreferences = new ArrayList<EndpointReference>(); + private List<EndpointListener> listeners = new ArrayList<EndpointListener>(); + + public EndpointRegistryImpl(ExtensionPointRegistry extensionPoints, String endpointRegistryURI, String domainURI) { + } + + public synchronized void addEndpoint(Endpoint endpoint) { + endpoints.add(endpoint); + for (EndpointListener listener : listeners) { + listener.endpointAdded(endpoint); + } + logger.info("Add endpoint - " + endpoint.toString()); + } + + public synchronized void addEndpointReference(EndpointReference endpointReference) { + endpointreferences.add(endpointReference); + logger.fine("Add endpoint reference - " + endpointReference.toString()); + } + + /** + * Parse the component/service/binding URI into an array of parts (componentURI, serviceName, bindingName) + * @param uri + * @return + */ + private String[] parse(String uri) { + String[] names = new String[3]; + int index = uri.lastIndexOf('#'); + if (index == -1) { + names[0] = uri; + } else { + names[0] = uri.substring(0, index); + String str = uri.substring(index + 1); + if (str.startsWith("service-binding(") && str.endsWith(")")) { + str = str.substring("service-binding(".length(), str.length() - 1); + String[] parts = str.split("/"); + if (parts.length != 2) { + throw new IllegalArgumentException("Invalid service-binding URI: " + uri); + } + names[1] = parts[0]; + names[2] = parts[1]; + } else if (str.startsWith("service(") && str.endsWith(")")) { + str = str.substring("service(".length(), str.length() - 1); + names[1] = str; + } else { + throw new IllegalArgumentException("Invalid component/service/binding URI: " + uri); + } + } + return names; + } + + private boolean matches(String target, String uri) { + String[] parts1 = parse(target); + String[] parts2 = parse(uri); + for (int i = 0; i < parts1.length; i++) { + if (parts1[i] == null || parts1[i].equals(parts2[i])) { + continue; + } else { + return false; + } + } + return true; + } + + public synchronized List<Endpoint> findEndpoint(EndpointReference endpointReference) { + List<Endpoint> foundEndpoints = new ArrayList<Endpoint>(); + + logger.fine("Find endpoint for reference - " + endpointReference.toString()); + + if (endpointReference.getReference() != null) { + Endpoint targetEndpoint = endpointReference.getTargetEndpoint(); + for (Endpoint endpoint : endpoints) { + // TODO: implement more complete matching + if (matches(targetEndpoint.getURI(), endpoint.getURI())) { + foundEndpoints.add(endpoint); + logger.fine("Found endpoint with matching service - " + endpoint); + } + // else the service name doesn't match + } + } + + return foundEndpoints; + } + + public synchronized List<EndpointReference> findEndpointReference(Endpoint endpoint) { + return null; + } + + public synchronized void removeEndpoint(Endpoint endpoint) { + endpoints.remove(endpoint); + endpointRemoved(endpoint); + } + + private void endpointRemoved(Endpoint endpoint) { + for (EndpointListener listener : listeners) { + listener.endpointRemoved(endpoint); + } + logger.info("Remove endpoint - " + endpoint.toString()); + } + + public synchronized void removeEndpointReference(EndpointReference endpointReference) { + endpointreferences.remove(endpointReference); + logger.fine("Remove endpoint reference - " + endpointReference.toString()); + } + + public synchronized List<EndpointReference> getEndpointRefereneces() { + return endpointreferences; + } + + public synchronized List<Endpoint> getEndpoints() { + return endpoints; + } + + public synchronized void addListener(EndpointListener listener) { + listeners.add(listener); + } + + public synchronized List<EndpointListener> getListeners() { + return listeners; + } + + public synchronized void removeListener(EndpointListener listener) { + listeners.remove(listener); + } + + 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<Endpoint> i = endpoints.iterator(); i.hasNext();) { + Endpoint ep = i.next(); + i.remove(); + endpointRemoved(ep); + } + endpointreferences.clear(); + listeners.clear(); + } + +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/EndpointSerializerImpl.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/EndpointSerializerImpl.java new file mode 100644 index 0000000000..82f8ebabea --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/EndpointSerializerImpl.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.assembly.impl; + +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; + +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.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.runtime.EndpointSerializer; + +public class EndpointSerializerImpl implements EndpointSerializer { + private ExtensionPointRegistry registry; + private XMLInputFactory inputFactory; + private XMLOutputFactory outputFactory; + private StAXArtifactProcessor<Endpoint> processor; + private StAXArtifactProcessor<EndpointReference> 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 void read(Endpoint endpoint, String xml) throws IOException { + try { + XMLStreamReader reader = inputFactory.createXMLStreamReader(new StringReader(xml)); + Endpoint result = processor.read(reader, new ProcessorContext(registry)); + endpoint.setComponent(result.getComponent()); + endpoint.setService(result.getService()); + endpoint.setBinding(result.getBinding()); + endpoint.setInterfaceContract(result.getService().getInterfaceContract()); + } catch (Exception e) { + throw new IOException(e.getMessage()); + } + + } + + public String write(Endpoint endpoint) throws IOException { + StringWriter sw = new StringWriter(); + try { + XMLStreamWriter writer = outputFactory.createXMLStreamWriter(sw); + processor.write(endpoint, writer, new ProcessorContext(registry)); + writer.flush(); + writer.close(); + return sw.toString(); + } catch (Exception e) { + throw new IOException(e.getMessage()); + } + } + + public void read(EndpointReference endpointReference, String xml) throws IOException { + try { + XMLStreamReader reader = inputFactory.createXMLStreamReader(new StringReader(xml)); + EndpointReference result = refProcessor.read(reader, new ProcessorContext(registry)); + reader.close(); + endpointReference.setComponent(result.getComponent()); + endpointReference.setReference(result.getReference()); + endpointReference.setBinding(result.getBinding()); + endpointReference.setInterfaceContract(result.getReference().getInterfaceContract()); + } catch (Exception e) { + throw new IOException(e.getMessage()); + } + } + + public String write(EndpointReference endpointReference) throws IOException { + 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 IOException(e.getMessage()); + } + } +}
\ No newline at end of file diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/ReferenceParameterProcessor.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/ReferenceParameterProcessor.java new file mode 100644 index 0000000000..4d6a98ca5f --- /dev/null +++ b/branches/sca-java-2.0-M4/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<ReferenceParameters> { + 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<ReferenceParameters> 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/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/ReferenceParametersImpl.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/ReferenceParametersImpl.java new file mode 100644 index 0000000000..7bd56271a5 --- /dev/null +++ b/branches/sca-java-2.0-M4/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/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeComponentImpl.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeComponentImpl.java new file mode 100644 index 0000000000..6032005b9a --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeComponentImpl.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.assembly.impl; + +import java.util.ArrayList; +import java.util.List; + +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; + +/** + * @version $Rev$ $Date$ + */ +public class RuntimeComponentImpl extends ComponentImpl implements RuntimeComponent, + ScopedRuntimeComponent, ResolverExtension { + protected RuntimeComponentContext componentContext; + protected ImplementationProvider implementationProvider; + protected List<PolicyProvider> policyProviders = new ArrayList<PolicyProvider>(); + 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<PolicyProvider> getPolicyProviders() { + return policyProviders; + } + + public ModelResolver getModelResolver() { + return modelResolver; + } + + public void setModelResolver(ModelResolver modelResolver) { + this.modelResolver = modelResolver; + } + + @Override + public String toString() { + return getName(); + } +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeComponentReferenceImpl.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeComponentReferenceImpl.java new file mode 100644 index 0000000000..3fdc35a720 --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeComponentReferenceImpl.java @@ -0,0 +1,150 @@ +/* + * 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.Collections; +import java.util.HashMap; +import java.util.List; + +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.assembly.impl.ComponentReferenceImpl; +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.provider.PolicyProvider; +import org.apache.tuscany.sca.provider.ReferenceBindingProvider; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeComponentReference; +import org.apache.tuscany.sca.runtime.RuntimeWire; + +/** + * Implementation of a Component Reference. + * + * @version $Rev$ $Date$ + */ +public class RuntimeComponentReferenceImpl extends ComponentReferenceImpl implements RuntimeComponentReference { + private ArrayList<RuntimeWire> wires; + private HashMap<Binding, ReferenceBindingProvider> bindingProviders = + new HashMap<Binding, ReferenceBindingProvider>(); + private HashMap<Binding, List<PolicyProvider>> policyProviders = new HashMap<Binding, List<PolicyProvider>>(); + + private RuntimeComponent component; + + public RuntimeComponentReferenceImpl() { + super(); + } + + public synchronized List<RuntimeWire> getRuntimeWires() { + if (wires == null) { + wires = new ArrayList<RuntimeWire>(); + component.getComponentContext().start(this); + } + return wires; + } + + // TODO - EPR - shouldn't rely on this anymore + public RuntimeWire getRuntimeWire(Binding binding) { + for (RuntimeWire wire : getRuntimeWires()) { + if (wire.getEndpointReference().getBinding() == binding) { + return wire; + } + } + + return null; + } + + public RuntimeWire getRuntimeWire(EndpointReference endpointReference) { + for (RuntimeWire wire : getRuntimeWires()) { + if (wire.getEndpointReference() == endpointReference) { + return wire; + } + } + + return null; + } + + public ReferenceBindingProvider getBindingProvider(Binding binding) { + return bindingProviders.get(binding); + } + + public void setBindingProvider(Binding binding, ReferenceBindingProvider bindingProvider) { + bindingProviders.put(binding, bindingProvider); + } + + public Invoker getInvoker(Binding binding, Operation operation) { + RuntimeWire wire = getRuntimeWire(binding); + if (wire == null) { + return null; + } + InvocationChain chain = wire.getInvocationChain(operation); + return chain == null ? null : chain.getHeadInvoker(); + } + + /** + * @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(); + ref.wires = null; + ref.bindingProviders = new HashMap<Binding, ReferenceBindingProvider>(); + ref.policyProviders = new HashMap<Binding, List<PolicyProvider>>(); + return ref; + } + + public void addPolicyProvider(Binding binding, PolicyProvider policyProvider) { + List<PolicyProvider> providers = policyProviders.get(binding); + if (providers == null) { + providers = new ArrayList<PolicyProvider>(); + policyProviders.put(binding, providers); + } + providers.add(policyProvider); + } + + public List<PolicyProvider> getPolicyProviders(Binding binding) { + List<PolicyProvider> providers = policyProviders.get(binding); + if (providers == null) { + return Collections.emptyList(); + } else { + return providers; + } + } + + @Override + public String toString() { + return getName(); + } +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeComponentServiceImpl.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeComponentServiceImpl.java new file mode 100644 index 0000000000..ffa488b7bd --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeComponentServiceImpl.java @@ -0,0 +1,169 @@ +/* + * 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.Collections; +import java.util.HashMap; +import java.util.List; + +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.impl.ComponentServiceImpl; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +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.provider.PolicyProvider; +import org.apache.tuscany.sca.provider.ServiceBindingProvider; +import org.apache.tuscany.sca.runtime.RuntimeComponentService; +import org.apache.tuscany.sca.runtime.RuntimeWire; +import org.oasisopen.sca.ServiceRuntimeException; + +/** + * Implementation of a Component Service. + * + * @version $Rev$ $Date$ + */ +public class RuntimeComponentServiceImpl extends ComponentServiceImpl implements RuntimeComponentService { + private ArrayList<RuntimeWire> wires = new ArrayList<RuntimeWire>(); + private ArrayList<RuntimeWire> callbackWires = new ArrayList<RuntimeWire>(); + private HashMap<Binding, ServiceBindingProvider> bindingProviders = new HashMap<Binding, ServiceBindingProvider>(); + private HashMap<Binding, List<PolicyProvider>> policyProviders = new HashMap<Binding, List<PolicyProvider>>(); + + public RuntimeComponentServiceImpl() { + super(); + } + + public List<RuntimeWire> getRuntimeWires() { + return wires; + } + + public RuntimeWire getRuntimeWire(Binding binding) { + for (RuntimeWire wire : wires) { + if (wire.getEndpoint().getBinding() == binding) { + return wire; + } + } + return null; + } + + public RuntimeWire getRuntimeWire(Binding binding, InterfaceContract interfaceContract) { + RuntimeWire wire = getRuntimeWire(binding); + if (wire == null) { + return null; + } + if (interfaceContract != null && interfaceContract != wire.getEndpointReference().getInterfaceContract()) { + try { + // FIXME: [rfeng] We could avoid clone() using a better comparison of the two interface contracts + wire = (RuntimeWire)wire.clone(); + wire.getEndpointReference().setInterfaceContract(interfaceContract); + wire.rebuild(); + } catch (CloneNotSupportedException e) { + throw new ServiceRuntimeException(e); + } + } + + return wire; + } + + public List<RuntimeWire> getCallbackWires() { + return callbackWires; + } + + public ServiceBindingProvider getBindingProvider(Binding binding) { + return bindingProviders.get(binding); + } + + public void setBindingProvider(Binding binding, ServiceBindingProvider bindingProvider) { + bindingProviders.put(binding, bindingProvider); + } + + public Invoker getInvoker(Binding binding, Operation operation) { + return getInvoker(binding, null, operation); + } + + public Invoker getInvoker(Binding binding, InterfaceContract interfaceContract, Operation operation) { + InvocationChain chain = getInvocationChain(binding, interfaceContract, operation); + if (chain != null) { + return chain.getHeadInvoker(); + } else { + return null; + } + } + + public InvocationChain getInvocationChain(Binding binding, InterfaceContract interfaceContract, Operation operation) { + RuntimeWire wire = getRuntimeWire(binding); + if (wire == null) { + return null; + } + if (interfaceContract != null && interfaceContract != wire.getEndpointReference().getInterfaceContract()) { + try { + // FIXME: [rfeng] We could avoid clone() using a better comparison of the two interface contracts + wire = (RuntimeWire)wire.clone(); + wire.getEndpointReference().setInterfaceContract(interfaceContract); + wire.rebuild(); + } catch (CloneNotSupportedException e) { + throw new ServiceRuntimeException(e); + } + } + return wire.getInvocationChain(operation); + } + + public InvocationChain getInvocationChain(Binding binding, Operation operation) { + return getInvocationChain(binding, null, operation); + } + + /** + * @see org.apache.tuscany.sca.assembly.impl.ComponentServiceImpl#clone() + */ + @SuppressWarnings("unchecked") + @Override + public Object clone() throws CloneNotSupportedException { + RuntimeComponentServiceImpl clone = (RuntimeComponentServiceImpl)super.clone(); + clone.bindingProviders = (HashMap<Binding, ServiceBindingProvider>)bindingProviders.clone(); + clone.wires = (ArrayList<RuntimeWire>)wires.clone(); + clone.callbackWires = (ArrayList<RuntimeWire>)callbackWires.clone(); + clone.policyProviders = (HashMap<Binding, List<PolicyProvider>>)policyProviders.clone(); + return clone; + } + + public void addPolicyProvider(Binding binding, PolicyProvider policyProvider) { + List<PolicyProvider> providers = policyProviders.get(binding); + if (providers == null) { + providers = new ArrayList<PolicyProvider>(); + policyProviders.put(binding, providers); + } + providers.add(policyProvider); + } + + public List<PolicyProvider> getPolicyProviders(Binding binding) { + List<PolicyProvider> providers = policyProviders.get(binding); + if (providers == null) { + return Collections.emptyList(); + } else { + return providers; + } + } + + @Override + public String toString() { + return getName(); + } +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeEndpointImpl.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeEndpointImpl.java new file mode 100644 index 0000000000..357d19091b --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeEndpointImpl.java @@ -0,0 +1,101 @@ +/* + * 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 org.apache.tuscany.sca.assembly.impl.EndpointImpl; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.UtilityExtensionPoint; +import org.apache.tuscany.sca.runtime.EndpointSerializer; + +/** + * Runtime model for Endpoint that supports java serialization + */ +public class RuntimeEndpointImpl extends EndpointImpl implements Externalizable { + private EndpointSerializer serializer; + private String bindingURI; + private String xml; + + /** + * No-arg constructor for Java serilization + */ + public RuntimeEndpointImpl() { + super(null); + } + + public RuntimeEndpointImpl(ExtensionPointRegistry registry) { + super(registry); + } + + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + this.uri = in.readUTF(); + this.xml = in.readUTF(); + // Defer the loading to resolve(); + } + + public void writeExternal(ObjectOutput out) throws IOException { + out.writeUTF(getURI()); + out.writeUTF(getSerializer().write(this)); + } + + private synchronized EndpointSerializer getSerializer() { + if (serializer == null) { + if (registry != null) { + serializer = + registry.getExtensionPoint(UtilityExtensionPoint.class).getUtility(EndpointSerializer.class); + } else { + throw new IllegalStateException("No extension registry is set"); + } + } + return serializer; + } + + @Override + protected void reset() { + super.reset(); + this.xml = null; + } + + @Override + public void resolve() { + if (component == null && xml != null) { + try { + getSerializer().read(this, xml); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + super.resolve(); + } + + @Override + public void setExtensionPointRegistry(ExtensionPointRegistry registry) { + if (this.registry != registry) { + super.setExtensionPointRegistry(registry); + serializer = null; + } + // resolve(); + } + +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeEndpointReferenceImpl.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeEndpointReferenceImpl.java new file mode 100644 index 0000000000..2b1c85b95a --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeEndpointReferenceImpl.java @@ -0,0 +1,100 @@ +/* + * 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 org.apache.tuscany.sca.assembly.impl.EndpointReferenceImpl; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.UtilityExtensionPoint; +import org.apache.tuscany.sca.runtime.EndpointSerializer; + +/** + * Runtime model for Endpoint that supports java serialization + */ +public class RuntimeEndpointReferenceImpl extends EndpointReferenceImpl implements Externalizable { + private EndpointSerializer serializer; + private String xml; + + /** + * No-arg constructor for Java serilization + */ + public RuntimeEndpointReferenceImpl() { + super(null); + } + + public RuntimeEndpointReferenceImpl(ExtensionPointRegistry registry) { + super(registry); + } + + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + this.uri = in.readUTF(); + this.xml = in.readUTF(); + // Defer the loading to resolve(); + } + + public void writeExternal(ObjectOutput out) throws IOException { + out.writeUTF(getURI()); + out.writeUTF(getSerializer().write(this)); + } + + private synchronized EndpointSerializer getSerializer() { + if (serializer == null) { + if (registry != null) { + serializer = + registry.getExtensionPoint(UtilityExtensionPoint.class).getUtility(EndpointSerializer.class); + } else { + throw new IllegalStateException("No extension registry is set"); + } + } + return serializer; + } + + @Override + protected void reset() { + super.reset(); + this.xml = null; + } + + @Override + protected void resolve() { + if (component == null && xml != null) { + try { + getSerializer().read(this, xml); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + super.resolve(); + } + + @Override + public void setExtensionPointRegistry(ExtensionPointRegistry registry) { + if (this.registry != registry) { + super.setExtensionPointRegistry(registry); + serializer = null; + } + // resolve(); + } + +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeWireImpl.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeWireImpl.java new file mode 100644 index 0000000000..62b71c47d1 --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/impl/RuntimeWireImpl.java @@ -0,0 +1,783 @@ +/* + * 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.lang.reflect.InvocationTargetException; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.List; + +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.Service; +import org.apache.tuscany.sca.context.CompositeContext; +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.invocation.ExtensibleWireProcessor; +import org.apache.tuscany.sca.core.invocation.NonBlockingInterceptor; +import org.apache.tuscany.sca.core.invocation.RuntimeWireInvoker; +import org.apache.tuscany.sca.core.invocation.impl.InvocationChainImpl; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.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.MessageFactory; +import org.apache.tuscany.sca.invocation.Phase; +import org.apache.tuscany.sca.provider.BindingProviderFactory; +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.PolicyProviderRRB; +import org.apache.tuscany.sca.provider.ProviderFactoryExtensionPoint; +import org.apache.tuscany.sca.provider.ReferenceBindingProvider; +import org.apache.tuscany.sca.provider.ReferenceBindingProviderRRB; +import org.apache.tuscany.sca.provider.ServiceBindingProvider; +import org.apache.tuscany.sca.provider.ServiceBindingProviderRRB; +import org.apache.tuscany.sca.runtime.EndpointReferenceBinder; +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.RuntimeWire; +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.SCARuntimeException; +import org.oasisopen.sca.ServiceRuntimeException; + +/** + * @version $Rev$ $Date$ + */ +public class RuntimeWireImpl implements RuntimeWire { + + private CompositeContext compositeContext; + private ExtensionPointRegistry extensionPoints; + + private Boolean isReferenceWire = false; + private EndpointReference endpointReference; + private Endpoint endpoint; + + private transient RuntimeWireProcessor wireProcessor; + private transient InterfaceContractMapper interfaceContractMapper; + private transient WorkScheduler workScheduler; + private transient MessageFactory messageFactory; + private transient RuntimeWireInvoker invoker; + + // the following is a very simple cache that avoids re-cloning a wire + // when consecutive callbacks to the same endpoint are made + private Endpoint lastCallback; + private RuntimeWire cachedWire; + private boolean wireReserved; + private RuntimeWireImpl clonedFrom; + + private List<InvocationChain> chains; + private InvocationChain bindingInvocationChain; + + private EndpointReferenceBinder eprBinder; + private final ProviderFactoryExtensionPoint providerFactories; + + /** + * @param source + * @param target + * @param interfaceContractMapper + * @param workScheduler + * @param wireProcessor + * @param messageFactory + * @param conversationManager + */ + public RuntimeWireImpl(CompositeContext compositeContext, + boolean isReferenceWire, + EndpointReference endpointReference, + Endpoint endpoint, + InterfaceContractMapper interfaceContractMapper, + WorkScheduler workScheduler, + RuntimeWireProcessor wireProcessor, + MessageFactory messageFactory) { + super(); + this.compositeContext = compositeContext; + this.extensionPoints = compositeContext.getExtensionPointRegistry(); + this.isReferenceWire = isReferenceWire; + this.endpointReference = endpointReference; + this.endpoint = endpoint; + this.interfaceContractMapper = interfaceContractMapper; + this.workScheduler = workScheduler; + this.wireProcessor = wireProcessor; + this.messageFactory = messageFactory; + this.invoker = new RuntimeWireInvoker(this.messageFactory, this); + + UtilityExtensionPoint utilities = extensionPoints.getExtensionPoint(UtilityExtensionPoint.class); + this.eprBinder = utilities.getUtility(EndpointReferenceBinder.class); + this.providerFactories = extensionPoints.getExtensionPoint(ProviderFactoryExtensionPoint.class); + } + + public RuntimeWireImpl(CompositeContext compositeContext, + boolean isReferenceWire, + EndpointReference endpointReference, + Endpoint endpoint) { + super(); + this.compositeContext = compositeContext; + this.extensionPoints = compositeContext.getExtensionPointRegistry(); + this.isReferenceWire = isReferenceWire; + this.endpointReference = endpointReference; + this.endpoint = endpoint; + + UtilityExtensionPoint utilities = extensionPoints.getExtensionPoint(UtilityExtensionPoint.class); + this.interfaceContractMapper = utilities.getUtility(InterfaceContractMapper.class); + this.workScheduler = utilities.getUtility(WorkScheduler.class); + this.wireProcessor = new ExtensibleWireProcessor(extensionPoints.getExtensionPoint(RuntimeWireProcessorExtensionPoint.class)); + FactoryExtensionPoint factories = extensionPoints.getExtensionPoint(FactoryExtensionPoint.class); + this.messageFactory = factories.getFactory(MessageFactory.class); + this.invoker = new RuntimeWireInvoker(this.messageFactory, this); + + this.eprBinder = utilities.getUtility(EndpointReferenceBinder.class); + this.providerFactories = extensionPoints.getExtensionPoint(ProviderFactoryExtensionPoint.class); + } + + public synchronized List<InvocationChain> getInvocationChains() { + if (chains == null) { + initInvocationChains(); + } + return chains; + } + + public synchronized InvocationChain getBindingInvocationChain() { + if (bindingInvocationChain == null) { + bindingInvocationChain = new InvocationChainImpl(null, null, isReferenceWire); + if (isReferenceWire) { + initReferenceBindingInvocationChains(); + } else { + initServiceBindingInvocationChains(); + } + } + return bindingInvocationChain; + } + + public InvocationChain getInvocationChain(Operation operation) { + for (InvocationChain chain : getInvocationChains()) { + Operation op = null; + if (isReferenceWire) { + op = chain.getSourceOperation(); + } else { + op = chain.getTargetOperation(); + } + if (interfaceContractMapper.isCompatible(operation, op, op.getInterface().isRemotable())) { + return chain; + } + } + return null; + } + + public Object invoke(Message msg) throws InvocationTargetException { + return getBindingInvocationChain().getHeadInvoker().invoke(msg); + } + + public Object invoke(Operation operation, Object[] args) throws InvocationTargetException { + Message msg = messageFactory.createMessage(); + msg.setBody(args); + return invoker.invoke(operation, msg); + } + + public Object invoke(Operation operation, Message msg) throws InvocationTargetException { + return invoker.invoke(operation, msg); + } + + /** + * 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; + } + + private InterfaceContract getLeafInterfaceContract(EndpointReference epr) { + ComponentReference reference = epr.getReference(); + if (reference == null) { + return epr.getInterfaceContract(); + } + InterfaceContract interfaceContract = getLeafContract(reference).getInterfaceContract(); + if (interfaceContract == null) { + interfaceContract = epr.getInterfaceContract(); + } + return interfaceContract; + } + + private InterfaceContract getLeafInterfaceContract(Endpoint ep) { + ComponentService service = ep.getService(); + if (service == null) { + return ep.getInterfaceContract(); + } + InterfaceContract interfaceContract = getLeafContract(service).getInterfaceContract(); + if (interfaceContract == null) { + interfaceContract = ep.getInterfaceContract(); + } + return interfaceContract; + } + + /** + * Initialize the invocation chains + */ + private void initInvocationChains() { + chains = new ArrayList<InvocationChain>(); + InterfaceContract sourceContract = endpointReference.getInterfaceContract(); + // 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); + + if (isReferenceWire) { + // It's the reference wire + resolveEndpointReference(); + + InterfaceContract targetContract = endpoint.getInterfaceContract(); + // 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); + + RuntimeComponentReference reference = (RuntimeComponentReference)endpointReference.getReference(); + Binding refBinding = endpointReference.getBinding(); + 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 " + + endpointReference.getComponent().getURI() + + "#" + + reference.getName()); + } + InvocationChain chain = new InvocationChainImpl(operation, targetOperation, true); + if (operation.isNonBlocking()) { + addNonBlockingInterceptor(reference, refBinding, chain); + } + chains.add(chain); + addReferenceBindingInterceptor(reference, refBinding, chain, operation); + } + + } else { + // It's the service wire + RuntimeComponentService service = (RuntimeComponentService)endpoint.getService(); + RuntimeComponent serviceComponent = (RuntimeComponent)endpoint.getComponent(); + Binding serviceBinding = endpoint.getBinding(); + //InterfaceContract targetContract = endpoint.getInterfaceContract(); + // 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); + endpoint.setInterfaceContract(targetContract); + 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); + if (operation.isNonBlocking()) { + addNonBlockingInterceptor(service, serviceBinding, chain); + } + addServiceBindingInterceptor(service, serviceBinding, chain, operation); + addImplementationInterceptor(serviceComponent, service, chain, targetOperation); + chains.add(chain); + } + + } + wireProcessor.process(this); + } + + + /** + * 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(){ + boolean ok = eprBinder.bind(compositeContext.getEndpointRegistry(), endpointReference); + + if (!ok) { + throw new SCARuntimeException("Unable to bind " + endpointReference); + } + + // set the endpoint based on the resolved endpoint + endpoint = endpointReference.getTargetEndpoint(); + + RuntimeComponentReference runtimeRef = (RuntimeComponentReference)endpointReference.getReference(); + + if (runtimeRef.getBindingProvider(endpointReference.getBinding()) == null) { + addReferenceBindingProvider(endpointReference, + (RuntimeComponent)endpointReference.getComponent(), + runtimeRef, + endpointReference.getBinding()); + } + + // start the binding provider + final ReferenceBindingProvider bindingProvider = runtimeRef.getBindingProvider(endpointReference.getBinding()); + + if (bindingProvider != null) { + // Allow bindings to add shutdown hooks. Requires RuntimePermission shutdownHooks in policy. + AccessController.doPrivileged(new PrivilegedAction<Object>() { + public Object run() { + bindingProvider.start(); + return null; + } + }); + } + for (PolicyProvider policyProvider : runtimeRef.getPolicyProviders(endpointReference.getBinding())) { + policyProvider.start(); + } + + InterfaceContract bindingContract = getInterfaceContract(endpointReference.getReference(), endpointReference.getBinding()); + Endpoint endpoint = endpointReference.getTargetEndpoint(); + endpoint.setInterfaceContract(bindingContract); + } + + private ReferenceBindingProvider addReferenceBindingProvider( + EndpointReference endpointReference, + RuntimeComponent component, RuntimeComponentReference reference, + Binding binding) { + BindingProviderFactory providerFactory = (BindingProviderFactory) providerFactories + .getProviderFactory(binding.getClass()); + if (providerFactory != null) { + @SuppressWarnings("unchecked") + ReferenceBindingProvider bindingProvider = providerFactory + .createReferenceBindingProvider(endpointReference); + if (bindingProvider != null) { + ((RuntimeComponentReference) reference).setBindingProvider( + binding, bindingProvider); + } + for (PolicyProviderFactory f : providerFactories + .getPolicyProviderFactories()) { + PolicyProvider policyProvider = f + .createReferencePolicyProvider(endpointReference); + if (policyProvider != null) { + reference.addPolicyProvider(binding, policyProvider); + } + } + + return bindingProvider; + } else { + throw new IllegalStateException( + "Provider factory not found for binding: " + + binding.getType()); + } + } + + private InterfaceContract getInterfaceContract(ComponentReference reference, Binding binding) { + InterfaceContract interfaceContract = reference.getInterfaceContract(); + if (interfaceContract == null) { + interfaceContract = endpoint.getInterfaceContract(); + } + ReferenceBindingProvider provider = ((RuntimeComponentReference)reference).getBindingProvider(binding); + if (provider != null) { + InterfaceContract bindingContract = provider.getBindingInterfaceContract(); + if (bindingContract != null) { + interfaceContract = bindingContract; + } + } + return interfaceContract.makeUnidirectional(false); + } + + private void initReferenceBindingInvocationChains() { + RuntimeComponentReference reference = (RuntimeComponentReference)endpointReference.getReference(); + Binding referenceBinding = endpointReference.getBinding(); + + // add the binding interceptors to the reference binding wire + ReferenceBindingProvider provider = reference.getBindingProvider(referenceBinding); + if ((provider != null) && (provider instanceof ReferenceBindingProviderRRB)) { + ((ReferenceBindingProviderRRB)provider).configureBindingChain(this); + } + + // add the policy interceptors to the service binding wire + // find out which policies are active + List<PolicyProvider> pps = ((RuntimeComponentReference)reference).getPolicyProviders(referenceBinding); + if (pps != null) { + for (PolicyProvider p : pps) { + if (p instanceof PolicyProviderRRB) { + Interceptor interceptor = ((PolicyProviderRRB)p).createBindingInterceptor(); + if (interceptor != null) { + bindingInvocationChain.addInterceptor(interceptor); + } + } + } + } + } + + private void initServiceBindingInvocationChains() { + RuntimeComponentService service = (RuntimeComponentService)endpoint.getService(); + Binding serviceBinding = endpoint.getBinding(); + + // add the binding interceptors to the service binding wire + ServiceBindingProvider provider = service.getBindingProvider(serviceBinding); + if ((provider != null) && (provider instanceof ServiceBindingProviderRRB)) { + ((ServiceBindingProviderRRB)provider).configureBindingChain(this); + } + + // add the policy interceptors to the service binding wire + List<PolicyProvider> pps = ((RuntimeComponentService)service).getPolicyProviders(serviceBinding); + if (pps != null) { + for (PolicyProvider p : pps) { + if (p instanceof PolicyProviderRRB) { + Interceptor interceptor = ((PolicyProviderRRB)p).createBindingInterceptor(); + if (interceptor != null) { + bindingInvocationChain.addInterceptor(interceptor); + } + } + } + } + + // TODO - add something on the end of the wire to invoke the + // invocation chain. Need to split out the runtime + // wire invoker into conversation, callback interceptors etc + bindingInvocationChain.addInvoker(invoker); + + } + + // =============================================================== + // TODO - EPR remove when we convert fully over to EndpointReference2 + + // TODO - remove. Just here during development +/* + static EndpointReference epr; + + public EndpointReference getSource() { + // TODO - EPR convert this into method that returns EndpointReference2 + + // convert the source info into old endpoint reference format + epr = + new EndpointReferenceImpl((RuntimeComponent)endpointReference.getComponent(), endpointReference + .getReference(), endpointReference.getBinding(), endpointReference.getInterfaceContract()); + + if (endpointReference.getCallbackEndpoint() != null) { + // convert the source callback endpoint into old endpoint reference format + EndpointReference cepr; + cepr = + new EndpointReferenceImpl((RuntimeComponent)endpointReference.getComponent(), endpointReference + .getCallbackEndpoint().getService(), endpointReference.getCallbackEndpoint().getBinding(), + endpointReference.getCallbackEndpoint().getInterfaceContract()); + epr.setCallbackEndpoint(cepr); + } + + // TODO - somtimes used to reset the interface contract so we + // copy it back in in the rebuild method below + return epr; + } + + public EndpointReference getTarget() { + // TODO - EPR convert this into method that returns Endpoint2 + + Endpoint2 endpoint = this.endpoint != null ? this.endpoint : endpointReference.getTargetEndpoint(); + + // convert the target info into old endpoint reference format + EndpointReference epr = + new EndpointReferenceImpl((RuntimeComponent)endpoint.getComponent(), endpoint.getService(), endpoint + .getBinding(), endpoint.getInterfaceContract()); + return epr; + } + + public void setTarget(EndpointReference target) { + // TODO - can we use the idea of setTarget to rebuild the wire? + + } +*/ + + // =================================================================== + + 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; + + this.endpointReference.setStatus(EndpointReference.NOT_CONFIGURED); + + // TODO - cheating here as I fixed the RuntimeComponentService code + // to call this when it resets the interface contract + //endpointReference.setInterfaceContract(epr.getInterfaceContract()); + } + + public EndpointReference getEndpointReference() { + return endpointReference; + } + + public Endpoint getEndpoint() { + return endpoint; + } + + /** + * Add the interceptor for a reference binding + * + * @param reference + * @param binding + * @param chain + * @param operation + */ + private void addReferenceBindingInterceptor(ComponentReference reference, + Binding binding, + InvocationChain chain, + Operation operation) { + ReferenceBindingProvider provider = ((RuntimeComponentReference)reference).getBindingProvider(binding); + if (provider != null) { + Invoker invoker = provider.createInvoker(operation); + if (invoker != null) { + chain.addInvoker(invoker); + } + } + List<PolicyProvider> pps = ((RuntimeComponentReference)reference).getPolicyProviders(binding); + if (pps != null) { + for (PolicyProvider p : pps) { + Interceptor interceptor = p.createInterceptor(operation); + if (interceptor != null) { + chain.addInterceptor(p.createInterceptor(operation)); + } + } + } + } + + /** + * Add the interceptor for a binding + * + * @param reference + * @param binding + * @param chain + * @param operation + */ + private void addServiceBindingInterceptor(ComponentService service, + Binding binding, + InvocationChain chain, + Operation operation) { + List<PolicyProvider> pps = ((RuntimeComponentService)service).getPolicyProviders(binding); + if (pps != null) { + for (PolicyProvider p : pps) { + Interceptor interceptor = p.createInterceptor(operation); + if (interceptor != null) { + chain.addInterceptor(p.createInterceptor(operation)); + } + } + } + } + + /** + * Add a non-blocking interceptor if the reference binding needs it + * + * @param reference + * @param binding + * @param chain + */ + private void addNonBlockingInterceptor(ComponentReference reference, Binding binding, InvocationChain chain) { + ReferenceBindingProvider provider = ((RuntimeComponentReference)reference).getBindingProvider(binding); + if (provider != null) { + boolean supportsOneWayInvocation = provider.supportsOneWayInvocation(); + if (!supportsOneWayInvocation) { + chain.addInterceptor(Phase.REFERENCE, new NonBlockingInterceptor(workScheduler)); + } + } + } + + /** + * Add a non-blocking interceptor if the service binding needs it + * + * @param service + * @param binding + * @param chain + */ + private void addNonBlockingInterceptor(ComponentService service, Binding binding, InvocationChain chain) { + ServiceBindingProvider provider = ((RuntimeComponentService)service).getBindingProvider(binding); + 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; + invoker = provider.createInvoker((RuntimeComponentService)service, operation); + chain.addInvoker(invoker); + } + // TODO - EPR - don't we need to get the policy from the right level in the + // model rather than the leafmost level + List<PolicyProvider> pps = ((RuntimeComponent)component).getPolicyProviders(); + if (pps != null) { + for (PolicyProvider p : pps) { + Interceptor interceptor = p.createInterceptor(operation); + if (interceptor != null) { + chain.addInterceptor(p.createInterceptor(operation)); + } + } + } + } + + /** + * @see java.lang.Object#clone() + */ + @Override + public Object clone() throws CloneNotSupportedException { + RuntimeWireImpl copy = (RuntimeWireImpl)super.clone(); + copy.endpointReference = (EndpointReference)endpointReference.clone(); + copy.endpoint = copy.endpointReference.getTargetEndpoint(); + copy.invoker = new RuntimeWireInvoker(copy.messageFactory, copy); + copy.cachedWire = null; // TUSCANY-2630 + return copy; + } + + public synchronized RuntimeWire lookupCache(Endpoint callback) { + if (lastCallback != null && + callback.getURI().equals(lastCallback.getURI()) && + !wireReserved) { + wireReserved = true; + return cachedWire; + } else { + return null; + } + } + + public synchronized void addToCache(Endpoint callback, RuntimeWire clonedWire) { + ((RuntimeWireImpl)clonedWire).setClonedFrom(this); + lastCallback = callback; + cachedWire = clonedWire; + wireReserved = true; + } + + public synchronized void releaseClonedWire(RuntimeWire wire) { + if (cachedWire == wire) { + wireReserved = false; + } + } + + public synchronized void releaseWire() { + clonedFrom.releaseClonedWire(this); + } + + private void setClonedFrom(RuntimeWireImpl wire) { + clonedFrom = wire; + } + + public ExtensionPointRegistry getExtensionPoints() { + return extensionPoints; + } + + /** + * 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; + } + } + + /** + * Follow a service promotion chain down to the innermost (non-composite) component. + * + * @param compositeService + * @return + */ + private 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 boolean isOutOfDate() { + return eprBinder.isOutOfDate(compositeContext.getEndpointRegistry(), getEndpointReference()); + } +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/context/DefaultComponentContextFactory.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/context/DefaultComponentContextFactory.java new file mode 100644 index 0000000000..2de52bebb2 --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/context/DefaultComponentContextFactory.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.context; + +import org.apache.tuscany.sca.context.ComponentContextFactory; +import org.apache.tuscany.sca.context.CompositeContext; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.context.impl.ComponentContextImpl; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.oasisopen.sca.ComponentContext; + +/** + * @version $Rev$ $Date$ + */ +public class DefaultComponentContextFactory implements ComponentContextFactory { + private final ExtensionPointRegistry registry; + + public DefaultComponentContextFactory(ExtensionPointRegistry registry) { + this.registry = registry; + } + + public ComponentContext createComponentContext(CompositeContext compositeContext, RuntimeComponent component) { + return new ComponentContextImpl(registry, compositeContext, component); + } + +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/context/DefaultRequestContextFactory.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/context/DefaultRequestContextFactory.java new file mode 100644 index 0000000000..ace4dc48e1 --- /dev/null +++ b/branches/sca-java-2.0-M4/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/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/context/ServiceReferenceExt.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/context/ServiceReferenceExt.java new file mode 100644 index 0000000000..9b60415132 --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/context/ServiceReferenceExt.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.context; + +import java.io.Externalizable; + +import javax.xml.stream.XMLStreamReader; + +import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.runtime.RuntimeWire; +import org.oasisopen.sca.ServiceReference; + +/** + * Extended ServiceReference + */ +public interface ServiceReferenceExt<B> extends ServiceReference<B>, Externalizable { + /** + * Return the wire that sits behind this service reference + * @return wire + */ + RuntimeWire getRuntimeWire(); + + /** + * Return the EndpointReference that sits behind this service reference + * @return endpoint reference + */ + EndpointReference getEndpointReference(); + + // TODO - EPR - the the following still required? + /** + * TBD + * + * @param callbackID + */ + void attachCallbackID(Object callbackID); + + /** + * TBD + * + * @return + */ + XMLStreamReader getXMLReader(); +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/CallbackServiceReferenceImpl.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/CallbackServiceReferenceImpl.java new file mode 100644 index 0000000000..5218a7fd01 --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/CallbackServiceReferenceImpl.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.context.impl; + + +import java.util.List; + +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.context.ThreadMessageContext; +import org.apache.tuscany.sca.core.assembly.impl.RuntimeWireImpl; +import org.apache.tuscany.sca.core.invocation.ProxyFactory; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.runtime.RuntimeComponentReference; +import org.apache.tuscany.sca.runtime.RuntimeWire; + +public class CallbackServiceReferenceImpl<B> extends ServiceReferenceImpl<B> { + private RuntimeWire wire; + private List<RuntimeWire> wires; + private Endpoint resolvedEndpoint; + + /* + * Public constructor for Externalizable serialization/deserialization + */ + public CallbackServiceReferenceImpl() { + super(); + } + + public CallbackServiceReferenceImpl(Class<B> interfaze, List<RuntimeWire> wires, ProxyFactory proxyFactory) { + super(interfaze, null, proxyFactory); + this.wires = wires; + init(); + } + + public void init() { + Message msgContext = ThreadMessageContext.getMessageContext(); + wire = selectCallbackWire(msgContext); + if (wire == null) { + //FIXME: need better exception + throw new RuntimeException("No callback binding found for " + msgContext.getTo().toString()); + } + resolvedEndpoint = msgContext.getFrom().getCallbackEndpoint(); + } + + @Override + protected Object createProxy() throws Exception { + return proxyFactory.createCallbackProxy(this); + } + + public RuntimeWire getCallbackWire() { + if (resolvedEndpoint == null) { + return null; + } else { + return cloneAndBind(wire); + } + } + + public Endpoint getResolvedEndpoint() { + return resolvedEndpoint; + } + + private RuntimeWire selectCallbackWire(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 RuntimeException("Destination for forward call is not available"); + } + for (RuntimeWire wire : wires) { + if (wire.getEndpointReference().getBinding().getName().equals(to.getBinding().getName())) { + return wire; + } + } + + // if no match, look for callback binding with same type as service binding + for (RuntimeWire wire : wires) { + if (wire.getEndpointReference().getBinding().getClass() == to.getBinding().getClass()) { + return wire; + } + } + + // no suitable callback wire was found + return null; + } + + private RuntimeWire cloneAndBind(RuntimeWire wire) { + RuntimeWire boundWire = null; + if (resolvedEndpoint != null) { + boundWire = ((RuntimeWireImpl)wire).lookupCache(resolvedEndpoint); + if (boundWire != null) { + return boundWire; + } + try { + // TODO - EPR - is this correct? + + // Fluff up a new response wire based on the callback endpoint + RuntimeComponentReference ref = + bind((RuntimeComponentReference)wire.getEndpointReference().getReference(), + resolvedEndpoint); + + boundWire = ref.getRuntimeWires().get(0); + + Binding binding = wire.getEndpointReference().getBinding(); + + ((RuntimeWireImpl)wire).addToCache(resolvedEndpoint, boundWire); + } catch (CloneNotSupportedException e) { + // will not happen + } + } + return boundWire; + } + + private RuntimeComponentReference bind(RuntimeComponentReference reference, + Endpoint callbackEndpoint) throws CloneNotSupportedException { + + // clone the callback reference ready to configure it for this callback endpoint + RuntimeComponentReference ref = (RuntimeComponentReference)reference.clone(); + ref.getTargets().clear(); + ref.getBindings().clear(); + ref.getEndpointReferences().clear(); + + // no access to the assembly factory so clone an existing epr + EndpointReference callbackEndpointReference = (EndpointReference)reference.getEndpointReferences().get(0).clone(); + + callbackEndpointReference.setReference(ref); + callbackEndpointReference.setTargetEndpoint(callbackEndpoint); + callbackEndpointReference.setUnresolved(true); + + // TODO - should really use incoming callback info but awaiting + // decision from OASIS on what will happen with callbacks + // The callback endpoint will be resolved with the registry + // when the wire chains are created + ref.getEndpointReferences().add(callbackEndpointReference); + + return ref; + } +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/ComponentContextImpl.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/ComponentContextImpl.java new file mode 100644 index 0000000000..4e71181747 --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/ComponentContextImpl.java @@ -0,0 +1,496 @@ +/* + * 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.Endpoint; +import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.assembly.Multiplicity; +import org.apache.tuscany.sca.assembly.OptimizableBinding; +import org.apache.tuscany.sca.assembly.Reference; +import org.apache.tuscany.sca.assembly.Service; +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.invocation.ExtensibleProxyFactory; +import org.apache.tuscany.sca.core.invocation.ProxyFactory; +import org.apache.tuscany.sca.core.invocation.ProxyFactoryExtensionPoint; +import org.apache.tuscany.sca.interfacedef.Interface; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +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.monitor.Monitor; +import org.apache.tuscany.sca.monitor.MonitorFactory; +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.RuntimeComponentService; +import org.oasisopen.sca.RequestContext; +import org.oasisopen.sca.SCARuntimeException; +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 Monitor monitor; + + public ComponentContextImpl(ExtensionPointRegistry registry, CompositeContext compositeContext, RuntimeComponent component) { + this.component = component; + FactoryExtensionPoint factories = registry.getExtensionPoint(FactoryExtensionPoint.class); + this.assemblyFactory = factories.getFactory(AssemblyFactory.class); + this.javaInterfaceFactory = factories.getFactory(JavaInterfaceFactory.class); + + UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); + this.compositeContext = compositeContext; + + this.compositeActivator = utilities.getUtility(CompositeActivator.class); + + this.requestContextFactory = + registry.getExtensionPoint(ContextFactoryExtensionPoint.class).getFactory(RequestContextFactory.class); + this.proxyFactory = new ExtensibleProxyFactory(registry.getExtensionPoint(ProxyFactoryExtensionPoint.class)); + this.propertyFactory = factories.getFactory(PropertyValueFactory.class); + + this.eprBinder = utilities.getUtility(EndpointReferenceBinder.class); + + MonitorFactory monitorFactory = utilities.getUtility(MonitorFactory.class); + this.monitor = monitorFactory.createMonitor(); + } + + public String getURI() { + return component.getURI(); + } + + public <B, R extends ServiceReference<B>> R cast(B target) throws IllegalArgumentException { + return (R)proxyFactory.cast(target); + } + + public <B> B getService(Class<B> businessInterface, String referenceName) { + ServiceReference<B> serviceRef = getServiceReference(businessInterface, referenceName); + return serviceRef.getService(); + } + + public <B> ServiceReference<B> getServiceReference(Class<B> businessInterface, String referenceName) { + try { + for (ComponentReference ref : component.getReferences()) { + if (referenceName.equals(ref.getName())) { + /* ******************** Contribution for issue TUSCANY-2281 ******************** */ + Multiplicity multiplicity = ref.getMultiplicity(); + if (multiplicity == Multiplicity.ZERO_N || multiplicity == Multiplicity.ONE_N) { + throw new IllegalArgumentException("Reference " + referenceName + + " has multiplicity " + + multiplicity); + } + /* ******************** Contribution for issue TUSCANY-2281 ******************** */ + + return getServiceReference(businessInterface, (RuntimeComponentReference)ref, null); + } + } + throw new ServiceRuntimeException("Reference not found: " + referenceName); + } catch (ServiceRuntimeException e) { + throw e; + } catch (Exception e) { + if (e instanceof RuntimeException) { + throw (RuntimeException)e; + } + throw new ServiceRuntimeException(e.getMessage(), e); + } + } + + /** + * 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> B getProperty(Class<B> type, String propertyName) { + for (ComponentProperty p : component.getProperties()) { + if (propertyName.equals(p.getName())) { + return propertyFactory.createPropertyValue(p, type); + } + } + throw new ServiceRuntimeException("Property not found: " + propertyName); + } + + /** + * @param component + */ + public static ComponentService getSingleService(Component component) { + ComponentService targetService; + List<ComponentService> services = component.getServices(); + List<ComponentService> regularServices = new ArrayList<ComponentService>(); + 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 <B> ServiceReference<B> createSelfReference(Class<B> businessInterface) { + ComponentService service = getSingleService(component); + try { + return createSelfReference(businessInterface, service); + } catch (Exception e) { + throw new ServiceRuntimeException(e.getMessage(), e); + } + } + + public <B> ServiceReference<B> createSelfReference(Class<B> businessInterface, String serviceName) { + try { + for (ComponentService service : component.getServices()) { + if (serviceName.equals(service.getName())) { + return createSelfReference(businessInterface, service); + } + } + throw new ServiceRuntimeException("Service not found: " + serviceName); + } catch (ServiceRuntimeException e) { + throw e; + } catch (Exception e) { + throw new ServiceRuntimeException(e.getMessage(), e); + } + } + + /** + * @param <B> + * @param businessInterface + * @param service + * @return + */ + public <B> ServiceReference<B> createSelfReference(Class<B> businessInterface, ComponentService service) { + try { + RuntimeComponentReference ref = + (RuntimeComponentReference)createSelfReference(component, service, businessInterface); + ref.setComponent(component); + return getServiceReference(businessInterface, ref, null); + } 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 <B> ServiceReference<B> getServiceReference(Class<B> businessInterface, + RuntimeComponentReference reference, + EndpointReference endpointReference) { + try { + RuntimeComponentReference ref = (RuntimeComponentReference)reference; + InterfaceContract interfaceContract = reference.getInterfaceContract(); + Reference componentTypeReference = reference.getReference(); + if (componentTypeReference != null && componentTypeReference.getInterfaceContract() != null) { + interfaceContract = componentTypeReference.getInterfaceContract(); + } + InterfaceContract refInterfaceContract = getInterfaceContract(interfaceContract, businessInterface); + if (refInterfaceContract != interfaceContract) { + ref = (RuntimeComponentReference)reference.clone(); + if (interfaceContract != null) { + ref.setInterfaceContract(interfaceContract); + } else { + ref.setInterfaceContract(refInterfaceContract); + } + } + ref.setComponent(component); + return new ServiceReferenceImpl<B>(businessInterface, component, ref, endpointReference, proxyFactory, + component.getComponentContext().getCompositeContext()); + } catch (Exception e) { + throw new ServiceRuntimeException(e); + } + } + + /** + * Bind a component reference to a component service + * @param <B> + * @param businessInterface + * @param reference + * @param service + * @return + * @throws CloneNotSupportedException + * @throws InvalidInterfaceException + */ + public <B> ServiceReference<B> getServiceReference(Class<B> businessInterface, + RuntimeComponentReference reference, + RuntimeComponent component, + RuntimeComponentService service) { + try { + RuntimeComponentReference ref = (RuntimeComponentReference)reference.clone(); + InterfaceContract interfaceContract = reference.getInterfaceContract(); + Reference componentTypeReference = reference.getReference(); + if (componentTypeReference != null && componentTypeReference.getInterfaceContract() != null) { + interfaceContract = componentTypeReference.getInterfaceContract(); + } + InterfaceContract refInterfaceContract = getInterfaceContract(interfaceContract, businessInterface); + if (refInterfaceContract != interfaceContract) { + ref = (RuntimeComponentReference)reference.clone(); + ref.setInterfaceContract(interfaceContract); + } + ref.getTargets().add(service); + ref.getBindings().clear(); + for (Binding binding : service.getBindings()) { + if (binding instanceof OptimizableBinding) { + OptimizableBinding optimizableBinding = (OptimizableBinding)((OptimizableBinding)binding).clone(); + optimizableBinding.setTargetBinding(binding); + optimizableBinding.setTargetComponent(component); + optimizableBinding.setTargetComponentService(service); + ref.getBindings().add(optimizableBinding); + } else { + ref.getBindings().add(binding); + } + } + return new ServiceReferenceImpl<B>(businessInterface, component, ref, null, proxyFactory, compositeContext); + } catch (Exception e) { + throw new ServiceRuntimeException(e); + } + } + + public <B> ServiceReference<B> getCallableReference(Class<B> businessInterface, + RuntimeComponent component, + RuntimeComponentService service) { + try { + if (businessInterface == null) { + InterfaceContract contract = service.getInterfaceContract(); + businessInterface = (Class<B>)((JavaInterface)contract.getInterface()).getJavaClass(); + } + RuntimeComponentReference ref = + (RuntimeComponentReference)createSelfReference(component, service, businessInterface); + ref.setComponent(component); + return new ServiceReferenceImpl<B>(businessInterface, component, ref, null, proxyFactory, + compositeContext); + } catch (Exception e) { + throw new ServiceRuntimeException(e); + } + } + + /** + * Create a self-reference for a component service + * @param component + * @param service + * @throws CloneNotSupportedException + * @throws InvalidInterfaceException + */ + private ComponentReference createSelfReference(Component component, + ComponentService service, + Class<?> businessInterface) throws CloneNotSupportedException, + InvalidInterfaceException { + ComponentReference componentReference = assemblyFactory.createComponentReference(); + componentReference.setName("$self$." + service.getName()); + + for (Binding binding : service.getBindings()) { + if (binding instanceof OptimizableBinding) { + OptimizableBinding optimizableBinding = (OptimizableBinding)((OptimizableBinding)binding).clone(); + optimizableBinding.setTargetBinding(binding); + optimizableBinding.setTargetComponent(component); + optimizableBinding.setTargetComponentService(service); + componentReference.getBindings().add(optimizableBinding); + } else { + componentReference.getBindings().add(binding); + } + } + + componentReference.setCallback(service.getCallback()); + componentReference.getTargets().add(service); + componentReference.getPolicySets().addAll(service.getPolicySets()); + componentReference.getRequiredIntents().addAll(service.getRequiredIntents()); + + 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.setUnresolved(false); + endpointReference.setStatus(EndpointReference.WIRED_TARGET_FOUND_READY_FOR_MATCHING); + + // create endpoint. + Endpoint endpoint = assemblyFactory.createEndpoint(); + endpoint.setComponent(component); + endpoint.setService(service); + endpoint.setUnresolved(true); + endpointReference.setTargetEndpoint(endpoint); + + componentReference.getEndpointReferences().add(endpointReference); + + // do binding matching + boolean ok = eprBinder.bind(compositeContext.getEndpointRegistry(), endpointReference); + + if (!ok) { + throw new SCARuntimeException("Unable to bind " + endpointReference); + } + + return componentReference; + } + + /** + * @param interfaceContract + * @param businessInterface + * @return + * @throws CloneNotSupportedException + * @throws InvalidInterfaceException + */ + private InterfaceContract getInterfaceContract(InterfaceContract interfaceContract, Class<?> businessInterface) + throws CloneNotSupportedException, InvalidInterfaceException { + 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) { + // The interface is not assignable from the interface contract + interfaceContract = javaInterfaceFactory.createJavaInterfaceContract(); + JavaInterface callInterface = javaInterfaceFactory.createJavaInterface(businessInterface); + interfaceContract.setInterface(callInterface); + if (callInterface.getCallbackClass() != null) { + interfaceContract.setCallbackInterface(javaInterfaceFactory.createJavaInterface(callInterface + .getCallbackClass())); + } + } + + return interfaceContract; + } + + /** + * @see org.apache.tuscany.sca.runtime.RuntimeComponentContext#start(org.apache.tuscany.sca.runtime.RuntimeComponentReference) + */ + public void start(RuntimeComponentReference reference) { + compositeActivator.start(compositeContext, component, reference); + } + + + /* ******************** Contribution for issue TUSCANY-2281 ******************** */ + + /** + * @see ComponentContext#getServices(Class<B>, String) + */ + public <B> Collection<B> getServices(Class<B> businessInterface, String referenceName) { + ArrayList<B> services = new ArrayList<B>(); + Collection<ServiceReference<B>> serviceRefs = getServiceReferences(businessInterface, referenceName); + for (ServiceReference<B> serviceRef : serviceRefs) { + services.add(serviceRef.getService()); + } + return services; + } + + /** + * @see ComponentContext#getServiceReferences(Class<B>, String) + */ + public <B> Collection<ServiceReference<B>> getServiceReferences(Class<B> businessInterface, String referenceName) { + try { + for (ComponentReference ref : component.getReferences()) { + if (referenceName.equals(ref.getName())) { + ArrayList<ServiceReference<B>> serviceRefs = new ArrayList<ServiceReference<B>>(); + for (EndpointReference endpointReference : ref.getEndpointReferences()) { + serviceRefs + .add(getServiceReference(businessInterface, (RuntimeComponentReference)ref, endpointReference)); + } + return serviceRefs; + } + } + throw new ServiceRuntimeException("Reference not found: " + referenceName); + } 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/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/RequestContextImpl.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/RequestContextImpl.java new file mode 100644 index 0000000000..e8a1254dc9 --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/RequestContextImpl.java @@ -0,0 +1,118 @@ +/* + * 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.context.ThreadMessageContext; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.invocation.ExtensibleProxyFactory; +import org.apache.tuscany.sca.core.invocation.ProxyFactory; +import org.apache.tuscany.sca.core.invocation.ProxyFactoryExtensionPoint; +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.RuntimeWire; +import org.oasisopen.sca.RequestContext; +import org.oasisopen.sca.ServiceReference; + +/** + * @version $Rev$ $Date$ + */ +public class RequestContextImpl implements RequestContext { + + private ProxyFactoryExtensionPoint proxyFactoryExtensionPoint; + + public RequestContextImpl(RuntimeComponent component) { + ExtensionPointRegistry registry = component.getComponentContext().getExtensionPointRegistry(); + proxyFactoryExtensionPoint = registry.getExtensionPoint(ProxyFactoryExtensionPoint.class); + } + + public Subject getSecuritySubject() { + Subject subject = null; + + for (Object header : ThreadMessageContext.getMessageContext().getHeaders()){ + if (header instanceof Subject){ + subject = (Subject)header; + break; + } + } + return subject; + } + + public String getServiceName() { + return ThreadMessageContext.getMessageContext().getTo().getService().getName(); + } + + public <B> ServiceReference<B> getServiceReference() { + Message msgContext = ThreadMessageContext.getMessageContext(); + // FIXME: [rfeng] Is this the service reference matching the caller side? + Endpoint to = msgContext.getTo(); + RuntimeComponentService service = (RuntimeComponentService) to.getService(); + RuntimeComponent component = (RuntimeComponent) to.getComponent(); + + ServiceReference<B> callableReference = component.getComponentContext().getCallableReference(null, component, service); + + //TODO - EPR - not required for OASIS + //ReferenceParameters parameters = msgContext.getFrom().getReferenceParameters(); + //((CallableReferenceExt<B>) callableReference).attachCallbackID(parameters.getCallbackID()); + //((CallableReferenceExt<B>) callableReference).attachConversation(parameters.getConversationID()); + + return callableReference; + } + + public <CB> CB getCallback() { + ServiceReference<CB> cb = getCallbackReference(); + if (cb == null) { + return null; + } + return cb.getService(); + } + + @SuppressWarnings("unchecked") + public <CB> ServiceReference<CB> getCallbackReference() { + Message msgContext = ThreadMessageContext.getMessageContext(); + 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<CB> javaClass = (Class<CB>)javaInterface.getJavaClass(); + List<RuntimeWire> wires = callbackReference.getRuntimeWires(); + ProxyFactory proxyFactory = new ExtensibleProxyFactory(proxyFactoryExtensionPoint); + ServiceReferenceImpl ref = new CallbackServiceReferenceImpl(javaClass, wires, proxyFactory); + if (ref != null) { + //ref.resolveTarget(); + // TODO - EPR - not required for OASIS + //ReferenceParameters parameters = msgContext.getFrom().getReferenceParameters(); + //ref.attachCallbackID(parameters.getCallbackID()); + //if (ref.getConversation() != null) { + // ref.attachConversationID(parameters.getConversationID()); + //} + } + return ref; + } +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/ServiceReferenceImpl.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/ServiceReferenceImpl.java new file mode 100644 index 0000000000..23126b5123 --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/ServiceReferenceImpl.java @@ -0,0 +1,481 @@ +/* + * 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.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.UUID; + +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 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.ContributionReadException; +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.ReferenceParametersImpl; +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.core.invocation.ProxyFactoryExtensionPoint; +import org.apache.tuscany.sca.interfacedef.Interface; +import org.apache.tuscany.sca.interfacedef.java.JavaInterface; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; +import org.apache.tuscany.sca.runtime.ReferenceParameters; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeComponentReference; +import org.apache.tuscany.sca.runtime.RuntimeWire; +import org.oasisopen.sca.ServiceRuntimeException; + +/** + * Default implementation of a ServiceReference. + * + * @version $Rev$ $Date$ + * @param <B> the type of the business interface + */ +public class ServiceReferenceImpl<B> implements ServiceReferenceExt<B> { + private static final long serialVersionUID = 6763709434194361540L; + + protected transient ProxyFactory proxyFactory; + protected transient Class<B> businessInterface; + protected transient Object proxy; + + protected Object callbackID; // The callbackID should be serializable + + protected transient RuntimeComponent component; + protected transient RuntimeComponentReference reference; + protected transient EndpointReference endpointReference; + + protected String scdl; + + private transient XMLStreamReader xmlReader; + + protected transient CompositeContext compositeContext; + private ExtensionPointRegistry registry; + private FactoryExtensionPoint modelFactories; + protected RuntimeAssemblyFactory assemblyFactory; + private StAXArtifactProcessorExtensionPoint staxProcessors; + private StAXArtifactProcessor<EndpointReference> staxProcessor; + private XMLInputFactory xmlInputFactory; + private XMLOutputFactory xmlOutputFactory; + private BuilderExtensionPoint builders; + + /* + * Public constructor for Externalizable serialization/deserialization + */ + public ServiceReferenceImpl() { + super(); + } + + /* + * Public constructor for use by XMLStreamReader2CallableReference + */ + // TODO - EPR - Is this required + public ServiceReferenceImpl(XMLStreamReader xmlReader) throws Exception { + this.xmlReader = xmlReader; + resolve(); + } + + protected ServiceReferenceImpl(Class<B> businessInterface, + RuntimeComponent component, + RuntimeComponentReference reference, + EndpointReference endpointReference, + ProxyFactory proxyFactory, + CompositeContext compositeContext) { + this.proxyFactory = proxyFactory; + this.businessInterface = businessInterface; + this.component = component; + this.reference = reference; + this.endpointReference = endpointReference; + this.compositeContext = compositeContext; + + getExtensions(); + + // FIXME: The SCA Specification is not clear how we should handle multiplicity + // for CallableReference + if (this.endpointReference == null) { + + // TODO - EPR - If no endpoint reference specified assume the first one + // This will happen when a self reference is created in which case the + // the reference should only have one endpointReference so use that + if (this.reference.getEndpointReferences().size() == 0){ + throw new ServiceRuntimeException("The reference " + reference.getName() + " in component " + + component.getName() + " has no endpoint references"); + } + + if (this.reference.getEndpointReferences().size() > 1){ + throw new ServiceRuntimeException("The reference " + reference.getName() + " in component " + + component.getName() + " has more than one endpoint reference"); + } + + this.endpointReference = this.reference.getEndpointReferences().get(0); + } + + // FIXME: Should we normalize the componentName/serviceName URI into an absolute SCA URI in the SCA binding? + // sca:component1/component11/component112/service1? + initCallbackID(); + } + + private void getExtensions() { + 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); + } + + public ServiceReferenceImpl(Class<B> businessInterface, RuntimeWire wire, ProxyFactory proxyFactory) { + this.proxyFactory = proxyFactory; + this.businessInterface = businessInterface; + //ExtensionPointRegistry registry = ((RuntimeWireImpl)wire).getExtensionPoints(); + //this.modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class); + //this.assemblyFactory = (RuntimeAssemblyFactory)modelFactories.getFactory(AssemblyFactory.class); + bind(wire); + } + + public RuntimeWire getRuntimeWire() { + try { + resolve(); + if (endpointReference != null){ + return reference.getRuntimeWire(endpointReference); + } else { + return null; + } + } catch (Exception e) { + throw new ServiceRuntimeException(e); + } + } + + public EndpointReference getEndpointReference() { + return endpointReference; + } + + protected void bind(RuntimeWire wire) { + if (wire != null) { + this.component = (RuntimeComponent)wire.getEndpointReference().getComponent(); + this.reference = (RuntimeComponentReference)wire.getEndpointReference().getReference(); + this.endpointReference = wire.getEndpointReference(); + this.compositeContext = component.getComponentContext().getCompositeContext(); + initCallbackID(); + } + } + + protected void initCallbackID() { + if (reference.getInterfaceContract() != null) { + if (reference.getInterfaceContract().getCallbackInterface() != null) { + this.callbackID = createCallbackID(); + } + } + } + + public B getProxy() throws ObjectCreationException { + try { + if (proxy == null) { + proxy = createProxy(); + } + return businessInterface.cast(proxy); + } catch (Exception e) { + throw new ObjectCreationException(e); + } + } + + public void setProxy(Object proxy) { + this.proxy = proxy; + } + + protected Object createProxy() throws Exception { + return proxyFactory.createProxy(this); + } + + public B getService() { + try { + resolve(); + return getProxy(); + } catch (Exception e) { + throw new ServiceRuntimeException(e); + } + } + + public Class<B> getBusinessInterface() { + try { + resolve(); + return businessInterface; + } catch (Exception e) { + throw new ServiceRuntimeException(e); + } + } + + public boolean isConversational() { + try { + resolve(); + return reference == null ? false : reference.getInterfaceContract().getInterface().isConversational(); + } catch (Exception e) { + throw new ServiceRuntimeException(e); + } + } + + public Object getCallbackID() { + try { + resolve(); + return callbackID; + } 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 { + 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 { + 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 + this.compositeContext = CompositeContext.getCurrentCompositeContext(); + getExtensions(); + } + + streamReader = xmlInputFactory.createXMLStreamReader(reader); + } + + endpointReference = 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) && component == null && reference == null) { + fromXMLString(); + + this.component = (RuntimeComponent)endpointReference.getComponent(); + compositeContext.bindComponent(this.component); + + this.reference = (RuntimeComponentReference)endpointReference.getReference(); + this.reference.setComponent(this.component); + + 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<ClassLoader>() { + 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<B>)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(component, 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(); + ProxyFactoryExtensionPoint proxyFactories = extensionPointRegistry.getExtensionPoint(ProxyFactoryExtensionPoint.class); + return new ExtensibleProxyFactory(proxyFactories); + } + + // ================================================================================== + + /** + * Create a callback id + * + * @return the callback id + */ + private String createCallbackID() { + return UUID.randomUUID().toString(); + } + + public void attachCallbackID(Object callbackID) { + this.callbackID = callbackID; + } + + protected ReferenceParameters getReferenceParameters() { + ReferenceParameters parameters = new ReferenceParametersImpl(); + parameters.setCallbackID(callbackID); + return parameters; + } + + public XMLStreamReader getXMLReader() { + return xmlReader; + } +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/factory/InstanceWrapper.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/factory/InstanceWrapper.java new file mode 100644 index 0000000000..2371897dce --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/factory/InstanceWrapper.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; + +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$ + */ +public interface InstanceWrapper<T> { + + /** + * @return + */ + T getInstance(); + + /** + * @throws TargetInitializationException + */ + void start() throws TargetInitializationException; + + /** + * @throws TargetDestructionException + */ + void stop() throws TargetDestructionException; + +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/factory/ObjectCreationException.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/factory/ObjectCreationException.java new file mode 100644 index 0000000000..d35b27fd24 --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/factory/ObjectCreationException.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.factory; + + +/** + * Denotes an error creating a new object instance + * + * @version $Rev$ $Date$ + */ +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/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/factory/ObjectFactory.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/factory/ObjectFactory.java new file mode 100644 index 0000000000..3f64d2405b --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/factory/ObjectFactory.java @@ -0,0 +1,35 @@ +/* + * 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$ + */ +public interface ObjectFactory<T> { + + /** + * Return a instance of the type that this factory creates. + * + * @return a instance from this factory + */ + T getInstance() throws ObjectCreationException; + +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallableReferenceObjectFactory.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallableReferenceObjectFactory.java new file mode 100644 index 0000000000..d4fe266d44 --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallableReferenceObjectFactory.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.invocation; + +import org.apache.tuscany.sca.assembly.EndpointReference; +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.RuntimeComponentReference; +import org.oasisopen.sca.ServiceReference; + +/** + * Uses a wire to return a CallableReference + * + * @version $Rev$ $Date$ + */ +public class CallableReferenceObjectFactory implements ObjectFactory<ServiceReference<?>> { + private Class<?> businessInterface; + private RuntimeComponent component; + private RuntimeComponentReference reference; + private EndpointReference endpointReference; + + /** + * Constructor. + * + * To support the @Reference protected CallableReference<MyService> 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, + RuntimeComponent component, + RuntimeComponentReference reference, + EndpointReference endpointReference) { + this.businessInterface = businessInterface; + this.component = component; + this.reference = reference; + this.endpointReference = endpointReference; + } + + public ServiceReference<?> getInstance() throws ObjectCreationException { + return component.getComponentContext().getServiceReference(businessInterface, reference, endpointReference); + } + +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackInterfaceInterceptor.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackInterfaceInterceptor.java new file mode 100644 index 0000000000..588eaa2d15 --- /dev/null +++ b/branches/sca-java-2.0-M4/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/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackReferenceObjectFactory.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackReferenceObjectFactory.java new file mode 100644 index 0000000000..021d588cb4 --- /dev/null +++ b/branches/sca-java-2.0-M4/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.core.context.impl.CallbackServiceReferenceImpl; +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.runtime.RuntimeWire; +import org.oasisopen.sca.ServiceReference; + +/** + * Uses a wire to return a CallableReference + * + * @version $Rev$ $Date$ + */ +public class CallbackReferenceObjectFactory implements ObjectFactory<ServiceReference<?>> { + private Class<?> businessInterface; + private ProxyFactory proxyFactory; + private List<RuntimeWire> wires; + + public CallbackReferenceObjectFactory(Class<?> interfaze, ProxyFactory proxyFactory, List<RuntimeWire> wires) { + this.businessInterface = interfaze; + this.proxyFactory = proxyFactory; + this.wires = wires; + } + + public ServiceReference<?> getInstance() throws ObjectCreationException { + return new CallbackServiceReferenceImpl(businessInterface, wires, proxyFactory); + } + +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackWireObjectFactory.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackWireObjectFactory.java new file mode 100644 index 0000000000..2b37c30451 --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackWireObjectFactory.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; + +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.RuntimeWire; + +/** + * Returns proxy instance for a wire callback + * + * @version $Rev$ $Date$ + */ +public class CallbackWireObjectFactory<B> implements ObjectFactory<B> { + private Class<B> businessInterface; + private ProxyFactory proxyFactory; + private List<RuntimeWire> wires; + + public CallbackWireObjectFactory(Class<B> interfaze, ProxyFactory proxyFactory, List<RuntimeWire> wires) { + this.businessInterface = interfaze; + this.proxyFactory = proxyFactory; + this.wires = wires; + } + + public B getInstance() throws ObjectCreationException { + return proxyFactory.createCallbackProxy(businessInterface, wires); + } + +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CglibProxyFactory.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CglibProxyFactory.java new file mode 100644 index 0000000000..11edc283a4 --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CglibProxyFactory.java @@ -0,0 +1,149 @@ +/* + * 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.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.RuntimeWire; +import org.oasisopen.sca.ServiceReference; + +/** + * The implementation of a wire service that uses cglib dynamic proxies + * + * @version $Rev$ $Date$ + */ +public class CglibProxyFactory implements ProxyFactory { + private MessageFactory messageFactory; + + public CglibProxyFactory(MessageFactory messageFactory, InterfaceContractMapper mapper) { + this.messageFactory = messageFactory; + + } + + public <T> T createProxy(Class<T> interfaze, RuntimeWire wire) throws ProxyCreationException { + ServiceReference<T> serviceReference = new ServiceReferenceImpl(interfaze, wire, this); + return createProxy(serviceReference); + } + + /** + * create the proxy with cglib. use the same JDKInvocationHandler as + * JDKProxyService. + */ + public <T> T createProxy(ServiceReference<T> callableReference) throws ProxyCreationException { + Enhancer enhancer = new Enhancer(); + Class<T> interfaze = callableReference.getBusinessInterface(); + enhancer.setSuperclass(interfaze); + enhancer.setCallback(new CglibMethodInterceptor<T>(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> T createCallbackProxy(Class<T> interfaze, final List<RuntimeWire> wires) throws ProxyCreationException { + ServiceReferenceImpl<T> callbackReference = new ServiceReferenceImpl(interfaze, wires.get(0), this); + return callbackReference != null ? createCallbackProxy(callbackReference) : null; + } + + /** + * create the callback proxy with cglib. use the same + * JDKCallbackInvocationHandler as JDKProxyService. + */ + public <T> T createCallbackProxy(ServiceReferenceImpl<T> callbackReference) throws ProxyCreationException { + Enhancer enhancer = new Enhancer(); + Class<T> interfaze = callbackReference.getBusinessInterface(); + enhancer.setSuperclass(interfaze); + enhancer.setCallback(new CglibMethodInterceptor<T>(callbackReference)); + Object proxy = enhancer.create(); + callbackReference.setProxy(proxy); + return interfaze.cast(proxy); + } + + @SuppressWarnings("unchecked") + public <B, R extends ServiceReference<B>> 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<T> implements MethodInterceptor { + private JDKInvocationHandler invocationHandler; + + public CglibMethodInterceptor(ServiceReference<T> callableReference) { + invocationHandler = new JDKInvocationHandler(messageFactory, callableReference); + } + + public CglibMethodInterceptor(ServiceReferenceImpl<T> callbackReference) { + invocationHandler = new JDKCallbackInvocationHandler(messageFactory, callbackReference); + } + + /* + public CglibMethodInterceptor(Class<T> interfaze, RuntimeWire wire) { + ServiceReference<T> serviceRef = new ServiceReferenceImpl<T>(interfaze, wire, CglibProxyFactory.this); + invocationHandler = new JDKInvocationHandler(messageFactory, serviceRef); + } + + public CglibMethodInterceptor(Class<T> interfaze, List<RuntimeWire> wires) { + CallbackReferenceImpl ref = new CallbackReferenceImpl(interfaze, CglibProxyFactory.this, wires); + invocationHandler = new JDKCallbackInvocationHandler(messageFactory, ref); + } + */ + + /** + * @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; + } + + } + +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/DefaultProxyFactoryExtensionPoint.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/DefaultProxyFactoryExtensionPoint.java new file mode 100644 index 0000000000..af6f039775 --- /dev/null +++ b/branches/sca-java-2.0-M4/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 extensionPoints) { + UtilityExtensionPoint utilities = extensionPoints.getExtensionPoint(UtilityExtensionPoint.class); + this.interfaceContractMapper = utilities.getUtility(InterfaceContractMapper.class); + + FactoryExtensionPoint modelFactories = extensionPoints.getExtensionPoint(FactoryExtensionPoint.class); + this.messageFactory = modelFactories.getFactory(MessageFactory.class); + + interfaceFactory = new JDKProxyFactory(messageFactory, interfaceContractMapper); + } + + public DefaultProxyFactoryExtensionPoint(MessageFactory messageFactory, InterfaceContractMapper mapper) { + this.interfaceContractMapper = mapper; + this.messageFactory = messageFactory; + interfaceFactory = new JDKProxyFactory(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/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ExtensibleProxyFactory.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ExtensibleProxyFactory.java new file mode 100644 index 0000000000..fbdfe8a8e6 --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ExtensibleProxyFactory.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; + +import java.util.List; + +import org.apache.tuscany.sca.core.context.impl.ServiceReferenceImpl; +import org.apache.tuscany.sca.runtime.RuntimeWire; +import org.oasisopen.sca.ServiceReference; + +/** + * An extensible proxy factory. + * + * @version $Rev$ $Date$ + */ +public class ExtensibleProxyFactory implements ProxyFactory { + + private ProxyFactoryExtensionPoint proxyFactories; + + public ExtensibleProxyFactory(ProxyFactoryExtensionPoint proxyFactories) { + this.proxyFactories = proxyFactories; + } + + /** + * @see org.apache.tuscany.sca.core.invocation.ProxyFactory#cast(java.lang.Object) + */ + @SuppressWarnings("unchecked") + public <B, R extends ServiceReference<B>> 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> T createCallbackProxy(Class<T> interfaze, List<RuntimeWire> 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> T createProxy(ServiceReference<T> 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> T createCallbackProxy(ServiceReferenceImpl<T> 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.RuntimeWire) + */ + public <T> T createProxy(Class<T> interfaze, RuntimeWire 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)); + } + +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ExtensibleWireProcessor.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ExtensibleWireProcessor.java new file mode 100644 index 0000000000..934f2f7aa0 --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ExtensibleWireProcessor.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.invocation; + +import org.apache.tuscany.sca.runtime.RuntimeWire; +import org.apache.tuscany.sca.runtime.RuntimeWireProcessor; +import org.apache.tuscany.sca.runtime.RuntimeWireProcessorExtensionPoint; + +/** + * The default implementation of an extensible <code>WireProcessor</code> + * + * @version $Rev$ $Date$ + */ +public class ExtensibleWireProcessor implements RuntimeWireProcessor { + + private RuntimeWireProcessorExtensionPoint processors; + + public ExtensibleWireProcessor(RuntimeWireProcessorExtensionPoint processors) { + this.processors = processors; + } + + public void process(RuntimeWire wire) { + for (RuntimeWireProcessor processor : processors.getWireProcessors()) { + processor.process(wire); + } + } + +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/NonBlockingInterceptor.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/NonBlockingInterceptor.java new file mode 100644 index 0000000000..ec2f0a0664 --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/NonBlockingInterceptor.java @@ -0,0 +1,202 @@ +/* + * 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.LinkedList; +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.runtime.RuntimeWire; +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 implements Interceptor { + + 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; + private Invoker next; + + 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; + } + + 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; + } + + public Invoker getNext() { + return next; + } + + public void setNext(Invoker next) { + this.next = next; + } + + /** + * A dummy message passed back on an invocation + */ + private static class ImmutableMessage implements Message { + + public Object getBody() { + return null; + } + + public void setBody(Object body) { + if (body != null) { + throw new UnsupportedOperationException(); + } + } + + public void setCallbackWires(LinkedList<RuntimeWire> wires) { + + } + + 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(); + } + + /** + * @see org.apache.tuscany.sca.invocation.Message#getReplyTo() + */ + public EndpointReference getReplyTo() { + return null; + } + + public Map<String, Object> getQoSContext() { + return null; + } + + public List<Object> getHeaders() { + return null; + } + public <T> T getBindingContext() { + return null; + } + + public <T> void setBindingContext(T bindingContext) { + } + } + +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyCreationException.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyCreationException.java new file mode 100644 index 0000000000..0b36b178f3 --- /dev/null +++ b/branches/sca-java-2.0-M4/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/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyFactory.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyFactory.java new file mode 100644 index 0000000000..d75ff309ff --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyFactory.java @@ -0,0 +1,88 @@ +/* + * 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.context.impl.ServiceReferenceImpl; +import org.apache.tuscany.sca.runtime.RuntimeWire; +import org.oasisopen.sca.ServiceReference; + +/** + * Creates proxies that implement Java interfaces and invocation handlers for fronting wires + * + * @version $Rev$ $Date$ + */ + +public interface ProxyFactory { + + /** + * Creates a Java proxy for the given wire + * + * @param interfaze the interface the proxy implements + * @param wire the wire to proxy + * @return the proxy + * @throws ProxyCreationException + */ + <T> T createProxy(Class<T> interfaze, RuntimeWire wire) throws ProxyCreationException; + + /** + * Creates a Java proxy for the given CallableReference + * + * @param callableReference The CallableReference + * @return the proxy + * @throws ProxyCreationException + */ + <T> T createProxy(ServiceReference<T> 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> T createCallbackProxy(Class<T> interfaze, List<RuntimeWire> wires) throws ProxyCreationException; + + /** + * Creates a Java proxy for the given callback reference + * + * @param callableReference The CallableReference + * @return the proxy + * @throws ProxyCreationException + */ + <T> T createCallbackProxy(ServiceReferenceImpl<T> 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 + */ + <B, R extends ServiceReference<B>> 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); + +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyFactoryExtensionPoint.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyFactoryExtensionPoint.java new file mode 100644 index 0000000000..875a252798 --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyFactoryExtensionPoint.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; + + +/** + * The extension point to plug in proxy factories + * @version $Rev$ $Date$ + */ +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/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/RuntimeWireInvoker.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/RuntimeWireInvoker.java new file mode 100644 index 0000000000..43726b85dd --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/RuntimeWireInvoker.java @@ -0,0 +1,268 @@ +/* + * 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 org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.context.ThreadMessageContext; +import org.apache.tuscany.sca.core.factory.InstanceWrapper; +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.RuntimeWire; +import org.oasisopen.sca.ServiceRuntimeException; + +/** + * @version $Rev$ $Date$ + */ +public class RuntimeWireInvoker implements Invoker{ + protected MessageFactory messageFactory; + protected Object conversationID; + protected Object callbackID; + protected Object callbackObject; + protected RuntimeWire wire; + + public RuntimeWireInvoker(MessageFactory messageFactory, RuntimeWire wire) { + this.messageFactory = messageFactory; + this.wire = wire; + //init(wire); + } + + /* TODO - EPR - not required for OASIS + protected void init(RuntimeWire wire) { + if (wire != null) { + + ReferenceParameters parameters = wire.getSource().getReferenceParameters(); + this.callbackID = parameters.getCallbackID(); + this.callbackObject = parameters.getCallbackReference(); + this.conversationID = parameters.getConversationID(); + InterfaceContract contract = wire.getSource().getInterfaceContract(); + this.conversational = contract.getInterface().isConversational(); + } + } + */ + + /* + * TODO - Introduced to allow the RuntimeWireInvoker to sit on the end of the + * service binding chain. Runtime wire invoke needs splitting up into + * separate conversation, callback interceptors etc. + */ + public Message invoke(Message msg) { + + try { + Object response = invoke(msg.getOperation(),msg); + // Hack to put the response back in a message. + // shouldn't take it out of the response message in the first place + msg.setBody(response); + } catch (InvocationTargetException e) { +// throw new ServiceRuntimeException(e); + } + + return msg; + } + + public Object invoke(Operation operation, Message msg) throws InvocationTargetException { + return invoke(wire, operation, msg); + } + + public Object invoke(RuntimeWire wire, Operation operation, Message msg) throws InvocationTargetException { + RuntimeWire runtimeWire = wire == null ? this.wire : wire; + InvocationChain chain = runtimeWire.getInvocationChain(operation); + return invoke(chain, msg, runtimeWire); + } + + protected Object invoke(InvocationChain chain, Message msg, RuntimeWire wire) throws InvocationTargetException { + EndpointReference from = msg.getFrom(); + EndpointReference epFrom = wire.getEndpointReference(); + if (from != null) { + from.setComponent(epFrom.getComponent()); + from.setReference(epFrom.getReference()); + from.setBinding(epFrom.getBinding()); + from.setInterfaceContract(epFrom.getInterfaceContract()); + from.setTargetEndpoint(epFrom.getTargetEndpoint()); + //from.setCallbackEndpoint(epFrom.getCallbackEndpoint()); + + // TODO - EPR - what's going on here? + //from.mergeEndpoint(epFrom); + } else { + msg.setFrom(epFrom); + } + msg.setTo(wire.getEndpoint()); + + Invoker headInvoker = chain.getHeadInvoker(); + Operation operation = chain.getTargetOperation(); + msg.setOperation(operation); + + Message msgContext = ThreadMessageContext.getMessageContext(); + // TODO - EPR - no required for OASIS + //Object currentConversationID = msgContext.getFrom().getReferenceParameters().getConversationID(); + + ThreadMessageContext.setMessageContext(msg); + try { + // TODO - EPR - no required for OASIS + //conversationPreinvoke(msg); + // handleCallback(msg, currentConversationID); + // dispatch the wire down the chain and get the response + Message resp = headInvoker.invoke(msg); + Object body = resp.getBody(); + if (resp.isFault()) { + throw new InvocationTargetException((Throwable)body); + } + return body; + } catch (InvocationTargetException e) { + throw e; + } catch (Throwable e) { + throw new ServiceRuntimeException(e); + } finally { + try { + // TODO - EPR - no required for OASIS + //conversationPostInvoke(msg); + //} catch (TargetDestructionException e) { + // throw new ServiceRuntimeException(e); + } finally { + ThreadMessageContext.setMessageContext(msgContext); + } + } + } + + /** + * @param msgContext + */ + /* TODO - EPR - no required for OASIS + protected EndpointReference getCallbackEndpoint(Message msgContext) { + EndpointReference from = msgContext.getFrom(); + return from == null ? null : from.getReferenceParameters().getCallbackReference(); + } + */ + + /** + * Pre-invoke for the conversation handling + * @param msg + * @throws TargetResolutionException + */ + /* TODO - EPR - no required for OASIS + private void conversationPreinvoke(Message msg) { + if (conversational) { + ReferenceParameters parameters = msg.getFrom().getReferenceParameters(); + // in some cases the ConversationID that should be used comes in with the + // message, e.g. when ws binding is in use. + Object convID = parameters.getConversationID(); + if (convID != null) { + conversationID = convID; + } + conversation = conversationManager.getConversation(conversationID); + + if (conversation == null || conversation.getState() == ConversationState.ENDED) { + conversation = conversationManager.startConversation(conversationID); + conversation.initializeConversationAttributes(wire.getTarget().getComponent()); + } else if (conversation.conversationalAttributesInitialized() == false) { + conversation.initializeConversationAttributes(wire.getTarget().getComponent()); + } else if (conversation.isExpired()){ + throw new ConversationEndedException("Conversation has expired."); + } + + conversation.updateLastReferencedTime(); + + parameters.setConversationID(conversation.getConversationID()); + } + } + */ + + /** + * Post-invoke for the conversation handling + * @param wire + * @param operation + * @throws TargetDestructionException + */ + /* TODO - EPR - no required for OASIS + @SuppressWarnings("unchecked") + private void conversationPostInvoke(Message msg) throws TargetDestructionException { + if (conversational) { + Operation operation = msg.getOperation(); + ConversationSequence sequence = operation.getConversationSequence(); + if (sequence == ConversationSequence.CONVERSATION_END) { + // in some cases the ConversationID that should be used comes in with the + // message, e.g. when ws binding is in use. + Object convID = msg.getFrom().getReferenceParameters().getConversationID(); + if (convID != null) { + conversationID = convID; + } + conversation = conversationManager.getConversation(conversationID); + + // remove conversation id from scope container + ScopeContainer scopeContainer = getConversationalScopeContainer(msg); + + if (scopeContainer != null) { + scopeContainer.remove(conversation.getConversationID()); + } + + conversation.end(); + } + } + } + + @SuppressWarnings("unchecked") + private ScopeContainer getConversationalScopeContainer(Message msg) { + ScopeContainer scopeContainer = null; + + RuntimeComponent component = (RuntimeComponent) msg.getTo().getComponent(); + + if (component instanceof ScopedRuntimeComponent) { + ScopedRuntimeComponent scopedRuntimeComponent = (ScopedRuntimeComponent)component; + ScopeContainer container = scopedRuntimeComponent.getScopeContainer(); + + if ((container != null) && (container.getScope() == Scope.CONVERSATION)) { + scopeContainer = container; + } + } + + return scopeContainer; + } + */ + + + /** + * Minimal wrapper for a callback object contained in a ServiceReference + */ + private static class CallbackObjectWrapper<T> implements InstanceWrapper<T> { + + private T instance; + + private CallbackObjectWrapper(T instance) { + this.instance = instance; + } + + public T getInstance() { + return instance; + } + + public void start() { + // do nothing + } + + public void stop() { + // do nothing + } + } + +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/WireObjectFactory.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/WireObjectFactory.java new file mode 100644 index 0000000000..2fc3d6c7eb --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/WireObjectFactory.java @@ -0,0 +1,55 @@ +/* + * 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.RuntimeWire; + +/** + * Uses a wire to return an object instance + * + * @version $Rev$ $Date$ + */ +public class WireObjectFactory<T> implements ObjectFactory<T> { + private Class<T> interfaze; + private RuntimeWire 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<T> interfaze, RuntimeWire wire, ProxyFactory proxyService) { + this.interfaze = interfaze; + this.wire = wire; + this.proxyService = proxyService; + } + + public T getInstance() throws ObjectCreationException { + return new ServiceReferenceImpl<T>(interfaze, wire, proxyService).getProxy(); + } + +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/AsyncJDKInvocationHandler.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/AsyncJDKInvocationHandler.java new file mode 100644 index 0000000000..aeccfa8b05 --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/AsyncJDKInvocationHandler.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 java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.concurrent.Future;
+
+import javax.xml.ws.AsyncHandler;
+import javax.xml.ws.Response;
+
+import org.apache.tuscany.sca.invocation.MessageFactory;
+import org.oasisopen.sca.ServiceReference;
+
+public class AsyncJDKInvocationHandler extends JDKInvocationHandler {
+ private static final long serialVersionUID = 1L;
+
+ public AsyncJDKInvocationHandler(MessageFactory messageFactory, ServiceReference<?> callableReference) {
+ super(messageFactory, callableReference);
+ }
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ if (isAsyncCallback(method)) {
+ return doInvokeAsyncCallback(proxy, method, args);
+ } else if (isAsyncPoll(method)) {
+ return doInvokeAsyncPoll(proxy, method, args);
+ } else {
+ return super.invoke(proxy, method, args);
+ }
+ }
+
+ protected boolean isAsyncCallback(Method method) {
+ if (method.getName().endsWith("Async") && (method.getReturnType().isAssignableFrom(Future.class))) {
+ if (method.getParameterTypes().length > 0) {
+ return method.getParameterTypes()[method.getParameterTypes().length-1].isAssignableFrom(AsyncHandler.class);
+ }
+ }
+ return false;
+ }
+
+ protected boolean isAsyncPoll(Method method) {
+ return method.getName().endsWith("Async") && (method.getReturnType().isAssignableFrom(Response.class));
+ }
+
+ protected AsyncResponse doInvokeAsyncPoll(Object proxy, Method asyncMethod, Object[] args) {
+ Object response;
+ boolean isException;
+ try {
+ response = super.invoke(proxy, getNonAsyncMethod(asyncMethod), args);
+ isException = false;
+ } catch (Throwable e) {
+ response = e;
+ isException = true;
+ }
+ return new AsyncResponse(response, isException);
+ }
+
+ private Object doInvokeAsyncCallback(Object proxy, Method asyncMethod, Object[] args) {
+ AsyncHandler handler = (AsyncHandler)args[args.length-1];
+ Response response = doInvokeAsyncPoll(proxy,asyncMethod,Arrays.copyOf(args, args.length-1));
+ handler.handleResponse(response);
+
+ return null;
+ }
+
+ 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 non-async method matching async method " + asyncMethod.getName());
+ }
+}
diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/AsyncResponse.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/AsyncResponse.java new file mode 100644 index 0000000000..07086dfae3 --- /dev/null +++ b/branches/sca-java-2.0-M4/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/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/InvocationChainImpl.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/InvocationChainImpl.java new file mode 100644 index 0000000000..d8eb746776 --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/InvocationChainImpl.java @@ -0,0 +1,195 @@ +/* + * 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.interfacedef.Operation; +import org.apache.tuscany.sca.invocation.DataExchangeSemantics; +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.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<Node> nodes = new ArrayList<Node>(); + + // FIXME: Not a good practice to use static reference + private static final PhaseManager phaseManager = new PhaseManager(); + private boolean forReference; + private boolean allowsPassByReference; + + public InvocationChainImpl(Operation sourceOperation, Operation targetOperation, boolean forReference) { + this.targetOperation = targetOperation; + this.sourceOperation = sourceOperation; + this.forReference = forReference; + } + + 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); + } + + 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(); + } + + /** + * @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) { + int index = phaseManager.getAllPhases().indexOf(phase); + if (index == -1) { + throw new IllegalArgumentException("Invalid phase name: " + phase); + } + Node node = new Node(index, invoker); + ListIterator<Node> 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 (after != null) { + if (invoker instanceof Interceptor) { + ((Interceptor)invoker).setNext(after.getInvoker()); + } + } + + } + + 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; + } + } + +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/JDKCallbackInvocationHandler.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/JDKCallbackInvocationHandler.java new file mode 100644 index 0000000000..e64b9f3068 --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/JDKCallbackInvocationHandler.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.invocation.impl; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + + +import org.apache.tuscany.sca.core.assembly.impl.RuntimeWireImpl; +import org.apache.tuscany.sca.core.context.impl.CallbackServiceReferenceImpl; +import org.apache.tuscany.sca.core.context.impl.ServiceReferenceImpl; +import org.apache.tuscany.sca.invocation.InvocationChain; +import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.runtime.RuntimeWire; +import org.oasisopen.sca.ServiceRuntimeException; + +/** + * Responsible for dispatching to a callback through a wire. <p/> TODO cache + * target invoker + * + * @version $Rev$ $Date$ + */ +public class JDKCallbackInvocationHandler extends JDKInvocationHandler { + private static final long serialVersionUID = -3350283555825935609L; + + public JDKCallbackInvocationHandler(MessageFactory messageFactory, ServiceReferenceImpl ref) { + super(messageFactory, ref); + this.fixedWire = false; + } + + @Override + @SuppressWarnings( {"unchecked"}) + 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 + RuntimeWire wire = ((CallbackServiceReferenceImpl)callableReference).getCallbackWire(); + 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 { + return invoke(chain, args, wire, wire.getEndpointReference()); + } catch (InvocationTargetException e) { + Throwable t = e.getCause(); + throw e; + } finally { + // allow the cloned wire to be reused by subsequent callbacks + ((RuntimeWireImpl)wire).releaseWire(); + } + } + +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/JDKInvocationHandler.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/JDKInvocationHandler.java new file mode 100644 index 0000000000..148749922e --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/JDKInvocationHandler.java @@ -0,0 +1,537 @@ +/* + * 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.HashMap; +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.ThreadMessageContext; +import org.apache.tuscany.sca.core.context.ServiceReferenceExt; +import org.apache.tuscany.sca.core.factory.InstanceWrapper; +import org.apache.tuscany.sca.core.scope.TargetResolutionException; +import org.apache.tuscany.sca.interfacedef.DataType; +import org.apache.tuscany.sca.interfacedef.Operation; +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.RuntimeWire; +import org.oasisopen.sca.SCARuntimeException; +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 boolean conversational; + protected MessageFactory messageFactory; + protected EndpointReference source; + protected Endpoint target; + protected RuntimeWire wire; + protected ServiceReferenceExt<?> callableReference; + protected Class<?> businessInterface; + + protected boolean fixedWire = true; + + protected transient Map<Method, InvocationChain> chains = new HashMap<Method, InvocationChain>(); + + public JDKInvocationHandler(MessageFactory messageFactory, Class<?> businessInterface, RuntimeWire wire) { + this.messageFactory = messageFactory; + this.wire = wire; + this.businessInterface = businessInterface; + init(this.wire); + } + + public JDKInvocationHandler(MessageFactory messageFactory, ServiceReference<?> callableReference) { + this.messageFactory = messageFactory; + this.callableReference = (ServiceReferenceExt<?>)callableReference; + if (callableReference != null) { + this.businessInterface = callableReference.getBusinessInterface(); + this.wire = ((ServiceReferenceExt<?>)callableReference).getRuntimeWire(); + if (wire != null) { + init(wire); + } + } + } + + protected void init(RuntimeWire wire) { + // TODO - EPR not required for OASIS + /* + if (wire != null) { + try { + // Clone the endpoint reference so that reference parameters can be changed + source = (EndpointReference)wire.getSource().clone(); + } catch (CloneNotSupportedException e) { + throw new ServiceRuntimeException(e); + } + initConversational(wire); + } + */ + } + + /* TODO - EPR - not required for OASIS + protected void initConversational(RuntimeWire wire) { + InterfaceContract contract = wire.getSource().getInterfaceContract(); + this.conversational = contract.getInterface().isConversational(); + } + */ + + public Class<?> getBusinessInterface() { + return businessInterface; + } + + + protected Object getCallbackID() { +// if (callableReference != null) { +// return callableReference.getCallbackID(); +// } else { + return null; +// } + } + + /* TODO - EPR - Not reqiured for OASIS + protected Object getCallbackObject() { + if (callableReference != null && callableReference instanceof ServiceReference) { + return ((ServiceReference)callableReference).getService(); + } else { + return null; + } + } + */ + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if (Object.class == method.getDeclaringClass()) { + return invokeObjectMethod(method, args); + } + if (wire == null) { + throw new ServiceRuntimeException("No runtime wire is available"); + } + + if (wire.isOutOfDate()) { + wire.rebuild(); + chains.clear(); + } + + InvocationChain chain = getInvocationChain(method, wire); + + if (chain == null) { + throw new IllegalArgumentException("No matching operation is found: " + method); + } + + // The EndpointReference is not now resolved until the invocation chain + // is first created so reset the source here + source = wire.getEndpointReference(); + + // send the invocation down the wire + Object result = invoke(chain, args, wire, source); + + 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<List<DataType>> inputType = null; + if (operation.isWrapperStyle()) { + inputType = operation.getWrapper().getUnwrappedInputType(); + } else { + inputType = operation.getInputType(); + } + List<DataType> 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, RuntimeWire wire) { + if (fixedWire && chains.containsKey(method)) { + return chains.get(method); + } + InvocationChain found = null; + for (InvocationChain chain : wire.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(InvocationChain chain, Object[] args, RuntimeWire wire, EndpointReference source) + throws Throwable { + Message msg = messageFactory.createMessage(); + msg.setFrom(source); + if (target != null) { + msg.setTo(target); + } else { + msg.setTo(wire.getEndpoint()); + } + Invoker headInvoker = chain.getHeadInvoker(); + Operation operation = chain.getTargetOperation(); + msg.setOperation(operation); + msg.setBody(args); + + Message msgContext = ThreadMessageContext.getMessageContext(); + + // TODO - EPR - not required for OASIS + //Object currentConversationID = msgContext.getFrom().getReferenceParameters().getConversationID(); + //conversationPreinvoke(msg, wire); + + handleCallback(msg, wire); + ThreadMessageContext.setMessageContext(msg); + boolean abnormalEndConversation = false; + try { + // dispatch the wire down the chain and get the response + Message resp = headInvoker.invoke(msg); + Object body = resp.getBody(); + if (resp.isFault()) { + /* TODO - EPR - not required in OASIS + // mark the conversation as ended if the exception is not a business exception + if (currentConversationID != null ){ + try { + boolean businessException = false; + + for (DataType dataType : operation.getFaultTypes()){ + if (dataType.getPhysical() == ((Throwable)body).getClass()){ + businessException = true; + break; + } + } + + if (businessException == false){ + abnormalEndConversation = true; + } + } catch (Exception ex){ + // TODO - sure what the best course of action is here. We have + // a system exception in the middle of a business exception + } + } + */ + throw (Throwable)body; + } + return body; + } finally { + //conversationPostInvoke(msg, wire, abnormalEndConversation); + ThreadMessageContext.setMessageContext(msgContext); + } + } + + /** + * @param msg + * @param wire + * @param interfaze + * @throws TargetResolutionException + */ + private void handleCallback(Message msg, RuntimeWire wire) + throws TargetResolutionException { + + //ReferenceParameters parameters = msg.getFrom().getReferenceParameters(); + //parameters.setCallbackID(getCallbackID()); + + if (msg.getFrom() == null || msg.getFrom().getCallbackEndpoint() == null) { + return; + } + + /* TODO - EPR - not required for OASIS + parameters.setCallbackReference(msg.getFrom().getCallbackEndpoint()); + + // If we are passing out a callback target + // register the calling component instance against this + // new conversation id so that stateful callbacks will be + // able to find it + Object callbackObject = getCallbackObject(); + if (conversational && callbackObject == null) { + // the component instance is already registered + // so add another registration + ScopeContainer<Object> scopeContainer = getConversationalScopeContainer(wire); + + if (scopeContainer != null && currentConversationID != null) { + scopeContainer.addWrapperReference(currentConversationID, conversation.getConversationID()); + } + } + + Interface interfaze = msg.getFrom().getCallbackEndpoint().getInterfaceContract().getInterface(); + if (callbackObject != null) { + if (callbackObject instanceof ServiceReference) { + CallableReferenceExt<?> callableReference = (CallableReferenceExt<?>)callbackObject; + EndpointReference callbackRef = callableReference.getEndpointReference(); + + // TODO - EPR - create chains on the callback reference in case this hasn't already happened + // needed as the bindings are not now matched until the chanins are created + callableReference.getRuntimeWire().getInvocationChains(); + + parameters.setCallbackReference(callbackRef); + } else { + if (interfaze != null) { + if (!interfaze.isConversational()) { + throw new IllegalArgumentException( + "Callback object for stateless callback is not a ServiceReference"); + } else { + if (!(callbackObject instanceof Serializable)) { + throw new IllegalArgumentException( + "Callback object for stateful callback is not Serializable"); + } + ScopeContainer scopeContainer = getConversationalScopeContainer(wire); + if (scopeContainer != null) { + InstanceWrapper wrapper = new CallbackObjectWrapper(callbackObject); + scopeContainer.registerWrapper(wrapper, conversation.getConversationID()); + } + parameters.setCallbackObjectID(callbackObject); + } + } + } + } + */ + } + + /** + * Pre-invoke for the conversation handling + * @param msg + * @throws TargetResolutionException + */ + /* TODO - EPR - not required for OASIS + private void conversationPreinvoke(Message msg, RuntimeWire wire) { + if (!conversational) { + // Not conversational or the conversation has been started + return; + } + + ConversationManager conversationManager = ((RuntimeWireImpl2)wire).getConversationManager(); + + if (conversation == null || conversation.getState() == ConversationState.ENDED) { + + conversation = conversationManager.startConversation(getConversationID()); + + // if this is a local wire then set up the conversation timeouts here based on the + // parameters from the component + if (wire.getEndpoint().getComponent() != null){ + conversation.initializeConversationAttributes((RuntimeComponent)wire.getEndpoint().getComponent()); + } + + // connect the conversation to the CallableReference so it can be retrieve in the future + if (callableReference != null) { + ((CallableReferenceImpl)callableReference).attachConversation(conversation); + } + } else if (conversation.isExpired()) { + throw new ConversationEndedException("Conversation " + conversation.getConversationID() + " has expired."); + } + + // if this is a local wire then schedule conversation timeouts based on the timeout + // parameters from the service implementation. If this isn't a local wire then + // the RuntimeWireInvoker will take care of this + if (wire.getEndpoint().getComponent() != null){ + conversation.updateLastReferencedTime(); + } + + msg.getFrom().getReferenceParameters().setConversationID(conversation.getConversationID()); + + } + */ + + /** + * Post-invoke for the conversation handling + * @param wire + * @param operation + * @throws TargetDestructionException + */ + /* TODO - not required for OASIS + @SuppressWarnings("unchecked") + private void conversationPostInvoke(Message msg, RuntimeWire wire, boolean abnormalEndConversation) + throws TargetDestructionException { + Operation operation = msg.getOperation(); + ConversationSequence sequence = operation.getConversationSequence(); + // We check that conversation has not already ended as there is only one + // conversation manager in the runtime and so, in the case of remote bindings, + // the conversation will already have been stopped when we get back to the client + if ((sequence == ConversationSequence.CONVERSATION_END || abnormalEndConversation) && + (conversation.getState() != ConversationState.ENDED)) { + + // remove conversation id from scope container + ScopeContainer scopeContainer = getConversationalScopeContainer(wire); + + if (scopeContainer != null) { + scopeContainer.remove(conversation.getConversationID()); + } + + conversation.end(); + } + } + + + private ScopeContainer<Object> getConversationalScopeContainer(RuntimeWire wire) { + ScopeContainer<Object> scopeContainer = null; + + RuntimeComponent runtimeComponent = (RuntimeComponent)wire.getEndpointReference().getComponent(); + + if (runtimeComponent instanceof ScopedRuntimeComponent) { + ScopedRuntimeComponent scopedRuntimeComponent = (ScopedRuntimeComponent)runtimeComponent; + ScopeContainer<Object> tmpScopeContainer = scopedRuntimeComponent.getScopeContainer(); + + if ((tmpScopeContainer != null) && (tmpScopeContainer.getScope() == Scope.CONVERSATION)) { + scopeContainer = tmpScopeContainer; + } + } + + return scopeContainer; + } + */ + + /** + * Creates a new conversation id + * + * @return the conversation id + */ + /* TODO - EPR - not required for OASIS + private Object createConversationID() { + if (getConversationID() != null) { + return getConversationID(); + } else { + return UUID.randomUUID().toString(); + } + } + */ + + /** + * @return the callableReference + */ + public ServiceReference<?> getCallableReference() { + return callableReference; + } + + /** + * @param callableReference the callableReference to set + */ + public void setCallableReference(ServiceReference<?> callableReference) { + this.callableReference = (ServiceReferenceExt<?>)callableReference; + } + + /** + * Minimal wrapper for a callback object contained in a ServiceReference + */ + private static class CallbackObjectWrapper<T> implements InstanceWrapper<T> { + + private T instance; + + private CallbackObjectWrapper(T instance) { + this.instance = instance; + } + + public T getInstance() { + return instance; + } + + public void start() { + // do nothing + } + + public void stop() { + // do nothing + } + + } + +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/JDKProxyFactory.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/JDKProxyFactory.java new file mode 100644 index 0000000000..853e28fafa --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/JDKProxyFactory.java @@ -0,0 +1,177 @@ +/* + * 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.List; +import java.util.concurrent.Future; + +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.LifeCycleListener; +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.RuntimeWire; +import org.oasisopen.sca.ServiceReference; + + +/** + * the default implementation of a wire service that uses JDK dynamic proxies + * + * @version $Rev$ $Date$ + */ +public class JDKProxyFactory implements ProxyFactory, LifeCycleListener { + protected InterfaceContractMapper contractMapper; + private MessageFactory messageFactory; + + public JDKProxyFactory(MessageFactory messageFactory, InterfaceContractMapper mapper) { + 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> T createProxy(Class<T> interfaze, RuntimeWire wire) throws ProxyCreationException { + ServiceReference<T> serviceReference = new ServiceReferenceImpl(interfaze, wire, this); + return createProxy(serviceReference); + } + + public <T> T createProxy(ServiceReference<T> callableReference) throws ProxyCreationException { + assert callableReference != null; + final Class<T> interfaze = callableReference.getBusinessInterface(); + InvocationHandler handler; + if (isAsync(interfaze)) { + handler = new AsyncJDKInvocationHandler(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<ClassLoader>() { + public ClassLoader run() { + return interfaze.getClassLoader(); + } + }); + Object proxy = newProxyInstance(cl, new Class[] {interfaze}, handler); + ((ServiceReferenceImpl)callableReference).setProxy(proxy); + return interfaze.cast(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> T createCallbackProxy(Class<T> interfaze, List<RuntimeWire> wires) throws ProxyCreationException { + ServiceReferenceImpl<T> callbackReference = new CallbackServiceReferenceImpl(interfaze, wires, this); + return callbackReference != null ? createCallbackProxy(callbackReference) : null; + } + + public <T> T createCallbackProxy(ServiceReferenceImpl<T> callbackReference) throws ProxyCreationException { + assert callbackReference != null; + Class<T> interfaze = callbackReference.getBusinessInterface(); + InvocationHandler handler = new JDKCallbackInvocationHandler(messageFactory, callbackReference); + ClassLoader cl = interfaze.getClassLoader(); + Object proxy = newProxyInstance(cl, new Class[] {interfaze}, handler); + callbackReference.setProxy(proxy); + return interfaze.cast(proxy); + } + + public <B, R extends ServiceReference<B>> 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<Class<?>, Constructor<?>> cache = new LRUCache<Class<?>, 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(); + } +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/MessageFactoryImpl.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/MessageFactoryImpl.java new file mode 100644 index 0000000000..6ce2ffca21 --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/MessageFactoryImpl.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.invocation.impl; + +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 { + + public Message createMessage() { + return new MessageImpl(); + } + +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/MessageImpl.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/MessageImpl.java new file mode 100644 index 0000000000..53fab3392c --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/MessageImpl.java @@ -0,0 +1,117 @@ +/* + * 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 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 List<Object> headers = new ArrayList<Object>(); + private Object body; + private Object messageID; + private boolean isFault; + private Operation operation; + + private EndpointReference from; + private Endpoint to; + + private Object bindingContext; + + public MessageImpl() { + // TODO - EPR - What to do by default? + //this.from = new EndpointReferenceImpl("/"); + //this.to = new EndpointReferenceImpl("/"); + this.from = null; + this.to = null; + } + + @SuppressWarnings("unchecked") + public <T> T getBody() { + return (T)body; + } + + public <T> 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 List<Object> getHeaders() { + return headers; + } + + @SuppressWarnings("unchecked") + public <T> T getBindingContext() { + return (T)bindingContext; + } + + public <T> void setBindingContext(T bindingContext) { + this.bindingContext = bindingContext; + } +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/NoMethodForOperationException.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/NoMethodForOperationException.java new file mode 100644 index 0000000000..45f4bf52bf --- /dev/null +++ b/branches/sca-java-2.0-M4/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/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/PhaseManager.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/PhaseManager.java new file mode 100644 index 0000000000..c9024fecef --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/PhaseManager.java @@ -0,0 +1,299 @@ +/* + * 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.extensibility.ServiceDeclaration; +import org.apache.tuscany.sca.extensibility.ServiceDiscovery; +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_INTERFACE, REFERENCE_POLICY, 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_POLICY, SERVICE_INTERFACE, SERVICE}; + + private static final String[] SYSTEM_IMPLEMENTATION_PHASES = {IMPLEMENTATION_POLICY, IMPLEMENTATION}; + + private String pattern = Phase.class.getName(); + private Map<String, Stage> stages; + private List<String> phases; + + public class Stage { + private String name; + private PhaseSorter<String> sorter = new PhaseSorter<String>(); + private Set<String> firstSet = new HashSet<String>(); + private Set<String> lastSet = new HashSet<String>(); + private List<String> phases = new ArrayList<String>(); + + public Stage(String name) { + super(); + this.name = name; + } + + public String getName() { + return name; + } + + public PhaseSorter<String> getSorter() { + return sorter; + } + + public Set<String> getFirstSet() { + return firstSet; + } + + public Set<String> getLastSet() { + return lastSet; + } + + public List<String> getPhases() { + return phases; + } + + @Override + public String toString() { + return name + phases; + } + } + + // For unit test purpose + PhaseManager(String pattern) { + super(); + this.pattern = pattern; + } + + public PhaseManager() { + } + + private List<String> getPhases(String stage) { + Stage s = getStages().get(stage); + return s == null ? null : s.getPhases(); + } + + public List<String> getReferencePhases() { + return getPhases(STAGE_REFERENCE); + } + + public List<String> getServicePhases() { + return getPhases(STAGE_SERVICE); + } + + public List<String> getReferenceBindingPhases() { + return getPhases(STAGE_REFERENCE_BINDING); + } + + public List<String> getServiceBindingPhases() { + return getPhases(STAGE_SERVICE_BINDING); + } + + public List<String> getImplementationPhases() { + return getPhases(STAGE_IMPLEMENTATION); + } + + public synchronized List<String> getAllPhases() { + if (phases == null) { + phases = new ArrayList<String>(); + phases.addAll(getReferencePhases()); + phases.addAll(getReferenceBindingPhases()); + phases.addAll(getServiceBindingPhases()); + phases.addAll(getServicePhases()); + phases.addAll(getImplementationPhases()); + } + return phases; + } + + public synchronized Map<String, Stage> getStages() { + if (stages != null) { + return stages; + } + init(); + + Collection<ServiceDeclaration> services; + try { + services = ServiceDiscovery.getInstance().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<String> graph = stage.getSorter(); + Set<String> 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<String>(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<String>(graph.getVertices().keySet())) { + if (!lastSet.contains(v)) { + graph.addEdge(v, s); + } + } + } + + } + + for (Stage s : stages.values()) { + List<String> 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<String, Stage>(); + + 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/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/PhaseSorter.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/PhaseSorter.java new file mode 100644 index 0000000000..175f3463ad --- /dev/null +++ b/branches/sca-java-2.0-M4/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 <V> The type of vertex object + * @param <E> The type of edge object + * + * @version $Rev$ $Date$ + */ +public class PhaseSorter<V> implements Cloneable { + private final Map<V, Vertex> vertices = new HashMap<V, Vertex>(); + + /** + * 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<Vertex, Edge> outEdges = new HashMap<Vertex, Edge>(); + private Map<Vertex, Edge> inEdges = new HashMap<Vertex, Edge>(); + + private Vertex(V value) { + this.value = value; + } + + @Override + public String toString() { + return "(" + value + ")"; + } + + public V getValue() { + return value; + } + + public Map<Vertex, Edge> getOutEdges() { + return outEdges; + } + + public Map<Vertex, Edge> 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<Edge>(vertex.outEdges.values())) { + removeEdge(e); + } + for (Edge e : new ArrayList<Edge>(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<V, Vertex> getVertices() { + return vertices; + } + + public void addGraph(PhaseSorter<V> 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<V> topologicalSort(boolean readOnly) { + PhaseSorter<V> graph = (!readOnly) ? this : (PhaseSorter<V>)clone(); + List<V> list = new ArrayList<V>(); + while (true) { + Vertex v = graph.getFirst(); + if (v == null) { + break; + } + list.add(v.getValue()); + graph.removeVertex(v); + } + + return list; + } + + @Override + public Object clone() { + PhaseSorter<V> copy = new PhaseSorter<V>(); + copy.addGraph(this); + return copy; + } +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/runtime/DefaultDomainRegistryFactory.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/runtime/DefaultDomainRegistryFactory.java new file mode 100644 index 0000000000..d80e2b5490 --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/runtime/DefaultDomainRegistryFactory.java @@ -0,0 +1,157 @@ +/* + * 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; + +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.net.URI; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.LifeCycleListener; +import org.apache.tuscany.sca.extensibility.ServiceDeclaration; +import org.apache.tuscany.sca.extensibility.ServiceDiscovery; +import org.apache.tuscany.sca.runtime.DomainRegistryFactory; +import org.apache.tuscany.sca.runtime.EndpointListener; +import org.apache.tuscany.sca.runtime.EndpointRegistry; + +/** + * The utility responsible for finding the endpoint regstry by the scheme and creating instances for the + * given domain + */ +public class DefaultDomainRegistryFactory implements DomainRegistryFactory, LifeCycleListener { + private ExtensionPointRegistry extensionRegistry; + private Map<String, ServiceDeclaration> declarations = new HashMap<String, ServiceDeclaration>(); + private Map<String, EndpointRegistry> endpointRegistries = new ConcurrentHashMap<String, EndpointRegistry>(); + private List<EndpointListener> listeners = new ArrayList<EndpointListener>(); + + /** + * @param extensionRegistry + */ + public DefaultDomainRegistryFactory(ExtensionPointRegistry extensionRegistry) { + super(); + this.extensionRegistry = extensionRegistry; + } + + public void start() { + Collection<ServiceDeclaration> sds = null; + try { + sds = ServiceDiscovery.getInstance().getServiceDeclarations(EndpointRegistry.class); + } catch (IOException e) { + throw new IllegalStateException(e); + } + for (ServiceDeclaration sd : sds) { + String scheme = sd.getAttributes().get("scheme"); + if (scheme != null) { + scheme = scheme.toLowerCase(); + } + declarations.put(scheme, sd); + } + } + + public synchronized EndpointRegistry getEndpointRegistry(String endpointRegistryURI, String domainURI) { + if (endpointRegistryURI == null) { + endpointRegistryURI = "vm://localhost"; + } + + String key = endpointRegistryURI + "," + domainURI; + + EndpointRegistry endpointRegistry = endpointRegistries.get(key); + if (endpointRegistry != null) { + return endpointRegistry; + } + + URI uri = URI.create(endpointRegistryURI); + String scheme = uri.getScheme(); + if (scheme != null) { + scheme = scheme.toLowerCase(); + } + + ServiceDeclaration sd = declarations.get(scheme); + + try { + Class<?> implClass = sd.loadClass(); + Constructor<?> constructor = null; + try { + constructor = implClass.getConstructor(ExtensionPointRegistry.class, String.class, String.class); + endpointRegistry = + (EndpointRegistry)constructor.newInstance(extensionRegistry, endpointRegistryURI, domainURI); + } catch (NoSuchMethodException e) { + constructor = + implClass.getConstructor(ExtensionPointRegistry.class, Map.class, String.class, String.class); + endpointRegistry = + (EndpointRegistry)constructor.newInstance(extensionRegistry, + sd.getAttributes(), + endpointRegistryURI, + domainURI); + } + } catch (Exception e) { + throw new IllegalStateException(e); + } + + if (endpointRegistry instanceof LifeCycleListener) { + ((LifeCycleListener)endpointRegistry).start(); + } + + for (EndpointListener listener : listeners) { + endpointRegistry.addListener(listener); + } + endpointRegistries.put(key, endpointRegistry); + return endpointRegistry; + } + + public void stop() { + declarations.clear(); + for (EndpointRegistry endpointRegistry : endpointRegistries.values()) { + if (endpointRegistry instanceof LifeCycleListener) { + ((LifeCycleListener)endpointRegistry).stop(); + } + } + endpointRegistries.clear(); + listeners.clear(); + } + + public synchronized Collection<EndpointRegistry> getEndpointRegistries() { + return new ArrayList<EndpointRegistry>(endpointRegistries.values()); + } + + public synchronized void addListener(EndpointListener listener) { + listeners.add(listener); + for(EndpointRegistry registry: endpointRegistries.values()) { + registry.addListener(listener); + } + } + + public synchronized List<EndpointListener> getListeners() { + return listeners; + } + + public synchronized void removeListener(EndpointListener listener) { + listeners.remove(listener); + for(EndpointRegistry registry: endpointRegistries.values()) { + registry.removeListener(listener); + } + } +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/runtime/impl/EndpointReferenceBinderImpl.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/runtime/impl/EndpointReferenceBinderImpl.java new file mode 100644 index 0000000000..bab83bad2d --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/runtime/impl/EndpointReferenceBinderImpl.java @@ -0,0 +1,299 @@ +/* + * 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.List; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +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.FactoryExtensionPoint; +import org.apache.tuscany.sca.core.UtilityExtensionPoint; +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.monitor.MonitorFactory; +import org.apache.tuscany.sca.monitor.Problem; +import org.apache.tuscany.sca.runtime.EndpointReferenceBinder; +import org.apache.tuscany.sca.runtime.EndpointRegistry; + +/** + * An 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 builder in case it is required by undresolved endpoints + * once the runtime has started. + * + * @version $Rev$ $Date$ + */ +public class EndpointReferenceBinderImpl implements EndpointReferenceBinder { + + protected ExtensionPointRegistry extensionPoints; + protected AssemblyFactory assemblyFactory; + protected InterfaceContractMapper interfaceContractMapper; + private Monitor monitor; + + + 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(); + } + + + + /** + * Build a single endpoint reference + * + * @param endpoint + * @param monitor + */ + public boolean bind(EndpointRegistry endpointRegistry, EndpointReference endpointReference) { + Problem problem = null; + if ( endpointReference.getStatus() == EndpointReference.WIRED_TARGET_FOUND_AND_MATCHED || + endpointReference.getStatus() == EndpointReference.RESOLVED_BINDING ) { + // The endpoint reference is already resolved to either + // a service endpoint local to this composite or it has + // a remote binding + + // still need to check that the callback endpoint is set correctly + if (hasCallback(endpointReference) && + endpointReference.getCallbackEndpoint() != null && + endpointReference.getCallbackEndpoint().isUnresolved() == true ){ + problem = selectCallbackEndpoint(endpointReference, + endpointReference.getReference().getCallbackService().getEndpoints()); + } + } else if (endpointReference.getStatus() == EndpointReference.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. + + problem = selectForwardEndpoint(endpointReference, + endpointReference.getTargetEndpoint().getService().getEndpoints()); + + if (problem == null && hasCallback(endpointReference)){ + problem = selectCallbackEndpoint(endpointReference, + endpointReference.getReference().getCallbackService().getEndpoints()); + } + + } else if (endpointReference.getStatus() == EndpointReference.WIRED_TARGET_NOT_FOUND || + endpointReference.getStatus() == EndpointReference.NOT_CONFIGURED){ + // The service is in a remote composite somewhere else in the domain + + // find the service in the endpoint registry + List<Endpoint> endpoints = endpointRegistry.findEndpoint(endpointReference); + + if (endpoints.size() == 0) { + problem = monitor.createProblem(this.getClass().getName(), + "endpoint-validation-messages", + Problem.Severity.ERROR, + this, + "NoEndpointsFound", + endpointReference.toString()); + } + + problem = selectForwardEndpoint(endpointReference, + endpoints); + + if (problem == null && hasCallback(endpointReference)){ + problem = selectCallbackEndpoint(endpointReference, + endpointReference.getReference().getCallbackService().getEndpoints()); + } + } + + if (problem != null){ + monitor.problem(problem); + return false; + } + + if (endpointReference.getStatus() != EndpointReference.WIRED_TARGET_FOUND_AND_MATCHED && + endpointReference.getStatus() != EndpointReference.RESOLVED_BINDING){ + problem = monitor.createProblem(this.getClass().getName(), + "endpoint-validation-messages", + Problem.Severity.ERROR, + this, + "EndpointReferenceCantBeMatched", + endpointReference.toString()); + monitor.problem(problem); + return false; + } + + return true; + + } + + private Problem selectForwardEndpoint(EndpointReference endpointReference, List<Endpoint> endpoints) { + + Endpoint matchedEndpoint = null; + + if (endpointReference.getReference().getName().startsWith("$self$.")){ + // just select the first one and don't do any policy matching + matchedEndpoint = endpoints.get(0); + } else { + // find the first endpoint that matches this endpoint reference + for (Endpoint endpoint : endpoints){ + if (haveMatchingPolicy(endpointReference, endpoint)){ + matchedEndpoint = endpoint; + break; + } + } + } + + if (matchedEndpoint == null){ + return null; + } + + endpointReference.setTargetEndpoint(matchedEndpoint); + endpointReference.setBinding(endpointReference.getTargetEndpoint().getBinding()); + endpointReference.setStatus(EndpointReference.WIRED_TARGET_FOUND_AND_MATCHED); + endpointReference.setUnresolved(false); + + return null; + } + + 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; + } + } + + private Problem selectCallbackEndpoint(EndpointReference endpointReference, List<Endpoint> endpoints) { + + Problem problem = null; + + // find the first callback endpoint that matches a callback endpoint reference + // at the service + Endpoint matchedEndpoint = null; + match: + for ( EndpointReference callbackEndpointReference : endpointReference.getTargetEndpoint().getCallbackEndpointReferences()){ + for (Endpoint endpoint : endpoints){ + if (haveMatchingPolicy(callbackEndpointReference, endpoint)){ + matchedEndpoint = endpoint; + break match; + } + } + } + + if (matchedEndpoint == null){ + return null; + } + + endpointReference.setCallbackEndpoint(matchedEndpoint); + + return problem; + } + + // FIXME: [rfeng] This implementation is wrong. It is the responsibility of the policy language + // to compare the reference and service side setting to determine if they are compatible. Some of + // policies apply to the reference side only, some of the policies apply to the service side only, + // while others apply to both sides. Even for those policies that apply to both side, they can be + // independent or related. + private boolean haveMatchingPolicy(EndpointReference endpointReference, Endpoint endpoint){ + + /* + // if no policy sets or intents are present then they match + if ((endpointReference.getRequiredIntents().size() == 0) && + (endpoint.getRequiredIntents().size() == 0) && + (endpointReference.getPolicySets().size() == 0) && + (endpoint.getPolicySets().size() == 0)) { + return true; + } + + // if there are different numbers of intents + // then they don't match + if (endpointReference.getRequiredIntents().size() != + endpoint.getRequiredIntents().size()) { + return false; + } + + // if there are different numbers of policy sets + // then they don't match + if (endpointReference.getPolicySets().size() != + endpoint.getPolicySets().size()) { + return false; + } + + // check intents for compatibility + for(Intent intentEPR : endpointReference.getRequiredIntents()){ + boolean matched = false; + for (Intent intentEP : endpoint.getRequiredIntents()){ + if (intentEPR.getName().equals(intentEP.getName())){ + matched = true; + break; + } + } + if (matched == false){ + return false; + } + } + + // check policy sets for compatibility. The list of policy sets + // may be a subset of the list of intents as some of the intents + // may be directly provided. We can't just rely on intent compatibility + // as different policy sets might have been attached at each end to + // satisfy the listed intents + + // if all of the policy sets on the endpoint reference match a + // policy set on the endpoint then they match + for(PolicySet policySetEPR : endpointReference.getPolicySets()){ + boolean matched = false; + for (PolicySet policySetEP : endpoint.getPolicySets()){ + // find if there is a policy set with the same name + if (policySetEPR.getName().equals(policySetEP.getName())){ + matched = true; + break; + } + // find if the policies inside the policy set match the + // policies inside a policy set on the endpoint + + // TODO - need a policy specific matcher to do this + // so need a new extension point + + } + + if (matched == false){ + return false; + } + } + */ + + return true; + } + + public boolean isOutOfDate(EndpointRegistry endpointRegistry, EndpointReference endpointReference) { + Endpoint te = endpointReference.getTargetEndpoint(); + if (!te.isUnresolved() && te.getURI()!= null) { + List<Endpoint> endpoints = endpointRegistry.findEndpoint(endpointReference); + return ! endpoints.contains(endpointReference.getTargetEndpoint()); + } + return false; + } + +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/AbstractScopeContainer.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/AbstractScopeContainer.java new file mode 100644 index 0000000000..4674456925 --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/AbstractScopeContainer.java @@ -0,0 +1,196 @@ +/* + * 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<KEY> implements ScopeContainer<KEY> { + protected Map<KEY, InstanceWrapper<?>> wrappers = new ConcurrentHashMap<KEY, InstanceWrapper<?>>(); + protected final Scope scope; + + protected RuntimeComponent component; + protected volatile int lifecycleState = UNINITIALIZED; + + + 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 [" + getLifecycleState() + "]"); + } + } + + /** + * 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 [" + lifecycleState + "]"); + } + 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 [" + lifecycleState + "]"); + } + setLifecycleState(STOPPED); + } + + public void stopContext(KEY contextId) { + wrappers.remove(contextId); + } + + @Override + public String toString() { + String s; + switch (lifecycleState) { + case ScopeContainer.CONFIG_ERROR: + s = "CONFIG_ERROR"; + break; + case ScopeContainer.ERROR: + s = "ERROR"; + break; + case ScopeContainer.INITIALIZING: + s = "INITIALIZING"; + break; + case ScopeContainer.INITIALIZED: + s = "INITIALIZED"; + break; + case ScopeContainer.RUNNING: + s = "RUNNING"; + break; + case ScopeContainer.STOPPING: + s = "STOPPING"; + break; + case ScopeContainer.STOPPED: + s = "STOPPED"; + break; + case ScopeContainer.UNINITIALIZED: + s = "UNINITIALIZED"; + break; + default: + s = "UNKNOWN"; + break; + } + return "In state [" + s + ']'; + } + + 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/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/DefaultScopeRegistry.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/DefaultScopeRegistry.java new file mode 100644 index 0000000000..2ea724ccf6 --- /dev/null +++ b/branches/sca-java-2.0-M4/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/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/Scope.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/Scope.java new file mode 100644 index 0000000000..0a7f2ef64f --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/Scope.java @@ -0,0 +1,62 @@ +/* + * 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$ + */ +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/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopeContainer.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopeContainer.java new file mode 100644 index 0000000000..2398ecea3e --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopeContainer.java @@ -0,0 +1,158 @@ +/* + * 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 <KEY> 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. + */ +public interface ScopeContainer<KEY> { + + /** + * 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/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopeContainerFactory.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopeContainerFactory.java new file mode 100644 index 0000000000..b19c14b3e0 --- /dev/null +++ b/branches/sca-java-2.0-M4/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/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopeRegistry.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopeRegistry.java new file mode 100644 index 0000000000..842ed4c547 --- /dev/null +++ b/branches/sca-java-2.0-M4/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/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopedImplementationProvider.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopedImplementationProvider.java new file mode 100644 index 0000000000..30d5c77181 --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopedImplementationProvider.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.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$ + */ +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(); + + /** + * @return the maxAge + */ + long getMaxAge(); + + /** + * @return the maxIdleTime + */ + long getMaxIdleTime(); + + /** + * Create a wrapper for the component instance for the scope management + * + * @return A wrapper for the component instance + */ + InstanceWrapper createInstanceWrapper(); + +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopedRuntimeComponent.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopedRuntimeComponent.java new file mode 100644 index 0000000000..c27b112f8a --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopedRuntimeComponent.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.runtime.RuntimeComponent; + +/** + * Scoped runtime component + * + * @version $Rev$ $Date$ + */ +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/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetDestructionException.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetDestructionException.java new file mode 100644 index 0000000000..0f83dad97d --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetDestructionException.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; + +/** + * Denotes an error destroying a target + * + * @version $Rev$ $Date$ + */ +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/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetInitializationException.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetInitializationException.java new file mode 100644 index 0000000000..15959c0608 --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetInitializationException.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; + +/** + * Denotes an error initializing a target + * + * @version $Rev$ $Date$ + */ +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/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetNotFoundException.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetNotFoundException.java new file mode 100644 index 0000000000..bb46a2499b --- /dev/null +++ b/branches/sca-java-2.0-M4/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/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetResolutionException.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetResolutionException.java new file mode 100644 index 0000000000..ea8d0e876c --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetResolutionException.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; + +/** + * Denotes an error retrieving a target instance + * + * @version $Rev$ $Date$ + */ +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/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/impl/CompositeScopeContainer.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/impl/CompositeScopeContainer.java new file mode 100644 index 0000000000..730f92e0f9 --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/impl/CompositeScopeContainer.java @@ -0,0 +1,87 @@ +/* + * 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<KEY> extends AbstractScopeContainer<KEY> { + 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) { + 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) { + 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/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/impl/CompositeScopeContainerFactory.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/impl/CompositeScopeContainerFactory.java new file mode 100644 index 0000000000..f61e70a598 --- /dev/null +++ b/branches/sca-java-2.0-M4/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/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/impl/ScopeRegistryImpl.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/impl/ScopeRegistryImpl.java new file mode 100644 index 0000000000..9884c5f053 --- /dev/null +++ b/branches/sca-java-2.0-M4/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<Scope, ScopeContainerFactory> scopeCache = new ConcurrentHashMap<Scope, ScopeContainerFactory>(); + + 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/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/impl/StatelessScopeContainer.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/impl/StatelessScopeContainer.java new file mode 100644 index 0000000000..1235fd2a67 --- /dev/null +++ b/branches/sca-java-2.0-M4/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<KEY> extends AbstractScopeContainer<KEY> { + + 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/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/impl/StatelessScopeContainerFactory.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/impl/StatelessScopeContainerFactory.java new file mode 100644 index 0000000000..5bf20a6a5f --- /dev/null +++ b/branches/sca-java-2.0-M4/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/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/DefaultWorkScheduler.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/DefaultWorkScheduler.java new file mode 100644 index 0000000000..9e6f3b3087 --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/DefaultWorkScheduler.java @@ -0,0 +1,195 @@ +/* + * 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 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. + * <p/> + * <p/> + * 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. </p> + * + * @version $Rev$ $Date$ + */ +public class DefaultWorkScheduler implements WorkScheduler, LifeCycleListener { + + /** + * Underlying JSR-237 work manager + */ + private ThreadPoolWorkManager jsr237WorkManager; + + /** + * Initializes the JSR 237 work manager. + * + * @param jsr237WorkManager JSR 237 work manager. + */ + public DefaultWorkScheduler() { + } + + 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(0); + } + 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 <T extends Runnable> 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 <T extends Runnable> void scheduleWork(T work, NotificationListener<T> listener) { + + if (work == null) { + throw new IllegalArgumentException("Work cannot be null"); + } + + Work<T> jsr237Work = new Work<T>(work); + try { + if (listener == null) { + getWorkManager().schedule(jsr237Work); + } else { + Jsr237WorkListener<T> jsr237WorkListener = new Jsr237WorkListener<T>(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<Object>() { + public Object run() { + ((ThreadPoolWorkManager)jsr237WorkManager).destroy(); + return null; + } + }); + } + } + + /* + * WorkListener for keeping track of work status callbacks. + * + */ + private class Jsr237WorkListener<T extends Runnable> implements WorkListener { + + // Notification listener + private NotificationListener<T> listener; + + // Work + private T work; + + /* + * Initializes the notification listener. + */ + public Jsr237WorkListener(NotificationListener<T> 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; + } + + } +} diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/ThreadPoolWorkManager.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/ThreadPoolWorkManager.java new file mode 100644 index 0000000000..e7728ca9a9 --- /dev/null +++ b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/ThreadPoolWorkManager.java @@ -0,0 +1,228 @@ +/* + * 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. + * <p/> + * <p/> + * This implementation supports only local work. + * <p/> + * TODO Elaborate the implementation. </p> + * + * @version $Rev$ $Date$ + */ +public class ThreadPoolWorkManager { + + // Map of work items currently handled by the work manager + private Map<WorkItem, WorkListener> workItems = new ConcurrentHashMap<WorkItem, WorkListener>(); + + // Thread-pool + private 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); + } + } + + /** + * 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(); + } + +} + diff --git a/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/Work.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/Work.java new file mode 100644 index 0000000000..ca06d0e854 --- /dev/null +++ b/branches/sca-java-2.0-M4/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<T extends Runnable> { + + // 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/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/WorkEvent.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/WorkEvent.java new file mode 100644 index 0000000000..4580011806 --- /dev/null +++ b/branches/sca-java-2.0-M4/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 <code>WorkEvent</code> 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/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/WorkItem.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/WorkItem.java new file mode 100644 index 0000000000..0fc104d0fc --- /dev/null +++ b/branches/sca-java-2.0-M4/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 <code>WorkItem</code> + * 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/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/WorkListener.java b/branches/sca-java-2.0-M4/modules/core/src/main/java/org/apache/tuscany/sca/core/work/impl/WorkListener.java new file mode 100644 index 0000000000..38bbaeebe0 --- /dev/null +++ b/branches/sca-java-2.0-M4/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); + +} |