001: /*
002: * Distributed as part of c3p0 v.0.9.1.2
003: *
004: * Copyright (C) 2005 Machinery For Change, Inc.
005: *
006: * Author: Steve Waldman <swaldman@mchange.com>
007: *
008: * This library is free software; you can redistribute it and/or modify
009: * it under the terms of the GNU Lesser General Public License version 2.1, as
010: * published by the Free Software Foundation.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public License
018: * along with this software; see the file LICENSE. If not, write to the
019: * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
020: * Boston, MA 02111-1307, USA.
021: */
022:
023: package com.mchange.v2.naming;
024:
025: import java.beans.*;
026: import java.util.*;
027: import javax.naming.*;
028: import com.mchange.v2.log.*;
029: import java.lang.reflect.Method;
030: import javax.naming.spi.ObjectFactory;
031: import com.mchange.v2.beans.BeansUtils;
032: import com.mchange.v2.lang.Coerce;
033: import com.mchange.v2.ser.SerializableUtils;
034:
035: public class JavaBeanObjectFactory implements ObjectFactory {
036: private final static MLogger logger = MLog
037: .getLogger(JavaBeanObjectFactory.class);
038:
039: final static Object NULL_TOKEN = new Object();
040:
041: public Object getObjectInstance(Object refObj, Name name,
042: Context nameCtx, Hashtable env) throws Exception {
043: if (refObj instanceof Reference) {
044: Reference ref = (Reference) refObj;
045: Map refAddrsMap = new HashMap();
046: for (Enumeration e = ref.getAll(); e.hasMoreElements();) {
047: RefAddr addr = (RefAddr) e.nextElement();
048: refAddrsMap.put(addr.getType(), addr);
049: }
050: Class beanClass = Class.forName(ref.getClassName());
051: Set refProps = null;
052: RefAddr refPropsRefAddr = (BinaryRefAddr) refAddrsMap
053: .remove(JavaBeanReferenceMaker.REF_PROPS_KEY);
054: if (refPropsRefAddr != null)
055: refProps = (Set) SerializableUtils
056: .fromByteArray((byte[]) refPropsRefAddr
057: .getContent());
058: Map propMap = createPropertyMap(beanClass, refAddrsMap);
059: return findBean(beanClass, propMap, refProps);
060: } else
061: return null;
062: }
063:
064: private Map createPropertyMap(Class beanClass, Map refAddrsMap)
065: throws Exception {
066: BeanInfo bi = Introspector.getBeanInfo(beanClass);
067: PropertyDescriptor[] pds = bi.getPropertyDescriptors();
068:
069: Map out = new HashMap();
070: for (int i = 0, len = pds.length; i < len; ++i) {
071: PropertyDescriptor pd = pds[i];
072: String propertyName = pd.getName();
073: Class propertyType = pd.getPropertyType();
074: Object addr = refAddrsMap.remove(propertyName);
075: if (addr != null) {
076: if (addr instanceof StringRefAddr) {
077: String content = (String) ((StringRefAddr) addr)
078: .getContent();
079: if (Coerce.canCoerce(propertyType))
080: out.put(propertyName, Coerce.toObject(content,
081: propertyType));
082: else {
083: PropertyEditor pe = BeansUtils
084: .findPropertyEditor(pd);
085: pe.setAsText(content);
086: out.put(propertyName, pe.getValue());
087: }
088: } else if (addr instanceof BinaryRefAddr) {
089: byte[] content = (byte[]) ((BinaryRefAddr) addr)
090: .getContent();
091: if (content.length == 0)
092: out.put(propertyName, NULL_TOKEN); //we use an empty array to mean null
093: else
094: out.put(propertyName, SerializableUtils
095: .fromByteArray(content)); //this will handle "indirectly serialized" objects.
096: } else {
097: if (logger.isLoggable(MLevel.WARNING))
098: logger.warning(this .getClass().getName()
099: + " -- unknown RefAddr subclass: "
100: + addr.getClass().getName());
101: }
102: }
103: }
104: for (Iterator ii = refAddrsMap.keySet().iterator(); ii
105: .hasNext();) {
106: String type = (String) ii.next();
107: if (logger.isLoggable(MLevel.WARNING))
108: logger.warning(this .getClass().getName()
109: + " -- RefAddr for unknown property: " + type);
110: }
111: return out;
112: }
113:
114: protected Object createBlankInstance(Class beanClass)
115: throws Exception {
116: return beanClass.newInstance();
117: }
118:
119: protected Object findBean(Class beanClass, Map propertyMap,
120: Set refProps) throws Exception {
121: Object bean = createBlankInstance(beanClass);
122: BeanInfo bi = Introspector.getBeanInfo(bean.getClass());
123: PropertyDescriptor[] pds = bi.getPropertyDescriptors();
124:
125: for (int i = 0, len = pds.length; i < len; ++i) {
126: PropertyDescriptor pd = pds[i];
127: String propertyName = pd.getName();
128: Object value = propertyMap.get(propertyName);
129: Method setter = pd.getWriteMethod();
130: if (value != null) {
131: if (setter != null)
132: setter.invoke(bean,
133: new Object[] { (value == NULL_TOKEN ? null
134: : value) });
135: else {
136: //System.err.println(this.getClass().getName() + ": Could not restore read-only property '" + propertyName + "'.");
137: if (logger.isLoggable(MLevel.WARNING))
138: logger
139: .warning(this .getClass().getName()
140: + ": Could not restore read-only property '"
141: + propertyName + "'.");
142: }
143: } else {
144: if (setter != null) {
145: if (refProps == null
146: || refProps.contains(propertyName)) {
147: //System.err.println(this.getClass().getName() +
148: //": WARNING -- Expected writable property '" + propertyName + "' left at default value");
149: if (logger.isLoggable(MLevel.WARNING))
150: logger
151: .warning(this .getClass().getName()
152: + " -- Expected writable property ''"
153: + propertyName
154: + "'' left at default value");
155: }
156: }
157: }
158: }
159:
160: return bean;
161: }
162: }
|