blob: b9a268ae69736b4e1eed15c495fcd18cd40cba13 [file] [log] [blame]
/****************************************************************************
* Copyright (c) 2017 Composent, Inc. and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* Contributors:
* Composent, Inc. - initial API and implementation
*
* SPDX-License-Identifier: EPL-2.0
*****************************************************************************/
package org.eclipse.ecf.osgi.services.remoteserviceadmin;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.eclipse.ecf.internal.osgi.services.remoteserviceadmin.Activator;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceReference;
import org.osgi.service.remoteserviceadmin.EndpointEvent;
import org.osgi.service.remoteserviceadmin.EndpointEventListener;
import org.osgi.service.remoteserviceadmin.RemoteServiceAdminEvent;
import org.osgi.util.tracker.BundleTracker;
import org.osgi.util.tracker.BundleTrackerCustomizer;
/**
* @since 4.6
*/
public class TopologyManagerImpl extends AbstractTopologyManager implements EndpointEventListener {
public static final int STARTUP_WAIT_TIME = Integer
.getInteger("org.eclipse.ecf.osgi.services.remoteserviceadmin.startupWaitTime", 20000); //$NON-NLS-1$
private final String ecfScope;
public TopologyManagerImpl(BundleContext context) {
this(context, null);
}
/**
* @since 4.9
*/
public TopologyManagerImpl(BundleContext context, String ecfScope) {
super(context);
this.ecfScope = (ecfScope == null) ? "" : ecfScope; //$NON-NLS-1$
}
protected String getFrameworkUUID() {
synchronized ("org.osgi.framework.uuid") { //$NON-NLS-1$
String result = getContext().getProperty("org.osgi.framework.uuid"); //$NON-NLS-1$
if (result == null) {
UUID newUUID = UUID.randomUUID();
result = newUUID.toString();
System.setProperty("org.osgi.framework.uuid", //$NON-NLS-1$
newUUID.toString());
}
return result;
}
}
protected void handleEndpointAdded(org.osgi.service.remoteserviceadmin.EndpointDescription endpoint,
String matchedFilter) {
if (matchedFilter != null && matchedFilter.equals(this.ecfScope)) {
handleECFEndpointAdded((EndpointDescription) endpoint);
} else {
logWarning("handleEndpointAdded", //$NON-NLS-1$
"matchedFilter=" + matchedFilter + " does not equal ECF topology manager filter=" + this.ecfScope //$NON-NLS-1$ //$NON-NLS-2$
+ " for endpoint=" + endpoint.getProperties()); //$NON-NLS-1$
}
}
protected void handleEndpointRemoved(org.osgi.service.remoteserviceadmin.EndpointDescription endpoint,
String matchedFilter) {
if (matchedFilter != null && matchedFilter.equals(this.ecfScope)) {
handleECFEndpointRemoved((EndpointDescription) endpoint);
} else {
logWarning("handleEndpointRemoved", //$NON-NLS-1$
"matchedFilter=" + matchedFilter + " does not equal ECF topology manager filter=" + this.ecfScope //$NON-NLS-1$ //$NON-NLS-2$
+ " for endpoint=" + endpoint.getProperties()); //$NON-NLS-1$
}
}
// EventListenerHook impl
protected void handleEvent(ServiceEvent event, Map listeners) {
super.handleEvent(event, listeners);
}
// RemoteServiceAdminListener impl
protected void handleRemoteAdminEvent(RemoteServiceAdminEvent event) {
if (!(event instanceof RemoteServiceAdmin.RemoteServiceAdminEvent))
return;
RemoteServiceAdmin.RemoteServiceAdminEvent rsaEvent = (RemoteServiceAdmin.RemoteServiceAdminEvent) event;
int eventType = event.getType();
EndpointDescription endpointDescription = rsaEvent.getEndpointDescription();
switch (eventType) {
case RemoteServiceAdminEvent.EXPORT_REGISTRATION:
advertiseEndpointDescription(endpointDescription);
break;
case RemoteServiceAdminEvent.EXPORT_UNREGISTRATION:
unadvertiseEndpointDescription(endpointDescription);
break;
case RemoteServiceAdminEvent.EXPORT_ERROR:
logError("handleRemoteAdminEvent.EXPORT_ERROR", "Export error with event=" + rsaEvent); //$NON-NLS-1$ //$NON-NLS-2$
break;
case RemoteServiceAdminEvent.EXPORT_WARNING:
logWarning("handleRemoteAdminEvent.EXPORT_WARNING", "Export warning with event=" + rsaEvent); //$NON-NLS-1$ //$NON-NLS-2$
break;
case RemoteServiceAdminEvent.EXPORT_UPDATE:
advertiseModifyEndpointDescription(endpointDescription);
break;
case RemoteServiceAdminEvent.IMPORT_REGISTRATION:
break;
case RemoteServiceAdminEvent.IMPORT_UNREGISTRATION:
break;
case RemoteServiceAdminEvent.IMPORT_ERROR:
logError("handleRemoteAdminEvent.IMPORT_ERROR", "Import error with event=" + rsaEvent); //$NON-NLS-1$//$NON-NLS-2$
break;
case RemoteServiceAdminEvent.IMPORT_WARNING:
logWarning("handleRemoteAdminEvent.IMPORT_WARNING", "Import warning with event=" + rsaEvent); //$NON-NLS-1$ //$NON-NLS-2$
break;
default:
logWarning("handleRemoteAdminEvent", //$NON-NLS-1$
"RemoteServiceAdminEvent=" + rsaEvent + " received with unrecognized type"); //$NON-NLS-1$ //$NON-NLS-2$
}
}
public void endpointChanged(EndpointEvent event, String matchedFilter) {
int eventType = event.getType();
org.osgi.service.remoteserviceadmin.EndpointDescription ed = event.getEndpoint();
switch (eventType) {
case EndpointEvent.ADDED:
handleEndpointAdded(ed, matchedFilter);
break;
case EndpointEvent.REMOVED:
handleEndpointRemoved(ed, matchedFilter);
break;
case EndpointEvent.MODIFIED:
handleEndpointModified(ed, matchedFilter);
break;
case EndpointEvent.MODIFIED_ENDMATCH:
handleEndpointModifiedEndmatch(ed, matchedFilter);
break;
}
}
protected void handleEndpointModifiedEndmatch(org.osgi.service.remoteserviceadmin.EndpointDescription endpoint,
String matchedFilter) {
// By default do nothing for end match. subclasses may decide
// to change this behavior
}
protected void handleEndpointModified(org.osgi.service.remoteserviceadmin.EndpointDescription endpoint,
String matchedFilter) {
if (matchedFilter != null && matchedFilter.equals(this.ecfScope)) {
handleECFEndpointModified((EndpointDescription) endpoint);
} else {
logWarning("handleEndpointModified", //$NON-NLS-1$
"matchedFilter=" + matchedFilter + " does not equal ECF topology manager filter=" + this.ecfScope //$NON-NLS-1$ //$NON-NLS-2$
+ " for endpoint=" + endpoint.getProperties()); //$NON-NLS-1$
}
}
protected void exportRegisteredServices(final String exportRegisteredSvcsFilter) {
new Thread(new Runnable() {
public void run() {
try {
final CountDownLatch latch = new CountDownLatch(1);
BundleTracker bt = new BundleTracker<Bundle>(getContext(), Bundle.INSTALLED | Bundle.RESOLVED
| Bundle.STARTING | Bundle.START_TRANSIENT | Bundle.ACTIVE, new BundleTrackerCustomizer() {
public Bundle addingBundle(Bundle bundle, BundleEvent event) {
String bsn = bundle.getSymbolicName();
if (bsn != null && bsn.equals(Activator.PLUGIN_ID)) {
if (bundle.getState() == Bundle.ACTIVE) {
latch.countDown();
return null;
} else
return bundle;
}
return null;
}
public void modifiedBundle(Bundle bundle, BundleEvent event, Object object) {
if (event != null && event.getType() == BundleEvent.STARTED)
latch.countDown();
}
public void removedBundle(Bundle bundle, BundleEvent event, Object object) {
}
});
bt.open();
// wait STARTUP_WAIT_TIME for latch going to zero
if (!latch.await(STARTUP_WAIT_TIME, TimeUnit.MILLISECONDS)) {
bt.close();
throw new TimeoutException(
"RemoteServiceAdmin did not become active in " + STARTUP_WAIT_TIME + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
}
// Otherwise we close bundle tracker and register remote services
bt.close();
final ServiceReference[] existingServiceRefs = getContext().getAllServiceReferences(null,
exportRegisteredSvcsFilter);
// Now export as if the service was registering right now...i.e.
// perform
// export
if (existingServiceRefs != null && existingServiceRefs.length > 0) {
// After having collected all pre-registered services (with
// marker prop) we are going to asynchronously remote them.
// Registering potentially is a long-running operation (due to
// discovery I/O...) and thus should no be carried out in the
// OSGi FW thread. (https://bugs.eclipse.org/405027)
for (int i = 0; i < existingServiceRefs.length; i++) {
// This method will check the service properties for
// remote service props. If previously registered as
// a
// remote service, it will export the remote
// service if not it will simply return/skip
handleServiceRegistering(existingServiceRefs[i]);
}
}
} catch (Exception e) {
logError("exportRegisteredServices", //$NON-NLS-1$
"Could not retrieve existing service references for exportRegisteredSvcsFilter=" //$NON-NLS-1$
+ exportRegisteredSvcsFilter,
e);
}
}
}, "BasicTopologyManagerPreRegSrvExporter").start(); //$NON-NLS-1$
}
}