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.io.*;
027: import java.util.*;
028: import javax.naming.*;
029: import com.mchange.v2.log.*;
030: import java.lang.reflect.Method;
031: import com.mchange.v2.lang.Coerce;
032: import com.mchange.v2.beans.BeansUtils;
033: import com.mchange.v2.ser.SerializableUtils;
034: import com.mchange.v2.ser.IndirectPolicy;
035:
036: public class JavaBeanReferenceMaker implements ReferenceMaker {
037: private final static MLogger logger = MLog
038: .getLogger(JavaBeanReferenceMaker.class);
039:
040: final static String REF_PROPS_KEY = "com.mchange.v2.naming.JavaBeanReferenceMaker.REF_PROPS_KEY";
041:
042: final static Object[] EMPTY_ARGS = new Object[0];
043:
044: final static byte[] NULL_TOKEN_BYTES = new byte[0];
045:
046: String factoryClassName = "com.mchange.v2.naming.JavaBeanObjectFactory";
047: String defaultFactoryClassLocation = null;
048:
049: Set referenceProperties = new HashSet();
050:
051: ReferenceIndirector indirector = new ReferenceIndirector();
052:
053: public Hashtable getEnvironmentProperties() {
054: return indirector.getEnvironmentProperties();
055: }
056:
057: public void setEnvironmentProperties(Hashtable environmentProperties) {
058: indirector.setEnvironmentProperties(environmentProperties);
059: }
060:
061: public void setFactoryClassName(String factoryClassName) {
062: this .factoryClassName = factoryClassName;
063: }
064:
065: public String getFactoryClassName() {
066: return factoryClassName;
067: }
068:
069: public String getDefaultFactoryClassLocation() {
070: return defaultFactoryClassLocation;
071: }
072:
073: public void setDefaultFactoryClassLocation(
074: String defaultFactoryClassLocation) {
075: this .defaultFactoryClassLocation = defaultFactoryClassLocation;
076: }
077:
078: public void addReferenceProperty(String propName) {
079: referenceProperties.add(propName);
080: }
081:
082: public void removeReferenceProperty(String propName) {
083: referenceProperties.remove(propName);
084: }
085:
086: public Reference createReference(Object bean)
087: throws NamingException {
088: try {
089: BeanInfo bi = Introspector.getBeanInfo(bean.getClass());
090: PropertyDescriptor[] pds = bi.getPropertyDescriptors();
091: List refAddrs = new ArrayList();
092: String factoryClassLocation = defaultFactoryClassLocation;
093:
094: boolean using_ref_props = referenceProperties.size() > 0;
095:
096: // we only include this so that on dereference we are not surprised to find some properties missing
097: if (using_ref_props)
098: refAddrs.add(new BinaryRefAddr(REF_PROPS_KEY,
099: SerializableUtils
100: .toByteArray(referenceProperties)));
101:
102: for (int i = 0, len = pds.length; i < len; ++i) {
103: PropertyDescriptor pd = pds[i];
104: String propertyName = pd.getName();
105: //System.err.println("Making Reference: " + propertyName);
106:
107: if (using_ref_props
108: && !referenceProperties.contains(propertyName)) {
109: //System.err.println("Not a ref_prop -- continuing.");
110: continue;
111: }
112:
113: Class propertyType = pd.getPropertyType();
114: Method getter = pd.getReadMethod();
115: Method setter = pd.getWriteMethod();
116: if (getter != null && setter != null) //only use properties that are both readable and writable
117: {
118: Object val = getter.invoke(bean, EMPTY_ARGS);
119: //System.err.println( "val: " + val );
120: if (propertyName.equals("factoryClassLocation")) {
121: if (String.class != propertyType)
122: throw new NamingException(
123: this .getClass().getName()
124: + " requires a factoryClassLocation property to be a string, "
125: + propertyType.getName()
126: + " is not valid.");
127: factoryClassLocation = (String) val;
128: }
129:
130: if (val == null) {
131: RefAddr addMe = new BinaryRefAddr(propertyName,
132: NULL_TOKEN_BYTES);
133: refAddrs.add(addMe);
134: } else if (Coerce.canCoerce(propertyType)) {
135: RefAddr addMe = new StringRefAddr(propertyName,
136: String.valueOf(val));
137: refAddrs.add(addMe);
138: } else //other Object properties
139: {
140: RefAddr addMe = null;
141: PropertyEditor pe = BeansUtils
142: .findPropertyEditor(pd);
143: if (pe != null) {
144: pe.setValue(val);
145: String textValue = pe.getAsText();
146: if (textValue != null)
147: addMe = new StringRefAddr(propertyName,
148: textValue);
149: }
150: if (addMe == null) //property editor approach failed
151: addMe = new BinaryRefAddr(
152: propertyName,
153: SerializableUtils
154: .toByteArray(
155: val,
156: indirector,
157: IndirectPolicy.INDIRECT_ON_EXCEPTION));
158: refAddrs.add(addMe);
159: }
160: } else {
161: // System.err.println(this.getClass().getName() +
162: // ": Skipping " + propertyName + " because it is " + (setter == null ? "read-only." : "write-only."));
163:
164: if (logger.isLoggable(MLevel.WARNING))
165: logger.warning(this .getClass().getName()
166: + ": Skipping "
167: + propertyName
168: + " because it is "
169: + (setter == null ? "read-only."
170: : "write-only."));
171: }
172:
173: }
174: Reference out = new Reference(bean.getClass().getName(),
175: factoryClassName, factoryClassLocation);
176: for (Iterator ii = refAddrs.iterator(); ii.hasNext();)
177: out.add((RefAddr) ii.next());
178: return out;
179: } catch (Exception e) {
180: //e.printStackTrace();
181: if (Debug.DEBUG && logger.isLoggable(MLevel.FINE))
182: logger.log(MLevel.FINE,
183: "Exception trying to create Reference.", e);
184:
185: throw new NamingException(
186: "Could not create reference from bean: "
187: + e.toString());
188: }
189: }
190:
191: }
|