| /******************************************************************************* |
| * Copyright (c) 2004 Composent, Inc. and others. All rights reserved. This |
| * program and the accompanying materials are made available under the terms of |
| * the Eclipse Public License v1.0 which accompanies this distribution, and is |
| * available at http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: Composent, Inc. - initial API and implementation |
| ******************************************************************************/ |
| package org.eclipse.ecf.provider.generic; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.io.InvalidClassException; |
| import java.io.NotSerializableException; |
| import java.io.ObjectInputStream; |
| import java.io.ObjectOutputStream; |
| import java.io.Serializable; |
| import java.security.AccessController; |
| import java.security.PrivilegedAction; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.core.runtime.IAdapterManager; |
| import org.eclipse.ecf.core.AbstractContainer; |
| import org.eclipse.ecf.core.ContainerConnectException; |
| import org.eclipse.ecf.core.events.IContainerEvent; |
| import org.eclipse.ecf.core.identity.ID; |
| import org.eclipse.ecf.core.identity.IDFactory; |
| import org.eclipse.ecf.core.identity.Namespace; |
| import org.eclipse.ecf.core.security.IConnectContext; |
| import org.eclipse.ecf.core.sharedobject.ISharedObject; |
| import org.eclipse.ecf.core.sharedobject.ISharedObjectConfig; |
| import org.eclipse.ecf.core.sharedobject.ISharedObjectContainer; |
| import org.eclipse.ecf.core.sharedobject.ISharedObjectContainerConfig; |
| import org.eclipse.ecf.core.sharedobject.ISharedObjectContainerTransaction; |
| import org.eclipse.ecf.core.sharedobject.ISharedObjectManager; |
| import org.eclipse.ecf.core.sharedobject.ReplicaSharedObjectDescription; |
| import org.eclipse.ecf.core.sharedobject.SharedObjectAddException; |
| import org.eclipse.ecf.core.sharedobject.SharedObjectDescription; |
| import org.eclipse.ecf.core.sharedobject.SharedObjectInitException; |
| import org.eclipse.ecf.core.sharedobject.events.ContainerSharedObjectMessageReceivingEvent; |
| import org.eclipse.ecf.core.sharedobject.events.ContainerSharedObjectMessageSendingEvent; |
| import org.eclipse.ecf.core.sharedobject.events.SharedObjectActivatedEvent; |
| import org.eclipse.ecf.core.sharedobject.events.SharedObjectDeactivatedEvent; |
| import org.eclipse.ecf.core.sharedobject.security.ISharedObjectPolicy; |
| import org.eclipse.ecf.core.sharedobject.util.IQueueEnqueue; |
| import org.eclipse.ecf.core.util.ECFException; |
| import org.eclipse.ecf.core.util.Event; |
| import org.eclipse.ecf.core.util.Trace; |
| import org.eclipse.ecf.internal.provider.ECFProviderDebugOptions; |
| import org.eclipse.ecf.internal.provider.Messages; |
| import org.eclipse.ecf.internal.provider.ProviderPlugin; |
| import org.eclipse.ecf.provider.comm.AsynchEvent; |
| import org.eclipse.ecf.provider.comm.ConnectionEvent; |
| import org.eclipse.ecf.provider.comm.DisconnectEvent; |
| import org.eclipse.ecf.provider.comm.IAsynchConnection; |
| import org.eclipse.ecf.provider.comm.IConnection; |
| import org.eclipse.ecf.provider.comm.ISynchAsynchEventHandler; |
| import org.eclipse.ecf.provider.comm.SynchEvent; |
| import org.eclipse.ecf.provider.generic.gmm.Member; |
| import org.eclipse.ecf.provider.util.IClassLoaderMapper; |
| import org.eclipse.ecf.provider.util.IdentifiableObjectInputStream; |
| import org.eclipse.ecf.provider.util.IdentifiableObjectOutputStream; |
| |
| public abstract class SOContainer extends AbstractContainer implements ISharedObjectContainer { |
| class LoadingSharedObject implements ISharedObject { |
| private ReplicaSharedObjectDescription description; |
| private Thread runner = null; |
| private ID fromID = null; |
| |
| LoadingSharedObject(ID fromID, ReplicaSharedObjectDescription sd) { |
| this.fromID = fromID; |
| this.description = sd; |
| } |
| |
| public void dispose(ID containerID) { |
| } |
| |
| public Object getAdapter(Class clazz) { |
| return null; |
| } |
| |
| ID getHomeID() { |
| ID homeID = description.getHomeID(); |
| if (homeID == null) |
| return getID(); |
| else |
| return homeID; |
| } |
| |
| ID getID() { |
| return description.getID(); |
| } |
| |
| public void handleEvent(Event event) { |
| } |
| |
| public void handleEvents(Event[] events) { |
| } |
| |
| public void init(ISharedObjectConfig initData) |
| throws SharedObjectInitException { |
| } |
| |
| void start() { |
| if (runner == null) { |
| runner = (Thread) AccessController |
| .doPrivileged(new PrivilegedAction() { |
| public Object run() { |
| return new Thread(loadingThreadGroup, |
| new Runnable() { |
| public void run() { |
| try { |
| if (Thread.currentThread() |
| .isInterrupted() |
| || isClosing()) |
| throw new InterruptedException( |
| Messages.SOContainer_Loading_Interrupted |
| + getID() |
| .getName()); |
| // First load object |
| ISharedObject obj = load(description); |
| // Create wrapper object and |
| // move from loading to |
| // active |
| // list. |
| SOWrapper wrap = createRemoteSharedObjectWrapper( |
| fromID, |
| description, obj); |
| wrap.init(); |
| // Check to make sure thread |
| // has not been |
| // interrupted...if it has, |
| // throw |
| if (Thread.currentThread() |
| .isInterrupted() |
| || isClosing()) |
| throw new InterruptedException( |
| Messages.SOContainer_Loading_Interrupted |
| + getID() |
| .getName()); |
| // Finally, we move from |
| // loading to active, and |
| // then the |
| // object is done |
| SOContainer.this |
| .moveFromLoadingToActive(wrap); |
| } catch (Exception e) { |
| traceStack( |
| "Exception loading:" + description, e); //$NON-NLS-1$ |
| SOContainer.this |
| .removeFromLoading(getID()); |
| try { |
| sendCreateResponse( |
| getHomeID(), |
| getID(), |
| e, |
| description |
| .getIdentifier()); |
| } catch (Exception e1) { |
| traceStack( |
| "Exception sending create response from LoadingSharedObject.run:" //$NON-NLS-1$ |
| + description, |
| e1); |
| } |
| } |
| } |
| }, getID().getName() + ":loading"); //$NON-NLS-1$ |
| } |
| }); |
| runner.setDaemon(true); |
| runner.start(); |
| } |
| } |
| } |
| |
| public static final String DEFAULT_OBJECT_ARG_KEY = SOContainer.class |
| .getName() |
| + ".sharedobjectargs"; //$NON-NLS-1$ |
| public static final String DEFAULT_OBJECT_ARGTYPES_KEY = SOContainer.class |
| .getName() |
| + ".sharedobjectargtypes"; //$NON-NLS-1$ |
| |
| private long sequenceNumber = 0L; |
| |
| protected ISharedObjectContainerConfig config = null; |
| |
| protected SOContainerGMM groupManager = null; |
| |
| protected boolean isClosing = false; |
| |
| protected ThreadGroup loadingThreadGroup = null; |
| |
| protected SOManager sharedObjectManager = null; |
| |
| protected ISharedObjectPolicy policy = null; |
| |
| protected ThreadGroup sharedObjectThreadGroup = null; |
| |
| protected ISynchAsynchEventHandler receiver = new ISynchAsynchEventHandler() { |
| public Object handleSynchEvent(SynchEvent event) throws IOException { |
| return processSynch(event); |
| } |
| |
| public ID getEventHandlerID() { |
| return getID(); |
| } |
| |
| public void handleConnectEvent(ConnectionEvent event) { |
| |
| } |
| |
| public void handleDisconnectEvent(DisconnectEvent event) { |
| processDisconnect(event); |
| } |
| |
| public void handleAsynchEvent(AsynchEvent event) throws IOException { |
| processAsynch(event); |
| } |
| }; |
| |
| public SOContainer(ISharedObjectContainerConfig config) { |
| Assert |
| .isNotNull(config, |
| Messages.SOContainer_Exception_Config_Not_Null); |
| this.config = config; |
| groupManager = new SOContainerGMM(this, new Member(config.getID())); |
| sharedObjectManager = new SOManager(this); |
| loadingThreadGroup = new ThreadGroup(getID() + ":loading"); |
| sharedObjectThreadGroup = new ThreadGroup(getID() + ":SOs"); |
| } |
| |
| // Implementation of IIdentifiable |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ecf.core.identity.IIdentifiable#getID() |
| */ |
| public ID getID() { |
| return config.getID(); |
| } |
| |
| // Implementation of IContainer |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ecf.core.ISharedObjectContainer#connect(org.eclipse.ecf.core.identity.ID, |
| * org.eclipse.ecf.core.security.IConnectContext) |
| */ |
| public abstract void connect(ID groupID, IConnectContext connectContext) |
| throws ContainerConnectException; |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ecf.core.ISharedObjectContainer#getGroupID() |
| */ |
| public abstract ID getConnectedID(); |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ecf.core.ISharedObjectContainer#leaveGroup() |
| */ |
| public abstract void disconnect(); |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ecf.core.IContainer#getConnectNamespace() |
| */ |
| public Namespace getConnectNamespace() { |
| // We expect StringIDs for the generic server |
| return IDFactory.getDefault().getNamespaceByName( |
| ProviderPlugin.getDefault().getNamespaceIdentifier()); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ecf.core.ISharedObjectContainer#dispose(long) |
| */ |
| public void dispose() { |
| isClosing = true; |
| // Clear group manager |
| if (groupManager != null) |
| groupManager.removeAllMembers(); |
| // Clear shared object manager |
| if (sharedObjectManager != null) { |
| sharedObjectManager.dispose(); |
| sharedObjectManager = null; |
| } |
| if (loadingThreadGroup != null) { |
| loadingThreadGroup.interrupt(); |
| loadingThreadGroup = null; |
| } |
| super.dispose(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ecf.core.ISharedObjectContainer#getAdapter(java.lang.Class) |
| */ |
| public Object getAdapter(Class adapter) { |
| if (adapter.isInstance(this)) { |
| return this; |
| } else { |
| IAdapterManager adapterManager = ProviderPlugin.getDefault() |
| .getAdapterManager(); |
| if (adapterManager == null) |
| return null; |
| return adapterManager.loadAdapter(this, adapter.getName()); |
| } |
| } |
| |
| // Impl of ISharedObjectContainer |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ecf.core.ISharedObjectContainer#getSharedObjectManager() |
| */ |
| public ISharedObjectManager getSharedObjectManager() { |
| return sharedObjectManager; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ecf.core.ISharedObjectContainer#getGroupMemberIDs() |
| */ |
| public ID[] getGroupMemberIDs() { |
| return groupManager.getMemberIDs(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ecf.core.ISharedObjectContainer#getConfig() |
| */ |
| public ISharedObjectContainerConfig getConfig() { |
| return config; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ecf.core.ISharedObjectContainer#isGroupManager() |
| */ |
| public abstract boolean isGroupManager(); |
| |
| // End of ISharedObjectContainer |
| |
| protected void setRemoteAddPolicy(ISharedObjectPolicy policy) { |
| synchronized (getGroupMembershipLock()) { |
| this.policy = policy; |
| } |
| } |
| |
| protected boolean addNewRemoteMember(ID memberID, Object data) { |
| return groupManager.addMember(new Member(memberID, data)); |
| } |
| |
| protected ISharedObjectContainerTransaction addSharedObject0(ID id, |
| ISharedObject s, Map props) throws Exception { |
| return addSharedObjectWrapper(createSharedObjectWrapper(id, s, props)); |
| } |
| |
| protected void addSharedObjectAndWait(ID id, ISharedObject s, Map properties) |
| throws Exception { |
| if (id == null || s == null) { |
| throw new SharedObjectAddException( |
| Messages.SOContainer_Exception_Add_Object); |
| } |
| ISharedObjectContainerTransaction t = addSharedObject0(id, s, |
| properties); |
| // Wait right here until committed |
| if (t != null) |
| t.waitToCommit(); |
| } |
| |
| protected ISharedObjectContainerTransaction addSharedObjectWrapper( |
| SOWrapper wrapper) throws Exception { |
| if (wrapper == null) |
| return null; |
| ID id = wrapper.getObjID(); |
| ISharedObjectContainerTransaction transaction = null; |
| synchronized (getGroupMembershipLock()) { |
| Object obj = groupManager.getFromAny(id); |
| if (obj != null) { |
| throw new SharedObjectAddException( |
| Messages.SOContainer_Exception_Object_With_ID |
| + id.getName() |
| + Messages.SOContainer_Exception_Already_In_Container); |
| } |
| // Call initialize. If this throws it halts everything |
| wrapper.init(); |
| // Call getAdapter(ISharedObjectContainerTransaction) |
| transaction = (ISharedObjectContainerTransaction) wrapper.sharedObject |
| .getAdapter(ISharedObjectContainerTransaction.class); |
| // Put in table |
| groupManager.addSharedObjectToActive(wrapper); |
| } |
| return transaction; |
| } |
| |
| protected boolean addToLoading(LoadingSharedObject lso) { |
| return groupManager.addLoadingSharedObject(lso); |
| } |
| |
| /** |
| * Check remote creation of shared objects. This method is called by the |
| * remote shared object creation message handler, to verify that the shared |
| * object from container 'fromID' to container 'toID' with description |
| * 'desc' is to be allowed to be created within the current container. If |
| * this method throws, a failure (and exception will be sent back to caller |
| * If this method returns null, the create message is ignored. If this |
| * method returns a non-null object, the creation is allowed to proceed. The |
| * default implementation is to return a non-null object |
| * |
| * @param fromID |
| * the ID of the container sending us this create request |
| * @param toID |
| * the ID (or null) of the container intended to receive this |
| * request |
| * @param desc |
| * the SharedObjectDescription that describes the shared object |
| * to be created |
| * |
| * @return Object null if the create message is to be ignored, non-null if |
| * the creation should continue |
| * |
| * @throws Exception |
| * may throw any Exception to communicate back (via |
| * sendCreateResponse) to the sender that the creation has |
| * failed |
| */ |
| protected Object checkRemoteCreate(ID fromID, ID toID, |
| ReplicaSharedObjectDescription desc) throws Exception { |
| debug("checkRemoteCreate(" + fromID + "," + toID + "," + desc + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ |
| if (policy != null) { |
| return policy.checkAddSharedObject(fromID, toID, getID(), desc); |
| } |
| return desc; |
| } |
| |
| protected void debug(String msg) { |
| Trace.trace(ProviderPlugin.PLUGIN_ID, ECFProviderDebugOptions.DEBUG, |
| msg + ":" + config.getID()); //$NON-NLS-1$ |
| } |
| |
| protected void traceStack(String msg, Throwable e) { |
| Trace.catching(ProviderPlugin.PLUGIN_ID, |
| ECFProviderDebugOptions.EXCEPTIONS_CATCHING, SOContainer.class, |
| config.getID() + ":" + msg, e); //$NON-NLS-1$ |
| } |
| |
| protected boolean destroySharedObject(ID sharedObjectID) { |
| return groupManager.removeSharedObject(sharedObjectID); |
| } |
| |
| protected final void forward(ID fromID, ID toID, ContainerMessage data) |
| throws IOException { |
| if (toID == null) |
| forwardExcluding(fromID, fromID, data); |
| else |
| forwardToRemote(fromID, toID, data); |
| } |
| |
| abstract protected void forwardExcluding(ID from, ID excluding, |
| ContainerMessage data) throws IOException; |
| |
| abstract protected void forwardToRemote(ID from, ID to, |
| ContainerMessage data) throws IOException; |
| |
| /** |
| * @param sd |
| * @return Object [] |
| */ |
| protected Object[] getArgsFromProperties(SharedObjectDescription sd) { |
| if (sd == null) |
| return null; |
| Map aMap = sd.getProperties(); |
| if (aMap == null) |
| return null; |
| Object obj = aMap.get(DEFAULT_OBJECT_ARG_KEY); |
| if (obj == null) |
| return null; |
| if (obj instanceof Object[]) { |
| Object[] ret = (Object[]) obj; |
| aMap.remove(DEFAULT_OBJECT_ARG_KEY); |
| return ret; |
| } else |
| return null; |
| } |
| |
| /** |
| * @param sd |
| * @return String [] |
| */ |
| protected String[] getArgTypesFromProperties(SharedObjectDescription sd) { |
| if (sd == null) |
| return null; |
| Map aMap = sd.getProperties(); |
| if (aMap == null) |
| return null; |
| Object obj = aMap.get(DEFAULT_OBJECT_ARGTYPES_KEY); |
| if (obj == null) |
| return null; |
| if (obj instanceof String[]) { |
| String[] ret = (String[]) obj; |
| aMap.remove(DEFAULT_OBJECT_ARGTYPES_KEY); |
| return ret; |
| } else |
| return null; |
| } |
| |
| protected byte[] serialize(Serializable obj) throws IOException { |
| ByteArrayOutputStream bos = new ByteArrayOutputStream(); |
| ObjectOutputStream oos = new ObjectOutputStream(bos); |
| oos.writeObject(obj); |
| return bos.toByteArray(); |
| } |
| |
| protected ClassLoader getClassLoaderForContainer() { |
| // Use classloader from SOContainer class (and buddy's as specified |
| // by ECF generic provider plugin org.eclipse.ecf.provider's buddy |
| // policy (currently set to 'global'). |
| return this.getClass().getClassLoader(); |
| } |
| |
| /** |
| * @param sd |
| * @return ClassLoader |
| */ |
| protected ClassLoader getClassLoaderForSharedObject( |
| SharedObjectDescription sd) { |
| return getClassLoaderForContainer(); |
| } |
| |
| protected Object getGroupMembershipLock() { |
| return groupManager; |
| } |
| |
| protected int getMaxGroupMembers() { |
| return groupManager.getMaxMembers(); |
| } |
| |
| protected Thread getNewSharedObjectThread(ID sharedObjectID, |
| Runnable runnable) { |
| return new Thread(sharedObjectThreadGroup, runnable, sharedObjectID |
| .getName() |
| + ":run"); //$NON-NLS-1$ |
| } |
| |
| protected long getNextSequenceNumber() { |
| if (sequenceNumber == Long.MAX_VALUE) { |
| sequenceNumber = 0; |
| return sequenceNumber; |
| } else |
| return sequenceNumber++; |
| } |
| |
| protected ContainerMessage deserializeContainerMessage(byte[] bytes) |
| throws IOException { |
| ByteArrayInputStream bis = new ByteArrayInputStream(bytes); |
| ObjectInputStream ois = new ObjectInputStream(bis); |
| Object obj = null; |
| try { |
| obj = ois.readObject(); |
| } catch (ClassNotFoundException e) { |
| traceStack("class not found for message", e); //$NON-NLS-1$ |
| return null; |
| } catch (InvalidClassException e) { |
| traceStack("invalid class for message", e); //$NON-NLS-1$ |
| return null; |
| } |
| if (obj instanceof ContainerMessage) |
| return (ContainerMessage) obj; |
| else { |
| traceStack("not a containermessage", new Exception()); //$NON-NLS-1$ |
| return null; |
| } |
| } |
| |
| protected ID[] getOtherMemberIDs() { |
| return groupManager.getOtherMemberIDs(); |
| } |
| |
| protected ISynchAsynchEventHandler getReceiver() { |
| return receiver; |
| } |
| |
| protected ISharedObject getSharedObject(ID id) { |
| SOWrapper wrap = getSharedObjectWrapper(id); |
| return (wrap == null) ? null : wrap.getSharedObject(); |
| } |
| |
| protected ID[] getSharedObjectIDs() { |
| return groupManager.getSharedObjectIDs(); |
| } |
| |
| protected SOWrapper getSharedObjectWrapper(ID id) { |
| return groupManager.getFromActive(id); |
| } |
| |
| protected void handleAsynchIOException(IOException except, AsynchEvent e) { |
| // If we get IO Exception, we'll disconnect...if we can |
| disconnect(e.getConnection()); |
| } |
| |
| protected void handleCreateMessage(ContainerMessage mess) |
| throws IOException { |
| ContainerMessage.CreateMessage create = (ContainerMessage.CreateMessage) mess |
| .getData(); |
| if (create == null) |
| throw new IOException( |
| Messages.SOContainer_Exception_Bad_Container_Message); |
| ReplicaSharedObjectDescription desc = (ReplicaSharedObjectDescription) create |
| .getData(); |
| if (desc == null) |
| throw new IOException( |
| Messages.SOContainer_Exception_Bad_Description); |
| ID fromID = mess.getFromContainerID(); |
| ID toID = mess.getToContainerID(); |
| Object checkCreateResult = null; |
| ID sharedObjectID = desc.getID(); |
| if (sharedObjectID == null) |
| throw new IOException( |
| Messages.SOContainer_Exception_ObjectID_Is_Null); |
| // Check to make sure that the remote creation is allowed. |
| // If this method throws, a failure (and exception will be sent back to |
| // caller |
| // If this method returns null, the create message is ignored. If this |
| // method |
| // returns a non-null object, the creation is allowed to proceed |
| try { |
| checkCreateResult = checkRemoteCreate(fromID, toID, desc); |
| } catch (Exception e) { |
| SharedObjectAddException addException = new SharedObjectAddException( |
| Messages.SOContainer_Shared_Object + sharedObjectID |
| + Messages.SOContainer_Rejected_By_Container |
| + getID(), e); |
| traceStack("Exception in checkRemoteCreate:" + desc, addException); //$NON-NLS-1$ |
| try { |
| sendCreateResponse(fromID, sharedObjectID, addException, desc |
| .getIdentifier()); |
| } catch (IOException except) { |
| traceStack( |
| "Exception from sendCreateResponse in handleCreateResponse", //$NON-NLS-1$ |
| except); |
| } |
| return; |
| } |
| // Then if result from check is non-null, we continue. If null, we |
| // ignore |
| if (checkCreateResult != null) { |
| LoadingSharedObject lso = new LoadingSharedObject(fromID, desc); |
| synchronized (getGroupMembershipLock()) { |
| if (!addToLoading(lso)) { |
| try { |
| sendCreateResponse( |
| fromID, |
| sharedObjectID, |
| new SharedObjectAddException( |
| Messages.SOContainer_Shared_Object |
| + sharedObjectID |
| + Messages.SOContainer_Exception_Already_Exists_In_Container |
| + getID()), desc |
| .getIdentifier()); |
| } catch (IOException e) { |
| traceStack( |
| "Exception in handleCreateMessage.sendCreateResponse", //$NON-NLS-1$ |
| e); |
| } |
| } |
| forward(fromID, toID, mess); |
| return; |
| } |
| } |
| synchronized (getGroupMembershipLock()) { |
| forward(fromID, toID, mess); |
| } |
| } |
| |
| protected void handleCreateResponseMessage(ContainerMessage mess) |
| throws IOException { |
| ID fromID = mess.getFromContainerID(); |
| ID toID = mess.getToContainerID(); |
| ContainerMessage.CreateResponseMessage resp = (ContainerMessage.CreateResponseMessage) mess |
| .getData(); |
| if (toID != null && toID.equals(getID())) { |
| ID sharedObjectID = resp.getSharedObjectID(); |
| SOWrapper sow = getSharedObjectWrapper(sharedObjectID); |
| if (sow != null) { |
| sow.deliverCreateResponse(fromID, resp); |
| } else { |
| debug("handleCreateResponseMessage...wrapper not found for " //$NON-NLS-1$ |
| + sharedObjectID); |
| } |
| } else { |
| forwardToRemote(fromID, toID, mess); |
| } |
| } |
| |
| /** |
| * @param mess |
| */ |
| protected abstract void handleLeaveGroupMessage(ContainerMessage mess); |
| |
| protected void handleSharedObjectDisposeMessage(ContainerMessage mess) |
| throws IOException { |
| ID fromID = mess.getFromContainerID(); |
| ID toID = mess.getToContainerID(); |
| ContainerMessage.SharedObjectDisposeMessage resp = (ContainerMessage.SharedObjectDisposeMessage) mess |
| .getData(); |
| ID sharedObjectID = resp.getSharedObjectID(); |
| synchronized (getGroupMembershipLock()) { |
| if (groupManager.isLoading(sharedObjectID)) { |
| groupManager.removeSharedObjectFromLoading(sharedObjectID); |
| } else { |
| groupManager.removeSharedObject(sharedObjectID); |
| } |
| forward(fromID, toID, mess); |
| } |
| } |
| |
| protected boolean verifyToIDForSharedObjectMessage(ID toID) { |
| if (toID == null || toID.equals(getID())) |
| return true; |
| else |
| return false; |
| } |
| |
| protected void handleSharedObjectMessage(ContainerMessage mess) |
| throws IOException { |
| ID fromID = mess.getFromContainerID(); |
| ID toID = mess.getToContainerID(); |
| ContainerMessage.SharedObjectMessage resp = (ContainerMessage.SharedObjectMessage) mess |
| .getData(); |
| ID sharedObjectID = resp.getFromSharedObjectID(); |
| synchronized (getGroupMembershipLock()) { |
| SOWrapper sow = getSharedObjectWrapper(sharedObjectID); |
| if (sow != null) { |
| try { |
| Serializable obj = (Serializable) deserializeSharedObjectMessage((byte[]) resp |
| .getData()); |
| // Fire container event notifying container listeners about |
| // receiving |
| // event. |
| fireContainerEvent(new ContainerSharedObjectMessageReceivingEvent( |
| getID(), fromID, sharedObjectID, obj)); |
| // Actually deliver event to shared object asynchronously |
| sow.deliverSharedObjectMessage(fromID, obj); |
| } catch (ClassNotFoundException e) { |
| traceStack( |
| "Exception in handleSharedObjectMessage:" + resp, e); //$NON-NLS-1$ |
| Trace |
| .catching( |
| ProviderPlugin.PLUGIN_ID, |
| ECFProviderDebugOptions.EXCEPTIONS_CATCHING, |
| this.getClass(), |
| "handleSharedObjectMessage", e); //$NON-NLS-1$ |
| } |
| } |
| forward(fromID, toID, mess); |
| } |
| } |
| |
| protected void handleUnidentifiedMessage(ContainerMessage mess) |
| throws IOException { |
| // do nothing |
| debug("received unidentified message: " + mess); |
| } |
| |
| protected abstract void handleViewChangeMessage(ContainerMessage mess) |
| throws IOException; |
| |
| protected boolean isClosing() { |
| return isClosing; |
| } |
| |
| protected void disconnect(IConnection conn) { |
| if (conn != null && conn.isConnected()) |
| conn.disconnect(); |
| } |
| |
| protected ISharedObject load(SharedObjectDescription sd) throws Exception { |
| return sharedObjectManager.loadSharedObject(sd); |
| } |
| |
| protected SOConfig createSharedObjectConfig(ID id, ISharedObject obj, |
| Map props) throws ECFException { |
| return new SOConfig(id, getID(), this, props); |
| } |
| |
| protected SOConfig createRemoteSharedObjectConfig(ID fromID, |
| ReplicaSharedObjectDescription sd, ISharedObject obj) { |
| ID homeID = sd.getHomeID(); |
| if (homeID == null) |
| homeID = fromID; |
| return new SOConfig(sd.getID(), homeID, this, sd.getProperties()); |
| } |
| |
| protected SOContext createSharedObjectContext(SOConfig soconfig, |
| IQueueEnqueue queue) { |
| return new SOContext(soconfig.getSharedObjectID(), soconfig |
| .getHomeContainerID(), this, soconfig.getProperties(), queue); |
| } |
| |
| protected SOContext createRemoteSharedObjectContext(SOConfig soconfig, |
| IQueueEnqueue queue) { |
| return new SOContext(soconfig.getSharedObjectID(), soconfig |
| .getHomeContainerID(), this, soconfig.getProperties(), queue); |
| } |
| |
| protected SOWrapper createSharedObjectWrapper(ID id, ISharedObject s, |
| Map props) throws ECFException { |
| SOConfig newConfig = createSharedObjectConfig(id, s, props); |
| return new SOWrapper(newConfig, s, this); |
| } |
| |
| protected SOWrapper createRemoteSharedObjectWrapper(ID fromID, |
| ReplicaSharedObjectDescription sd, ISharedObject s) { |
| SOConfig newConfig = createRemoteSharedObjectConfig(fromID, sd, s); |
| return new SOWrapper(newConfig, s, this); |
| } |
| |
| protected void handleLeave(ID leftID, IConnection conn) { |
| if (leftID == null) |
| return; |
| if (groupManager.removeMember(leftID)) { |
| try { |
| forwardExcluding(getID(), leftID, ContainerMessage |
| .createViewChangeMessage(getID(), null, |
| getNextSequenceNumber(), new ID[] { leftID }, |
| false, null)); |
| } catch (IOException e) { |
| traceStack("Exception in memberLeave.forwardExcluding", e); //$NON-NLS-1$ |
| } |
| } |
| if (conn != null) |
| disconnect(conn); |
| } |
| |
| protected void moveFromLoadingToActive(SOWrapper wrap) { |
| groupManager.moveSharedObjectFromLoadingToActive(wrap); |
| } |
| |
| protected void notifySharedObjectActivated(ID sharedObjectID) { |
| synchronized (getGroupMembershipLock()) { |
| groupManager.notifyOthersActivated(sharedObjectID); |
| fireContainerEvent(new SharedObjectActivatedEvent(getID(), |
| sharedObjectID)); |
| } |
| } |
| |
| protected void notifySharedObjectDeactivated(ID sharedObjectID) { |
| synchronized (getGroupMembershipLock()) { |
| groupManager.notifyOthersDeactivated(sharedObjectID); |
| fireContainerEvent(new SharedObjectDeactivatedEvent(getID(), |
| sharedObjectID)); |
| } |
| } |
| |
| protected ContainerMessage validateContainerMessage(Object mess) { |
| // Message must not be null |
| if (mess == null) |
| return null; |
| if (mess instanceof ContainerMessage) { |
| ContainerMessage contmess = (ContainerMessage) mess; |
| ID fromID = contmess.getFromContainerID(); |
| if (fromID == null) |
| return null; |
| // OK..let it continue on it's journey |
| return contmess; |
| } else |
| return null; |
| } |
| |
| protected void processAsynch(AsynchEvent event) throws IOException { |
| try { |
| Object obj = event.getData(); |
| if (obj == null) { |
| debug("Ignoring null data in event " + event); //$NON-NLS-1$ |
| return; |
| } |
| if (!(obj instanceof byte[])) { |
| debug("Ignoring event without valid data " + event); //$NON-NLS-1$ |
| return; |
| } |
| ContainerMessage mess = validateContainerMessage(deserializeContainerMessage((byte[]) obj)); |
| if (mess == null) { |
| debug("event not validated: " + event); //$NON-NLS-1$ |
| return; |
| } |
| Serializable submess = mess.getData(); |
| if (submess == null) { |
| debug("submess is null: " + event); |
| return; |
| } |
| if (submess instanceof ContainerMessage.CreateMessage) |
| handleCreateMessage(mess); |
| else if (submess instanceof ContainerMessage.CreateResponseMessage) |
| handleCreateResponseMessage(mess); |
| else if (submess instanceof ContainerMessage.SharedObjectDisposeMessage) |
| handleSharedObjectDisposeMessage(mess); |
| else if (submess instanceof ContainerMessage.SharedObjectMessage) |
| handleSharedObjectMessage(mess); |
| else if (submess instanceof ContainerMessage.ViewChangeMessage) |
| handleViewChangeMessage(mess); |
| else |
| handleUnidentifiedMessage(mess); |
| |
| } catch (IOException except) { |
| handleAsynchIOException(except, event); |
| } |
| } |
| |
| protected abstract ID getIDForConnection(IAsynchConnection connection); |
| |
| protected abstract void processDisconnect(DisconnectEvent event); |
| |
| protected Serializable processSynch(SynchEvent e) throws IOException { |
| ContainerMessage mess = deserializeContainerMessage((byte[]) e |
| .getData()); |
| Serializable data = mess.getData(); |
| // Must be non null |
| if (data != null && data instanceof ContainerMessage.LeaveGroupMessage) |
| handleLeaveGroupMessage(mess); |
| return null; |
| } |
| |
| abstract protected void queueContainerMessage(ContainerMessage mess) |
| throws IOException; |
| |
| protected void removeFromLoading(ID id) { |
| groupManager.removeSharedObjectFromLoading(id); |
| } |
| |
| protected boolean removeRemoteMember(ID remoteMember) { |
| return groupManager.removeMember(remoteMember); |
| } |
| |
| protected ISharedObject removeSharedObject(ID id) { |
| synchronized (getGroupMembershipLock()) { |
| SOWrapper wrap = groupManager.getFromActive(id); |
| if (wrap == null) |
| return null; |
| groupManager.removeSharedObject(id); |
| return wrap.getSharedObject(); |
| } |
| } |
| |
| protected void sendCreate(ID sharedObjectID, ID toContainerID, |
| SharedObjectDescription sd) throws IOException { |
| sendCreateSharedObjectMessage(toContainerID, sd); |
| } |
| |
| protected void sendCreateResponse(ID homeID, ID sharedObjectID, |
| Throwable t, long identifier) throws IOException { |
| sendCreateResponseSharedObjectMessage(homeID, sharedObjectID, t, |
| identifier); |
| } |
| |
| protected void sendCreateResponseSharedObjectMessage(ID toContainerID, |
| ID fromSharedObject, Throwable t, long ident) throws IOException { |
| sendMessage(ContainerMessage.createSharedObjectCreateResponseMessage( |
| getID(), toContainerID, getNextSequenceNumber(), |
| fromSharedObject, t, ident)); |
| } |
| |
| protected ID[] sendCreateSharedObjectMessage(ID toContainerID, |
| SharedObjectDescription sd) throws IOException { |
| ID[] returnIDs = null; |
| if (toContainerID == null) { |
| synchronized (getGroupMembershipLock()) { |
| // Send message to all |
| sendMessage(ContainerMessage.createSharedObjectCreateMessage( |
| getID(), toContainerID, getNextSequenceNumber(), sd)); |
| returnIDs = getOtherMemberIDs(); |
| } |
| } else { |
| // If the create msg is directed to this space, no msg will be sent |
| if (getID().equals(toContainerID)) { |
| returnIDs = new ID[0]; |
| } else { |
| sendMessage(ContainerMessage.createSharedObjectCreateMessage( |
| getID(), toContainerID, getNextSequenceNumber(), sd)); |
| returnIDs = new ID[1]; |
| returnIDs[0] = toContainerID; |
| } |
| } |
| return returnIDs; |
| } |
| |
| protected Map createContainerPropertiesForSharedObject(ID sharedObjectID) { |
| return new HashMap(); |
| } |
| |
| protected void sendDispose(ID toContainerID, ID sharedObjectID) |
| throws IOException { |
| sendDisposeSharedObjectMessage(toContainerID, sharedObjectID); |
| } |
| |
| protected void sendDisposeSharedObjectMessage(ID toContainerID, |
| ID fromSharedObject) throws IOException { |
| sendMessage(ContainerMessage.createSharedObjectDisposeMessage(getID(), |
| toContainerID, getNextSequenceNumber(), fromSharedObject)); |
| } |
| |
| protected void sendMessage(ContainerMessage data) throws IOException { |
| synchronized (getGroupMembershipLock()) { |
| ID ourID = getID(); |
| // We don't send to ourselves |
| if (!ourID.equals(data.getToContainerID())) |
| queueContainerMessage(data); |
| } |
| } |
| |
| protected byte[] serializeSharedObjectMessage(ID sharedObjectID, |
| Object message) throws IOException { |
| if (!(message instanceof Serializable)) |
| throw new NotSerializableException( |
| Messages.SOContainer_Shared_Object_Message + message |
| + Messages.SOContainer_Not_Serializable); |
| ByteArrayOutputStream bouts = new ByteArrayOutputStream(); |
| IdentifiableObjectOutputStream ioos = new IdentifiableObjectOutputStream( |
| sharedObjectID.getName(), bouts); |
| ioos.writeObject(message); |
| return bouts.toByteArray(); |
| } |
| |
| protected Object deserializeSharedObjectMessage(byte[] bytes) |
| throws IOException, ClassNotFoundException { |
| ByteArrayInputStream bins = new ByteArrayInputStream(bytes); |
| Object obj = null; |
| try { |
| // First try normal classloading. In Eclipse environment this will |
| // use |
| // buddy classloading |
| ObjectInputStream oins = new ObjectInputStream(bins); |
| obj = oins.readObject(); |
| } catch (ClassNotFoundException e) { |
| // first reset stream |
| bins.reset(); |
| // Now try with shared object classloader |
| IdentifiableObjectInputStream iins = new IdentifiableObjectInputStream( |
| new IClassLoaderMapper() { |
| public ClassLoader mapNameToClassLoader(String name) { |
| ISharedObjectManager manager = getSharedObjectManager(); |
| ID[] ids = manager.getSharedObjectIDs(); |
| ID found = null; |
| for (int i = 0; i < ids.length; i++) { |
| ID id = ids[i]; |
| if (name.equals(id.getName())) { |
| found = id; |
| break; |
| } |
| } |
| if (found == null) |
| return null; |
| ISharedObject obj = manager.getSharedObject(found); |
| if (obj == null) |
| return null; |
| return obj.getClass().getClassLoader(); |
| } |
| }, bins); |
| obj = iins.readObject(); |
| } |
| return obj; |
| } |
| |
| protected void sendMessage(ID toContainerID, ID sharedObjectID, |
| Object message) throws IOException { |
| if (message == null) |
| return; |
| // fire IContainerSharedObjectMessageSendingEvent |
| fireContainerEvent(new ContainerSharedObjectMessageSendingEvent( |
| getID(), toContainerID, sharedObjectID, message)); |
| byte[] sendData = serializeSharedObjectMessage(sharedObjectID, message); |
| sendSharedObjectMessage(toContainerID, sharedObjectID, sendData); |
| } |
| |
| protected void sendSharedObjectMessage(ID toContainerID, |
| ID fromSharedObject, Serializable data) throws IOException { |
| sendMessage(ContainerMessage.createSharedObjectMessage(getID(), |
| toContainerID, getNextSequenceNumber(), fromSharedObject, data)); |
| } |
| |
| protected void setMaxGroupMembers(int max) { |
| groupManager.setMaxMembers(max); |
| } |
| |
| /** |
| * @param containerEvent |
| */ |
| protected void fireDelegateContainerEvent( |
| IContainerEvent containerEvent) { |
| super.fireContainerEvent(containerEvent); |
| |
| } |
| |
| } |