/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.core.communication.rpc.internal;
import java.io.Serializable;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.osgi.framework.BundleContext;
import de.rcenvironment.core.communication.api.PlatformService;
import de.rcenvironment.core.communication.common.InstanceNodeSessionId;
import de.rcenvironment.core.communication.rpc.api.CallbackService;
import de.rcenvironment.core.communication.rpc.api.RemotableCallbackService;
import de.rcenvironment.core.communication.spi.CallbackObject;
import de.rcenvironment.core.utils.common.rpc.RemoteOperationException;
import de.rcenvironment.core.utils.common.security.AllowRemoteAccess;
import de.rcenvironment.core.utils.common.security.MethodPermissionCheck;
import de.rcenvironment.core.utils.common.security.MethodPermissionCheckHasAnnotation;
/**
* Implementation of {@link CallbackService} (including {@link RemotableCallbackService}).
*
* @author Doreen Seider
*/
public class CallbackServiceImpl implements CallbackService, RemotableCallbackService {
// the callback that verifies the presence of @AllowRemoteAccess annotations
private static final MethodPermissionCheck METHOD_PERMISSION_CHECK = new MethodPermissionCheckHasAnnotation(AllowRemoteAccess.class);
private Map<String, WeakReference<Object>> objects = Collections.synchronizedMap(new HashMap<String, WeakReference<Object>>());
private Map<String, InstanceNodeSessionId> remotePlatforms = Collections.synchronizedMap(new HashMap<String, InstanceNodeSessionId>());
private Map<String, Long> ttls = Collections.synchronizedMap(new HashMap<String, Long>());
private PlatformService platformService;
protected void activate(BundleContext context) {
CleanJob.scheduleJob(CallbackService.class, objects, ttls, remotePlatforms);
}
protected void deactivate(BundleContext context) {
CleanJob.unscheduleJob(CallbackService.class);
}
/**
* Bind method called by OSGi-DS.
*
* @param newPlatformService Service to bind.
*/
protected void bindPlatformService(PlatformService newPlatformService) {
platformService = newPlatformService;
}
@Override
public String addCallbackObject(Object callbackObject, InstanceNodeSessionId nodeId) {
String identifier = null;
synchronized (objects) {
for (String id : objects.keySet()) {
if (objects.get(id).get() == callbackObject) {
return id;
}
}
}
identifier = UUID.randomUUID().toString();
objects.put(identifier, new WeakReference<Object>(callbackObject));
remotePlatforms.put(identifier, nodeId);
ttls.put(identifier, new Date(System.currentTimeMillis() + CleanJob.TTL_MSEC).getTime());
return identifier;
}
@Override
public Object getCallbackObject(String objectIdentifier) {
WeakReference<Object> weakRef = objects.get(objectIdentifier);
if (weakRef != null) {
return weakRef.get();
} else {
return null;
}
}
@Override
@AllowRemoteAccess
public Object callback(String objectIdentifier, String methodName, List<? extends Serializable> parameters)
throws RemoteOperationException {
WeakReference<Object> weakRef = objects.get(objectIdentifier);
if (weakRef != null) {
Object objectToCall = weakRef.get();
if (objectToCall != null) {
// LOGGER.debug("Received method call: " + methodName + "@" +
// objectToCall.toString());
try {
return MethodCaller.callMethod(objectToCall, methodName, parameters, METHOD_PERMISSION_CHECK);
} catch (InvocationTargetException e) {
// TODO (p2) review (was _FIXME 7.0.0)
throw new RemoteOperationException("Callback method threw an exception: " + e.toString());
}
}
}
throw new RemoteOperationException("The object to call back is not reachable anymore, requested method: " + methodName + "(...)");
}
@Override
@AllowRemoteAccess
public void setTTL(String objectIdentifier, Long ttl) {
ttls.put(objectIdentifier, ttl);
}
@Override
public Object createCallbackProxy(CallbackObject callbackObject, String objectIdentifier,
InstanceNodeSessionId proxyHome) {
InvocationHandler handler = new CallbackInvocationHandler(callbackObject, objectIdentifier,
platformService.getLocalInstanceNodeSessionId(), proxyHome);
Object proxy = Proxy.newProxyInstance(CallbackProxy.class.getClassLoader(),
new Class[] { callbackObject.getInterface(), CallbackProxy.class }, handler);
return proxy;
}
@Override
public String getCallbackObjectIdentifier(Object callbackObject) {
synchronized (objects) {
for (String id : objects.keySet()) {
if (objects.get(id).get() != null) {
if (objects.get(id).get() == callbackObject) {
return id;
}
}
}
}
return null;
}
}