001    /*
002     * Copyright 2002-2004 The Apache Software Foundation
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *     http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.apache.commons.clazz.reflect.common;
017    
018    import java.lang.reflect.Method;
019    import java.util.ArrayList;
020    import java.util.List;
021    
022    import org.apache.commons.clazz.Clazz;
023    import org.apache.commons.clazz.reflect.ReflectedClazz;
024    
025    /**
026     * Base class for <code>Reflected*PropertyParseResults</code> classes;
027     * aggregates parse results for individual accessor methods.
028     * 
029     * @author <a href="mailto:dmitri@apache.org">Dmitri Plotnikov</a>
030     * @version $Id: ReflectedPropertyParseResults.java 155436 2005-02-26 13:17:48Z dirkv $
031     */
032    public abstract class ReflectedPropertyParseResults implements Comparable {
033        private ReflectedClazz clazz;
034        private String propertyName;
035        private List aliases;
036    
037        protected AccessorMethodParseResults readMethodParseResults;
038        protected AccessorMethodParseResults writeMethodParseResults;
039        protected List extraneousAccessors;
040    
041        private static final String[] EMPTY_STRING_ARRAY = new String[0];
042    
043        public ReflectedPropertyParseResults(
044            ReflectedClazz clazz,
045            String propertyName) 
046        {
047            this.clazz = clazz;
048            this.propertyName = propertyName;
049        }
050    
051        public ReflectedClazz getClazz() {
052            return clazz;
053        }
054    
055        /**
056         * Returns the propertyName.
057         * @return String
058         */
059        public String getPropertyName() {
060            return propertyName;
061        }
062    
063        public int compareTo(Object object) {
064            String n1 = getPropertyName();
065            String n2 = ((ReflectedPropertyParseResults) object).getPropertyName();
066            return n1.compareTo(n2);
067        }
068    
069        public String[] getAliases() {
070            if (aliases == null) {
071                return EMPTY_STRING_ARRAY;
072            }
073            return (String[]) aliases.toArray(EMPTY_STRING_ARRAY);
074        }
075    
076        public void addAlias(String alias) {
077            if (!alias.equals(propertyName)) {
078                if (aliases == null) {
079                    aliases = new ArrayList();
080                    aliases.add(alias);
081                }
082                else if (!aliases.contains(alias)) {
083                    aliases.add(alias);
084                }
085            }
086        }
087    
088        protected abstract String getPropertyCategory();
089    
090        public void merge(ReflectedPropertyParseResults other) {
091            addAlias(other.getPropertyName());
092            String[] aliases = other.getAliases();
093            for (int i = 0; i < aliases.length; i++) {
094                addAlias(aliases[i]);
095            }
096        }
097    
098        public Class getPropertyType() {
099            if (readMethodParseResults != null) {
100                return readMethodParseResults.getType();
101            }
102            if (writeMethodParseResults != null) {
103                return writeMethodParseResults.getType();
104            }
105            return null;
106        }
107    
108        public Method getReadMethod() {
109            if (readMethodParseResults == null) {
110                return null;
111            }
112            return readMethodParseResults.getMethod();
113        }
114    
115        public Method getWriteMethod() {
116            if (writeMethodParseResults == null) {
117                return null;
118            }
119            return writeMethodParseResults.getMethod();
120        }
121    
122        /**
123         * Sets the readMethodParseResults.
124         * @param readMethodParseResults The readMethodParseResults to set
125         */
126        public void setReadMethodParseResults(
127                AccessorMethodParseResults readMethodParseResults) 
128        {
129            checkForExtraneousAccessor(
130                this.readMethodParseResults,
131                readMethodParseResults);
132            this.readMethodParseResults = readMethodParseResults;
133        }
134    
135        /**
136         * Sets the writeMethodParseResults.
137         * @param writeMethodParseResults The writeMethodParseResults to set
138         */
139        public void setWriteMethodParseResults(
140                AccessorMethodParseResults writeMethodParseResults) 
141        {
142            checkForExtraneousAccessor(
143                this.writeMethodParseResults,
144                writeMethodParseResults);
145            this.writeMethodParseResults = writeMethodParseResults;
146        }
147    
148        /**
149         * Checks if there is an existing parse result recorded and if
150         * so saves it into the extraneousAccessors for error reporting.
151         */
152        protected void checkForExtraneousAccessor(
153            AccessorMethodParseResults currentValue,
154            AccessorMethodParseResults newValue) 
155        {
156            if (currentValue != null
157                && newValue != null
158                && currentValue != newValue) {
159                if (extraneousAccessors == null) {
160                    extraneousAccessors = new ArrayList();
161                    extraneousAccessors.add(currentValue);
162                }
163            }
164        }
165    
166        public boolean checkConsistency() {
167            if (extraneousAccessors != null) {
168                return false;
169            }
170    
171            return true;
172        }
173    
174        public String toString() {
175            boolean consistent = checkConsistency();
176    
177            StringBuffer buffer = new StringBuffer();
178            buffer.append("[");
179            if (consistent) {
180                buffer.append(propertyName);
181                if (!getPropertyCategory().equals("scalar")) {
182                    buffer.append(" (");
183                    buffer.append(getPropertyCategory());
184                    buffer.append(")");
185                }
186            }
187            else {
188                buffer.append("*");
189                buffer.append(propertyName);
190                buffer.append(" - NOT a ");
191                if (!getPropertyCategory().equals("scalar")) {
192                    buffer.append(getPropertyCategory());
193                }
194                buffer.append(" property");
195                appendInconsistencyDescriptions(buffer);
196            }
197            if (aliases != null) {
198                buffer.append("\n  [aliases: ");
199                for (int i = 0; i < aliases.size(); i++) {
200                    if (i != 0) {
201                        buffer.append(", ");
202                    }
203                    buffer.append(aliases.get(i));
204                }
205                buffer.append("]");
206            }
207            appendDescription(buffer);
208            buffer.append("\n  [accessor methods:");
209            appendMethodDescriptions(buffer);
210            buffer.append("\n  ]");
211            buffer.append("\n]");
212            return buffer.toString();
213        }
214    
215        protected void appendDescription(StringBuffer buffer) {
216            Class type = getPropertyType();
217            if (type != null) {
218                buffer.append("\n  [type]           ");
219                buffer.append(Clazz.getCanonicalClassName(type));
220            }
221        }
222    
223        protected void appendMethodDescriptions(StringBuffer buffer) {
224            if (readMethodParseResults != null) {
225                buffer.append("\n    [get~()]       ");
226                buffer.append(readMethodParseResults.getMethod());
227            }
228            if (writeMethodParseResults != null) {
229                buffer.append("\n    [set~(v)]      ");
230                buffer.append(writeMethodParseResults.getMethod());
231            }
232        }
233    
234        protected boolean appendInconsistencyDescriptions(StringBuffer buffer) {
235            if (extraneousAccessors != null) {
236                buffer.append("\n     - Has extraneous accessors:");
237                for (int i = 0; i < extraneousAccessors.size(); i++) {
238                    AccessorMethodParseResults results =
239                        (AccessorMethodParseResults) extraneousAccessors.get(i);
240                    buffer.append("\n         ");
241                    buffer.append(results.getMethod());
242                }
243            }
244            return true;
245        }
246    }