Home » openejb-3.1.2-src » org.apache » openejb » resource » [javadoc | source]

    1   /**
    2    *
    3    * Licensed to the Apache Software Foundation (ASF) under one or more
    4    * contributor license agreements.  See the NOTICE file distributed with
    5    * this work for additional information regarding copyright ownership.
    6    * The ASF licenses this file to You under the Apache License, Version 2.0
    7    * (the "License"); you may not use this file except in compliance with
    8    * the License.  You may obtain a copy of the License at
    9    *
   10    *     http://www.apache.org/licenses/LICENSE-2.0
   11    *
   12    *  Unless required by applicable law or agreed to in writing, software
   13    *  distributed under the License is distributed on an "AS IS" BASIS,
   14    *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   15    *  See the License for the specific language governing permissions and
   16    *  limitations under the License.
   17    */
   18   package org.apache.openejb.resource;
   19   
   20   import org.apache.geronimo.connector.outbound.ConnectionInfo;
   21   import org.apache.geronimo.connector.outbound.ConnectionReturnAction;
   22   import org.apache.geronimo.connector.outbound.ConnectionTrackingInterceptor;
   23   import org.apache.geronimo.connector.outbound.ManagedConnectionInfo;
   24   import org.apache.geronimo.connector.outbound.connectiontracking.ConnectionTracker;
   25   
   26   import javax.resource.ResourceException;
   27   import javax.resource.spi.DissociatableManagedConnection;
   28   import java.lang.ref.PhantomReference;
   29   import java.lang.ref.ReferenceQueue;
   30   import java.lang.reflect.InvocationHandler;
   31   import java.lang.reflect.InvocationTargetException;
   32   import java.lang.reflect.Method;
   33   import java.lang.reflect.Proxy;
   34   import java.util.concurrent.ConcurrentHashMap;
   35   import java.util.concurrent.ConcurrentMap;
   36   
   37   public class AutoConnectionTracker implements ConnectionTracker {
   38       private final ConcurrentMap<ManagedConnectionInfo, ProxyPhantomReference> references = new ConcurrentHashMap<ManagedConnectionInfo,ProxyPhantomReference>();
   39       private final ReferenceQueue referenceQueue = new ReferenceQueue();
   40   
   41       /**
   42        * Releases any managed connections held by a garbage collected connection proxy.
   43        * @param connectionInfo the connection to be obtained
   44        * @param key the unique id of the connection manager
   45        */
   46       public void setEnvironment(ConnectionInfo connectionInfo, String key) {
   47           ProxyPhantomReference reference = (ProxyPhantomReference) referenceQueue.poll();
   48           while (reference != null) {
   49               reference.clear();
   50               references.remove(reference.managedConnectionInfo);
   51   
   52               ConnectionInfo released = new ConnectionInfo(reference.managedConnectionInfo);
   53               reference.interceptor.returnConnection(released, ConnectionReturnAction.DESTROY);
   54               reference = (ProxyPhantomReference) referenceQueue.poll();
   55           }
   56       }
   57   
   58       /**
   59        * Proxies new connection handles so we can detect when they have been garbage collected.
   60        *
   61        * @param interceptor the interceptor used to release the managed connection when the handled is garbage collected.
   62        * @param connectionInfo the connection that was obtained
   63        * @param reassociate should always be false
   64        */
   65       public void handleObtained(ConnectionTrackingInterceptor interceptor, ConnectionInfo connectionInfo, boolean reassociate) throws ResourceException {
   66           if (!reassociate) {
   67               proxyConnection(interceptor, connectionInfo);
   68           }
   69       }
   70   
   71       /**
   72        * Removes the released collection from the garbage collection reference tracker, since this
   73        * connection is being release via a normal close method.
   74        *
   75        * @param interceptor ignored
   76        * @param connectionInfo the connection that was released
   77        * @param action ignored
   78        */
   79       public void handleReleased(ConnectionTrackingInterceptor interceptor, ConnectionInfo connectionInfo, ConnectionReturnAction action) {
   80           PhantomReference phantomReference = references.remove(connectionInfo.getManagedConnectionInfo());
   81           if (phantomReference != null) {
   82               phantomReference.clear();
   83           }
   84       }
   85   
   86       private void proxyConnection(ConnectionTrackingInterceptor interceptor, ConnectionInfo connectionInfo) throws ResourceException {
   87           // if this connection already has a proxy no need to create another
   88           if (connectionInfo.getConnectionProxy() != null) return;
   89   
   90           // DissociatableManagedConnection do not need to be proxied
   91           if (connectionInfo.getManagedConnectionInfo().getManagedConnection() instanceof DissociatableManagedConnection) {
   92               return;
   93           }
   94   
   95           try {
   96               Object handle = connectionInfo.getConnectionHandle();
   97               ConnectionInvocationHandler invocationHandler = new ConnectionInvocationHandler(handle);
   98               Object proxy = Proxy.newProxyInstance(handle.getClass().getClassLoader(), handle.getClass().getInterfaces(), invocationHandler);
   99               connectionInfo.setConnectionProxy(proxy);
  100               ProxyPhantomReference reference = new ProxyPhantomReference(interceptor, connectionInfo.getManagedConnectionInfo(), invocationHandler, referenceQueue);
  101               references.put(connectionInfo.getManagedConnectionInfo(), reference);
  102           } catch (Throwable e) {
  103               throw new ResourceException("Unable to construct connection proxy", e);
  104           }
  105       }
  106   
  107       public static class ConnectionInvocationHandler implements InvocationHandler {
  108           private final Object handle;
  109   
  110           public ConnectionInvocationHandler(Object handle) {
  111               this.handle = handle;
  112           }
  113   
  114           public Object invoke(Object object, Method method, Object[] args) throws Throwable {
  115               if (method.getDeclaringClass() == Object.class) {
  116                   if (method.getName().equals("finalize")) {
  117                       // ignore the handle will get called if it implemented the method
  118                       return null;
  119                   }
  120                   if (method.getName().equals("clone")) {
  121                       throw new CloneNotSupportedException();
  122                   }
  123               }
  124   
  125               try {
  126                   Object value = method.invoke(handle, args);
  127                   return value;
  128               } catch (InvocationTargetException ite) {
  129                   // catch InvocationTargetExceptions and turn them into the target exception (if there is one)
  130                   Throwable t = ite.getTargetException();
  131                   if (t != null) {
  132                       throw t;
  133                   }
  134                   throw ite;
  135               }
  136           }
  137       }
  138   
  139       private static class ProxyPhantomReference extends PhantomReference<ConnectionInvocationHandler> {
  140           private ConnectionTrackingInterceptor interceptor;
  141           private ManagedConnectionInfo managedConnectionInfo;
  142   
  143           @SuppressWarnings({"unchecked"})
  144           public ProxyPhantomReference(ConnectionTrackingInterceptor interceptor,
  145                   ManagedConnectionInfo managedConnectionInfo,
  146                   ConnectionInvocationHandler handler,
  147                   ReferenceQueue referenceQueue) {
  148               super(handler, referenceQueue);
  149               this.interceptor = interceptor;
  150               this.managedConnectionInfo = managedConnectionInfo;
  151           }
  152       }
  153   }

Home » openejb-3.1.2-src » org.apache » openejb » resource » [javadoc | source]