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