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
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 }