Ranides Atterwim 4 лет назад
Родитель
Сommit
78da94ee76

+ 2 - 1
assira.commons/src/main/java/net/ranides/assira/io/uri/impl/CFTPHandler.java

@@ -353,8 +353,9 @@ public class CFTPHandler implements URIHandler {
         }
 
         @Override
-        protected void reset(FTPClient host) throws IOException {
+        protected FTPClient reset(FTPClient host) throws IOException {
             host.completePendingCommand();
+            return host;
         }
 
         @Override

+ 132 - 8
assira.core/src/main/java/net/ranides/assira/io/uri/impl/CHandleManager.java

@@ -14,6 +14,24 @@ import java.util.Map;
 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 <C> C
@@ -23,13 +41,60 @@ import java.util.Set;
 public abstract class CHandleManager<P,C> {
     
     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;
-    
+
+    /**
+     * 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 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) {
         synchronized(resources) {
             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 {
         synchronized(resources) {
             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 {
         synchronized(this) {
             CResource<C> res = resources.get(path);
@@ -65,7 +156,24 @@ public abstract class CHandleManager<P,C> {
             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 {
         synchronized(resources) {
             CResource<C> res = resources.get(path);
@@ -83,7 +191,23 @@ public abstract class CHandleManager<P,C> {
             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 {
         synchronized(resources) {
             CResource<C> res = resources.get(path);
@@ -94,7 +218,7 @@ public abstract class CHandleManager<P,C> {
                 return;
             }
             if(null == res.shared && 0 != res.counter) {
-                reset(res.shared = channel);
+                res.shared = reset(channel);
             } else {
                 disconnect(channel);
             }

+ 2 - 2
assira.core/src/main/java/net/ranides/assira/io/uri/impl/CJarHandler.java

@@ -257,8 +257,8 @@ public class CJarHandler implements URIHandler {
         }
 
         @Override
-        protected void reset(ZipFile zip) {
-            // do nothing
+        protected ZipFile reset(ZipFile zip) {
+            return zip;
         }
 
         @Override