/* * 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; } }