/*
* 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.osgi.remoteserviceadmin.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import org.apache.tuscany.sca.core.ExtensionPointRegistry;
import org.apache.tuscany.sca.core.UtilityExtensionPoint;
import org.apache.tuscany.sca.definitions.Definitions;
import org.apache.tuscany.sca.deployment.Deployer;
import org.apache.tuscany.sca.policy.BindingType;
import org.apache.tuscany.sca.policy.Intent;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedService;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventAdmin;
import org.osgi.service.remoteserviceadmin.EndpointDescription;
import org.osgi.service.remoteserviceadmin.ExportReference;
import org.osgi.service.remoteserviceadmin.ExportRegistration;
import org.osgi.service.remoteserviceadmin.ImportReference;
import org.osgi.service.remoteserviceadmin.ImportRegistration;
import org.osgi.service.remoteserviceadmin.RemoteConstants;
import org.osgi.service.remoteserviceadmin.RemoteServiceAdmin;
import org.osgi.service.remoteserviceadmin.RemoteServiceAdminEvent;
import org.osgi.service.remoteserviceadmin.RemoteServiceAdminListener;
import org.osgi.util.tracker.ServiceTracker;
/**
* SCA Implementation of {@link RemoteServiceAdmin}
*/
public class RemoteServiceAdminImpl implements RemoteServiceAdmin, ManagedService {
private BundleContext context;
private ServiceRegistration registration;
private ServiceRegistration managedService;
private ServiceTracker listeners;
private OSGiServiceExporter exporter;
private OSGiServiceImporter importer;
private Collection<ImportRegistration> importRegistrations = new ArrayList<ImportRegistration>();
private Collection<ExportRegistration> exportedRegistrations = new ArrayList<ExportRegistration>();
public RemoteServiceAdminImpl(BundleContext context) {
this.context = context;
}
public void start() {
this.exporter = new OSGiServiceExporter(context);
this.importer = new OSGiServiceImporter(context);
exporter.start();
importer.start();
Hashtable<String, Object> props = new Hashtable<String, Object>();
props.put(RemoteConstants.REMOTE_CONFIGS_SUPPORTED, new String[] {"org.osgi.sca"});
ExtensionPointRegistry registry = exporter.getExtensionPointRegistry();
UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class);
Deployer deployer = utilities.getUtility(Deployer.class);
Definitions definitions = deployer.getSystemDefinitions();
String[] intents = new String[definitions.getIntents().size()];
int i = 0;
for (Intent intent : definitions.getIntents()) {
intents[i++] = intent.toString();
}
String[] bindingTypes = new String[definitions.getBindingTypes().size()];
i = 0;
for (BindingType bindingType : definitions.getBindingTypes()) {
bindingTypes[i++] = bindingType.getType().toString();
}
// FIXME: We should ask SCA domain for the supported intents
props.put(RemoteConstants.REMOTE_INTENTS_SUPPORTED, intents);
// FIXME: We should ask SCA domain for the supported binding types
props.put("org.osgi.sca.binding.types", bindingTypes);
registration = context.registerService(RemoteServiceAdmin.class.getName(), this, props);
props = new Hashtable<String, Object>();
props.put(Constants.SERVICE_PID, RemoteServiceAdminImpl.class.getName());
managedService = context.registerService(ManagedService.class.getName(), this, props);
listeners = new ServiceTracker(this.context, RemoteServiceAdminListener.class.getName(), null);
listeners.open();
}
public void stop() {
if (registration != null) {
try {
registration.unregister();
} catch (IllegalStateException e) {
// The service has been unregistered, ignore it
}
registration = null;
}
if (managedService != null) {
try {
managedService.unregister();
} catch (IllegalStateException e) {
// The service has been unregistered, ignore it
}
managedService = null;
}
if (listeners != null) {
listeners.close();
listeners = null;
}
for (ExportRegistration exportRegistration : exportedRegistrations) {
exportRegistration.close();
}
exportedRegistrations.clear();
for (ImportRegistration importRegistration : importRegistrations) {
importRegistration.close();
}
importRegistrations.clear();
if (importer != null) {
importer.stop();
importer = null;
}
if (exporter != null) {
exporter.stop();
exporter = null;
}
}
/**
* @see org.osgi.remoteserviceadmin.RemoteServiceAdmin#exportService(org.osgi.framework.ServiceReference,
* java.util.Map)
*/
public List<ExportRegistration> exportService(ServiceReference ref, Map properties) {
List<ExportRegistration> exportRegistrations = exporter.exportService(ref, properties);
if (exportRegistrations != null) {
exportRegistrations.addAll(exportedRegistrations);
fireExportEvents(ref.getBundle(), exportRegistrations);
}
return exportRegistrations;
}
private void fireExportEvents(Bundle source, List<ExportRegistration> exportRegistrations) {
for (ExportRegistration registration : exportRegistrations) {
RemoteServiceAdminEvent rsaEvent =
new RemoteServiceAdminEvent(RemoteServiceAdminEvent.EXPORT_REGISTRATION, source, registration
.getExportReference(), registration.getException());
EventAdmin eventAdmin = getEventAdmin();
if (eventAdmin != null) {
eventAdmin.postEvent(wrap(rsaEvent));
}
for (Object listener : listeners.getServices()) {
RemoteServiceAdminListener rsaListener = (RemoteServiceAdminListener)listener;
rsaListener.remoteAdminEvent(rsaEvent);
}
}
}
private EventAdmin getEventAdmin() {
ServiceReference reference = context.getServiceReference(EventAdmin.class.getName());
if (reference == null) {
return null;
} else {
return (EventAdmin)context.getService(reference);
}
}
private Event wrap(RemoteServiceAdminEvent rsaEvent) {
int type = rsaEvent.getType();
String eventType = null;
switch (type) {
case RemoteServiceAdminEvent.EXPORT_ERROR:
eventType = "EXPORT_ERROR";
break;
case RemoteServiceAdminEvent.EXPORT_REGISTRATION:
eventType = "EXPORT_REGISTRATION";
break;
case RemoteServiceAdminEvent.EXPORT_UNREGISTRATION:
eventType = "EXPORT_UNREGISTRATION";
break;
case RemoteServiceAdminEvent.EXPORT_WARNING:
eventType = "EXPORT_WARNING";
break;
case RemoteServiceAdminEvent.IMPORT_ERROR:
eventType = "IMPORT_ERROR";
break;
case RemoteServiceAdminEvent.IMPORT_REGISTRATION:
eventType = "IMPORT_REGISTRATION";
break;
case RemoteServiceAdminEvent.IMPORT_UNREGISTRATION:
eventType = "EXPORT_ERROR";
break;
case RemoteServiceAdminEvent.IMPORT_WARNING:
eventType = "IMPORT_UNREGISTRATION";
break;
}
String topic = "org/osgi/service/remoteserviceadmin/" + eventType;
Map<String, Object> props = new HashMap<String, Object>();
/*
* <ul>
<li>bundle (Bundle) The Remote Service Admin bundle
<li>bundle-id (Long) The id of the Blueprint bundle.
<li>bundle-symbolicname (String) The Bundle Symbolic Name of the
Remote Service Admin bundle.
<li>bundle-version - (Version) The version of the Blueprint bundle.
<li>cause The exception, if present.
<li>import.registration An imported endpoint, if present
<li>export.registration An exported endpoint, if present
<li>service.remote.id Remote service UUID, if present
<li>service.remote.uuid Remote service UUID, if present
<li>service.remote.uri (String) The URI of the endpoint, if present
<li>objectClass (String[]) The interface names, if present
<li>service.imported.configs (String+) The configuration types of the
imported services, if present
<li>timestamp (Long) The time when the event occurred
<li>event (RemoteServiceAdminEvent) The RemoteServiceAdminEvent
object that caused this event.
</ul>
*/
Bundle rsaBundle = context.getBundle();
props.put("bundle", rsaBundle);
props.put("bundle-id", rsaBundle.getBundleId());
props.put("bundle-symbolicname", rsaBundle.getSymbolicName());
props.put("bundle-version", rsaBundle.getHeaders().get(Constants.BUNDLE_VERSION));
props.put("cause", rsaEvent.getException());
props.put("import.registration", rsaEvent.getImportReference());
props.put("export.registration", rsaEvent.getExportReference());
EndpointDescription ep = null;
if (rsaEvent.getImportReference() != null) {
ep = rsaEvent.getImportReference().getImportedEndpoint();
}
if (rsaEvent.getExportReference() != null) {
ep = rsaEvent.getExportReference().getExportedEndpoint();
}
if (ep != null) {
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());
Object bindings = ep.getProperties().get("org.osgi.sca.bindings");
if (bindings != null) {
props.put("org.osgi.sca.bindings", bindings);
}
Object config = ep.getProperties().get("org.osgi.sca.config.url");
if (config != null) {
props.put("org.osgi.sca.config.url", config);
}
config = ep.getProperties().get("org.osgi.sca.config.xml");
if (config != null) {
props.put("org.osgi.sca.config.xml", config);
} }
props.put("timestamp", Long.valueOf(System.currentTimeMillis()));
props.put("event", rsaEvent);
return new Event(topic, props);
}
private void fireImportEvents(Bundle source, ImportRegistration registration) {
RemoteServiceAdminEvent rsaEvent =
new RemoteServiceAdminEvent(RemoteServiceAdminEvent.IMPORT_REGISTRATION, source, registration
.getImportReference(), registration.getException());
EventAdmin eventAdmin = getEventAdmin();
if (eventAdmin != null) {
eventAdmin.postEvent(wrap(rsaEvent));
}
for (Object listener : listeners.getServices()) {
RemoteServiceAdminListener rsaListener = (RemoteServiceAdminListener)listener;
rsaListener.remoteAdminEvent(rsaEvent);
}
}
/**
* @see org.osgi.remoteserviceadmin.RemoteServiceAdmin#getExportedServices()
*/
public Collection<ExportReference> getExportedServices() {
Collection<ExportReference> exportedServices = new ArrayList<ExportReference>();
for (ExportRegistration registration : exportedRegistrations) {
exportedServices.add(registration.getExportReference());
}
return exportedServices;
}
/**
* @see org.osgi.remoteserviceadmin.RemoteServiceAdmin#getImportedEndpoints()
*/
public Collection<ImportReference> getImportedEndpoints() {
Collection<ImportReference> importedEndpoints = new ArrayList<ImportReference>();
for (ImportRegistration registration : importRegistrations) {
importedEndpoints.add(registration.getImportReference());
}
return importedEndpoints;
}
/**
* @see org.osgi.remoteserviceadmin.RemoteServiceAdmin#importService(org.apache.tuscany.sca.dosgi.discovery.EndpointDescription)
*/
public ImportRegistration importService(EndpointDescription endpoint) {
Bundle bundle = (Bundle)endpoint.getProperties().get(Bundle.class.getName());
ImportRegistration importReg = importer.importService(bundle, endpoint);
if (importReg != null) {
fireImportEvents(bundle, importReg);
importRegistrations.add(importReg);
}
return importReg;
}
public synchronized void updated(Dictionary props) throws ConfigurationException {
if (props == null) {
// It can be null in Apache Felix
return;
}
String domainRegistry = (String)props.get("org.osgi.sca.domain.registry");
String domainURI = (String)props.get("org.osgi.sca.domain.uri");
if (domainRegistry != null) {
exporter.setDomainRegistry(domainRegistry);
importer.setDomainRegistry(domainRegistry);
}
if (domainURI != null) {
exporter.setDomainURI(domainURI);
importer.setDomainURI(domainURI);
}
}
}