View Javadoc
1   package com.github.davidmoten.rx;
2   
3   import java.io.Closeable;
4   import java.io.IOException;
5   import java.util.concurrent.Callable;
6   import java.util.concurrent.atomic.AtomicReference;
7   
8   import com.github.davidmoten.util.Preconditions;
9   
10  import rx.Observable;
11  import rx.functions.Action1;
12  import rx.functions.Func0;
13  import rx.functions.Func1;
14  import rx.plugins.RxJavaHooks;
15  
16  //TODO as suggested by George Campbell, may replace with his PR
17  public class ResourceManager<T> {
18  
19      private final Func0<T> resourceFactory;
20      private final Action1<? super T> disposeAction;
21      private final boolean disposeEagerly;
22  
23      protected ResourceManager(Func0<T> resourceFactory, Action1<? super T> disposeAction,
24              boolean disposeEagerly) {
25          Preconditions.checkNotNull(resourceFactory);
26          Preconditions.checkNotNull(disposeAction);
27          this.resourceFactory = resourceFactory;
28          this.disposeAction = disposeAction;
29          this.disposeEagerly = disposeEagerly;
30      }
31  
32      public static <T> ResourceManagerBuilder<T> resourceFactory(Func0<T> resourceFactory) {
33          return new ResourceManagerBuilder<T>(resourceFactory);
34      }
35  
36      public static <T extends Closeable> CloseableResourceManagerBuilder<T> closeableResourceFactory(
37              Func0<T> resourceFactory) {
38          return new CloseableResourceManagerBuilder<T>(resourceFactory);
39      }
40  
41      public final static class ResourceManagerBuilder<T> {
42  
43          private final Func0<T> resourceFactory;
44          private boolean disposeEagerly = false;
45  
46          private ResourceManagerBuilder(Func0<T> resourceFactory) {
47              this.resourceFactory = resourceFactory;
48          }
49  
50          public ResourceManagerBuilder<T> disposeEagerly(boolean value) {
51              this.disposeEagerly = value;
52              return this;
53          }
54  
55          public ResourceManager<T> disposeAction(Action1<? super T> disposeAction) {
56              return new ResourceManager<T>(resourceFactory, disposeAction, disposeEagerly);
57          }
58      }
59  
60      public final static class CloseableResourceManagerBuilder<T extends Closeable> {
61  
62          private final Func0<T> resourceFactory;
63          private boolean disposeEagerly = false;
64  
65          private CloseableResourceManagerBuilder(Func0<T> resourceFactory) {
66              this.resourceFactory = resourceFactory;
67          }
68  
69          public CloseableResourceManagerBuilder<T> disposeEagerly(boolean value) {
70              this.disposeEagerly = value;
71              return this;
72          }
73  
74          public ResourceManager<T> create() {
75              return new ResourceManager<T>(resourceFactory, CloserHolder.INSTANCE, disposeEagerly);
76          }
77  
78      }
79  
80      public static <T> ResourceManager<T> create(Func0<T> resourceFactory,
81              Action1<? super T> disposeAction) {
82          return new ResourceManager<T>(resourceFactory, disposeAction, false);
83      }
84  
85      public static <T> ResourceManager<T> create(Callable<T> resourceFactory,
86              Action1<? super T> disposeAction) {
87          return new ResourceManager<T>(Functions.toFunc0(resourceFactory), disposeAction, false);
88      }
89  
90      public static <T> ResourceManager<T> create(Callable<T> resourceFactory,
91              Checked.A1<? super T> disposeAction) {
92          return new ResourceManager<T>(Functions.toFunc0(resourceFactory), Checked.a1(disposeAction),
93                  false);
94      }
95  
96      public static <T extends Closeable> ResourceManager<T> create(Func0<T> resourceFactory) {
97          return create(resourceFactory, CloserHolder.INSTANCE);
98      }
99  
100     public static <T extends Closeable> ResourceManager<T> create(Callable<T> resourceFactory) {
101         return create(Functions.toFunc0(resourceFactory), CloserHolder.INSTANCE);
102     }
103 
104     public <R> Observable<R> observable(
105             Func1<? super T, ? extends Observable<? extends R>> observableFactory) {
106         return Observable.using(resourceFactory, observableFactory, disposeAction, disposeEagerly);
107     }
108 
109     public <R> ResourceManager<R> map(final Checked.F1<? super T, ? extends R> resourceMapper,
110             final Checked.A1<? super R> disposeAction) {
111         return map(Checked.f1(resourceMapper), Checked.a1(disposeAction));
112     }
113 
114     public <R> ResourceManager<R> map(final Func1<? super T, ? extends R> resourceMapper,
115             final Action1<? super R> disposeAction) {
116         final AtomicReference<T> ref = new AtomicReference<T>();
117         Func0<R> rf = new Func0<R>() {
118             @Override
119             public R call() {
120                 T a = resourceFactory.call();
121                 try {
122                     R b = resourceMapper.call(a);
123                     ref.set(a);
124                     return b;
125                 } catch (Throwable e) {
126                     ResourceManager.this.disposeAction.call(a);
127                     if (e instanceof RuntimeException) {
128                         throw (RuntimeException) e;
129                     } else {
130                         throw new RuntimeException(e);
131                     }
132                 }
133             }
134         };
135         Action1<R> disposer = new Action1<R>() {
136             @Override
137             public void call(R r) {
138                 try {
139                     disposeAction.call(r);
140                 } catch (Throwable e) {
141                     RxJavaHooks.onError(e);
142                 }
143                 try {
144                     ResourceManager.this.disposeAction.call(ref.get());
145                 } catch (Throwable e) {
146                     RxJavaHooks.onError(e);
147                 }
148             }
149         };
150         return create(rf, disposer);
151     }
152 
153     public <R extends Closeable> ResourceManager<R> map(
154             final Func1<? super T, ? extends R> resourceMapper) {
155         return map(resourceMapper, CloserHolder.INSTANCE);
156     }
157 
158     private static final class CloserHolder {
159 
160         static final Action1<Closeable> INSTANCE = new Action1<Closeable>() {
161 
162             @Override
163             public void call(Closeable c) {
164                 try {
165                     c.close();
166                 } catch (IOException e) {
167                     RxJavaHooks.onError(e);
168                 }
169             }
170         };
171     }
172 
173 }