|
@@ -14,6 +14,24 @@ import java.util.Map;
|
|
|
import java.util.Set;
|
|
import java.util.Set;
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
|
|
+ * CHandleManager stores all opened resources of type "C" associated with path "P".
|
|
|
|
|
+ *
|
|
|
|
|
+ * You can use shared resources, which are opened only once when first client used it
|
|
|
|
|
+ * and closed only once when last client closed it.
|
|
|
|
|
+ *
|
|
|
|
|
+ * You can use forked resources, which should be used only by one client.
|
|
|
|
|
+ *
|
|
|
|
|
+ * One path can be associated with at most one shared resources
|
|
|
|
|
+ * and any number of forked resources.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Manager is able to promote forked resources to shared state and vice versa, to avoid
|
|
|
|
|
+ * opening unecessary connections.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Transition from forked to shared must be implemented in "reset" method.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Reference to forked resource must be stored internally by client.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Reference to shared resource must NOT be stored internally by client.
|
|
|
*
|
|
*
|
|
|
* @param <P> P
|
|
* @param <P> P
|
|
|
* @param <C> C
|
|
* @param <C> C
|
|
@@ -23,13 +41,60 @@ import java.util.Set;
|
|
|
public abstract class CHandleManager<P,C> {
|
|
public abstract class CHandleManager<P,C> {
|
|
|
|
|
|
|
|
private final Map<P, CResource<C>> resources = new OpenMap<>();
|
|
private final Map<P, CResource<C>> resources = new OpenMap<>();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * This method opens resource.
|
|
|
|
|
+ * It must not be called directly.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Please note, that manager tries to call this method as late as possible.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param path path
|
|
|
|
|
+ * @return opened resource
|
|
|
|
|
+ * @throws IOException on error
|
|
|
|
|
+ */
|
|
|
protected abstract C connect(P path) throws IOException;
|
|
protected abstract C connect(P path) throws IOException;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * This method closes resource.
|
|
|
|
|
+ * It must not be called directly.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Both shared and forked resources are closed using this method, in the end.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param channel channel
|
|
|
|
|
+ * @throws IOException on error
|
|
|
|
|
+ */
|
|
|
protected abstract void disconnect(C channel) throws IOException;
|
|
protected abstract void disconnect(C channel) throws IOException;
|
|
|
-
|
|
|
|
|
- protected abstract void reset(C channel) throws IOException;
|
|
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * This method does not close resource, but resets its state.
|
|
|
|
|
+ * It must not be called directly.
|
|
|
|
|
+ *
|
|
|
|
|
+ * This method is called, if one of "forked" resources is moved back to "shared" pool.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Shared resources should not be used in statefull way, but forked resources could be.
|
|
|
|
|
+ * You should clear all state, for example, push/flush all pending changes.
|
|
|
|
|
+ *
|
|
|
|
|
+ * In best case, the same channel is retured (possibly with cleared state)
|
|
|
|
|
+ * In worst case, method is allowed to completely close resource and return new one.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param channel channel
|
|
|
|
|
+ * @return channel
|
|
|
|
|
+ * @throws IOException on error
|
|
|
|
|
+ */
|
|
|
|
|
+ protected abstract C reset(C channel) throws IOException;
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Tells manager, that you will use this shared resource in the future.
|
|
|
|
|
+ *
|
|
|
|
|
+ * It does not open resource. Opening resource is responsibility of {@link #shared(Object)} method,
|
|
|
|
|
+ * but you must call "open" before first use of resource.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Manager tracks number of clients who reserved resource.
|
|
|
|
|
+ * This method increments usage counter. You must call "close"
|
|
|
|
|
+ * when you don't plan to use resource anymore.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param path
|
|
|
|
|
+ */
|
|
|
public void open(P path) {
|
|
public void open(P path) {
|
|
|
synchronized(resources) {
|
|
synchronized(resources) {
|
|
|
CResource<C> res = resources.get(path);
|
|
CResource<C> res = resources.get(path);
|
|
@@ -40,6 +105,20 @@ public abstract class CHandleManager<P,C> {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Tells manager, that you won't use this shared resource in the future.
|
|
|
|
|
+ * If you are the last user of shared resource, manager will close it.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Method does not affect forked resources, which are still opened.
|
|
|
|
|
+ * Forked resources must be closed using {@link #close(Object, Object)}.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Manager tracks number of clients who reserved resource.
|
|
|
|
|
+ * This method decrements usage counter. You can call "close"
|
|
|
|
|
+ * only when you reserved resource in the past using "open".
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param path path
|
|
|
|
|
+ * @throws IOException on error
|
|
|
|
|
+ */
|
|
|
public void close(P path) throws IOException {
|
|
public void close(P path) throws IOException {
|
|
|
synchronized(resources) {
|
|
synchronized(resources) {
|
|
|
CResource<C> res = resources.get(path);
|
|
CResource<C> res = resources.get(path);
|
|
@@ -53,6 +132,18 @@ public abstract class CHandleManager<P,C> {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Returns shared resource for specified path.
|
|
|
|
|
+ *
|
|
|
|
|
+ * If shared resource is not opened yet, it is opened.
|
|
|
|
|
+ *
|
|
|
|
|
+ * You should not store returned reference, it must be obtained on every use.
|
|
|
|
|
+ * You should not obtain shared reference, if you never reserved it by using {@link #open(Object)}.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param path path
|
|
|
|
|
+ * @return active, opened resource
|
|
|
|
|
+ * @throws IOException on error
|
|
|
|
|
+ */
|
|
|
public C shared(P path) throws IOException {
|
|
public C shared(P path) throws IOException {
|
|
|
synchronized(this) {
|
|
synchronized(this) {
|
|
|
CResource<C> res = resources.get(path);
|
|
CResource<C> res = resources.get(path);
|
|
@@ -65,7 +156,24 @@ public abstract class CHandleManager<P,C> {
|
|
|
return res.shared;
|
|
return res.shared;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Changes state of resource from shared to fork state.
|
|
|
|
|
+ *
|
|
|
|
|
+ * You can create forked resources even if shared resource was never opened.
|
|
|
|
|
+ * In such case new forked connection is created and shared pool is not affected at all.
|
|
|
|
|
+ *
|
|
|
|
|
+ * If there is already opened shared resource, it moves opened connection
|
|
|
|
|
+ * to "forked" pool and clears shared pool. Next access to shared resource
|
|
|
|
|
+ * will open new shared connection.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Forked resource can be used only by one client. Client must store
|
|
|
|
|
+ * reference to forked resource internally, and close it using {@link #close(Object, Object)}.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param path path
|
|
|
|
|
+ * @return active, opened resource
|
|
|
|
|
+ * @throws IOException on error
|
|
|
|
|
+ */
|
|
|
public C fork(P path) throws IOException {
|
|
public C fork(P path) throws IOException {
|
|
|
synchronized(resources) {
|
|
synchronized(resources) {
|
|
|
CResource<C> res = resources.get(path);
|
|
CResource<C> res = resources.get(path);
|
|
@@ -83,7 +191,23 @@ public abstract class CHandleManager<P,C> {
|
|
|
return channel;
|
|
return channel;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Closes forked "channel".
|
|
|
|
|
+ *
|
|
|
|
|
+ * If channel is not in forked state, it does nothing
|
|
|
|
|
+ *
|
|
|
|
|
+ * Please note, that "fork" operation changes channel from shared state to fork state lazily.
|
|
|
|
|
+ * Becuse of that, it is possible, that forked resource is removed from "shared" pool, but
|
|
|
|
|
+ * shared resource is not recreated yet. In such case we don't close resource, but reset its
|
|
|
|
|
+ * state and move back to shared pool.
|
|
|
|
|
+ *
|
|
|
|
|
+ * If shared resource is recreated, we simply disconnect channel.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param path path
|
|
|
|
|
+ * @param channel channel
|
|
|
|
|
+ * @throws IOException on error
|
|
|
|
|
+ */
|
|
|
public void close(P path, C channel) throws IOException {
|
|
public void close(P path, C channel) throws IOException {
|
|
|
synchronized(resources) {
|
|
synchronized(resources) {
|
|
|
CResource<C> res = resources.get(path);
|
|
CResource<C> res = resources.get(path);
|
|
@@ -94,7 +218,7 @@ public abstract class CHandleManager<P,C> {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
if(null == res.shared && 0 != res.counter) {
|
|
if(null == res.shared && 0 != res.counter) {
|
|
|
- reset(res.shared = channel);
|
|
|
|
|
|
|
+ res.shared = reset(channel);
|
|
|
} else {
|
|
} else {
|
|
|
disconnect(channel);
|
|
disconnect(channel);
|
|
|
}
|
|
}
|