View Javadoc

1   package org.csc.phynixx.connection;
2   
3   /*
4    * #%L
5    * phynixx-connection
6    * %%
7    * Copyright (C) 2014 csc
8    * %%
9    * Licensed under the Apache License, Version 2.0 (the "License");
10   * you may not use this file except in compliance with the License.
11   * You may obtain a copy of the License at
12   * 
13   *      http://www.apache.org/licenses/LICENSE-2.0
14   * 
15   * Unless required by applicable law or agreed to in writing, software
16   * distributed under the License is distributed on an "AS IS" BASIS,
17   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18   * See the License for the specific language governing permissions and
19   * limitations under the License.
20   * #L%
21   */
22  
23  
24  import org.csc.phynixx.common.exceptions.DelegatedRuntimeException;
25  import org.csc.phynixx.common.generator.IDGenerator;
26  import org.csc.phynixx.common.generator.IDGenerators;
27  import org.csc.phynixx.common.logger.IPhynixxLogger;
28  import org.csc.phynixx.common.logger.PhynixxLogManager;
29  
30  import java.lang.annotation.Annotation;
31  import java.lang.reflect.InvocationHandler;
32  import java.lang.reflect.InvocationTargetException;
33  import java.lang.reflect.Method;
34  import java.lang.reflect.Proxy;
35  
36  /**
37   * <p/>
38   * provided generic proxies on base of java DynaProxies
39   * <p/>
40   * This proxy
41   *
42   * @param <C>
43   */
44  class DynaPhynixxManagedConnectionFactory<C extends IPhynixxConnection> extends AbstractDynaProxyFactory {
45  
46      private static final IDGenerator<Long> idGenerator = IDGenerators.createLongGenerator(1,true);
47  
48      private Class<C> connectionInterface;
49      private CloseStrategy<C> closeStrategy=null;
50  
51      DynaPhynixxManagedConnectionFactory(Class<C> connectionInterface, CloseStrategy<C> closeStrategy, boolean synchronize) {
52          super(new Class<?>[]{connectionInterface},
53                  new Class[]{IPhynixxConnection.class, IPhynixxManagedConnection.class},
54                  new Class[]{IXADataRecorderAware.class, ICloseable.class, IAutoCommitAware.class},
55                  synchronize);
56          this.connectionInterface = connectionInterface;
57          this.closeStrategy= closeStrategy;
58  
59  
60      }
61  
62      DynaPhynixxManagedConnectionFactory(Class<C> connectionInterface,CloseStrategy<C> closeStrategy) {
63          this(connectionInterface, closeStrategy, true);
64      }
65  
66      IPhynixxManagedConnection<C> getManagedConnection(C coreConnection) {
67  
68          Long connectionId = null;
69          synchronized (idGenerator) {
70              connectionId = idGenerator.generate();
71          }
72          ConnectionPhynixxGuard proxy = new ConnectionPhynixxGuard(connectionId, connectionInterface, coreConnection,closeStrategy);
73  
74          IPhynixxManagedConnection<C> proxied = (IPhynixxManagedConnection<C>)
75                  Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
76                          this.getImplementedInterfaces(), proxy);
77          proxy.proxiedObject = proxied;
78          return proxied;
79      }
80  
81  
82      class ConnectionPhynixxGuard<C extends IPhynixxConnection> extends PhynixxManagedConnectionGuard<C> implements InvocationHandler {
83  
84  
85  
86  
87          private final IPhynixxLogger log = PhynixxLogManager.getLogger(ConnectionPhynixxGuard.class);
88          /**
89           * As the proxy contains more information than the current implentation we have to store
90           * the proxy an use it in all call backs
91           */
92          private IPhynixxManagedConnection<C> proxiedObject;
93  
94          ConnectionPhynixxGuard(long id, Class<C> connectionInterface, C connection, CloseStrategy<C> closeStrategy) {
95              super(id, connectionInterface, connection,closeStrategy);
96          }
97  
98          /**
99           * if the interface method is decorated with {@link org.csc.phynixx.connection.RequiresTransaction}
100          *
101          * @param method
102          * @return
103          */
104         private boolean requiresTransaction(Method method) {
105 
106             Annotation[] annotations = method.getDeclaredAnnotations();
107             if (annotations == null || annotations.length == 0) {
108                 return false;
109             }
110             for (int i = 0; i < annotations.length; i++) {
111                 if (RequiresTransaction.class.isAssignableFrom(annotations[i].annotationType())) {
112                     RequiresTransaction requiresTransactionAnnotation = (RequiresTransaction) annotations[i];
113                     return requiresTransactionAnnotation.value();
114                 }
115             }
116 
117             return false;
118 
119         }
120 
121 
122         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
123 
124 
125             /**
126              * methods of the IConnectionProxy are redirected to the current object
127              */
128 
129             // execute
130             try {
131                 if (DynaPhynixxManagedConnectionFactory.this.declaredBySystemInterface(method)) {
132                     // System.out.println("Thread " + Thread.currentThread()+" Connection IF expected to " + this+" on "+method);
133                     Object obj = null;
134                     if (this.isSynchronized()) {
135                         synchronized (this) {
136                             obj = method.invoke(this, args);
137                         }
138                     } else {
139                         obj = method.invoke(this, args);
140                     }
141                     return obj;
142                 } else if (DynaPhynixxManagedConnectionFactory.this.declaredBySupportedInterface(method)) {
143 
144                     Object target = this.getCoreConnection();
145 
146                     // System.out.println("Thread " + Thread.currentThread()+" Delegated to Connection " + target+" on "+method);
147 
148                     Object obj = null;
149                     boolean requireTransaction = this.requiresTransaction(method);
150                     try {
151                         if (this.isSynchronized()) {
152                             synchronized (this) {
153                                 if (requireTransaction) {
154                                     this.fireConnectionRequiresTransaction();
155                                 }
156                                 obj = method.invoke(target, args);
157                                 if (requireTransaction) {
158                                     fireConnectionRequiresTransactionExecuted();
159                                 }
160                             }
161                         } else {
162                             if (requireTransaction) {
163                                 this.fireConnectionRequiresTransaction();
164                             }
165                             obj = method.invoke(target, args);
166                             if (requireTransaction) {
167                                 fireConnectionRequiresTransactionExecuted();
168                             }
169                         }
170                         return obj;
171                     } catch (InvocationTargetException targetException) {
172                         if (requireTransaction) {
173                             Exception e = null;
174                             if (!(targetException.getTargetException() instanceof Exception)) {
175                                 e = new Exception(targetException.getCause());
176                             } else {
177                                 e = (Exception) (targetException.getTargetException());
178                             }
179                             fireConnectionRequiresTransactionExecuted(e);
180                         }
181 
182 
183                         // rethrow;
184                         throw targetException;
185 
186                     }
187                 } else {
188                     Object obj = null;
189                     if (this.isSynchronized()) {
190                         synchronized (this) {
191                             obj = method.invoke(this, args);
192                         }
193                     } else {
194                         obj = method.invoke(this, args);
195                     }
196                     return obj;
197                 }
198             } catch (InvocationTargetException targetEx) {
199                 // log.fatal("Error calling method " + method + " on " + target + " :: " + targetEx.getMessage() + "\n" + ExceptionUtils.getStackTrace(targetEx.getTargetException()));
200                 throw new DelegatedRuntimeException("Invoking " + method, targetEx.getTargetException());
201             } catch (Throwable ex) {
202                 // log.fatal("Error calling method " + method + " on " + target + " :: " + ex + "\n" + ExceptionUtils.getStackTrace(ex));
203                 throw new DelegatedRuntimeException("Invoking " + method, ex);
204             }
205         }
206 
207         protected IPhynixxManagedConnection<C> getObservableProxy() {
208             return (IPhynixxManagedConnection) proxiedObject;
209         }
210 
211     }
212 }