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    }