001    /**
002     *  Licensed to the Apache Software Foundation (ASF) under one or more
003     *  contributor license agreements.  See the NOTICE file distributed with
004     *  this work for additional information regarding copyright ownership.
005     *  The ASF licenses this file to You under the Apache License, Version 2.0
006     *  (the "License"); you may not use this file except in compliance with
007     *  the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    
018    package org.apache.geronimo.connector.outbound;
019    
020    import java.lang.reflect.Constructor;
021    import java.util.HashMap;
022    import java.util.LinkedHashSet;
023    import java.util.Map;
024    
025    import javax.resource.ResourceException;
026    import javax.resource.spi.ManagedConnectionFactory;
027    import javax.resource.spi.ResourceAdapterAssociation;
028    
029    import org.apache.commons.logging.Log;
030    import org.apache.commons.logging.LogFactory;
031    import org.apache.geronimo.connector.ResourceAdapterWrapper;
032    import org.apache.geronimo.gbean.AbstractName;
033    import org.apache.geronimo.gbean.DynamicGBean;
034    import org.apache.geronimo.gbean.DynamicGBeanDelegate;
035    import org.apache.geronimo.gbean.GBeanLifecycle;
036    import org.apache.geronimo.naming.ResourceSource;
037    import org.apache.geronimo.kernel.Kernel;
038    import org.apache.geronimo.management.geronimo.JCAManagedConnectionFactory;
039    
040    /**
041     * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
042     */
043    public class ManagedConnectionFactoryWrapper implements GBeanLifecycle, DynamicGBean, JCAManagedConnectionFactory, ResourceSource<ResourceException> {
044    
045        private static final Log log = LogFactory.getLog(ManagedConnectionFactoryWrapper.class);
046    
047        private final String managedConnectionFactoryClass;
048        private final String connectionFactoryInterface;
049        private final String[] implementedInterfaces;
050        private final String connectionFactoryImplClass;
051        private final String connectionInterface;
052        private final String connectionImplClass;
053    
054        private final LinkedHashSet<Class> allImplementedInterfaces = new LinkedHashSet<Class>();
055    
056        private final ResourceAdapterWrapper resourceAdapterWrapper;
057        private final ConnectionManagerContainer connectionManagerContainer;
058    
059        private ManagedConnectionFactory managedConnectionFactory;
060    
061        private DynamicGBeanDelegate delegate;
062    
063    
064        private boolean registered = false;
065        private final Kernel kernel;
066        private final AbstractName abstractName;
067        private final String objectName;
068        private final ClassLoader classLoader;
069    
070        //default constructor for enhancement proxy endpoint
071        public ManagedConnectionFactoryWrapper() {
072            managedConnectionFactoryClass = null;
073            connectionFactoryInterface = null;
074            implementedInterfaces = null;
075            connectionFactoryImplClass = null;
076            connectionInterface = null;
077            connectionImplClass = null;
078            kernel = null;
079            abstractName = null;
080            objectName = null;
081            classLoader = null;
082            resourceAdapterWrapper = null;
083            connectionManagerContainer = null;
084        }
085    
086        public ManagedConnectionFactoryWrapper(String managedConnectionFactoryClass,
087                                               String connectionFactoryInterface,
088                                               String[] implementedInterfaces,
089                                               String connectionFactoryImplClass,
090                                               String connectionInterface,
091                                               String connectionImplClass,
092                                               ResourceAdapterWrapper resourceAdapterWrapper,
093                                               ConnectionManagerContainer connectionManagerContainer,
094                                               Kernel kernel,
095                                               AbstractName abstractName,
096                                               String objectName,
097                                               ClassLoader cl) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
098            this.managedConnectionFactoryClass = managedConnectionFactoryClass;
099            this.connectionFactoryInterface = connectionFactoryInterface;
100            this.implementedInterfaces = implementedInterfaces;
101            this.connectionFactoryImplClass = connectionFactoryImplClass;
102            this.connectionInterface = connectionInterface;
103            this.connectionImplClass = connectionImplClass;
104    
105            allImplementedInterfaces.add(cl.loadClass(connectionFactoryInterface));
106            for (String interfaceName: implementedInterfaces) {
107                allImplementedInterfaces.add(cl.loadClass(interfaceName));
108            }
109    
110            this.resourceAdapterWrapper = resourceAdapterWrapper;
111            this.connectionManagerContainer = connectionManagerContainer;
112    
113            //set up that must be done before start
114            classLoader = cl;
115            Class clazz = cl.loadClass(managedConnectionFactoryClass);
116            managedConnectionFactory = (ManagedConnectionFactory) clazz.newInstance();
117            delegate = new DynamicGBeanDelegate();
118            delegate.addAll(managedConnectionFactory);
119            this.kernel = kernel;
120            this.abstractName = abstractName;
121            this.objectName = objectName;
122        }
123    
124        public String getManagedConnectionFactoryClass() {
125            return managedConnectionFactoryClass;
126        }
127    
128        public String getConnectionFactoryInterface() {
129            return connectionFactoryInterface;
130        }
131    
132        public String[] getImplementedInterfaces() {
133            return implementedInterfaces;
134        }
135    
136        public String getConnectionFactoryImplClass() {
137            return connectionFactoryImplClass;
138        }
139    
140        public String getConnectionInterface() {
141            return connectionInterface;
142        }
143    
144        public String getConnectionImplClass() {
145            return connectionImplClass;
146        }
147    
148        public ResourceAdapterWrapper getResourceAdapterWrapper() {
149            return resourceAdapterWrapper;
150        }
151    
152        public Object getConnectionManagerContainer() {
153            return connectionManagerContainer;
154        }
155    
156        public void doStart() throws Exception {
157            //register with resource adapter if not yet done
158            if (!registered && (managedConnectionFactory instanceof ResourceAdapterAssociation)) {
159                if (resourceAdapterWrapper == null) {
160                    throw new IllegalStateException("Managed connection factory expects to be registered with a ResourceAdapter, but there is no ResourceAdapter");
161                }
162                resourceAdapterWrapper.registerResourceAdapterAssociation((ResourceAdapterAssociation) managedConnectionFactory);
163                registered = true;
164                log.debug("Registered managedConnectionFactory with ResourceAdapter " + resourceAdapterWrapper.toString());
165            }
166            connectionManagerContainer.doRecovery(managedConnectionFactory);
167        }
168    
169        public void doStop() {
170        }
171    
172        public void doFail() {
173            doStop();
174        }
175    
176        //DynamicGBean implementation
177        public Object getAttribute(String name) throws Exception {
178            Thread thread = Thread.currentThread();
179            ClassLoader oldTCL = thread.getContextClassLoader();
180            thread.setContextClassLoader(classLoader);
181            try {
182                return delegate.getAttribute(name);
183            } finally {
184                thread.setContextClassLoader(oldTCL);
185            }
186        }
187    
188        public void setAttribute(String name, Object value) throws Exception {
189            Thread thread = Thread.currentThread();
190            ClassLoader oldTCL = thread.getContextClassLoader();
191            thread.setContextClassLoader(classLoader);
192            try {
193                delegate.setAttribute(name, value);
194            } finally {
195                thread.setContextClassLoader(oldTCL);
196            }
197        }
198    
199        public Object invoke(String name, Object[] arguments, String[] types) throws Exception {
200            //we have no dynamic operations.
201            return null;
202        }
203    
204        public Object getConnectionFactory() throws ResourceException {
205            return $getConnectionFactory();
206        }
207    
208        public Object $getResource() throws ResourceException {
209            return $getConnectionFactory();
210        }
211    
212        public Object $getConnectionFactory() throws ResourceException {
213            Object connectionFactory =  connectionManagerContainer.createConnectionFactory(managedConnectionFactory);
214            for (Class intf: allImplementedInterfaces) {
215                if (!intf.isAssignableFrom(connectionFactory.getClass())) {
216                    throw new ResourceException("ConnectionFactory does not implement expected interface: " + intf.getName());
217                }
218            }
219            return connectionFactory;
220        }
221    
222        public ManagedConnectionFactory $getManagedConnectionFactory() {
223            return managedConnectionFactory;
224        }
225    
226        /**
227         * Gets the config properties in the form of a map where the key is the
228         * property name and the value is property type (as a Class).
229         */
230        public Map<String, Class> getConfigProperties() {
231            String[] props = delegate.getProperties();
232            Map<String, Class> map = new HashMap<String, Class>();
233            for (String prop : props) {
234                if (prop.equals("logWriter")) {
235                    continue;
236                }
237                map.put(prop, delegate.getPropertyType(prop));
238            }
239            return map;
240        }
241    
242        public void setConfigProperty(String property, Object value) throws Exception {
243            Class cls = delegate.getPropertyType(property);
244            if(value != null && value instanceof String && !cls.getName().equals("java.lang.String")) {
245                if(cls.isPrimitive()) {
246                    if(cls.equals(int.class)) {
247                        cls = Integer.class;
248                    } else if(cls.equals(boolean.class)) {
249                        cls = Boolean.class;
250                    } else if(cls.equals(float.class)) {
251                        cls = Float.class;
252                    } else if(cls.equals(double.class)) {
253                        cls = Double.class;
254                    } else if(cls.equals(long.class)) {
255                        cls = Long.class;
256                    } else if(cls.equals(short.class)) {
257                        cls = Short.class;
258                    } else if(cls.equals(byte.class)) {
259                        cls = Byte.class;
260                    } else if(cls.equals(char.class)) {
261                        cls = Character.class;
262                    }
263                }
264                Constructor con = cls.getConstructor(new Class[]{String.class});
265                value = con.newInstance(new Object[]{value});
266            }
267            kernel.setAttribute(abstractName, property, value);
268        }
269    
270        public Object getConfigProperty(String property) throws Exception {
271            return delegate.getAttribute(property);
272        }
273    
274        public String getObjectName() {
275            return objectName;
276        }
277    
278        public boolean isStateManageable() {
279            return false;
280        }
281    
282        public boolean isStatisticsProvider() {
283            return false;
284        }
285    
286        public boolean isEventProvider() {
287            return false;
288        }
289    }