| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.naming.factory; |
| |
| import java.beans.BeanInfo; |
| import java.beans.Introspector; |
| import java.beans.PropertyDescriptor; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.util.Enumeration; |
| import java.util.HashMap; |
| import java.util.Hashtable; |
| import java.util.Locale; |
| import java.util.Map; |
| |
| import javax.naming.Context; |
| import javax.naming.Name; |
| import javax.naming.NamingException; |
| import javax.naming.RefAddr; |
| import javax.naming.Reference; |
| import javax.naming.spi.ObjectFactory; |
| |
| import org.apache.naming.ResourceRef; |
| |
| /** |
| * Object factory for any Resource conforming to the JavaBean spec. |
| * |
| * <p>This factory can be configured in a <code><Context></code> element |
| * in your <code>conf/server.xml</code> |
| * configuration file. An example of factory configuration is:</p> |
| * <pre> |
| * <Resource name="jdbc/myDataSource" auth="SERVLET" |
| * type="oracle.jdbc.pool.OracleConnectionCacheImpl"/> |
| * <ResourceParams name="jdbc/myDataSource"> |
| * <parameter> |
| * <name>factory</name> |
| * <value>org.apache.naming.factory.BeanFactory</value> |
| * </parameter> |
| * <parameter> |
| * <name>driverType</name> |
| * <value>thin</value> |
| * </parameter> |
| * <parameter> |
| * <name>serverName</name> |
| * <value>hue</value> |
| * </parameter> |
| * <parameter> |
| * <name>networkProtocol</name> |
| * <value>tcp</value> |
| * </parameter> |
| * <parameter> |
| * <name>databaseName</name> |
| * <value>XXXX</value> |
| * </parameter> |
| * <parameter> |
| * <name>portNumber</name> |
| * <value>NNNN</value> |
| * </parameter> |
| * <parameter> |
| * <name>user</name> |
| * <value>XXXX</value> |
| * </parameter> |
| * <parameter> |
| * <name>password</name> |
| * <value>XXXX</value> |
| * </parameter> |
| * <parameter> |
| * <name>maxLimit</name> |
| * <value>5</value> |
| * </parameter> |
| * </ResourceParams> |
| * </pre> |
| * |
| * @author Aner Perez [aner at ncstech.com] |
| */ |
| public class BeanFactory |
| implements ObjectFactory { |
| |
| // ----------------------------------------------------------- Constructors |
| |
| |
| // -------------------------------------------------------------- Constants |
| |
| |
| // ----------------------------------------------------- Instance Variables |
| |
| |
| // --------------------------------------------------------- Public Methods |
| |
| |
| // -------------------------------------------------- ObjectFactory Methods |
| |
| |
| /** |
| * Create a new Bean instance. |
| * |
| * @param obj The reference object describing the Bean |
| */ |
| @Override |
| public Object getObjectInstance(Object obj, Name name, Context nameCtx, |
| Hashtable<?,?> environment) |
| throws NamingException { |
| |
| if (obj instanceof ResourceRef) { |
| |
| try { |
| |
| Reference ref = (Reference) obj; |
| String beanClassName = ref.getClassName(); |
| Class<?> beanClass = null; |
| ClassLoader tcl = |
| Thread.currentThread().getContextClassLoader(); |
| if (tcl != null) { |
| try { |
| beanClass = tcl.loadClass(beanClassName); |
| } catch(ClassNotFoundException e) { |
| } |
| } else { |
| try { |
| beanClass = Class.forName(beanClassName); |
| } catch(ClassNotFoundException e) { |
| e.printStackTrace(); |
| } |
| } |
| if (beanClass == null) { |
| throw new NamingException |
| ("Class not found: " + beanClassName); |
| } |
| |
| BeanInfo bi = Introspector.getBeanInfo(beanClass); |
| PropertyDescriptor[] pda = bi.getPropertyDescriptors(); |
| |
| Object bean = beanClass.newInstance(); |
| |
| /* Look for properties with explicitly configured setter */ |
| RefAddr ra = ref.get("forceString"); |
| Map<String, Method> forced = new HashMap<>(); |
| String value; |
| |
| if (ra != null) { |
| value = (String)ra.getContent(); |
| Class<?> paramTypes[] = new Class[1]; |
| paramTypes[0] = String.class; |
| String setterName; |
| int index; |
| |
| /* Items are given as comma separated list */ |
| for (String param: value.split(",")) { |
| param = param.trim(); |
| /* A single item can either be of the form name=method |
| * or just a property name (and we will use a standard |
| * setter) */ |
| index = param.indexOf('='); |
| if (index >= 0) { |
| setterName = param.substring(index + 1).trim(); |
| param = param.substring(0, index).trim(); |
| } else { |
| setterName = "set" + |
| param.substring(0, 1).toUpperCase(Locale.ENGLISH) + |
| param.substring(1); |
| } |
| try { |
| forced.put(param, |
| beanClass.getMethod(setterName, paramTypes)); |
| } catch (NoSuchMethodException|SecurityException ex) { |
| throw new NamingException |
| ("Forced String setter " + setterName + |
| " not found for property " + param); |
| } |
| } |
| } |
| |
| Enumeration<RefAddr> e = ref.getAll(); |
| |
| while (e.hasMoreElements()) { |
| |
| ra = e.nextElement(); |
| String propName = ra.getType(); |
| |
| if (propName.equals(Constants.FACTORY) || |
| propName.equals("scope") || propName.equals("auth") || |
| propName.equals("forceString") || |
| propName.equals("singleton")) { |
| continue; |
| } |
| |
| value = (String)ra.getContent(); |
| |
| Object[] valueArray = new Object[1]; |
| |
| /* Shortcut for properties with explicitly configured setter */ |
| Method method = forced.get(propName); |
| if (method != null) { |
| valueArray[0] = value; |
| try { |
| method.invoke(bean, valueArray); |
| } catch (IllegalAccessException| |
| IllegalArgumentException| |
| InvocationTargetException ex) { |
| throw new NamingException |
| ("Forced String setter " + method.getName() + |
| " threw exception for property " + propName); |
| } |
| continue; |
| } |
| |
| int i = 0; |
| for (i = 0; i<pda.length; i++) { |
| |
| if (pda[i].getName().equals(propName)) { |
| |
| Class<?> propType = pda[i].getPropertyType(); |
| |
| if (propType.equals(String.class)) { |
| valueArray[0] = value; |
| } else if (propType.equals(Character.class) |
| || propType.equals(char.class)) { |
| valueArray[0] = |
| Character.valueOf(value.charAt(0)); |
| } else if (propType.equals(Byte.class) |
| || propType.equals(byte.class)) { |
| valueArray[0] = Byte.valueOf(value); |
| } else if (propType.equals(Short.class) |
| || propType.equals(short.class)) { |
| valueArray[0] = Short.valueOf(value); |
| } else if (propType.equals(Integer.class) |
| || propType.equals(int.class)) { |
| valueArray[0] = Integer.valueOf(value); |
| } else if (propType.equals(Long.class) |
| || propType.equals(long.class)) { |
| valueArray[0] = Long.valueOf(value); |
| } else if (propType.equals(Float.class) |
| || propType.equals(float.class)) { |
| valueArray[0] = Float.valueOf(value); |
| } else if (propType.equals(Double.class) |
| || propType.equals(double.class)) { |
| valueArray[0] = Double.valueOf(value); |
| } else if (propType.equals(Boolean.class) |
| || propType.equals(boolean.class)) { |
| valueArray[0] = Boolean.valueOf(value); |
| } else { |
| throw new NamingException |
| ("String conversion for property " + propName + |
| " of type '" + propType.getName() + |
| "' not available"); |
| } |
| |
| Method setProp = pda[i].getWriteMethod(); |
| if (setProp != null) { |
| setProp.invoke(bean, valueArray); |
| } else { |
| throw new NamingException |
| ("Write not allowed for property: " |
| + propName); |
| } |
| |
| break; |
| |
| } |
| |
| } |
| |
| if (i == pda.length) { |
| throw new NamingException |
| ("No set method found for property: " + propName); |
| } |
| |
| } |
| |
| return bean; |
| |
| } catch (java.beans.IntrospectionException ie) { |
| NamingException ne = new NamingException(ie.getMessage()); |
| ne.setRootCause(ie); |
| throw ne; |
| } catch (java.lang.IllegalAccessException iae) { |
| NamingException ne = new NamingException(iae.getMessage()); |
| ne.setRootCause(iae); |
| throw ne; |
| } catch (java.lang.InstantiationException ie2) { |
| NamingException ne = new NamingException(ie2.getMessage()); |
| ne.setRootCause(ie2); |
| throw ne; |
| } catch (java.lang.reflect.InvocationTargetException ite) { |
| Throwable cause = ite.getCause(); |
| if (cause instanceof ThreadDeath) { |
| throw (ThreadDeath) cause; |
| } |
| if (cause instanceof VirtualMachineError) { |
| throw (VirtualMachineError) cause; |
| } |
| NamingException ne = new NamingException(ite.getMessage()); |
| ne.setRootCause(ite); |
| throw ne; |
| } |
| |
| } else { |
| return null; |
| } |
| |
| } |
| } |