diff options
author | pnehrer | 2005-02-02 20:45:19 +0000 |
---|---|---|
committer | pnehrer | 2005-02-02 20:45:19 +0000 |
commit | d44dd594131c7c864d335be33ec6b2f0436e3bdd (patch) | |
tree | cf2dcbc8fa9a44747f79b2958f8869ba137fe079 /examples | |
parent | 1ebdaf7cddc27342e532e6ae0f8d3f404b32ba15 (diff) | |
download | org.eclipse.ecf-d44dd594131c7c864d335be33ec6b2f0436e3bdd.tar.gz org.eclipse.ecf-d44dd594131c7c864d335be33ec6b2f0436e3bdd.tar.xz org.eclipse.ecf-d44dd594131c7c864d335be33ec6b2f0436e3bdd.zip |
Refactored, fixed bugs, and made SharedSDOEditor work!
Diffstat (limited to 'examples')
9 files changed, 713 insertions, 503 deletions
diff --git a/examples/bundles/org.eclipse.ecf.example.sdo.editor/META-INF/MANIFEST.MF b/examples/bundles/org.eclipse.ecf.example.sdo.editor/META-INF/MANIFEST.MF index 8d07a12cd..22615b4d4 100644 --- a/examples/bundles/org.eclipse.ecf.example.sdo.editor/META-INF/MANIFEST.MF +++ b/examples/bundles/org.eclipse.ecf.example.sdo.editor/META-INF/MANIFEST.MF @@ -15,3 +15,5 @@ Require-Bundle: org.eclipse.ui, org.eclipse.ecf.test.provider, org.eclipse.ecf.example.collab Eclipse-AutoStart: true +Provide-Package: org.eclipse.ecf.example.sdo.editor +Export-Package: org.eclipse.ecf.example.sdo.editor diff --git a/examples/bundles/org.eclipse.ecf.example.sdo.editor/src/org/eclipse/ecf/example/sdo/editor/EditorPlugin.java b/examples/bundles/org.eclipse.ecf.example.sdo.editor/src/org/eclipse/ecf/example/sdo/editor/EditorPlugin.java index 7f6f5f349..82381c9fe 100644 --- a/examples/bundles/org.eclipse.ecf.example.sdo.editor/src/org/eclipse/ecf/example/sdo/editor/EditorPlugin.java +++ b/examples/bundles/org.eclipse.ecf.example.sdo.editor/src/org/eclipse/ecf/example/sdo/editor/EditorPlugin.java @@ -21,9 +21,10 @@ import org.eclipse.ecf.core.identity.IDFactory; import org.eclipse.ecf.core.util.ECFException; import org.eclipse.ecf.example.collab.Client; import org.eclipse.ecf.sdo.ISharedDataGraph; -import org.eclipse.ecf.sdo.ISubscriptionCallback; import org.eclipse.ecf.sdo.IUpdateConsumer; import org.eclipse.ecf.sdo.SDOPlugin; +import org.eclipse.ecf.sdo.WaitablePublicationCallback; +import org.eclipse.ecf.sdo.WaitableSubscriptionCallback; import org.eclipse.ecf.sdo.emf.EMFUpdateProvider; import org.eclipse.ecf.test.EventSpy; import org.eclipse.ui.plugin.AbstractUIPlugin; @@ -37,141 +38,159 @@ import commonj.sdo.DataGraph; * @author pnehrer */ public class EditorPlugin extends AbstractUIPlugin { - // The shared instance. - private static EditorPlugin plugin; - - // Resource bundle. - private ResourceBundle resourceBundle; - - private ISharedObjectContainer container; - - private PublishedGraphTracker tracker; - - /** - * The constructor. - */ - public EditorPlugin() { - super(); - plugin = this; - try { - resourceBundle = ResourceBundle - .getBundle("org.eclipse.ecf.example.sdo.editor.EditorPluginResources"); - } catch (MissingResourceException x) { - resourceBundle = null; - } - } - - /** - * This method is called upon plug-in activation - */ - public void start(BundleContext context) throws Exception { - super.start(context); - } - - /** - * This method is called when the plug-in is stopped - */ - public void stop(BundleContext context) throws Exception { - super.stop(context); - } - - /** - * Returns the shared instance. - */ - public static EditorPlugin getDefault() { - return plugin; - } - - /** - * Returns the string from the plugin's resource bundle, or 'key' if not - * found. - */ - public static String getResourceString(String key) { - ResourceBundle bundle = EditorPlugin.getDefault().getResourceBundle(); - try { - return (bundle != null) ? bundle.getString(key) : key; - } catch (MissingResourceException e) { - return key; - } - } - - /** - * Returns the plugin's resource bundle, - */ - public ResourceBundle getResourceBundle() { - return resourceBundle; - } - - public void log(Throwable t) { - if (t instanceof CoreException) - getLog().log(((CoreException) t).getStatus()); - else - getLog().log( - new Status(Status.ERROR, getBundle().getSymbolicName(), 0, - "An unexpected error occurred.", t)); - } - - public synchronized ISharedDataGraph subscribe(String path, - ISubscriptionCallback callback, IUpdateConsumer consumer) - throws ECFException { - initialize(); - SDOPlugin.getDefault().setDebug(true); - ID id = IDFactory.makeStringID(path); - ISharedDataGraph result = SDOPlugin.getDefault().getDataGraphSharing( - container).subscribe(id, callback, new EMFUpdateProvider(), - consumer); - tracker.add(id); - return result; - } - - public synchronized ISharedDataGraph publish(String path, - DataGraph dataGraph, IUpdateConsumer consumer) throws ECFException { - initialize(); - SDOPlugin.getDefault().setDebug(true); - ID id = IDFactory.makeStringID(path); - ISharedDataGraph result = SDOPlugin.getDefault().getDataGraphSharing( - container).publish(dataGraph, id, new EMFUpdateProvider(), - consumer); - tracker.add(id); - return result; - } - - public synchronized boolean isPublished(String path) throws ECFException { - initialize(); - return tracker.isPublished(IDFactory.makeStringID(path)); - } - - public synchronized void checkConnected() throws ECFException { - initialize(); - } - - private void initialize() throws ECFException { - if (tracker == null) { - Client client; - try { - client = new Client(); - } catch (Exception e) { - throw new ECFException(e); - } - - container = client.getContainer(); - if (container == null) - throw new ECFException("Not connected."); - - PublishedGraphTracker tracker = new PublishedGraphTracker(); - container.getSharedObjectManager().addSharedObject( - IDFactory.makeStringID(PublishedGraphTracker.class - .getName()), tracker, null, null); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - // ignore - } - - this.tracker = tracker; - container.getSharedObjectManager() - .addSharedObject(IDFactory.makeStringID("debug"), - new EventSpy(), null, null); - } - } + // The shared instance. + private static EditorPlugin plugin; + + // Resource bundle. + private ResourceBundle resourceBundle; + + private ISharedObjectContainer container; + + private PublishedGraphTracker tracker; + + /** + * The constructor. + */ + public EditorPlugin() { + super(); + plugin = this; + try { + resourceBundle = ResourceBundle + .getBundle("org.eclipse.ecf.example.sdo.editor.EditorPluginResources"); + } catch (MissingResourceException x) { + resourceBundle = null; + } + } + + /** + * This method is called upon plug-in activation + */ + public void start(BundleContext context) throws Exception { + super.start(context); + } + + /** + * This method is called when the plug-in is stopped + */ + public void stop(BundleContext context) throws Exception { + super.stop(context); + } + + /** + * Returns the shared instance. + */ + public static EditorPlugin getDefault() { + return plugin; + } + + /** + * Returns the string from the plugin's resource bundle, or 'key' if not + * found. + */ + public static String getResourceString(String key) { + ResourceBundle bundle = EditorPlugin.getDefault().getResourceBundle(); + try { + return (bundle != null) ? bundle.getString(key) : key; + } catch (MissingResourceException e) { + return key; + } + } + + /** + * Returns the plugin's resource bundle, + */ + public ResourceBundle getResourceBundle() { + return resourceBundle; + } + + public void log(Throwable t) { + if (t instanceof CoreException) + getLog().log(((CoreException) t).getStatus()); + else + getLog().log( + new Status(Status.ERROR, getBundle().getSymbolicName(), 0, + "An unexpected error occurred.", t)); + } + + public synchronized ISharedDataGraph subscribe(String path, + IUpdateConsumer consumer) throws ECFException { + initialize(); + SDOPlugin.getDefault().setDebug(true); + ID id = IDFactory.makeStringID(path); + WaitableSubscriptionCallback mutex = new WaitableSubscriptionCallback(); + ISharedDataGraph result = SDOPlugin.getDefault().getDataGraphSharing( + container).subscribe(id, new EMFUpdateProvider(), consumer, + mutex); + ID containerID = null; + try { + containerID = mutex.waitForSubscription(5000); + } catch (InterruptedException e) { + throw new ECFException(e); + } + + if (containerID == null) + throw new ECFException("Subscription timed out."); + + tracker.add(id); + return result; + } + + public synchronized ISharedDataGraph publish(String path, + DataGraph dataGraph, IUpdateConsumer consumer) throws ECFException { + initialize(); + SDOPlugin.getDefault().setDebug(true); + ID id = IDFactory.makeStringID(path); + WaitablePublicationCallback mutex = new WaitablePublicationCallback(); + ISharedDataGraph result = SDOPlugin.getDefault().getDataGraphSharing( + container).publish(dataGraph, id, new EMFUpdateProvider(), + consumer, mutex); + try { + if (!mutex.waitForPublication(5000)) + throw new ECFException("Publication timed out."); + } catch (InterruptedException e) { + throw new ECFException(e); + } + + tracker.add(id); + return result; + } + + public synchronized boolean isPublished(String path) throws ECFException { + initialize(); + return tracker.isPublished(IDFactory.makeStringID(path)); + } + + public synchronized void checkConnected() throws ECFException { + initialize(); + } + + private void initialize() throws ECFException { + if (tracker == null) { + Client client; + try { + client = new Client(); + } catch (Exception e) { + throw new ECFException(e); + } + + container = client.getContainer(); + if (container == null) + throw new ECFException("Not connected."); + + ID id = IDFactory.makeStringID(PublishedGraphTracker.class + .getName()); + PublishedGraphTracker tracker = (PublishedGraphTracker) container + .getSharedObjectManager().getSharedObject(id); + if (tracker == null) { + tracker = new PublishedGraphTracker(); + container.getSharedObjectManager().addSharedObject(id, tracker, + null, null); + } + + this.tracker = tracker; + container.getSharedObjectManager() + .addSharedObject(IDFactory.makeStringID("debug"), + new EventSpy(), null, null); + } + } }
\ No newline at end of file diff --git a/examples/bundles/org.eclipse.ecf.example.sdo.editor/src/org/eclipse/ecf/example/sdo/editor/PublishedGraphTracker.java b/examples/bundles/org.eclipse.ecf.example.sdo.editor/src/org/eclipse/ecf/example/sdo/editor/PublishedGraphTracker.java index e48d8c6b7..ba19e9581 100644 --- a/examples/bundles/org.eclipse.ecf.example.sdo.editor/src/org/eclipse/ecf/example/sdo/editor/PublishedGraphTracker.java +++ b/examples/bundles/org.eclipse.ecf.example.sdo.editor/src/org/eclipse/ecf/example/sdo/editor/PublishedGraphTracker.java @@ -11,14 +11,16 @@ package org.eclipse.ecf.example.sdo.editor; import java.io.IOException; -import java.util.Arrays; +import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; +import java.util.Map; -import org.eclipse.core.runtime.PlatformObject; import org.eclipse.ecf.core.ISharedObject; import org.eclipse.ecf.core.ISharedObjectConfig; +import org.eclipse.ecf.core.ISharedObjectContext; +import org.eclipse.ecf.core.SharedObjectDescription; import org.eclipse.ecf.core.SharedObjectInitException; import org.eclipse.ecf.core.events.ISharedObjectActivatedEvent; import org.eclipse.ecf.core.events.ISharedObjectContainerDepartedEvent; @@ -30,254 +32,370 @@ import org.eclipse.ecf.core.util.ECFException; import org.eclipse.ecf.core.util.Event; /** + * <p> + * Tracks explicit data graph publication (or any shared object presence, + * really) across all containers in a connected group using the server replica + * to bootstrap new members. + * </p> + * <p> + * It works something like this: + * </p> + * <ul> + * <li>The client should first check if an instance of this shared object + * already exists in their container. If not, create one and add it.</li> + * <li>The client should call {@link #add(ID) add()}once published/subscribed + * to a data graph. The method will block until this object activates (if it + * hasn't already).</li> + * <li>Upon activation, the primary instance replicates everywhere. This is to + * assure that there is a server replica (and a replica in the initial set of + * connected containers).</li> + * <li>When a new container joins the group, the server will create a replica + * in it, initialized with its current graph location table. This is to assure + * that new members are properly bootstrapped.</li> + * <li>All replicas broadcast additions/removals of their local data graphs and + * listen to remote additions/removals in order to keep track of what is + * published and where.</li> + * <li>When a container leaves the group, all replicas note it and update their + * graph location tables. Likewise, when a replica deactivates, it broadcasts + * its departure so others may update their tables.</li> + * </ul> + * <p> + * It is assumed that the container implementation used with this class is + * server-centric. That is, there is a server that is always connected before + * any other container may connect. When the server disconnects, everyone else + * in effect disconnects. + * </p> + * * @author pnehrer */ -class PublishedGraphTracker extends PlatformObject implements ISharedObject { - - private static final ID[] NO_GRAPHS = {}; - - private static final int JOIN = 0; - - private static final int LEAVE = 1; - - private static final int ADD = 2; - - private static final int REMOVE = 3; - - private class Table { - - private final Hashtable graphs = new Hashtable(); - - private final Hashtable containers = new Hashtable(); - - public synchronized void add(ID containerID, ID[] graphs) { - HashSet list = (HashSet) this.graphs.get(containerID); - if (list == null) { - list = new HashSet(); - this.graphs.put(containerID, list); - } - - list.addAll(Arrays.asList(graphs)); - for (int i = 0; i < graphs.length; ++i) { - list = (HashSet) containers.get(graphs[i]); - if (list == null) { - list = new HashSet(); - containers.put(graphs[i], list); - } - - list.add(containerID); - } - } - - public synchronized void remove(ID containerID, ID graph) { - HashSet list = (HashSet) graphs.get(containerID); - if (list != null) { - list.remove(graph); - if (list.isEmpty()) - graphs.remove(containerID); - } - - list = (HashSet) containers.get(graph); - if (list != null) { - list.remove(containerID); - if (list.isEmpty()) - containers.remove(graph); - } - } - - public synchronized void remove(ID containerID) { - HashSet list = (HashSet) graphs.get(containerID); - if (list != null) { - for (Iterator i = list.iterator(); i.hasNext();) { - ID graph = (ID) i.next(); - list = (HashSet) containers.get(graph); - if (list != null) { - list.remove(containerID); - if (list.isEmpty()) - containers.remove(graph); - } - } - } - } - - public synchronized boolean contains(ID graph) { - return containers.containsKey(graph); - } - - public synchronized ID[] getGraphs(ID containerID) { - HashSet list = (HashSet) graphs.get(containerID); - return list == null ? NO_GRAPHS : (ID[]) list.toArray(new ID[list - .size()]); - } - } - - private final Table table = new Table(); - - private ISharedObjectConfig config; - - public synchronized void add(ID graph) throws ECFException { - if (config == null) - throw new ECFException("Not connected."); - - ID[] graphs = new ID[] { graph }; - try { - config.getContext().sendMessage(null, - new Object[] { new Integer(ADD), graphs }); - } catch (IOException e) { - throw new ECFException(e); - } - - handleAdd(config.getContext().getLocalContainerID(), graphs); - } - - public synchronized boolean isPublished(ID graph) { - return table.contains(graph); - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.ecf.core.ISharedObject#init(org.eclipse.ecf.core.ISharedObjectConfig) - */ - public synchronized void init(ISharedObjectConfig initData) - throws SharedObjectInitException { - if (config == null) - config = initData; - else - throw new SharedObjectInitException("Already initialized."); - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.ecf.core.ISharedObject#handleEvent(org.eclipse.ecf.core.util.Event) - */ - public void handleEvent(Event event) { - if (event instanceof ISharedObjectMessageEvent) { - ISharedObjectMessageEvent e = (ISharedObjectMessageEvent) event; - Object[] data = (Object[]) e.getData(); - Integer type = (Integer) data[0]; - switch (type.intValue()) { - case JOIN: - handleJoin(e.getRemoteContainerID(), - data.length > 1 ? (ID[]) data[1] : null); - break; - - case LEAVE: - handleLeave(e.getRemoteContainerID()); - break; - - case ADD: - handleAdd(e.getRemoteContainerID(), (ID[]) data[1]); - break; - - case REMOVE: - handleRemove(e.getRemoteContainerID(), (ID) data[1]); - } - } else if (event instanceof ISharedObjectContainerJoinedEvent) { - if (((ISharedObjectContainerJoinedEvent) event) - .getJoinedContainerID().equals( - config.getContext().getLocalContainerID())) - handleJoined(); - } else if (event instanceof ISharedObjectContainerDepartedEvent) { - ISharedObjectContainerDepartedEvent e = (ISharedObjectContainerDepartedEvent) event; - if (!e.getDepartedContainerID().equals( - config.getContext().getLocalContainerID())) - handleLeave(e.getDepartedContainerID()); - } else if (event instanceof ISharedObjectActivatedEvent) { - ISharedObjectActivatedEvent e = (ISharedObjectActivatedEvent) event; - if (e.getActivatedID().equals(config.getSharedObjectID())) - handleJoined(); - } else if (event instanceof ISharedObjectDeactivatedEvent) { - ISharedObjectDeactivatedEvent e = (ISharedObjectDeactivatedEvent) event; - if (e.getDeactivatedID().equals(config.getSharedObjectID())) - handleDeactivated(); - else if (table.contains(e.getDeactivatedID())) - handleRemoved(e.getDeactivatedID()); - } - } - - private void handleJoin(ID containerID, ID[] graphs) { - if (graphs != null) - table.add(containerID, graphs); - - graphs = table.getGraphs(config.getContext().getLocalContainerID()); - if (graphs.length > 0) - try { - config.getContext().sendMessage(containerID, - new Object[] { new Integer(ADD), graphs }); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - private void handleLeave(ID containerID) { - table.remove(containerID); - } - - private void handleAdd(ID containerID, ID[] graphs) { - table.add(containerID, graphs); - } - - private void handleRemove(ID containerID, ID graph) { - table.remove(containerID, graph); - } - - private void handleJoined() { - ID[] graphs = table - .getGraphs(config.getContext().getLocalContainerID()); - Object[] data = graphs.length == 0 ? new Object[] { new Integer(JOIN) } - : new Object[] { new Integer(JOIN), graphs }; - try { - config.getContext().sendMessage(null, data); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - private void handleDeactivated() { - try { - config.getContext().sendMessage(null, - new Object[] { new Integer(LEAVE) }); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - private void handleRemoved(ID graph) { - try { - config.getContext().sendMessage(null, - new Object[] { new Integer(REMOVE), graph }); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - handleRemove(config.getContext().getLocalContainerID(), graph); - } - - /* - * (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]); - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.ecf.core.ISharedObject#dispose(org.eclipse.ecf.core.identity.ID) - */ - public synchronized void dispose(ID containerID) { - if (config != null - && config.getContext().getLocalContainerID() - .equals(containerID)) - config = null; - } +public class PublishedGraphTracker implements ISharedObject { + + private static final ID[] NO_GRAPHS = {}; + + private static final int ADD = 0; + + private static final int REMOVE = 1; + + private static final int LEAVE = 2; + + private static final String ARG_TABLE = "table"; + + private class Table { + + private final Hashtable graphs = new Hashtable(); + + private final Hashtable containers = new Hashtable(); + + public synchronized void add(ID containerID, ID graphID) { + HashSet list = (HashSet) graphs.get(containerID); + if (list == null) { + list = new HashSet(); + graphs.put(containerID, list); + } + + list.add(graphID); + list = (HashSet) containers.get(containerID); + if (list == null) { + list = new HashSet(); + containers.put(graphID, list); + } + + list.add(containerID); + } + + public synchronized void remove(ID containerID, ID graphID) { + HashSet list = (HashSet) graphs.get(containerID); + if (list != null) { + list.remove(graphID); + if (list.isEmpty()) + graphs.remove(containerID); + } + + list = (HashSet) containers.get(graphID); + if (list != null) { + list.remove(containerID); + if (list.isEmpty()) + containers.remove(graphID); + } + } + + public synchronized void remove(ID containerID) { + HashSet list = (HashSet) graphs.get(containerID); + if (list != null) { + for (Iterator i = list.iterator(); i.hasNext();) { + ID graphID = (ID) i.next(); + list = (HashSet) containers.get(graphID); + if (list != null) { + list.remove(containerID); + if (list.isEmpty()) + containers.remove(graphID); + } + } + } + } + + public synchronized boolean contains(ID graphID) { + return containers.containsKey(graphID); + } + + public synchronized ID[] getGraphs(ID containerID) { + HashSet list = (HashSet) graphs.get(containerID); + return list == null ? NO_GRAPHS : (ID[]) list.toArray(new ID[list + .size()]); + } + + public synchronized Object createMemento() { + return new Hashtable[] { graphs, containers }; + } + + public synchronized void load(Object memento) { + Hashtable[] tables = (Hashtable[]) memento; + graphs.putAll(tables[0]); + containers.putAll(tables[1]); + } + } + + private final Table table = new Table(); + + private ISharedObjectConfig config; + + private ISharedObjectContext context; + + private final Object activationMutex = new Object(); + + private boolean activated; + + /** + * Adds a graph to the list of published graphs. + * + * @param graphID + * identifier of the graph that was published + * @throws ECFException + */ + public synchronized void add(ID graphID) throws ECFException { + if (config == null) + throw new ECFException("Not initialized."); + + // wait to be activated before proceeding + synchronized (activationMutex) { + if (!activated) + try { + activationMutex.wait(1000); + } catch (InterruptedException e) { + throw new ECFException(e); + } + + if (!activated) + throw new ECFException("Not activated."); + } + + // tell everyone a graph was published + try { + getContext().sendMessage(null, + new Object[] { new Integer(ADD), graphID }); + } catch (IOException e) { + throw new ECFException(e); + } + + // track it yourself + handleAdd(getContext().getLocalContainerID(), graphID); + } + + /** + * Answers whether a graph is published (at the time of invocation). + * + * @param graphID + * identifier of the graph whose publishing status to return + * @return <code>true</code> if the graph is published + */ + public synchronized boolean isPublished(ID graphID) { + return table.contains(graphID); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.ISharedObject#init(org.eclipse.ecf.core.ISharedObjectConfig) + */ + public synchronized void init(ISharedObjectConfig initData) + throws SharedObjectInitException { + if (config == null) + config = initData; + else + throw new SharedObjectInitException("Already initialized."); + + Map props = (Map) config.getProperties(); + if (props != null) { + Object memento = props.get(ARG_TABLE); + if (memento != null) + table.load(memento); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.ISharedObject#handleEvent(org.eclipse.ecf.core.util.Event) + */ + public void handleEvent(Event event) { + if (event instanceof ISharedObjectMessageEvent) { + // track graph additions/removals and peer departures + // (deactivations) + ISharedObjectMessageEvent e = (ISharedObjectMessageEvent) event; + Object[] data = (Object[]) e.getData(); + Integer type = (Integer) data[0]; + switch (type.intValue()) { + case ADD: + handleAdd(e.getRemoteContainerID(), (ID) data[1]); + break; + + case REMOVE: + handleRemove(e.getRemoteContainerID(), (ID) data[1]); + break; + + case LEAVE: + handleLeave(e.getRemoteContainerID()); + break; + } + } else if (event instanceof ISharedObjectContainerJoinedEvent) { + ISharedObjectContainerJoinedEvent e = (ISharedObjectContainerJoinedEvent) event; + if (e.getJoinedContainerID().equals( + getContext().getLocalContainerID())) + // this container joined + handleJoined(); + else if (getContext().isGroupServer()) + // some other container joined and we're the server + handleJoined(e.getJoinedContainerID()); + } else if (event instanceof ISharedObjectContainerDepartedEvent) { + ISharedObjectContainerDepartedEvent e = (ISharedObjectContainerDepartedEvent) event; + // some other container departed -- same as peer deactivation + if (!e.getDepartedContainerID().equals( + getContext().getLocalContainerID())) + handleLeave(e.getDepartedContainerID()); + } else if (event instanceof ISharedObjectActivatedEvent) { + ISharedObjectActivatedEvent e = (ISharedObjectActivatedEvent) event; + if (e.getActivatedID().equals(config.getSharedObjectID())) + // we're being activated + handleActivated(); + } else if (event instanceof ISharedObjectDeactivatedEvent) { + ISharedObjectDeactivatedEvent e = (ISharedObjectDeactivatedEvent) event; + if (e.getDeactivatedID().equals(config.getSharedObjectID())) + // we're being deactivated + handleDeactivated(); + else if (table.contains(e.getDeactivatedID())) + // a local graph we track is being deactivated + handleRemoved(e.getDeactivatedID()); + } + } + + private void handleAdd(ID containerID, ID graphID) { + table.add(containerID, graphID); + } + + private void handleRemove(ID containerID, ID graphID) { + table.remove(containerID, graphID); + } + + private void handleLeave(ID containerID) { + table.remove(containerID); + } + + private void handleJoined() { + if (config.getHomeContainerID().equals( + getContext().getLocalContainerID())) { + // we're the primary copy -- replicate everywhere + try { + getContext().sendCreate( + null, + new SharedObjectDescription(config.getSharedObjectID(), + getClass())); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + + private void handleJoined(ID containerID) { + Map props = new HashMap(1); + props.put(ARG_TABLE, table.createMemento()); + try { + getContext().sendCreate( + containerID, + new SharedObjectDescription(config.getSharedObjectID(), + getClass(), props)); + } catch (IOException ex) { + // TODO Auto-generated catch block + ex.printStackTrace(); + } + } + + private void handleActivated() { + handleJoined(); + synchronized (activationMutex) { + activated = true; + activationMutex.notifyAll(); + } + } + + private void handleDeactivated() { + try { + getContext().sendMessage(null, new Object[] { new Integer(LEAVE) }); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + synchronized (activationMutex) { + activated = false; + activationMutex.notifyAll(); + } + } + + private void handleRemoved(ID graphID) { + try { + getContext().sendMessage(null, + new Object[] { new Integer(REMOVE), graphID }); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + handleRemove(getContext().getLocalContainerID(), graphID); + } + + /* + * (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]); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.ISharedObject#dispose(org.eclipse.ecf.core.identity.ID) + */ + public synchronized void dispose(ID containerID) { + config = null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.PlatformObject#getAdapter(java.lang.Class) + */ + public Object getAdapter(Class adapter) { + return null; + } + + private ISharedObjectContext getContext() { + if (context == null) + context = config.getContext(); + + return context; + } } diff --git a/examples/bundles/org.eclipse.ecf.example.sdo.editor/src/org/eclipse/ecf/example/sdo/editor/SharedSDOEditor.java b/examples/bundles/org.eclipse.ecf.example.sdo.editor/src/org/eclipse/ecf/example/sdo/editor/SharedSDOEditor.java index e5758874a..67e1e1804 100644 --- a/examples/bundles/org.eclipse.ecf.example.sdo.editor/src/org/eclipse/ecf/example/sdo/editor/SharedSDOEditor.java +++ b/examples/bundles/org.eclipse.ecf.example.sdo.editor/src/org/eclipse/ecf/example/sdo/editor/SharedSDOEditor.java @@ -17,7 +17,6 @@ import org.eclipse.ecf.core.identity.ID; import org.eclipse.ecf.core.util.ECFException; import org.eclipse.ecf.sdo.ISharedDataGraph; import org.eclipse.ecf.sdo.IUpdateConsumer; -import org.eclipse.ecf.sdo.WaitableSubscriptionCallback; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.sdo.EDataGraph; @@ -32,104 +31,86 @@ import commonj.sdo.DataGraph; */ public class SharedSDOEditor extends SDOEditor { - private class UpdateConsumer implements IUpdateConsumer { - public boolean consumeUpdate(ISharedDataGraph graph, ID containerID) { - ChangeSummary changeSummary = graph.getDataGraph() - .getChangeSummary(); - changeSummary.endLogging(); - SharedSDOEditor.super.doSave(null); - changeSummary.beginLogging(); - return true; - } + private class UpdateConsumer implements IUpdateConsumer { + public boolean consumeUpdate(ISharedDataGraph graph, ID containerID) { + ChangeSummary changeSummary = graph.getDataGraph() + .getChangeSummary(); + changeSummary.endLogging(); + SharedSDOEditor.super.doSave(null); + changeSummary.beginLogging(); + return true; + } - public void updateFailed(ISharedDataGraph graph, ID containerID, - Throwable cause) { - EditorPlugin.getDefault().log( - new CoreException(new Status(Status.ERROR, EditorPlugin - .getDefault().getBundle().getSymbolicName(), 0, - "Data graph upate failed.", cause))); - } - } + public void updateFailed(ISharedDataGraph graph, ID containerID, + Throwable cause) { + EditorPlugin.getDefault().log( + new CoreException(new Status(Status.ERROR, EditorPlugin + .getDefault().getBundle().getSymbolicName(), 0, + "Data graph upate failed.", cause))); + } + } - private ISharedDataGraph sharedDataGraph; + private ISharedDataGraph sharedDataGraph; - /* - * (non-Javadoc) - * - * @see org.eclipse.emf.ecore.sdo.presentation.SDOEditor#createModel() - */ - public void createModel() { - try { - IFileEditorInput modelFile = (IFileEditorInput) getEditorInput(); - String path = modelFile.getFile().getFullPath().toString(); - URI uri = URI.createPlatformResourceURI(modelFile.getFile() - .getFullPath().toString()); - if (EditorPlugin.getDefault().isPublished(path)) { - WaitableSubscriptionCallback mutex = new WaitableSubscriptionCallback(); - sharedDataGraph = EditorPlugin.getDefault().subscribe(path, - mutex, new UpdateConsumer()); - ID containerID = null; - Throwable cause = null; - try { - containerID = mutex.waitForSubscription(10000); - } catch (InterruptedException e) { - cause = e; - } + /* + * (non-Javadoc) + * + * @see org.eclipse.emf.ecore.sdo.presentation.SDOEditor#createModel() + */ + public void createModel() { + try { + IFileEditorInput modelFile = (IFileEditorInput) getEditorInput(); + String path = modelFile.getFile().getFullPath().toString(); + URI uri = URI.createPlatformResourceURI(modelFile.getFile() + .getFullPath().toString()); + if (EditorPlugin.getDefault().isPublished(path)) { + sharedDataGraph = EditorPlugin.getDefault().subscribe(path, + new UpdateConsumer()); + EDataGraph dataGraph = (EDataGraph) sharedDataGraph + .getDataGraph(); + dataGraph.getDataGraphResource().setURI(uri); + editingDomain.getResourceSet().getResources().addAll( + dataGraph.getResourceSet().getResources()); + dataGraph.setResourceSet(editingDomain.getResourceSet()); + } else { + Resource resource = editingDomain.loadResource(uri.toString()); + DataGraph dataGraph = (DataGraph) resource.getContents().get(0); + sharedDataGraph = EditorPlugin.getDefault().publish(path, + dataGraph, new UpdateConsumer()); + } + } catch (ECFException e) { + EditorPlugin.getDefault().log(e); + if (sharedDataGraph != null) { + sharedDataGraph.dispose(); + sharedDataGraph = null; + } + } + } - if (containerID == null) { - EditorPlugin.getDefault().log( - new CoreException(new Status(Status.ERROR, - EditorPlugin.getDefault().getBundle() - .getSymbolicName(), 0, - "Failed to subscribe.", cause))); - return; - } + /* + * (non-Javadoc) + * + * @see org.eclipse.emf.ecore.sdo.presentation.SDOEditor#doSave(org.eclipse.core.runtime.IProgressMonitor) + */ + public void doSave(IProgressMonitor progressMonitor) { + super.doSave(progressMonitor); + if (sharedDataGraph != null) + try { + sharedDataGraph.commit(); + } catch (ECFException e) { + EditorPlugin.getDefault().log(e); + } + } - EDataGraph dataGraph = (EDataGraph) sharedDataGraph - .getDataGraph(); - dataGraph.getDataGraphResource().setURI(uri); - editingDomain.getResourceSet().getResources().addAll( - dataGraph.getResourceSet().getResources()); - dataGraph.setResourceSet(editingDomain.getResourceSet()); - } else { - Resource resource = editingDomain.loadResource(uri.toString()); - DataGraph dataGraph = (DataGraph) resource.getContents().get(0); - sharedDataGraph = EditorPlugin.getDefault().publish(path, - dataGraph, new UpdateConsumer()); - } - } catch (ECFException e) { - EditorPlugin.getDefault().log(e); - if (sharedDataGraph != null) { - sharedDataGraph.dispose(); - sharedDataGraph = null; - } - } - } + /* + * (non-Javadoc) + * + * @see org.eclipse.emf.ecore.sdo.presentation.SDOEditor#dispose() + */ + public void dispose() { + if (sharedDataGraph != null) + sharedDataGraph.dispose(); - /* - * (non-Javadoc) - * - * @see org.eclipse.emf.ecore.sdo.presentation.SDOEditor#doSave(org.eclipse.core.runtime.IProgressMonitor) - */ - public void doSave(IProgressMonitor progressMonitor) { - super.doSave(progressMonitor); - if (sharedDataGraph != null) - try { - sharedDataGraph.commit(); - } catch (ECFException e) { - EditorPlugin.getDefault().log(e); - } - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.emf.ecore.sdo.presentation.SDOEditor#dispose() - */ - public void dispose() { - if (sharedDataGraph != null) - sharedDataGraph.dispose(); - - super.dispose(); - } + super.dispose(); + } }
\ No newline at end of file diff --git a/examples/bundles/org.eclipse.ecf.sdo/src/org/eclipse/ecf/internal/sdo/DataGraphSharing.java b/examples/bundles/org.eclipse.ecf.sdo/src/org/eclipse/ecf/internal/sdo/DataGraphSharing.java index fadf0cd58..d1dcf55c5 100644 --- a/examples/bundles/org.eclipse.ecf.sdo/src/org/eclipse/ecf/internal/sdo/DataGraphSharing.java +++ b/examples/bundles/org.eclipse.ecf.sdo/src/org/eclipse/ecf/internal/sdo/DataGraphSharing.java @@ -19,6 +19,7 @@ import org.eclipse.ecf.core.identity.ID; import org.eclipse.ecf.core.util.ECFException; import org.eclipse.ecf.core.util.Event; import org.eclipse.ecf.sdo.IDataGraphSharing; +import org.eclipse.ecf.sdo.IPublicationCallback; import org.eclipse.ecf.sdo.ISharedDataGraph; import org.eclipse.ecf.sdo.ISubscriptionCallback; import org.eclipse.ecf.sdo.IUpdateConsumer; @@ -45,11 +46,12 @@ public class DataGraphSharing extends PlatformObject implements * @see org.eclipse.ecf.sdo.IDataGraphSharing#publish(commonj.sdo.DataGraph, * org.eclipse.ecf.core.identity.ID, * org.eclipse.ecf.sdo.IUpdateProvider, - * org.eclipse.ecf.sdo.IUpdateConsumer) + * org.eclipse.ecf.sdo.IUpdateConsumer, + * org.eclipse.ecf.sdo.IPublicationCallback) */ public synchronized ISharedDataGraph publish(DataGraph dataGraph, ID id, - IUpdateProvider provider, IUpdateConsumer consumer) - throws ECFException { + IUpdateProvider provider, IUpdateConsumer consumer, + IPublicationCallback callback) throws ECFException { if (config == null) throw new ECFException("Not initialized."); @@ -57,7 +59,7 @@ public class DataGraphSharing extends PlatformObject implements // create local object ISharedObjectManager mgr = config.getContext().getSharedObjectManager(); SharedDataGraph sdg = new SharedDataGraph(dataGraph, provider, - consumer, null); + consumer, callback, null); sdg.setDebug(debug); mgr.addSharedObject(id, sdg, null, null); @@ -73,8 +75,8 @@ public class DataGraphSharing extends PlatformObject implements * org.eclipse.ecf.sdo.IUpdateConsumer) */ public synchronized ISharedDataGraph subscribe(ID id, - ISubscriptionCallback callback, IUpdateProvider provider, - IUpdateConsumer consumer) throws ECFException { + IUpdateProvider provider, IUpdateConsumer consumer, + ISubscriptionCallback callback) throws ECFException { if (config == null) throw new ECFException("Not initialized."); @@ -82,7 +84,7 @@ public class DataGraphSharing extends PlatformObject implements // create local object ISharedObjectManager mgr = config.getContext().getSharedObjectManager(); SharedDataGraph sdg = new SharedDataGraph(null, provider, consumer, - callback); + null, callback); sdg.setDebug(debug); mgr.addSharedObject(id, sdg, null, null); diff --git a/examples/bundles/org.eclipse.ecf.sdo/src/org/eclipse/ecf/internal/sdo/SharedDataGraph.java b/examples/bundles/org.eclipse.ecf.sdo/src/org/eclipse/ecf/internal/sdo/SharedDataGraph.java index 6f50b5bd6..870c0ea9b 100644 --- a/examples/bundles/org.eclipse.ecf.sdo/src/org/eclipse/ecf/internal/sdo/SharedDataGraph.java +++ b/examples/bundles/org.eclipse.ecf.sdo/src/org/eclipse/ecf/internal/sdo/SharedDataGraph.java @@ -22,6 +22,7 @@ import org.eclipse.ecf.core.events.ISharedObjectMessageEvent; import org.eclipse.ecf.core.identity.ID; import org.eclipse.ecf.core.util.ECFException; import org.eclipse.ecf.core.util.Event; +import org.eclipse.ecf.sdo.IPublicationCallback; import org.eclipse.ecf.sdo.ISharedDataGraph; import org.eclipse.ecf.sdo.ISubscriptionCallback; import org.eclipse.ecf.sdo.IUpdateConsumer; @@ -40,6 +41,8 @@ public class SharedDataGraph extends PlatformObject implements ISharedObject, private final ISubscriptionCallback subscriptionCallback; + private final IPublicationCallback publicationCallback; + private final IUpdateProvider updateProvider; private ISharedObjectConfig config; @@ -52,6 +55,7 @@ public class SharedDataGraph extends PlatformObject implements ISharedObject, SharedDataGraph(DataGraph dataGraph, IUpdateProvider updateProvider, IUpdateConsumer updateConsumer, + IPublicationCallback publicationCallback, ISubscriptionCallback subscriptionCallback) { if (updateProvider == null) throw new IllegalArgumentException("updateProvider"); @@ -62,6 +66,7 @@ public class SharedDataGraph extends PlatformObject implements ISharedObject, this.dataGraph = dataGraph; this.updateProvider = updateProvider; this.updateConsumer = updateConsumer; + this.publicationCallback = publicationCallback; this.subscriptionCallback = subscriptionCallback; } @@ -138,6 +143,12 @@ public class SharedDataGraph extends PlatformObject implements ISharedObject, config = initData; else throw new SharedObjectInitException("Already initialized."); + + if (version == null) + version = new Version(config.getSharedObjectID()); + + if (dataGraph != null) + dataGraph.getChangeSummary().beginLogging(); } /* @@ -158,12 +169,8 @@ public class SharedDataGraph extends PlatformObject implements ISharedObject, if (subscriptionCallback != null) subscriptionCallback.subscriptionFailed(this, e); } - } else { - if (version == null) - version = new Version(config.getSharedObjectID()); - - dataGraph.getChangeSummary().beginLogging(); - } + } else if (publicationCallback != null) + publicationCallback.dataGraphPublished(this); } } else if (event instanceof ISharedObjectDeactivatedEvent && ((ISharedObjectDeactivatedEvent) event).getDeactivatedID() diff --git a/examples/bundles/org.eclipse.ecf.sdo/src/org/eclipse/ecf/sdo/IDataGraphSharing.java b/examples/bundles/org.eclipse.ecf.sdo/src/org/eclipse/ecf/sdo/IDataGraphSharing.java index 451fb7a52..8fe8faa69 100644 --- a/examples/bundles/org.eclipse.ecf.sdo/src/org/eclipse/ecf/sdo/IDataGraphSharing.java +++ b/examples/bundles/org.eclipse.ecf.sdo/src/org/eclipse/ecf/sdo/IDataGraphSharing.java @@ -36,31 +36,35 @@ public interface IDataGraphSharing { * implementation * @param consumer * application-specific update consumer + * @param callback + * optional callback used to notify the caller about publication + * status * @return shared data graph * @throws ECFException */ ISharedDataGraph publish(DataGraph dataGraph, ID id, - IUpdateProvider provider, IUpdateConsumer consumer) - throws ECFException; + IUpdateProvider provider, IUpdateConsumer consumer, + IPublicationCallback callback) throws ECFException; /** * Subscribes to a data graph with the given id. * * @param id * identifier of a previously-published data graph - * @param callback - * optional callback used to notify the caller about subscription - * status * @param provider * update provider compatible with the given data graph's * implementation * @param consumer * application-specific update consumer + * @param callback + * optional callback used to notify the caller about subscription + * status + * * @return shared data graph * @throws ECFException */ - ISharedDataGraph subscribe(ID id, ISubscriptionCallback callback, - IUpdateProvider provider, IUpdateConsumer consumer) + ISharedDataGraph subscribe(ID id, IUpdateProvider provider, + IUpdateConsumer consumer, ISubscriptionCallback callback) throws ECFException; /** diff --git a/examples/bundles/org.eclipse.ecf.sdo/src/org/eclipse/ecf/sdo/IPublicationCallback.java b/examples/bundles/org.eclipse.ecf.sdo/src/org/eclipse/ecf/sdo/IPublicationCallback.java new file mode 100644 index 000000000..6c3068c56 --- /dev/null +++ b/examples/bundles/org.eclipse.ecf.sdo/src/org/eclipse/ecf/sdo/IPublicationCallback.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2004 Peter Nehrer and Composent, Inc. + * 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: + * Peter Nehrer - initial API and implementation + *******************************************************************************/ +package org.eclipse.ecf.sdo; + +/** + * Interface used by service implementations to notify publishing applications + * of the publication status. + * + * @author pnehrer + */ +public interface IPublicationCallback { + + /** + * Notifies implementor that the give data graph has been successfully + * published. + * + * @param graph + * data graph that has been published + */ + void dataGraphPublished(ISharedDataGraph graph); +} diff --git a/examples/bundles/org.eclipse.ecf.sdo/src/org/eclipse/ecf/sdo/WaitablePublicationCallback.java b/examples/bundles/org.eclipse.ecf.sdo/src/org/eclipse/ecf/sdo/WaitablePublicationCallback.java new file mode 100644 index 000000000..5c9d0a7c5 --- /dev/null +++ b/examples/bundles/org.eclipse.ecf.sdo/src/org/eclipse/ecf/sdo/WaitablePublicationCallback.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2004 Peter Nehrer and Composent, Inc. + * 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: + * Peter Nehrer - initial API and implementation + *******************************************************************************/ +package org.eclipse.ecf.sdo; + +/** + * Convenience callback implementation that can be used to block the calling + * thread until the data graph is published. + * + * @author pnehrer + */ +public class WaitablePublicationCallback implements IPublicationCallback { + + private boolean published; + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.sdo.IPublicationCallback#dataGraphPublished(org.eclipse.ecf.sdo.ISharedDataGraph) + */ + public synchronized void dataGraphPublished(ISharedDataGraph graph) { + published = true; + notifyAll(); + } + + /** + * Blocks the calling thread until the data graph is published. + * + * @param timeout + * period, in milliseconds, to wait for publication + * @throws InterruptedException + * if interrupted while waiting for notification + */ + public synchronized boolean waitForPublication(long timeout) + throws InterruptedException { + if (!published) + wait(timeout); + + return published; + } +} |