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.lang.reflect.Field;
019 import java.util.ArrayList;
020 import java.util.List;
021
022 import org.apache.commons.lang.StringUtils;
023 import org.apache.commons.lang.SystemUtils;
024 import org.apache.commons.lang.builder.ToStringBuilder;
025 import org.apache.ojb.broker.metadata.MetadataException;
026 import org.apache.ojb.broker.util.logging.Logger;
027 import org.apache.ojb.broker.util.logging.LoggerFactory;
028
029 /**
030 * Abstract {@link PersistentField} base implementation class.
031 *
032 * @author <a href="mailto:armin@codeAuLait.de">Armin Waibel</a>
033 * @version $Id: PersistentFieldBase.java,v 1.1 2007-08-24 22:17:35 ewestfal Exp $
034 */
035 public abstract class PersistentFieldBase implements PersistentField
036 {
037 public static final String PATH_TOKEN = "::";
038
039 private String fieldName;
040 protected Class rootObjectType;
041
042 /**
043 * For internal use only!!
044 * TODO: Default constructor only needed to support
045 * PersistentFieldFactory#usesAccessorsAndMutators()
046 * method - find a better solution. Make 'public' to
047 * allow helper class to instantiate class.
048 */
049 public PersistentFieldBase()
050 {
051 }
052
053 public PersistentFieldBase(Class clazz, String fieldname)
054 {
055 this.rootObjectType = clazz;
056 this.fieldName = fieldname;
057 }
058
059 /**
060 * A value of true indicates that this field should
061 * suppress Java language access checking when it is used.
062 */
063 protected abstract boolean makeAccessible();
064
065 public String getName()
066 {
067 return fieldName;
068 }
069
070 public Class getDeclaringClass()
071 {
072 return rootObjectType;
073 }
074
075 protected List getFieldGraph(boolean makeAccessible)
076 {
077 List result = new ArrayList();
078 String[] fields = StringUtils.split(getName(), PATH_TOKEN);
079 Field fld = null;
080 for (int i = 0; i < fields.length; i++)
081 {
082 String fieldName = fields[i];
083 try
084 {
085 if (fld == null)
086 {
087 fld = getFieldRecursive(rootObjectType, fieldName);
088 }
089 else
090 {
091 fld = getFieldRecursive(fld.getType(), fieldName);
092 }
093 if (makeAccessible)
094 {
095 fld.setAccessible(true);
096 }
097 }
098 catch (NoSuchFieldException e)
099 {
100 throw new MetadataException("Can't find member '"
101 + fieldName + "' in class " + (fld != null ? fld.getDeclaringClass() : rootObjectType), e);
102 }
103 result.add(fld);
104 }
105 return result;
106 }
107
108 /**
109 * try to find a field in class c, recurse through class hierarchy if necessary
110 *
111 * @throws NoSuchFieldException if no Field was found into the class hierarchy
112 */
113 private Field getFieldRecursive(Class c, String name) throws NoSuchFieldException
114 {
115 try
116 {
117 return c.getDeclaredField(name);
118 }
119 catch (NoSuchFieldException e)
120 {
121 // if field could not be found in the inheritance hierarchy, signal error
122 if ((c == Object.class) || (c.getSuperclass() == null) || c.isInterface())
123 {
124 throw e;
125 }
126 // if field could not be found in class c try in superclass
127 else
128 {
129 return getFieldRecursive(c.getSuperclass(), name);
130 }
131 }
132 }
133
134 protected Logger getLog()
135 {
136 return LoggerFactory.getLogger("PersistentField");
137 }
138
139 public String toString()
140 {
141 ToStringBuilder buf = new ToStringBuilder(this);
142 buf.append("rootType", rootObjectType);
143 buf.append("fieldName", fieldName);
144 return buf.toString();
145 }
146
147 /**
148 * Build a String representation of given arguments.
149 */
150 protected String buildErrorSetMsg(Object obj, Object value, Field aField)
151 {
152 String eol = SystemUtils.LINE_SEPARATOR;
153 StringBuffer buf = new StringBuffer();
154 buf
155 .append(eol + "[try to set 'object value' in 'target object'")
156 .append(eol + "target obj class: " + (obj != null ? obj.getClass().getName() : null))
157 .append(eol + "target field name: " + (aField != null ? aField.getName() : null))
158 .append(eol + "target field type: " + (aField != null ? aField.getType() : null))
159 .append(eol + "target field declared in: " + (aField != null ? aField.getDeclaringClass().getName() : null))
160 .append(eol + "object value class: " + (value != null ? value.getClass().getName() : null))
161 .append(eol + "object value: " + (value != null ? value : null))
162 .append(eol + "]");
163 return buf.toString();
164 }
165
166 /**
167 * Build a String representation of given arguments.
168 */
169 protected String buildErrorGetMsg(Object obj, Field aField)
170 {
171 String eol = SystemUtils.LINE_SEPARATOR;
172 StringBuffer buf = new StringBuffer();
173 buf
174 .append(eol + "[try to read from source object")
175 .append(eol + "source obj class: " + (obj != null ? obj.getClass().getName() : null))
176 .append(eol + "target field name: " + (aField != null ? aField.getName() : null))
177 .append(eol + "target field type: " + (aField != null ? aField.getType() : null))
178 .append(eol + "target field declared in: " + (aField != null ? aField.getDeclaringClass().getName() : null))
179 .append(eol + "]");
180 return buf.toString();
181 }
182 }