1 /*
2 * #%L
3 * AbstractProxyConnection.java - mongodb-async-driver - Allanbank Consulting, Inc.
4 * %%
5 * Copyright (C) 2011 - 2014 Allanbank Consulting, Inc.
6 * %%
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * #L%
19 */
20
21 package com.allanbank.mongodb.client.connection.proxy;
22
23 import java.beans.PropertyChangeEvent;
24 import java.beans.PropertyChangeListener;
25 import java.io.IOException;
26 import java.util.concurrent.TimeUnit;
27
28 import com.allanbank.mongodb.MongoDbException;
29 import com.allanbank.mongodb.client.Message;
30 import com.allanbank.mongodb.client.callback.ReplyCallback;
31 import com.allanbank.mongodb.client.connection.Connection;
32 import com.allanbank.mongodb.util.IOUtils;
33
34 /**
35 * A helper class for constructing connections that are really just proxies on
36 * top of other connections.
37 *
38 * @api.no This class is <b>NOT</b> part of the drivers API. This class may be
39 * mutated in incompatible ways between any two releases of the driver.
40 * @copyright 2011-2014, Allanbank Consulting, Inc., All Rights Reserved
41 */
42 public abstract class AbstractProxyConnection implements Connection {
43
44 /** The proxied connection. */
45 private final Connection myProxiedConnection;
46
47 /**
48 * Creates a AbstractProxyConnection.
49 *
50 * @param proxiedConnection
51 * The connection to forward to.
52 */
53 public AbstractProxyConnection(final Connection proxiedConnection) {
54 myProxiedConnection = proxiedConnection;
55 }
56
57 /**
58 * {@inheritDoc}
59 * <p>
60 * Overridden to create a proxy connection if not already created and add
61 * the listener to that connection.
62 * </p>
63 */
64 @Override
65 public void addPropertyChangeListener(final PropertyChangeListener listener) {
66 try {
67 myProxiedConnection
68 .addPropertyChangeListener(new ProxiedChangeListener(this,
69 listener));
70 }
71 catch (final MongoDbException error) {
72 onExceptin(error);
73 listener.propertyChange(new PropertyChangeEvent(this,
74 OPEN_PROP_NAME, Boolean.TRUE, Boolean.FALSE));
75 }
76 }
77
78 /**
79 * Closes the underlying connection.
80 *
81 * @see Connection#close()
82 */
83 @Override
84 public void close() throws IOException {
85 myProxiedConnection.close();
86 }
87
88 /**
89 * {@inheritDoc}
90 * <p>
91 * Forwards the call to the proxied {@link Connection}.
92 * </p>
93 *
94 * @see java.io.Flushable#flush()
95 */
96 @Override
97 public void flush() throws IOException {
98 try {
99 myProxiedConnection.flush();
100 }
101 catch (final MongoDbException error) {
102 onExceptin(error);
103 throw error;
104 }
105 }
106
107 /**
108 * {@inheritDoc}
109 * <p>
110 * Forwards the call to the proxied {@link Connection}.
111 * </p>
112 */
113 @Override
114 public int getPendingCount() {
115 try {
116 return myProxiedConnection.getPendingCount();
117 }
118 catch (final MongoDbException error) {
119 onExceptin(error);
120 throw error;
121 }
122 }
123
124 /**
125 * {@inheritDoc}
126 * <p>
127 * Overridden to forward the call to the proxied connection.
128 * </p>
129 */
130 @Override
131 public String getServerName() {
132 return getProxiedConnection().getServerName();
133 }
134
135 /**
136 * {@inheritDoc}
137 * <p>
138 * Forwards the call to the proxied {@link Connection}.
139 * </p>
140 */
141 @Override
142 public boolean isAvailable() {
143 try {
144 return myProxiedConnection.isAvailable();
145 }
146 catch (final MongoDbException error) {
147 onExceptin(error);
148 throw error;
149 }
150 }
151
152 /**
153 * {@inheritDoc}
154 * <p>
155 * Forwards the call to the proxied {@link Connection}.
156 * </p>
157 */
158 @Override
159 public boolean isIdle() {
160 try {
161 return myProxiedConnection.isIdle();
162 }
163 catch (final MongoDbException error) {
164 onExceptin(error);
165 throw error;
166 }
167 }
168
169 /**
170 * {@inheritDoc}
171 * <p>
172 * Forwards the call to the proxied {@link Connection}.
173 * </p>
174 */
175 @Override
176 public boolean isOpen() {
177 try {
178 return myProxiedConnection.isOpen();
179 }
180 catch (final MongoDbException error) {
181 onExceptin(error);
182 throw error;
183 }
184 }
185
186 /**
187 * {@inheritDoc}
188 * <p>
189 * Forwards the call to the proxied {@link Connection}.
190 * </p>
191 */
192 @Override
193 public boolean isShuttingDown() {
194 return myProxiedConnection.isShuttingDown();
195 }
196
197 /**
198 * {@inheritDoc}
199 * <p>
200 * Forwards the call to the proxied {@link Connection}.
201 * </p>
202 */
203 @Override
204 public void raiseErrors(final MongoDbException exception) {
205 myProxiedConnection.raiseErrors(exception);
206 }
207
208 /**
209 * {@inheritDoc}
210 * <p>
211 * Overridden to create a proxy connection if not already created and add
212 * the listener to that connection.
213 * </p>
214 */
215 @Override
216 public void removePropertyChangeListener(
217 final PropertyChangeListener listener) {
218 myProxiedConnection
219 .removePropertyChangeListener(new ProxiedChangeListener(this,
220 listener));
221 }
222
223 /**
224 * {@inheritDoc}
225 * <p>
226 * Forwards the call to the proxied {@link Connection}.
227 * </p>
228 */
229 @Override
230 public void send(final Message message1, final Message message2,
231 final ReplyCallback replyCallback) throws MongoDbException {
232 try {
233 myProxiedConnection.send(message1, message2, replyCallback);
234 }
235 catch (final MongoDbException error) {
236 onExceptin(error);
237 throw error;
238 }
239 }
240
241 /**
242 * {@inheritDoc}
243 * <p>
244 * Forwards the call to the proxied {@link Connection}.
245 * </p>
246 */
247 @Override
248 public void send(final Message message, final ReplyCallback replyCallback)
249 throws MongoDbException {
250 try {
251 myProxiedConnection.send(message, replyCallback);
252 }
253 catch (final MongoDbException error) {
254 onExceptin(error);
255 throw error;
256 }
257 }
258
259 /**
260 * {@inheritDoc}
261 * <p>
262 * Forwards the call to the proxied {@link Connection}.
263 * </p>
264 */
265 @Override
266 public void shutdown(final boolean force) {
267 myProxiedConnection.shutdown(force);
268 }
269
270 /**
271 * {@inheritDoc}
272 * <p>
273 * Forwards the call to the proxied {@link Connection}.
274 * </p>
275 */
276 @Override
277 public void waitForClosed(final int timeout, final TimeUnit timeoutUnits) {
278 try {
279 myProxiedConnection.waitForClosed(timeout, timeoutUnits);
280 }
281 catch (final MongoDbException error) {
282 onExceptin(error);
283 throw error;
284 }
285 }
286
287 /**
288 * Returns the proxiedConnection value.
289 *
290 * @return The proxiedConnection value.
291 */
292 protected Connection getProxiedConnection() {
293 return myProxiedConnection;
294 }
295
296 /**
297 * Provides the ability for derived classes to intercept any exceptions from
298 * the underlying proxied connection.
299 * <p>
300 * Closes the underlying connection.
301 * </p>
302 *
303 * @param exception
304 * The thrown exception.
305 */
306 protected void onExceptin(final MongoDbException exception) {
307 // Close without fear of an exception.
308 IOUtils.close(this);
309 }
310
311 /**
312 * ProxiedChangeListener provides a change listener to modify the source of
313 * the event to the outer connection from the (inner) proxied connection.
314 *
315 * @copyright 2012-2013, Allanbank Consulting, Inc., All Rights Reserved
316 */
317 protected static class ProxiedChangeListener implements
318 PropertyChangeListener {
319
320 /** The delegate listener. */
321 private final PropertyChangeListener myDelegate;
322
323 /** The proxied connection. */
324 private final AbstractProxyConnection myProxiedConn;
325
326 /**
327 * Creates a new ProxiedChangeListener.
328 *
329 * @param proxiedConn
330 * The proxied connection.
331 * @param delegate
332 * The delegate listener.
333 */
334 public ProxiedChangeListener(final AbstractProxyConnection proxiedConn,
335 final PropertyChangeListener delegate) {
336 myProxiedConn = proxiedConn;
337 myDelegate = delegate;
338 }
339
340 /**
341 * {@inheritDoc}
342 * <p>
343 * Overridden to compare the nested delegate listeners.
344 * </p>
345 */
346 @Override
347 public boolean equals(final Object object) {
348 boolean result = false;
349 if (this == object) {
350 result = true;
351 }
352 else if ((object != null) && (getClass() == object.getClass())) {
353 final ProxiedChangeListener other = (ProxiedChangeListener) object;
354
355 result = myDelegate.equals(other.myDelegate);
356 }
357 return result;
358 }
359
360 /**
361 * {@inheritDoc}
362 * <p>
363 * Overridden to return the delegates hash code.
364 * </p>
365 */
366 @Override
367 public int hashCode() {
368 return ((myDelegate == null) ? 13 : myDelegate.hashCode());
369 }
370
371 /**
372 * {@inheritDoc}
373 * <p>
374 * Overridden to change the source of the property change event to the
375 * outer connection instead of the inner connection.
376 * </p>
377 */
378 @Override
379 public void propertyChange(final PropertyChangeEvent event) {
380
381 final PropertyChangeEvent newEvent = new PropertyChangeEvent(
382 myProxiedConn, event.getPropertyName(),
383 event.getOldValue(), event.getNewValue());
384 newEvent.setPropagationId(event.getPropagationId());
385 myDelegate.propertyChange(newEvent);
386 }
387 }
388 }