001    package org.apache.ojb.broker.metadata.fieldaccess;
002    
003    /* Copyright 2002-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.io.Serializable;
019    
020    import org.apache.ojb.broker.metadata.MetadataException;
021    import org.apache.ojb.broker.util.ClassHelper;
022    
023    /**
024     * PeristentField implementation that attempts to detect the nature of
025     * the field it is persisting.
026     * <p>
027     * First checks to see if it is a Field, then Property, then DynaBean
028     * <p>
029     * It will match in that order.
030     */
031    public class PersistentFieldAutoProxyImpl extends PersistentFieldBase
032    {
033        static final long serialVersionUID = 6286229945422476325L;
034    
035        /**
036         * Define the number and ordering of the used {@link PersistentField}
037         * implementaions. Override this field to add new classes or to change
038         * setection order.
039         */
040        protected Class[] persistentFieldClasses = new Class[]{
041            PersistentFieldDirectImpl.class
042            , PersistentFieldIntrospectorImpl.class
043            , PersistentFieldPrivilegedImpl.class
044            , PersistentFieldDynaBeanImpl.class};
045    
046        private PersistentField currentPF;
047        private ExceptionWrapper latestException;
048        int index = 0;
049    
050        public PersistentFieldAutoProxyImpl()
051        {
052        }
053    
054        public PersistentFieldAutoProxyImpl(Class clazz, String fieldname)
055        {
056            super(clazz, fieldname);
057        }
058    
059        private PersistentField getCurrent()
060        {
061            if (currentPF == null)
062            {
063                if(index >= persistentFieldClasses.length)
064                {
065                    index = 0;
066                    currentPF = null;
067                    throw new AutoDetectException("Can't autodetect valid PersistentField implementation: "
068                            + latestException.message, latestException.exception);
069                }
070                try
071                {
072                    currentPF = createPersistentFieldForIndex();
073                }
074                catch (Exception e)
075                {
076                    throw new AutoDetectException("Can't create instance for " + persistentFieldClasses[index], e);
077                }
078            }
079            return currentPF;
080        }
081    
082        private void handleException(String message, Exception e)
083        {
084            latestException = new ExceptionWrapper(message, e);
085            currentPF = null;
086            ++index;
087        }
088    
089    
090        public Object get(Object anObject) throws MetadataException
091        {
092            try
093            {
094                return getCurrent().get(anObject);
095            }
096            catch (Exception e)
097            {
098                if(e instanceof AutoDetectException)
099                {
100                    throw (MetadataException) e;
101                }
102                else
103                {
104                    handleException("Can't extract field value for field " + getName()
105                            + " from object " + (anObject != null ? anObject.getClass() : null), e);
106                    return get(anObject);
107                }
108            }
109        }
110    
111        public void set(Object obj, Object value) throws MetadataException
112        {
113            try
114            {
115                getCurrent().set(obj, value);
116            }
117            catch (Exception e)
118            {
119                if(e instanceof AutoDetectException)
120                {
121                    throw (MetadataException) e;
122                }
123                else
124                {
125                    handleException("Can't set value for field " + getName()
126                            + " to object " + (obj != null ? obj.getClass() : null), e);
127                    set(obj, value);
128                }
129            }
130        }
131    
132        public Class getType()
133        {
134            try
135            {
136                return getCurrent().getType();
137            }
138            catch (Exception e)
139            {
140                if(e instanceof AutoDetectException)
141                {
142                    throw (MetadataException) e;
143                }
144                else
145                {
146                    handleException("Can't identify field type for field " + getName(), null);
147                    return getType();
148                }
149            }
150        }
151    
152        protected boolean makeAccessible()
153        {
154            return false;
155        }
156    
157        public boolean usesAccessorsAndMutators()
158        {
159            return false;
160        }
161    
162        private PersistentField createPersistentFieldForIndex() throws Exception
163        {
164            return newInstance(persistentFieldClasses[index]);
165        }
166    
167        private PersistentField newInstance(Class pfClass) throws Exception
168        {
169            Class[] types = new Class[]{Class.class, String.class};
170            Object[] args = new Object[]{getDeclaringClass(), getName()};
171            return (PersistentField) ClassHelper.newInstance(pfClass, types, args);
172        }
173    
174        static class ExceptionWrapper implements Serializable
175        {
176            private static final long serialVersionUID = 3691042088451912249L;
177            Exception exception;
178            String message;
179    
180            public ExceptionWrapper(String message, Exception exception)
181            {
182                this.message = message;
183                this.exception = exception;
184            }
185        }
186    
187        static class AutoDetectException extends MetadataException
188        {
189            private static final long serialVersionUID = 3257290223049585970L;
190    
191            public AutoDetectException()
192            {
193                super();
194            }
195    
196            public AutoDetectException(Throwable t)
197            {
198                super(t);
199            }
200    
201            public AutoDetectException(String message)
202            {
203                super(message);
204            }
205    
206            public AutoDetectException(String message, Throwable t)
207            {
208                super(message, t);
209            }
210        }
211    }