diff options
Diffstat (limited to 'source/com/c2kernel/persistency/RemoteMap.java')
| -rwxr-xr-x | source/com/c2kernel/persistency/RemoteMap.java | 404 |
1 files changed, 404 insertions, 0 deletions
diff --git a/source/com/c2kernel/persistency/RemoteMap.java b/source/com/c2kernel/persistency/RemoteMap.java new file mode 100755 index 0000000..ca9cbc4 --- /dev/null +++ b/source/com/c2kernel/persistency/RemoteMap.java @@ -0,0 +1,404 @@ +package com.c2kernel.persistency;
+
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+import com.c2kernel.common.ObjectNotFoundException;
+import com.c2kernel.entity.C2KLocalObject;
+import com.c2kernel.entity.proxy.*;
+import com.c2kernel.entity.proxy.EntityProxyObserver;
+import com.c2kernel.lookup.EntityPath;
+import com.c2kernel.process.Gateway;
+import com.c2kernel.utils.Logger;
+
+/**
+ * Maps a storage cluster onto a java.util.Map
+ *
+ * @author Andrew Branson
+ * $Revision: 1.22 $
+ * $Date: 2006/03/03 13:52:21 $
+ *
+ * Copyright (C) 2003 CERN - European Organization for Nuclear Research
+ * All rights reserved.
+ */
+public class RemoteMap implements C2KLocalObject, Map {
+
+ protected static final boolean KEYS = false;
+ protected static final boolean VALUES = true;
+
+ private int mID=-1;
+ private String mName;
+ protected int mSysKey;
+ private String mPath = "";
+ protected String[] keys = null;
+ Object keyLock = new Object();
+ protected C2KLocalObject[] values = null;
+ TransactionManager storage;
+ EntityProxyObserver listener;
+ EntityProxy source;
+ Object mLocker; // if this remote map will participate in a transaction
+
+ public RemoteMap(int sysKey, String path, Object locker) {
+ mSysKey = sysKey;
+ mLocker = locker;
+
+ // split the path into path/name
+ int lastSlash = path.lastIndexOf("/");
+ mName = path.substring(lastSlash+1);
+ if (lastSlash>0) mPath = path.substring(0,lastSlash);
+
+ // see if the name is also a suitable id
+ try {
+ mID = Integer.parseInt(mName);
+ } catch (NumberFormatException e) {}
+ storage = Gateway.getStorage();
+
+ listener = new EntityProxyObserver() {
+ public void add(C2KLocalObject obj) {
+ synchronized (keyLock) {
+ if (keys == null) return;
+ boolean found = false;
+ for (int i=0; i<keys.length; i++) {
+ if (keys[i].equals(obj.getName())) { //replaced
+ values[i] = obj;
+ found = true;
+ break;
+ }
+ }
+
+ if (found == false) { // new
+ String[] newKeys = new String[keys.length+1];
+ C2KLocalObject[] newValues = new C2KLocalObject[keys.length+1];
+ System.arraycopy(keys, 0, newKeys, 0, keys.length);
+ if (values!=null) System.arraycopy(values, 0, newValues, 0, keys.length);
+ newKeys[newKeys.length-1] = obj.getName();
+ newValues[newValues.length-1] = obj;
+ keys = newKeys;
+ values = newValues;
+ }
+ }
+ }
+
+ public void remove(String id) {
+ synchronized (keyLock) {
+ if (keys == null) return;
+ boolean found = false;
+ for (int i=0; i<keys.length; i++) {
+ if (keys[i].equals(id)) { //replaced
+ String[] newKeys = new String[keys.length-1];
+ C2KLocalObject[] newValues = new C2KLocalObject[keys.length-1];
+ int pos = 0;
+ for (int j=0; j<keys.length;j++) {
+ if (i!=j) {
+ newKeys[pos] = keys[j];
+ newValues[pos++] = values[j];
+ }
+ }
+ keys = newKeys;
+ values = newValues;
+ break;
+ }
+ }
+ }
+ }
+ };
+
+ try {
+ source = Gateway.getProxyManager().getProxy(new EntityPath(sysKey));
+ source.subscribe(listener, path, false);
+ } catch (Exception ex) {
+ Logger.error("Error subscribing to remote map. Changes will not be received");
+ Logger.error(ex);
+ }
+ }
+
+ protected void loadKeys() throws ClusterStorageException {
+ synchronized(keyLock) {
+ keys = storage.getClusterContents(mSysKey, mPath+mName);
+ values = new C2KLocalObject[keys.length];
+ }
+ }
+
+ protected String[] getKeys() {
+ try {
+ if (keys == null) loadKeys();
+ } catch (ClusterStorageException e) {
+ Logger.error(e);
+ keys = new String[0];
+ }
+ return keys;
+ }
+
+ public synchronized int getLastId() {
+
+ synchronized (this) {
+ int lastID = -1;
+
+ String[] allIds = getKeys();
+
+ for (int i = 0; i < allIds.length; i++) {
+ try {
+ int thisID = Integer.parseInt(allIds[i]);
+ if (thisID > lastID) lastID = thisID;
+ } catch (NumberFormatException e) {
+ Logger.warning("RemoteMap.getLastID() - Cluster contained invalid id: "+allIds[i]);
+ }
+ }
+ Logger.msg(7, "RemoteMap.getLastID() - last id in "+mPath+mName+" of "+mSysKey+" is "+lastID);
+ return lastID;
+ }
+ }
+
+
+ // c2kLocalObject methods
+ public void setID(int id) { mID = id; }
+
+ public int getID() { return mID; }
+
+ public void setName(String name) { mName = name; }
+
+ public String getName() { return mName; }
+
+ /**
+ * Cannot be stored
+ */
+ public String getClusterType() {
+ return null;
+ }
+ /**
+ * @see java.util.Map#clear()
+ */
+ public synchronized void clear() {
+ keys = null;
+ }
+
+
+
+ /**
+ * @see java.util.Map#containsKey(Object)
+ */
+ public synchronized boolean containsKey(Object key) {
+ getKeys();
+ for (int i = 0; i < keys.length; i++) {
+ if (key.equals(keys[i]))
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * This must retrieve all the values until a match is made.
+ * Very expensive, but if you must, you must.
+ * @see java.util.Map#containsValue(Object)
+ */
+ public synchronized boolean containsValue(Object value) {
+ getKeys();
+ synchronized(keyLock) {
+ if (values == null) values = new C2KLocalObject[keys.length];
+ for (int i = 0; i < keys.length; i++) {
+ try {
+ if (values[i] == null) values[i] = storage.get(mSysKey, mPath+mName+"/"+keys[i], mLocker);
+ if (value.equals(values[i])) return true;
+ } catch (ClusterStorageException ex) {
+ Logger.error(ex);
+ } catch (ObjectNotFoundException e) {
+ Logger.error(e);
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @see java.util.Map#entrySet()
+ */
+ public synchronized Set entrySet() {
+ return new RemoteMap.RemoteSet(this, KEYS);
+ }
+
+ /**
+ * @see java.util.Map#get(Object)
+ */
+ public synchronized Object get(Object key) {
+ getKeys();
+ synchronized(keyLock) {
+ if (values == null) values = new C2KLocalObject[keys.length];
+ try {
+ for (int i = 0; i < keys.length; i++) {
+ if (key.equals(keys[i])) {
+ if (values[i] == null)
+ values[i] = storage.get(mSysKey, mPath+mName+"/"+keys[i], mLocker);
+ return values[i];
+ }
+ }
+ } catch (ClusterStorageException e) {
+ Logger.error(e);
+ } catch (ObjectNotFoundException e) {
+ Logger.error(e);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @see java.util.Map#isEmpty()
+ */
+ public synchronized boolean isEmpty() {
+ return getKeys().length==0;
+ }
+
+ /**
+ * @see java.util.Map#keySet()
+ */
+ public synchronized Set keySet() {
+ return new RemoteMap.RemoteSet(this, KEYS);
+ }
+
+ /**
+ * Inserts the given object into the storage
+ * the key is ignored - it can be fetched from the value.
+ * @see java.util.Map#put(Object, Object)
+ */
+ public synchronized Object put(Object key, Object value) {
+ try {
+ C2KLocalObject newValue = (C2KLocalObject)value;
+ synchronized(keyLock) {
+ storage.put(mSysKey, newValue, mLocker);
+ keys = null; values = null;
+ }
+ } catch (ClusterStorageException e) {
+ Logger.error(e);
+ return null;
+ } catch (ClassCastException e) {
+ Logger.error("RemoteMap.put() - value was not a localobject, it was a "+value.getClass().getName());
+ return null;
+ }
+ return value;
+ }
+
+ /**
+ * @see java.util.Map#putAll(Map)
+ */
+ public synchronized void putAll(Map t) {
+ for (Iterator iter = t.keySet().iterator(); iter.hasNext();) {
+ Object key = iter.next();
+ put(key, t.get(key));
+ }
+ }
+
+ /**
+ * @see java.util.Map#remove(Object)
+ */
+ public synchronized Object remove(Object key) {
+ try {
+ synchronized(keyLock) {
+ storage.remove(mSysKey, mPath+mName+"/"+key, mLocker);
+ keys = null; values = null;
+ }
+ } catch (ClusterStorageException e) {
+ Logger.error(e);
+ }
+ return null;
+ }
+
+ /**
+ * @see java.util.Map#size()
+ */
+ public synchronized int size() {
+ return getKeys().length;
+ }
+
+ /**
+ * @see java.util.Map#values()
+ */
+ public synchronized Collection values() {
+ return new RemoteMap.RemoteSet(this, VALUES);
+ }
+
+ /**
+ * Basic implementation of Set and Collection to bridge to the Iterator
+ * Disallows all writes.
+ */
+
+ private class RemoteSet extends AbstractSet {
+ RemoteMap mParent;
+ boolean mMode;
+
+ public RemoteSet(RemoteMap parent, boolean mode) {
+ mParent = parent;
+ mMode = mode;
+ }
+
+ // no modifications allowed
+ public boolean add(Object o) {
+ throw new UnsupportedOperationException();
+ }
+ public boolean addAll(Collection c) {
+ throw new UnsupportedOperationException();
+ }
+ public void clear() {
+ throw new UnsupportedOperationException();
+ }
+ public boolean remove(Object o) {
+ throw new UnsupportedOperationException();
+ }
+ public boolean removeAll(Collection c) {
+ throw new UnsupportedOperationException();
+ }
+ public boolean retainAll(Collection c) {
+ throw new UnsupportedOperationException();
+ }
+
+ public Iterator iterator() {
+ return new RemoteIterator(mParent, mMode);
+ }
+
+ public int size() {
+ return mParent.size();
+ }
+
+ }
+ /**
+ * Iterator view on RemoteMap data. Doesn't preload anything.
+ * REVISIT: Will go strange if the RemoteMap is modified. Detect this and throw ConcurrentMod ex
+ */
+ private class RemoteIterator implements Iterator {
+ RemoteMap mParent;
+ boolean mMode;
+ String[] keyArr;
+ int pos;
+
+ public RemoteIterator(RemoteMap parent, boolean mode) {
+ mParent = parent;
+ mMode = mode;
+ keyArr = mParent.getKeys();
+ }
+
+ public boolean hasNext() {
+ return (pos<keyArr.length);
+ }
+
+ public Object next() {
+ if (pos == keyArr.length)
+ throw new NoSuchElementException();
+
+ if (mMode == KEYS)
+ return keyArr[pos++];
+ else
+ return mParent.get(keyArr[pos++]);
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ }
+
+
+
+
+}
|
