diff options
Diffstat (limited to '')
16 files changed, 264 insertions, 181 deletions
diff --git a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/EndpointIntrospector.java b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/EndpointIntrospector.java index 0080e69540..c22506d560 100644 --- a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/EndpointIntrospector.java +++ b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/EndpointIntrospector.java @@ -21,9 +21,6 @@ package org.apache.tuscany.sca.osgi.remoteserviceadmin.impl; import static org.apache.tuscany.sca.assembly.Base.SCA11_TUSCANY_NS; import static org.apache.tuscany.sca.implementation.osgi.OSGiProperty.SCA_BINDINGS; -import static org.apache.tuscany.sca.implementation.osgi.OSGiProperty.SERVICE_EXPORTED_INTENTS; -import static org.apache.tuscany.sca.implementation.osgi.OSGiProperty.SERVICE_EXPORTED_INTENTS_EXTRA; -import static org.apache.tuscany.sca.implementation.osgi.OSGiProperty.SERVICE_EXPORTED_INTERFACES; import static org.apache.tuscany.sca.osgi.remoteserviceadmin.impl.OSGiHelper.getStringArray; import static org.osgi.framework.Constants.OBJECTCLASS; import static org.osgi.framework.Constants.SERVICE_ID; @@ -77,9 +74,9 @@ import org.apache.tuscany.sca.policy.PolicyFactory; import org.oasisopen.sca.ServiceRuntimeException; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; -import org.osgi.framework.Constants; import org.osgi.framework.ServiceReference; import org.osgi.service.remoteserviceadmin.EndpointDescription; +import org.osgi.service.remoteserviceadmin.RemoteConstants; import org.osgi.util.tracker.ServiceTracker; /** @@ -128,7 +125,6 @@ public class EndpointIntrospector { super(); // this.context = context; this.discoveryTracker = discoveryTracker; - // this.registry = registry; this.factories = registry.getExtensionPoint(FactoryExtensionPoint.class); this.modelResolvers = registry.getExtensionPoint(ModelResolverExtensionPoint.class); // this.compositeProcessor = @@ -192,10 +188,10 @@ public class EndpointIntrospector { } } for (Map.Entry<String, Object> p : props.entrySet()) { - if (Constants.OBJECTCLASS.equalsIgnoreCase(p.getKey())) { - throw new IllegalArgumentException(Constants.OBJECTCLASS + " property cannot be overridden."); - } else if (Constants.SERVICE_ID.equalsIgnoreCase(p.getKey())) { - throw new IllegalArgumentException(Constants.SERVICE_ID + " property cannot be overridden."); + if (OBJECTCLASS.equalsIgnoreCase(p.getKey())) { + throw new IllegalArgumentException(OBJECTCLASS + " property cannot be overridden."); + } else if (SERVICE_ID.equalsIgnoreCase(p.getKey())) { + throw new IllegalArgumentException(SERVICE_ID + " property cannot be overridden."); } String key = nameMap.get(p.getKey().toLowerCase()); if (key != null) { @@ -238,11 +234,12 @@ public class EndpointIntrospector { public Contribution introspect(ServiceReference reference, Map<String, Object> props) throws Exception { Bundle bundle = reference.getBundle(); Map<String, Object> properties = getProperties(reference, props); + Collection<OSGiProperty> osgiProps = implementationFactory.createOSGiProperties(reference); Long sid = (Long)reference.getProperty(SERVICE_ID); - String[] requiredIntents = getStringArray(properties.get(SERVICE_EXPORTED_INTENTS)); + String[] requiredIntents = getStringArray(properties.get(RemoteConstants.SERVICE_EXPORTED_INTENTS)); List<Intent> intents = getIntents(requiredIntents); - String[] requiredIntentsExtra = getStringArray(properties.get(SERVICE_EXPORTED_INTENTS_EXTRA)); + String[] requiredIntentsExtra = getStringArray(properties.get(RemoteConstants.SERVICE_EXPORTED_INTENTS_EXTRA)); List<Intent> extraIntents = getIntents(requiredIntentsExtra); Set<Intent> allIntents = new HashSet<Intent>(intents); allIntents.addAll(extraIntents); @@ -250,7 +247,7 @@ public class EndpointIntrospector { String[] bindingNames = getStringArray(properties.get(SCA_BINDINGS)); Collection<Binding> bindings = loadBindings(bindingNames); - String[] remoteInterfaces = getStringArray(reference.getProperty(SERVICE_EXPORTED_INTERFACES)); + String[] remoteInterfaces = getStringArray(reference.getProperty(RemoteConstants.SERVICE_EXPORTED_INTERFACES)); if (remoteInterfaces == null || remoteInterfaces.length > 0 && "*".equals(remoteInterfaces[0])) { remoteInterfaces = getStringArray(reference.getProperty(OBJECTCLASS)); } else { @@ -263,7 +260,7 @@ public class EndpointIntrospector { } } - Contribution contribution = generateContribution(bundle, sid, remoteInterfaces, bindings, allIntents); + Contribution contribution = generateContribution(bundle, sid, remoteInterfaces, bindings, allIntents, osgiProps); return contribution; } @@ -282,7 +279,8 @@ public class EndpointIntrospector { Long sid, String[] remoteInterfaces, Collection<Binding> bindings, - Set<Intent> allIntents) throws ClassNotFoundException, + Set<Intent> allIntents, + Collection<OSGiProperty> osgiProps) throws ClassNotFoundException, InvalidInterfaceException { String id = "osgi.service." + UUID.randomUUID(); Composite composite = assemblyFactory.createComposite(); @@ -311,12 +309,13 @@ public class EndpointIntrospector { service.setName(name); service.setInterfaceContract(interfaceContract); - service.getExtensions().add(serviceID); - implementation.getServices().add(service); ComponentService componentService = assemblyFactory.createComponentService(); componentService.setName(service.getName()); + componentService.getExtensions().add(serviceID); + componentService.getExtensions().addAll(osgiProps); + component.getServices().add(componentService); componentService.setService(service); } @@ -355,28 +354,31 @@ public class EndpointIntrospector { Collection<String> interfaces = Collections.emptyList(); Collection<Intent> intents = Collections.emptyList(); Endpoint ep = (Endpoint)endpoint.getProperties().get(Endpoint.class.getName()); + Collection<OSGiProperty> osgiProps = implementationFactory.createOSGiProperties(endpoint.getProperties()); if (ep != null) { bindings = Collections.singletonList(ep.getBinding()); interfaces = Collections.singletonList(((JavaInterface)ep.getComponentServiceInterfaceContract().getInterface()).getName()); - intents = ep.getRequiredIntents(); + // FIXME: [rfeng] We need to build the in-memory composite so that intents are calculated at the ep level + intents = ep.getService().getRequiredIntents(); } else { Map<String, Object> properties = endpoint.getProperties(); interfaces = endpoint.getInterfaces(); - String[] requiredIntents = getStringArray(properties.get(SERVICE_EXPORTED_INTENTS)); + String[] requiredIntents = getStringArray(properties.get(RemoteConstants.SERVICE_INTENTS)); intents = getIntents(requiredIntents); String[] bindingNames = getStringArray(properties.get(SCA_BINDINGS)); bindings = loadBindings(bindingNames); } - Contribution contribution = generateContribution(bundle, interfaces, bindings, intents); + Contribution contribution = generateContribution(bundle, interfaces, bindings, intents, osgiProps); return contribution; } private Contribution generateContribution(Bundle bundle, Collection<String> remoteInterfaces, Collection<Binding> bindings, - Collection<Intent> intents) throws ClassNotFoundException, + Collection<Intent> intents, + Collection<OSGiProperty> osgiProps) throws ClassNotFoundException, InvalidInterfaceException, ContributionResolveException { String id = "osgi.reference." + UUID.randomUUID(); Composite composite = assemblyFactory.createComposite(); @@ -406,6 +408,7 @@ public class EndpointIntrospector { ComponentReference componentReference = assemblyFactory.createComponentReference(); componentReference.setName(reference.getName()); + componentReference.getExtensions().addAll(osgiProps); component.getReferences().add(componentReference); componentReference.setReference(reference); componentReference.setWiredByImpl(true); diff --git a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/ExportReferenceImpl.java b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/ExportReferenceImpl.java index 473e5742e9..13c7dd3cf3 100644 --- a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/ExportReferenceImpl.java +++ b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/ExportReferenceImpl.java @@ -19,23 +19,28 @@ package org.apache.tuscany.sca.osgi.remoteserviceadmin.impl; +import org.apache.tuscany.sca.node.Node; import org.osgi.framework.ServiceReference; import org.osgi.service.remoteserviceadmin.EndpointDescription; import org.osgi.service.remoteserviceadmin.ExportReference; +import org.osgi.service.remoteserviceadmin.ExportRegistration; /** * */ public class ExportReferenceImpl implements ExportReference { + private Node node; private final ServiceReference exportedService; private final EndpointDescription endpointDescription; + private int count; /** * @param exportedService * @param endpointDescription */ - public ExportReferenceImpl(ServiceReference exportedService, EndpointDescription endpointDescription) { + public ExportReferenceImpl(Node node, ServiceReference exportedService, EndpointDescription endpointDescription) { super(); + this.node = node; this.exportedService = exportedService; this.endpointDescription = endpointDescription; } @@ -47,6 +52,22 @@ public class ExportReferenceImpl implements ExportReference { public EndpointDescription getExportedEndpoint() { return endpointDescription; } + + public synchronized ExportRegistration register() { + count++; + return new ExportRegistrationImpl(this); + } + public synchronized void unregister() { + if (count > 0) { + count--; + } + if (count == 0) { + if (node != null) { + node.stop(); + node = null; + } + } + } } diff --git a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/ExportRegistrationImpl.java b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/ExportRegistrationImpl.java index 2335d31020..39cbd7b9e6 100644 --- a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/ExportRegistrationImpl.java +++ b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/ExportRegistrationImpl.java @@ -19,7 +19,6 @@ package org.apache.tuscany.sca.osgi.remoteserviceadmin.impl; -import org.apache.tuscany.sca.node.Node; import org.osgi.framework.ServiceReference; import org.osgi.service.remoteserviceadmin.EndpointDescription; import org.osgi.service.remoteserviceadmin.ExportReference; @@ -29,8 +28,7 @@ import org.osgi.service.remoteserviceadmin.ExportRegistration; * Implementation of {@link ExportRegistration} */ public class ExportRegistrationImpl implements ExportRegistration { - private Node node; - private ExportReference exportReference; + private ExportReferenceImpl exportReference; private Throwable exception; /** @@ -38,13 +36,9 @@ public class ExportRegistrationImpl implements ExportRegistration { * @param endpointDescription * @param exception */ - public ExportRegistrationImpl(Node node, - ServiceReference exportedService, - EndpointDescription endpointDescription, - Throwable exception) { + public ExportRegistrationImpl(ExportReferenceImpl exportReference, Throwable exception) { super(); - this.node = node; - this.exportReference = new ExportReferenceImpl(exportedService, endpointDescription); + this.exportReference = exportReference; this.exception = exception; } @@ -52,20 +46,19 @@ public class ExportRegistrationImpl implements ExportRegistration { * @param exportedService * @param endpointDescription */ - public ExportRegistrationImpl(Node node, ServiceReference exportedService, EndpointDescription endpointDescription) { - this(node, exportedService, endpointDescription, null); + public ExportRegistrationImpl(ExportReferenceImpl exportReference) { + this(exportReference, null); } /** * @see org.osgi.remoteserviceadmin.ExportRegistration#close() */ public void close() { - if (node != null) { - node.stop(); - node = null; + if (exportReference != null) { + exportReference.unregister(); } exception = null; - exportReference = new ExportReferenceImpl(null, null); + exportReference = null; } public ServiceReference getExportedService() { @@ -80,10 +73,6 @@ public class ExportRegistrationImpl implements ExportRegistration { return exception; } - public Node getNode() { - return node; - } - public ExportReference getExportReference() throws IllegalStateException { return exportReference; } diff --git a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/ImportReferenceImpl.java b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/ImportReferenceImpl.java index 8ecc696795..9c5b1818c8 100644 --- a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/ImportReferenceImpl.java +++ b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/ImportReferenceImpl.java @@ -19,24 +19,28 @@ package org.apache.tuscany.sca.osgi.remoteserviceadmin.impl; +import org.apache.tuscany.sca.node.Node; import org.osgi.framework.ServiceReference; import org.osgi.service.remoteserviceadmin.EndpointDescription; import org.osgi.service.remoteserviceadmin.ImportReference; +import org.osgi.service.remoteserviceadmin.ImportRegistration; /** - * + * Implementation of ImportReference. It keeps a reference count of ImportRegistrations */ public class ImportReferenceImpl implements ImportReference { - + private Node node; private final ServiceReference importedService; private final EndpointDescription endpointDescription; + private int count = 0; /** * @param exportedService * @param endpointDescription */ - public ImportReferenceImpl(ServiceReference importedService, EndpointDescription endpointDescription) { + public ImportReferenceImpl(Node node, ServiceReference importedService, EndpointDescription endpointDescription) { super(); + this.node = node; this.importedService = importedService; this.endpointDescription = endpointDescription; } @@ -48,5 +52,21 @@ public class ImportReferenceImpl implements ImportReference { public EndpointDescription getImportedEndpoint() { return endpointDescription; } + + public synchronized ImportRegistration register() { + count++; + return new ImportRegistrationImpl(this); + } + public synchronized void unregister() { + if (count > 0) { + count--; + } + if (count == 0) { + if (node != null) { + node.stop(); + node = null; + } + } + } } diff --git a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/ImportRegistrationImpl.java b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/ImportRegistrationImpl.java index 8961d031cc..9506128286 100644 --- a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/ImportRegistrationImpl.java +++ b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/ImportRegistrationImpl.java @@ -19,9 +19,6 @@ package org.apache.tuscany.sca.osgi.remoteserviceadmin.impl; -import org.apache.tuscany.sca.node.Node; -import org.osgi.framework.ServiceReference; -import org.osgi.service.remoteserviceadmin.EndpointDescription; import org.osgi.service.remoteserviceadmin.ImportReference; import org.osgi.service.remoteserviceadmin.ImportRegistration; @@ -29,55 +26,43 @@ import org.osgi.service.remoteserviceadmin.ImportRegistration; * */ public class ImportRegistrationImpl implements ImportRegistration { - private Node node; - private ImportReference importReference; + private ImportReferenceImpl importReference; private Throwable exception; /** - * @param exportedService - * @param endpointDescription - * @param exception + * @param importReference */ - public ImportRegistrationImpl(Node node, - ServiceReference importedService, - EndpointDescription endpointDescription, - Throwable exception) { + public ImportRegistrationImpl(ImportReferenceImpl importReference) { super(); - this.node = node; - this.importReference = new ImportReferenceImpl(importedService, endpointDescription); - this.exception = exception; + this.importReference = importReference; } /** * @param exportedService * @param endpointDescription + * @param exception */ - public ImportRegistrationImpl(Node node, ServiceReference importedService, EndpointDescription endpointDescription) { + public ImportRegistrationImpl(ImportReferenceImpl importReference, Throwable exception) { super(); - this.node = node; - this.importReference = new ImportReferenceImpl(importedService, endpointDescription); + this.importReference = importReference; + this.exception = exception; } /** * @see org.osgi.remoteserviceadmin.ImportRegistration#close() */ public void close() { - if (node != null) { - node.stop(); - node = null; + if (importReference != null) { + importReference.unregister(); } exception = null; - importReference = new ImportReferenceImpl(null, null); + importReference = null; } public Throwable getException() { return exception; } - public Node getNode() { - return node; - } - public ImportReference getImportReference() { return importReference; } diff --git a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/OSGiServiceExporter.java b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/OSGiServiceExporter.java index b644ca14c9..4466c04563 100644 --- a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/OSGiServiceExporter.java +++ b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/OSGiServiceExporter.java @@ -31,6 +31,9 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Level; +import java.util.logging.Logger; import org.apache.tuscany.sca.assembly.Component; import org.apache.tuscany.sca.assembly.ComponentService; @@ -48,6 +51,10 @@ import org.osgi.util.tracker.ServiceTrackerCustomizer; * Watching and exporting OSGi services */ public class OSGiServiceExporter extends AbstractOSGiServiceHandler implements ServiceTrackerCustomizer { + private final static Logger logger = Logger.getLogger(OSGiServiceExporter.class.getName()); + + private Map<EndpointDescription, ExportReferenceImpl> exportReferences = + new ConcurrentHashMap<EndpointDescription, ExportReferenceImpl>(); /** * @param context @@ -62,6 +69,11 @@ public class OSGiServiceExporter extends AbstractOSGiServiceHandler implements S init(); } + public void stop() { + exportReferences.clear(); + super.stop(); + } + public Object addingService(ServiceReference reference) { return exportService(reference, null); } @@ -97,17 +109,23 @@ public class OSGiServiceExporter extends AbstractOSGiServiceHandler implements S List<ExportRegistration> exportedServices = new ArrayList<ExportRegistration>(); for (Endpoint endpoint : service.getEndpoints()) { EndpointDescription endpointDescription = createEndpointDescription(context, endpoint); - ExportRegistration exportRegistration = - new ExportRegistrationImpl(node, reference, endpointDescription); - exportedServices.add(exportRegistration); + synchronized (this) { + ExportReferenceImpl exportReference = exportReferences.get(endpointDescription); + if (exportReference == null) { + exportReference = new ExportReferenceImpl(node, reference, endpointDescription); + } + ExportRegistration exportRegistration = exportReference.register(); + exportedServices.add(exportRegistration); + } } return exportedServices; } else { return null; } } catch (Exception e) { - e.printStackTrace(); - return null; + logger.log(Level.SEVERE, e.getMessage(), e); + ExportRegistration exportRegistration = new ExportRegistrationImpl(null, e); + return Collections.singletonList(exportRegistration); } } @@ -118,7 +136,7 @@ public class OSGiServiceExporter extends AbstractOSGiServiceHandler implements S public void removedService(ServiceReference reference, Object service) { List<ExportRegistration> exportedServices = (List<ExportRegistration>)service; - for(ExportRegistration exportRegistration: exportedServices) { + for (ExportRegistration exportRegistration : exportedServices) { exportRegistration.close(); } } diff --git a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/OSGiServiceImporter.java b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/OSGiServiceImporter.java index d33fd5a5e6..f24e9af7c1 100644 --- a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/OSGiServiceImporter.java +++ b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/OSGiServiceImporter.java @@ -20,11 +20,14 @@ package org.apache.tuscany.sca.osgi.remoteserviceadmin.impl; import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Level; +import java.util.logging.Logger; import org.apache.tuscany.sca.assembly.Component; import org.apache.tuscany.sca.assembly.ComponentReference; import org.apache.tuscany.sca.contribution.Contribution; -import org.apache.tuscany.sca.node.Node; import org.apache.tuscany.sca.node.configuration.NodeConfiguration; import org.apache.tuscany.sca.node.impl.NodeImpl; import org.osgi.framework.Bundle; @@ -37,6 +40,9 @@ import org.osgi.service.remoteserviceadmin.ImportRegistration; * Watching and exporting OSGi services */ public class OSGiServiceImporter extends AbstractOSGiServiceHandler { + private final static Logger logger = Logger.getLogger(OSGiServiceImporter.class.getName()); + private Map<EndpointDescription, ImportReferenceImpl> importReferences = + new ConcurrentHashMap<EndpointDescription, ImportReferenceImpl>(); /** * @param context @@ -51,6 +57,11 @@ public class OSGiServiceImporter extends AbstractOSGiServiceHandler { // Defer init() to importService() } + public void stop() { + importReferences.clear(); + super.stop(); + } + public ImportRegistration importService(Bundle bundle, EndpointDescription endpointDescription) { init(); try { @@ -77,19 +88,27 @@ public class OSGiServiceImporter extends AbstractOSGiServiceHandler { + "#reference(" + componentReference.getName() + ")"); - return new ImportRegistrationImpl(node, serviceReference, endpointDescription); + synchronized (this) { + ImportReferenceImpl importReference = importReferences.get(endpointDescription); + if (importReference == null) { + importReference = new ImportReferenceImpl(node, serviceReference, endpointDescription); + importReferences.put(endpointDescription, importReference); + } + return importReference.register(); + } } else { return null; } } catch (Exception e) { - e.printStackTrace(); - return null; + logger.log(Level.SEVERE, e.getMessage(), e); + return new ImportRegistrationImpl(null, e); } } public void unimportService(ImportRegistration importRegistration) { - Node node = (Node)importRegistration.getImportReference().getImportedService().getProperty("sca.node"); - node.stop(); + if (importRegistration != null) { + importRegistration.close(); + } } } diff --git a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/RemoteServiceAdminImpl.java b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/RemoteServiceAdminImpl.java index f4521cfbfc..b1ebeb9df0 100644 --- a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/RemoteServiceAdminImpl.java +++ b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/RemoteServiceAdminImpl.java @@ -253,9 +253,9 @@ public class RemoteServiceAdminImpl implements RemoteServiceAdmin, ManagedServic } else { ep = rsaEvent.getExportReference().getExportedEndpoint(); } - props.put("endpoint.service.id", ep.getRemoteServiceID()); - props.put("endpoint.framework.uuid", ep.getRemoteFrameworkUUID()); - props.put("endpoint.id", ep.getRemoteID()); + props.put("endpoint.service.id", ep.getServiceId()); + props.put("endpoint.framework.uuid", ep.getFrameworkUUID()); + props.put("endpoint.id", ep.getId()); props.put("objectClass", ep.getInterfaces()); props.put("service.imported.configs", ep.getConfigurationTypes()); props.put("timestamp", new Long(System.currentTimeMillis())); diff --git a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/AbstractDiscoveryService.java b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/AbstractDiscoveryService.java index 4bbf130c74..886e79197d 100644 --- a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/AbstractDiscoveryService.java +++ b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/AbstractDiscoveryService.java @@ -64,7 +64,7 @@ public abstract class AbstractDiscoveryService implements Discovery, LifeCycleLi private Map<String, List<EndpointListener>> filtersToListeners = new HashMap<String, List<EndpointListener>>(); // this is effectively a set which allows for multiple service descriptions with the // same interface name but different properties and takes care of itself with respect to concurrency - protected Map<EndpointDescription, Bundle> servicesInfo = new ConcurrentHashMap<EndpointDescription, Bundle>(); + protected Map<EndpointDescription, Bundle> endpointDescriptions = new ConcurrentHashMap<EndpointDescription, Bundle>(); private Map<EndpointListener, Collection<String>> listenersToFilters = new HashMap<EndpointListener, Collection<String>>(); private ServiceTracker trackerTracker; @@ -176,7 +176,7 @@ public abstract class AbstractDiscoveryService implements Discovery, LifeCycleLi } if (logger.isLoggable(Level.FINE)) { - if (servicesInfo.size() > 0) { + if (endpointDescriptions.size() > 0) { logger.fine("search for matches to trigger callbacks with delta: " + deltaInterest); } else { logger.fine("nothing to search for matches to trigger callbacks with delta: " + deltaInterest); @@ -185,7 +185,7 @@ public abstract class AbstractDiscoveryService implements Discovery, LifeCycleLi Iterator<String> i = deltaInterest.iterator(); while (i.hasNext()) { String next = i.next(); - for (EndpointDescription sd : servicesInfo.keySet()) { + for (EndpointDescription sd : endpointDescriptions.keySet()) { triggerCallbacks(listener, next, sd, ADDED); } } @@ -267,7 +267,7 @@ public abstract class AbstractDiscoveryService implements Discovery, LifeCycleLi return collection; } - protected void endpointChanged(EndpointDescription sd, int type) { + protected synchronized void endpointChanged(EndpointDescription sd, int type) { for (Map.Entry<EndpointListener, Collection<String>> entry : listenersToFilters.entrySet()) { for (String filter : entry.getValue()) { if (filterMatches(filter, sd)) { diff --git a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/DomainDiscoveryService.java b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/DomainDiscoveryService.java index a7c6d04ee9..a02be672a2 100644 --- a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/DomainDiscoveryService.java +++ b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/DomainDiscoveryService.java @@ -65,7 +65,7 @@ public class DomainDiscoveryService extends AbstractDiscoveryService implements thread.start(); } - private void startEndpointRegistry() { + private synchronized void startEndpointRegistry() { // The following code forced the start() of the domain registry in absense of services String domainRegistry = context.getProperty("org.osgi.sca.domain.registry"); if (domainRegistry == null) { @@ -80,7 +80,7 @@ public class DomainDiscoveryService extends AbstractDiscoveryService implements } } - public void endpointAdded(Endpoint endpoint) { + public synchronized void endpointAdded(Endpoint endpoint) { Implementation impl = endpoint.getComponent().getImplementation(); if (!(impl instanceof OSGiImplementation)) { return; @@ -94,59 +94,35 @@ public class DomainDiscoveryService extends AbstractDiscoveryService implements bundleContext = bundle != null ? bundle.getBundleContext() : null; } - /* - if (!endpoint.isRemote()) { - Interface intf = endpoint.getService().getInterfaceContract().getInterface(); - JavaInterface javaInterface = (JavaInterface)intf; - // String filter = getOSGiFilter(provider.getOSGiProperties(service)); - // FIXME: What is the filter? - String filter = "(!(sca.reference=*))"; - // "(sca.service=" + component.getURI() + "#service-name\\(" + service.getName() + "\\))"; - ServiceReference ref = null; - try { - ref = bundleContext.getServiceReferences(javaInterface.getName(), filter)[0]; - } catch (InvalidSyntaxException e) { - // Ignore - } - if (ref != null) { - - } - } else - */ - { // Notify the endpoint listeners EndpointDescription description = createEndpointDescription(bundleContext, endpoint); // Set the owning bundle to runtime bundle to avoid NPE - servicesInfo.put(description, context.getBundle()); + endpointDescriptions.put(description, context.getBundle()); endpointChanged(description, ADDED); - } } - public void endpointRemoved(Endpoint endpoint) { - /* - if (!endpoint.isRemote()) { - // export services - } else - */ - { + public synchronized void endpointRemoved(Endpoint endpoint) { EndpointDescription description = createEndpointDescription(context, endpoint); - servicesInfo.remove(description); + endpointDescriptions.remove(description); endpointChanged(description, REMOVED); - } } - public void endpointUpdated(Endpoint oldEndpoint, Endpoint newEndpoint) { + public synchronized void endpointUpdated(Endpoint oldEndpoint, Endpoint newEndpoint) { // FIXME: This is a quick and dirty way for the update endpointRemoved(oldEndpoint); endpointAdded(newEndpoint); } public void stop() { - domainRegistryFactory.removeListener(this); - if (endpointRegistry instanceof LifeCycleListener) { - ((LifeCycleListener)endpointRegistry).stop(); + if (domainRegistryFactory != null) { + domainRegistryFactory.removeListener(this); + if (endpointRegistry instanceof LifeCycleListener) { + ((LifeCycleListener)endpointRegistry).stop(); + } + domainRegistryFactory = null; + endpointRegistry = null; + super.stop(); } - super.stop(); } @Override diff --git a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/LocalDiscoveryService.java b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/LocalDiscoveryService.java index a4c9414b92..56a830a1e6 100644 --- a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/LocalDiscoveryService.java +++ b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/LocalDiscoveryService.java @@ -105,7 +105,7 @@ public class LocalDiscoveryService extends AbstractDiscoveryService implements B } private void removeServicesDeclaredInBundle(Bundle bundle) { - for (Iterator<Map.Entry<EndpointDescription, Bundle>> i = servicesInfo.entrySet().iterator(); i.hasNext();) { + for (Iterator<Map.Entry<EndpointDescription, Bundle>> i = endpointDescriptions.entrySet().iterator(); i.hasNext();) { Entry<EndpointDescription, Bundle> entry = i.next(); if (entry.getValue().equals(bundle)) { serviceDescriptionRemoved(entry.getKey()); @@ -163,7 +163,7 @@ public class LocalDiscoveryService extends AbstractDiscoveryService implements B for (ServiceDescriptions sds : extender.getRemoteServiceDescriptions()) { for (ServiceDescription sd : sds) { EndpointDescription sed = createEndpointDescription(sd); - servicesInfo.put(sed, bundle); + endpointDescriptions.put(sed, bundle); serviceDescriptionAdded(sed); } } diff --git a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/EndpointDescription.java b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/EndpointDescription.java index 65f1000265..ee7e5ba1bd 100644 --- a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/EndpointDescription.java +++ b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/EndpointDescription.java @@ -65,9 +65,9 @@ import org.osgi.framework.Version; public class EndpointDescription { private final Map<String, Object> properties; private final List<String> interfaces; - private final long remoteServiceID; - private final String remoteFrameworkUUID; - private final String remoteID; + private final long serviceId; + private final String frameworkUUID; + private final String id; /** * Create an Endpoint Description from a Map. @@ -110,10 +110,10 @@ public class EndpointDescription { this.properties = Collections.unmodifiableMap(props); /* properties must be initialized before calling the following methods */ interfaces = verifyObjectClassProperty(); - remoteServiceID = verifyLongProperty(ENDPOINT_SERVICE_ID); - remoteFrameworkUUID = verifyStringProperty(ENDPOINT_FRAMEWORK_UUID); - remoteID = verifyStringProperty(ENDPOINT_ID); - if (remoteID == null) { + serviceId = verifyLongProperty(ENDPOINT_SERVICE_ID); + frameworkUUID = verifyStringProperty(ENDPOINT_FRAMEWORK_UUID); + id = verifyStringProperty(ENDPOINT_ID); + if (id == null) { throw new IllegalArgumentException(ENDPOINT_ID + " property must be set"); } @@ -204,10 +204,10 @@ public class EndpointDescription { this.properties = Collections.unmodifiableMap(props); /* properties must be initialized before calling the following methods */ interfaces = verifyObjectClassProperty(); - remoteServiceID = verifyLongProperty(ENDPOINT_SERVICE_ID); - remoteFrameworkUUID = verifyStringProperty(ENDPOINT_FRAMEWORK_UUID); - remoteID = verifyStringProperty(ENDPOINT_ID); - if (remoteID == null) { + serviceId = verifyLongProperty(ENDPOINT_SERVICE_ID); + frameworkUUID = verifyStringProperty(ENDPOINT_FRAMEWORK_UUID); + id = verifyStringProperty(ENDPOINT_ID); + if (id == null) { throw new IllegalArgumentException(ENDPOINT_ID + " property must be set"); } @@ -312,8 +312,8 @@ public class EndpointDescription { * * @return The id of the endpoint, never <code>null</code>. */ - public String getRemoteID() { - return remoteID; + public String getId() { + return id; } /** @@ -382,8 +382,8 @@ public class EndpointDescription { * not relate to an OSGi service. * */ - public long getRemoteServiceID() { - return remoteServiceID; + public long getServiceId() { + return serviceId; } /** @@ -477,8 +477,8 @@ public class EndpointDescription { * @return Remote Framework UUID, or null if this endpoint is not associated * with an OSGi framework having a framework uuid. */ - public String getRemoteFrameworkUUID() { - return remoteFrameworkUUID; + public String getFrameworkUUID() { + return frameworkUUID; } /** @@ -507,13 +507,13 @@ public class EndpointDescription { return true; } - if (this.getRemoteFrameworkUUID() == null) { + if (this.getFrameworkUUID() == null) { return false; } - return (this.getRemoteServiceID() == other.getRemoteServiceID()) - && this.getRemoteFrameworkUUID().equals( - other.getRemoteFrameworkUUID()); + return (this.getServiceId() == other.getServiceId()) + && this.getFrameworkUUID().equals( + other.getFrameworkUUID()); } /** @@ -522,7 +522,7 @@ public class EndpointDescription { * @return An integer which is a hash code value for this object. */ public int hashCode() { - return getRemoteID().hashCode(); + return getId().hashCode(); } /** @@ -544,8 +544,8 @@ public class EndpointDescription { if (!(other instanceof EndpointDescription)) { return false; } - return getRemoteID().equals( - ((EndpointDescription) other).getRemoteID()); + return getId().equals( + ((EndpointDescription) other).getId()); } /** @@ -580,6 +580,63 @@ public class EndpointDescription { } /** + * Returns the string representation of this EndpointDescription. + * + * @return String form of this EndpointDescription. + */ + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append('{'); + Iterator<Map.Entry<String, Object>> iter = properties.entrySet() + .iterator(); + boolean comma = false; + while (iter.hasNext()) { + Map.Entry<String, Object> entry = iter.next(); + if (comma) { + sb.append(", "); + } + else { + comma = true; + } + sb.append(entry.getKey()); + sb.append('='); + Object value = entry.getValue(); + if (value != null) { + Class< ? > valueType = value.getClass(); + if (Object[].class.isAssignableFrom(valueType)) { + append(sb, (Object[]) value); + continue; + } + } + sb.append(value); + } + sb.append('}'); + return sb.toString(); + } + + /** + * Append the specified Object array to the specified StringBuffer. + * + * @param sb Receiving StringBuffer. + * @param value Object array to append to the specified StringBuffer. + */ + private static void append(StringBuffer sb, Object[] value) { + sb.append('['); + boolean comma = false; + final int length = value.length; + for (int i = 0; i < length; i++) { + if (comma) { + sb.append(", "); + } + else { + comma = true; + } + sb.append(String.valueOf(value[i])); + } + sb.append(']'); + } + + /** * Unmodifiable Dictionary wrapper for a Map. This class is also used by * EndpointPermission. */ diff --git a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/EndpointListener.java b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/EndpointListener.java index 9a56c53f4f..941b899fbb 100644 --- a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/EndpointListener.java +++ b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/EndpointListener.java @@ -23,17 +23,17 @@ package org.osgi.service.remoteserviceadmin; * is interested in Endpoint Descriptions. * * This white board service can be used in many different scenarios. However, - * the primary use case is to allow a remote manager to be informed of End Point + * the primary use case is to allow a remote manager to be informed of Endpoint * Descriptions available in the network and inform the network about available - * End Point Descriptions. + * Endpoint Descriptions. * * Both the network bundle and the manager bundle register an Endpoint Listener - * service. The manager informs the network bundle about End Points that it + * service. The manager informs the network bundle about Endpoints that it * creates. The network bundles then uses a protocol like SLP to announce these * local end-points to the network. * * If the network bundle discovers a new Endpoint through its discovery - * protocol, then it sends an End Point Description to all the End Point + * protocol, then it sends an Endpoint Description to all the Endpoint * Listener services that are registered (except its own) that have specified an * interest in that endpoint. * diff --git a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/EndpointPermission.java b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/EndpointPermission.java index 84a7ba512e..433e22e543 100644 --- a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/EndpointPermission.java +++ b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/EndpointPermission.java @@ -165,11 +165,11 @@ public final class EndpointPermission extends Permission { setTransients(null, parseActions(actions)); Map<String, Object> props; if ((localFrameworkUUID != null) - && localFrameworkUUID.equals(endpoint.getRemoteFrameworkUUID())) { + && localFrameworkUUID.equals(endpoint.getFrameworkUUID())) { props = new TreeMap<String, Object>(String.CASE_INSENSITIVE_ORDER); props.putAll(endpoint.getProperties()); props.put(ENDPOINT_FRAMEWORK_UUID, new String[] { - endpoint.getRemoteFrameworkUUID(), "<<LOCAL>>"}); + endpoint.getFrameworkUUID(), "<<LOCAL>>"}); } else { props = endpoint.getProperties(); @@ -190,7 +190,7 @@ public final class EndpointPermission extends Permission { throw new IllegalArgumentException("invalid endpoint: null"); } StringBuffer sb = new StringBuffer("(" + ENDPOINT_ID + "="); - sb.append(endpoint.getRemoteID()); + sb.append(endpoint.getId()); sb.append(")"); return sb.toString(); } diff --git a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/RemoteServiceAdmin.java b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/RemoteServiceAdmin.java index 0b436c361a..98f56a07ae 100644 --- a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/RemoteServiceAdmin.java +++ b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/RemoteServiceAdmin.java @@ -36,15 +36,13 @@ import org.osgi.framework.ServiceReference; public interface RemoteServiceAdmin { /** - * Export a service to a given endpoint. The Remote Service Admin must - * create an endpoint from the given description that can be used by other + * Export a service to a given Endpoint. The Remote Service Admin must + * create an Endpoint from the given description that can be used by other * Distrbution Providers to connect to this Remote Service Admin and use the * exported service. This method can return null if the service could not be - * exported because the endpoint could not be implemented by this Remote + * exported because the Endpoint could not be implemented by this Remote * Service Admin. * - * TODO Peter to update for case insensitive properties - * * The properties on a Service Reference are case insensitive while the * properties on a <code>properties</code> are case sensitive. A value in * the <code>properties</code> must therefore override any case variant in @@ -52,26 +50,23 @@ public interface RemoteServiceAdmin { * * <p> * If the caller does not have the appropriate - * <code>EndpointPermission[endpoint,EXPORT]</code> for an endpoint, and the + * <code>EndpointPermission[endpoint,EXPORT]</code> for an Endpoint, and the * Java Runtime Environment supports permissions, then the * {@link ExportRegistration#getException() getException} method on the * corresponding returned {@link ExportRegistration} will return a * <code>SecurityException</code>. * * @param reference The Service Reference to export. - * @param properties The properties to create a local endpoint that can be + * @param properties The properties to create a local Endpoint that can be * implemented by this Remote Service Admin. If this is null, the - * endpoint will be determined by the properties on the service. The + * Endpoint will be determined by the properties on the service. The * properties are the same as given for an exported service. They are * overlaid over any properties the service defines (case * insensitive). This parameter can be <code>null</code>, this should * be treated as an empty map. * - * TODO Peter The return description does not mesh with returning a - * list! Why a list and not just one? * @return An Export Registration that combines the Endpoint Description and - * the Service Reference or <code>null</code> if the service could - * not be exported. + * the Service Reference. Is never <code>null</code>. * @throws IllegalArgumentException If any of the properties has a value * that is not syntactically correct or if the service properties * and the overlaid properties do not contain a @@ -84,17 +79,17 @@ public interface RemoteServiceAdmin { Map<String, Object> properties); /** - * Import a service from an endpoint. The Remote Service Admin must use the - * given endpoint to create a proxy. This method can return null if the + * Import a service from an Endpoint. The Remote Service Admin must use the + * given Endpoint to create a proxy. This method can return null if the * service could not be imported. * * @param endpoint The Endpoint Description to be used for import. * @return An Import Registration that combines the Endpoint Description and - * the Service Reference or <code>null</code> if the endpoint could + * the Service Reference or <code>null</code> if the Endpoint could * not be imported. * @throws SecurityException If the caller does not have the appropriate * <code>EndpointPermission[endpoint,IMPORT]</code> for the - * endpoint, and the Java Runtime Environment supports permissions. + * Endpoint, and the Java Runtime Environment supports permissions. */ ImportRegistration importService(EndpointDescription endpoint); @@ -103,9 +98,9 @@ public interface RemoteServiceAdmin { * * <p> * If the caller does not have the appropriate - * <code>EndpointPermission[endpoint,READ]</code> for an endpoint, and the + * <code>EndpointPermission[endpoint,READ]</code> for an Endpoint, and the * Java Runtime Environment supports permissions, then returned collection - * will not contain a reference to the exported endpoint. + * will not contain a reference to the exported Endpoint. * * @return A <code>Collection</code> of {@link ExportReference}s that are * currently active. @@ -117,9 +112,9 @@ public interface RemoteServiceAdmin { * * <p> * If the caller does not have the appropriate - * <code>EndpointPermission[endpoint,READ]</code> for an endpoint, and the + * <code>EndpointPermission[endpoint,READ]</code> for an Endpoint, and the * Java Runtime Environment supports permissions, then returned collection - * will not contain a reference to the imported endpoint. + * will not contain a reference to the imported Endpoint. * * @return A <code>Collection</code> of {@link ImportReference}s that are * currently active. diff --git a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/RemoteServiceAdminListener.java b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/RemoteServiceAdminListener.java index 0030b870c7..2941f8b117 100644 --- a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/RemoteServiceAdminListener.java +++ b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/RemoteServiceAdminListener.java @@ -17,7 +17,7 @@ package org.osgi.service.remoteserviceadmin; /** - * A {@link RemoteServiceAdminEvent} listener is notified asynchronously of any + * A {@link RemoteServiceAdminEvent} listener is notified synchronously of any * export or import registrations and unregistrations. * * <p> @@ -36,7 +36,7 @@ package org.osgi.service.remoteserviceadmin; public interface RemoteServiceAdminListener { /** * Receive notification of any export or import registrations and - * unregistrations. + * unregistrations as well as errors and warnings. * * @param event The {@link RemoteServiceAdminEvent} object. */ |