001: package org.apache.ojb.broker.metadata.fieldaccess;
002:
003: /* Copyright 2003-2005 The Apache Software Foundation
004: *
005: * Licensed under the Apache License, Version 2.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * 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: import java.beans.BeanInfo;
019: import java.beans.IntrospectionException;
020: import java.beans.Introspector;
021: import java.beans.PropertyDescriptor;
022: import java.lang.reflect.Method;
023: import java.util.ArrayList;
024: import java.util.List;
025:
026: import org.apache.commons.lang.StringUtils;
027: import org.apache.ojb.broker.core.proxy.ProxyHelper;
028: import org.apache.ojb.broker.metadata.MetadataException;
029: import org.apache.ojb.broker.util.ClassHelper;
030: import org.apache.ojb.broker.util.logging.Logger;
031:
032: /**
033: * A {@link PersistentField} implementation using
034: * JavaBeans compliant calls only to access persistent attributes.
035: * No Reflection is needed. But for each attribute xxx there must be
036: * public getXxx() and setXxx() methods. In metadata the field name must be
037: * the bean compliant 'xxx'.
038: *
039: * @version $Id: PersistentFieldIntrospectorImpl.java,v 1.11.2.2 2005/12/21 22:26:41 tomdz Exp $
040: */
041: public class PersistentFieldIntrospectorImpl extends
042: PersistentFieldBase {
043: private static final long serialVersionUID = 8805309492150404444L;
044: private Class type;
045: private transient List propertyGraph;
046:
047: public PersistentFieldIntrospectorImpl() {
048: super ();
049: }
050:
051: public PersistentFieldIntrospectorImpl(Class aClass,
052: String aPropertyName) {
053: super (aClass, aPropertyName);
054: }
055:
056: public Class getType() {
057: if (type == null) {
058: type = getPropertyDescriptor().getPropertyType();
059: }
060: return type;
061: }
062:
063: public void set(Object target, Object value)
064: throws MetadataException {
065: if (target == null)
066: return;
067: List propertyDescriptors = getPropertyGraph();
068: int size = propertyDescriptors.size() - 1;
069: PropertyDescriptor pd;
070: for (int i = 0; i < size; i++) {
071: Object attribute;
072: pd = (PropertyDescriptor) propertyDescriptors.get(i);
073: attribute = getValueFrom(pd, target);
074: if (attribute != null || value != null) {
075: if (attribute == null) {
076: try {
077: attribute = ClassHelper.newInstance(pd
078: .getPropertyType());
079: } catch (Exception e) {
080: throw new MetadataException(
081: "Can't instantiate nested object of type '"
082: + pd.getPropertyType()
083: + "' for field '"
084: + pd.getName() + "'", e);
085: }
086: }
087: setValueFor(pd, target, attribute);
088: } else {
089: return;
090: }
091: target = attribute;
092: }
093: pd = (PropertyDescriptor) propertyDescriptors.get(size);
094: setValueFor(pd, target, value);
095: }
096:
097: public Object get(Object target) throws MetadataException {
098: List propertyDescriptors = getPropertyGraph();
099: for (int i = 0; i < propertyDescriptors.size(); i++) {
100: PropertyDescriptor pd = (PropertyDescriptor) propertyDescriptors
101: .get(i);
102: target = getValueFrom(pd, target);
103: if (target == null)
104: break;
105: }
106: return target;
107: }
108:
109: private Object getValueFrom(PropertyDescriptor pd, Object target) {
110: if (target == null)
111: return null;
112: Method m = pd.getReadMethod();
113: if (m != null) {
114: try {
115: return m
116: .invoke(ProxyHelper.getRealObject(target), null);
117: } catch (Throwable e) {
118: logProblem(pd, target, null,
119: "Can't read value from given object");
120: throw new MetadataException("Error invoking method:"
121: + m.getName() + " in object "
122: + target.getClass().getName(), e);
123: }
124: } else {
125: throw new MetadataException(
126: "Can't get ReadMethod for property:" + pd.getName()
127: + " in object "
128: + target.getClass().getName());
129: }
130: }
131:
132: private void setValueFor(PropertyDescriptor pd, Object target,
133: Object value) {
134: Method m = pd.getWriteMethod();
135: Object[] args = { value };
136: if (m != null) {
137: try {
138: /**
139: * MBAIRD: it is safe to call getParameterTypes()[0] because this is
140: * the "set" method and it needs to take one parameter only.
141: * we need to be able to set values to null. We can only set something to null if
142: * the type is not a primitive (assignable from Object).
143: */
144: if ((value != null)
145: || !m.getParameterTypes()[0].isPrimitive()) {
146: m.invoke(ProxyHelper.getRealObject(target), args);
147: }
148: } catch (Throwable e) {
149: logProblem(pd, target, value,
150: "Can't set value on given object.");
151: throw new MetadataException("Error invoking method:"
152: + m.getName() + " in object:"
153: + target.getClass().getName(), e);
154: }
155: } else {
156: throw new MetadataException(
157: "Can't get WriteMethod for property:"
158: + pd.getName() + " in object:"
159: + target.getClass().getName());
160: }
161: }
162:
163: private List getPropertyGraph() {
164: if (propertyGraph == null) {
165: propertyGraph = buildPropertyGraph();
166: }
167: return propertyGraph;
168: }
169:
170: private List buildPropertyGraph() {
171: List result = new ArrayList();
172: String[] fields = StringUtils.split(getName(), PATH_TOKEN);
173: PropertyDescriptor pd = null;
174: for (int i = 0; i < fields.length; i++) {
175: String fieldName = fields[i];
176: if (pd == null) {
177: pd = findPropertyDescriptor(getDeclaringClass(),
178: fieldName);
179: } else {
180: pd = findPropertyDescriptor(pd.getPropertyType(),
181: fieldName);
182: }
183: result.add(pd);
184: }
185: return result;
186: }
187:
188: /**
189: * Get the PropertyDescriptor for aClass and aPropertyName
190: */
191: protected static PropertyDescriptor findPropertyDescriptor(
192: Class aClass, String aPropertyName) {
193: BeanInfo info;
194: PropertyDescriptor[] pd;
195: PropertyDescriptor descriptor = null;
196:
197: try {
198: info = Introspector.getBeanInfo(aClass);
199: pd = info.getPropertyDescriptors();
200: for (int i = 0; i < pd.length; i++) {
201: if (pd[i].getName().equals(aPropertyName)) {
202: descriptor = pd[i];
203: break;
204: }
205: }
206: if (descriptor == null) {
207: /*
208: * Daren Drummond: Throw here so we are consistent
209: * with PersistentFieldDefaultImpl.
210: */
211: throw new MetadataException("Can't find property "
212: + aPropertyName + " in " + aClass.getName());
213: }
214: return descriptor;
215: } catch (IntrospectionException ex) {
216: /*
217: * Daren Drummond: Throw here so we are consistent
218: * with PersistentFieldDefaultImpl.
219: */
220: throw new MetadataException("Can't find property "
221: + aPropertyName + " in " + aClass.getName(), ex);
222: }
223: }
224:
225: /**
226: * Returns the PropertyDescriptor.
227: *
228: * @return java.beans.PropertyDescriptor
229: */
230: protected PropertyDescriptor getPropertyDescriptor() {
231: return (PropertyDescriptor) getPropertyGraph().get(
232: getPropertyGraph().size() - 1);
233: }
234:
235: /**
236: * This implementation returns always 'false'.
237: */
238: public boolean makeAccessible() {
239: return false;
240: }
241:
242: /**
243: * Always returns 'false'.
244: *
245: * @see PersistentField#usesAccessorsAndMutators
246: */
247: public boolean usesAccessorsAndMutators() {
248: return true;
249: }
250:
251: /**
252: * Let's give the user some hints as to what could be wrong.
253: */
254: protected void logProblem(PropertyDescriptor pd, Object anObject,
255: Object aValue, String msg) {
256: Logger logger = getLog();
257: logger.error("Error in [PersistentFieldPropertyImpl], " + msg);
258: logger.error("Declaring class ["
259: + getDeclaringClass().getName() + "]");
260: logger.error("Property Name [" + getName() + "]");
261: logger.error("Property Type [" + pd.getPropertyType().getName()
262: + "]");
263:
264: if (anObject != null) {
265: logger.error("anObject was class ["
266: + anObject.getClass().getName() + "]");
267: } else {
268: logger.error("anObject was null");
269: }
270: if (aValue != null) {
271: logger.error("aValue was class ["
272: + aValue.getClass().getName() + "]");
273: } else {
274: logger.error("aValue was null");
275: }
276: }
277: }
|