/**************************************************************************** * 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.example.collab.share; import java.io.IOException; import java.io.Serializable; import java.util.Hashtable; import java.util.Random; import org.eclipse.core.runtime.Assert; import org.eclipse.ecf.core.events.IContainerConnectedEvent; import org.eclipse.ecf.core.events.IContainerDisconnectedEvent; import org.eclipse.ecf.core.identity.ID; import org.eclipse.ecf.core.identity.IDFactory; import org.eclipse.ecf.core.sharedobject.ISharedObject; import org.eclipse.ecf.core.sharedobject.ISharedObjectConfig; import org.eclipse.ecf.core.sharedobject.ISharedObjectContainerTransaction; import org.eclipse.ecf.core.sharedobject.ISharedObjectContext; import org.eclipse.ecf.core.sharedobject.ReplicaSharedObjectDescription; import org.eclipse.ecf.core.sharedobject.SharedObjectInitException; import org.eclipse.ecf.core.sharedobject.events.ISharedObjectActivatedEvent; import org.eclipse.ecf.core.sharedobject.events.ISharedObjectCreateResponseEvent; import org.eclipse.ecf.core.sharedobject.events.ISharedObjectDeactivatedEvent; import org.eclipse.ecf.core.sharedobject.events.ISharedObjectMessageEvent; import org.eclipse.ecf.core.sharedobject.events.RemoteSharedObjectEvent; import org.eclipse.ecf.core.sharedobject.util.IQueueEnqueue; import org.eclipse.ecf.core.sharedobject.util.QueueException; import org.eclipse.ecf.core.util.Event; import org.eclipse.ecf.internal.example.collab.ClientPlugin; public class GenericSharedObject implements ISharedObject { protected static final String ARGS_PROPERTY_NAME = "args"; //$NON-NLS-1$ protected static final class MsgMap { String meth; Object obj; MsgMap(Object o, String m) { obj = o; meth = m; } public Object getObject() { return obj; } } private static long replicateID = 0; protected ISharedObjectConfig config; protected SharedObjectMsg currentMsg; protected ID currentMsgFromContainerID; protected ID currentMsgFromObjID; protected Hashtable msgMap; protected Object msgMapLock = new Object(); ID localContainerID; protected static long getNextReplicateID() { return replicateID++; } public void activated(ID[] ids) { if (isHost()) replicate(null); } public void deactivated() { } public void destroyRemote(ID remoteID) throws IOException { getContext().sendDispose(remoteID); } public void destroySelf() { if (isHost()) { try { // Send destroy message to all known remotes destroyRemote(null); } catch (IOException e) { log("Exception sending destroy message to remotes", e); //$NON-NLS-1$ } } destroySelfLocal(); } public void destroySelfLocal() { getContext().getSharedObjectManager().removeSharedObject( getConfig().getSharedObjectID()); } /* * (non-Javadoc) * * @see org.eclipse.ecf.core.ISharedObject#dispose(org.eclipse.ecf.core.identity.ID) */ public void dispose(ID containerID) { } protected void execMsg(ID fromID, SharedObjectMsg msg) { try { MsgMap m = null; synchronized (msgMapLock) { m = (MsgMap) ((msgMap == null) ? null : (msgMap.get(msg .getMethodName()))); } Object o = this; String methName = null; if (m != null) { if (m.obj != null) { o = m.obj; } if (m.meth != null) { methName = m.meth; } } if (methName != null) { msg = SharedObjectMsg.createMsg(msg.getClassName(), methName, msg.getArgs()); } if (currentMsgFromObjID == null) currentMsgFromObjID = getID(); currentMsgFromContainerID = fromID; currentMsg = msg; // Actually invoke msg on given object. Typically will be 'this'. execMsgInvoke(msg, currentMsgFromObjID, o); currentMsg = null; currentMsgFromContainerID = null; } catch (Throwable e) { msgException(this, msg, e); } } protected void execMsgInvoke(SharedObjectMsg msg, ID fromID, Object o) throws Exception { if (msg == null || fromID == null || o == null) return; try { msg.invoke(o); } catch (NoSuchMethodException e) { msg.invokeFrom(fromID, o); } } protected void forwardMsgHome(SharedObjectMsg msg) throws IOException { forwardMsgTo(config.getHomeContainerID(), msg); } protected void forwardMsgTo(ID toID, SharedObjectMsg msg) throws IOException { getContext().sendMessage(toID, new RemoteSharedObjectMsgEvent(getID(), toID, msg)); } /* * (non-Javadoc) * * @see org.eclipse.ecf.core.ISharedObject#getAdapter(java.lang.Class) */ public Object getAdapter(Class clazz) { if (clazz.equals(ISharedObjectContainerTransaction.class) && (this instanceof ISharedObjectContainerTransaction)) { return this; } return null; } public ISharedObjectContext getContext() { return getConfig().getContext(); } public ISharedObjectConfig getConfig() { return config; } protected ID getHomeContainerID() { return getConfig().getHomeContainerID(); } public ID getID() { return getConfig().getSharedObjectID(); } protected ReplicaSharedObjectDescription getReplicaDescription(ID receiver) { return new ReplicaSharedObjectDescription(getClass(), getID(), getHomeContainerID(), getConfig().getProperties(), getNextReplicateID()); } protected void handleCreateResponse(ID fromID, Throwable t, Long identifier) { } /* * (non-Javadoc) * * @see org.eclipse.ecf.core.ISharedObject#handleEvent(org.eclipse.ecf.core.util.Event) */ public void handleEvent(Event event) { if (event instanceof ISharedObjectActivatedEvent) { ISharedObjectActivatedEvent ae = (ISharedObjectActivatedEvent) event; ID myID = getID(); if (myID == null) return; if (myID.equals(ae.getActivatedID())) { activated(getContext().getSharedObjectManager() .getSharedObjectIDs()); } else { otherActivated(ae.getActivatedID()); } } else if (event instanceof ISharedObjectDeactivatedEvent) { ISharedObjectDeactivatedEvent ae = (ISharedObjectDeactivatedEvent) event; ID myID = getID(); if (myID == null) return; if (myID.equals(ae.getDeactivatedID())) { deactivated(); } else { otherDeactivated(ae.getDeactivatedID()); } } else if (event instanceof IContainerConnectedEvent) { memberAdded(((IContainerConnectedEvent) event).getTargetID()); } else if (event instanceof IContainerDisconnectedEvent) { memberRemoved(((IContainerDisconnectedEvent) event).getTargetID()); } else if (event instanceof ISharedObjectMessageEvent) { handleSharedObjectMessageEvent(((ISharedObjectMessageEvent) event)); } } protected void handleSharedObjectMessageEvent( ISharedObjectMessageEvent event) { if (event instanceof RemoteSharedObjectEvent) { if (event instanceof ISharedObjectCreateResponseEvent) { handleCreateResponseMessageEvent((ISharedObjectCreateResponseEvent) event); } else if (event instanceof RemoteSharedObjectMsgEvent) { handleSelfSendMessageEvent((RemoteSharedObjectMsgEvent) event); } else { RemoteSharedObjectMsgEvent me = (RemoteSharedObjectMsgEvent) event .getData(); SharedObjectMsg msg = me.getMsg(); execMsg(me.getRemoteContainerID(), msg); } } } protected void handleSelfSendMessageEvent(RemoteSharedObjectMsgEvent event) { execMsg(event.getRemoteContainerID(), event.getMsg()); } protected void handleCreateResponseMessageEvent( ISharedObjectCreateResponseEvent event) { handleCreateResponse(event.getRemoteContainerID(), event.getException(), new Long(event.getSequence())); } /* * (non-Javadoc) * * @see org.eclipse.ecf.core.ISharedObject#handleEvents(org.eclipse.ecf.core.util.Event[]) */ public void handleEvents(Event[] events) { for (int i = 0; i < events.length; i++) { handleEvent(events[i]); } } public void handleRemoteData(ID spaceID, Serializable msg) { SharedObjectMsg aMsg = (SharedObjectMsg) msg; if (isReplicaMsgAllowed(spaceID, aMsg) != null) { execMsg(spaceID, aMsg); } else { ignoreReplicaMsg(spaceID, aMsg); } } protected void ignoreReplicaMsg(ID fromID, SharedObjectMsg msg) { // Do nothing } protected void ignoreSharedObjectMsg(ID fromID, SharedObjectMsg aMsg) { // Do nothing } /* * (non-Javadoc) * * @see org.eclipse.ecf.core.ISharedObject#init(org.eclipse.ecf.core.ISharedObjectConfig) */ public void init(ISharedObjectConfig initData) throws SharedObjectInitException { this.config = initData; this.localContainerID = getContext().getLocalContainerID(); } public boolean isHost() { ID homeContainerID = getHomeContainerID(); if (homeContainerID == null) return false; else return (homeContainerID.equals(localContainerID)); } protected Object isMsgAllowed(ID fromID, SharedObjectMsg aMsg) { return this; } protected Object isReplicaMsgAllowed(ID fromID, SharedObjectMsg aMsg) { return this; } public boolean isServer() { return getContext().isGroupManager(); } public void memberAdded(ID member) { if (isHost()) replicate(member); } public void memberRemoved(ID member) { } public void msgException(Object target, SharedObjectMsg aMsg, Throwable e) { if (e != null) e.printStackTrace(System.err); } public void otherActivated(ID member) { } public void otherDeactivated(ID member) { } public void registerProxy(Object object, String msg) { registerProxy(object, msg, null); } protected void registerProxy(Object target, String msg, String method) { Assert.isNotNull(msg); Assert.isNotNull(target); synchronized (msgMapLock) { // Create table lazily if (msgMap == null) msgMap = new Hashtable(); else if (msgMap.containsKey(msg)) throw new IllegalArgumentException( "registerProxy: proxy already registered for " //$NON-NLS-1$ + method + " by " + target); //$NON-NLS-1$ // Then put entry into table with msg as key msgMap.put(msg, new MsgMap(target, method)); } } protected void replicate(ID remote) { try { // Get current group membership ID[] group = getContext().getGroupMemberIDs(); if (group == null || group.length < 1) { // we're done return; } ReplicaSharedObjectDescription createInfo = getReplicaDescription(remote); if (createInfo != null) getContext().sendCreate(remote, createInfo); else return; } catch (IOException e) { log("Exception in replicate", e); //$NON-NLS-1$ } } protected void sendSelf(SharedObjectMsg msg) { IQueueEnqueue queue = getContext().getQueue(); try { queue.enqueue(new RemoteSharedObjectMsgEvent(getID(), getContext() .getLocalContainerID(), msg)); } catch (QueueException e) { log("QueueException enqueing message to self", e); //$NON-NLS-1$ } } public void sharedObjectMsg(ID fromID, SharedObjectMsg msg) { if (isMsgAllowed(fromID, msg) != null) { currentMsgFromObjID = fromID; execMsg(localContainerID, msg); currentMsgFromObjID = null; } else { ignoreSharedObjectMsg(fromID, msg); } } protected void trace(String msg) { } protected void log(String msg, Throwable t) { ClientPlugin.log(msg, t); } public ID createObject(ID target, ReplicaSharedObjectDescription desc) throws Exception { if (target == null) { if (desc.getID() == null) { desc.setID(IDFactory.getDefault().createStringID( getUniqueString())); } try { return getContext().getSharedObjectManager() .createSharedObject(desc); } catch (Exception e) { log("Exception creating replicated object", e); //$NON-NLS-1$ throw e; } } else throw new Exception( "Cannot send object creation request direct to target"); //$NON-NLS-1$ } public String getUniqueString() { return String.valueOf((new Random()).nextLong()); } }