001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  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    package org.fusesource.hawtbuf.proto.compiler;
018    
019    import java.beans.PropertyEditor;
020    import java.beans.PropertyEditorManager;
021    import java.io.File;
022    import java.lang.reflect.Field;
023    import java.lang.reflect.Method;
024    import java.lang.reflect.Modifier;
025    import java.net.URI;
026    import java.net.URISyntaxException;
027    import java.util.ArrayList;
028    import java.util.Arrays;
029    import java.util.HashMap;
030    import java.util.Iterator;
031    import java.util.LinkedHashMap;
032    import java.util.Map;
033    import java.util.Set;
034    import java.util.StringTokenizer;
035    import java.util.Map.Entry;
036    
037    /**
038     * Support class used to do introspection/reflection based setting and getting of properties on a Java Bean.
039     * 
040     * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
041     */
042    public final class IntrospectionSupport {
043        
044        private IntrospectionSupport() {
045        }
046    
047        public static boolean getProperties(Object target, Map props, String optionPrefix) {
048    
049            boolean rc = false;
050            if (target == null) {
051                throw new IllegalArgumentException("target was null.");
052            }
053            if (props == null) {
054                throw new IllegalArgumentException("props was null.");
055            }
056    
057            if (optionPrefix == null) {
058                optionPrefix = "";
059            }
060    
061            Class clazz = target.getClass();
062            Method[] methods = clazz.getMethods();
063            for (int i = 0; i < methods.length; i++) {
064                Method method = methods[i];
065                String name = method.getName();
066                Class type = method.getReturnType();
067                Class params[] = method.getParameterTypes();
068                if (name.startsWith("get") && params.length == 0 && type != null && isSettableType(type)) {
069    
070                    try {
071    
072                        Object value = method.invoke(target, new Object[] {});
073                        if (value == null) {
074                            continue;
075                        }
076    
077                        String strValue = convertToString(value, type);
078                        if (strValue == null) {
079                            continue;
080                        }
081    
082                        name = name.substring(3, 4).toLowerCase() + name.substring(4);
083                        props.put(optionPrefix + name, strValue);
084                        rc = true;
085    
086                    } catch (Throwable ignore) {
087                    }
088    
089                }
090            }
091    
092            return rc;
093        }
094    
095        public static boolean setProperties(Object target, Map<String, ?> props, String optionPrefix) {
096            boolean rc = false;
097            if (target == null) {
098                throw new IllegalArgumentException("target was null.");
099            }
100            if (props == null) {
101                throw new IllegalArgumentException("props was null.");
102            }
103    
104            for (Iterator<String> iter = props.keySet().iterator(); iter.hasNext();) {
105                String name = iter.next();
106                if (name.startsWith(optionPrefix)) {
107                    Object value = props.get(name);
108                    name = name.substring(optionPrefix.length());
109                    if (setProperty(target, name, value)) {
110                        iter.remove();
111                        rc = true;
112                    }
113                }
114            }
115            return rc;
116        }
117    
118        public static Map<String, Object> extractProperties(Map props, String optionPrefix) {
119            if (props == null) {
120                throw new IllegalArgumentException("props was null.");
121            }
122    
123            HashMap<String, Object> rc = new HashMap<String, Object>(props.size());
124    
125            for (Iterator iter = props.keySet().iterator(); iter.hasNext();) {
126                String name = (String)iter.next();
127                if (name.startsWith(optionPrefix)) {
128                    Object value = props.get(name);
129                    name = name.substring(optionPrefix.length());
130                    rc.put(name, value);
131                    iter.remove();
132                }
133            }
134    
135            return rc;
136        }
137    
138        public static boolean setProperties(Object target, Map props) {
139            boolean rc = false;
140    
141            if (target == null) {
142                throw new IllegalArgumentException("target was null.");
143            }
144            if (props == null) {
145                throw new IllegalArgumentException("props was null.");
146            }
147    
148            for (Iterator iter = props.entrySet().iterator(); iter.hasNext();) {
149                Map.Entry entry = (Entry)iter.next();
150                if (setProperty(target, (String)entry.getKey(), entry.getValue())) {
151                    iter.remove();
152                    rc = true;
153                }
154            }
155    
156            return rc;
157        }
158    
159        public static boolean setProperty(Object target, String name, Object value) {
160            try {
161                Class clazz = target.getClass();
162                Method setter = findSetterMethod(clazz, name);
163                if (setter == null) {
164                    return false;
165                }
166    
167                // If the type is null or it matches the needed type, just use the
168                // value directly
169                if (value == null || value.getClass() == setter.getParameterTypes()[0]) {
170                    setter.invoke(target, new Object[] {value});
171                } else {
172                    // We need to convert it
173                    setter.invoke(target, new Object[] {convert(value, setter.getParameterTypes()[0])});
174                }
175                return true;
176            } catch (Throwable ignore) {
177                return false;
178            }
179        }
180    
181        private static Object convert(Object value, Class type) throws URISyntaxException {
182            PropertyEditor editor = PropertyEditorManager.findEditor(type);
183            if (editor != null) {
184                editor.setAsText(value.toString());
185                return editor.getValue();
186            }
187            if (type == URI.class) {
188                return new URI(value.toString());
189            }
190            if (type == File.class) {
191                return new File(value.toString());
192            }
193            if (type == File[].class) {
194                ArrayList<File> files = new ArrayList<File>();
195                StringTokenizer st = new StringTokenizer(value.toString(), ":");
196                while(st.hasMoreTokens()) {
197                    String t = st.nextToken();
198                    if( t!=null && t.trim().length()>0 ) {
199                        files.add(new File(t.trim()));
200                    }
201                }
202                File rc[] = new File[files.size()];
203                files.toArray(rc);
204                return rc;
205            }
206            return null;
207        }
208    
209        private static String convertToString(Object value, Class type) throws URISyntaxException {
210            PropertyEditor editor = PropertyEditorManager.findEditor(type);
211            if (editor != null) {
212                editor.setValue(value);
213                return editor.getAsText();
214            }
215            if (type == URI.class) {
216                return ((URI)value).toString();
217            }
218            return null;
219        }
220    
221        private static Method findSetterMethod(Class clazz, String name) {
222            // Build the method name.
223            name = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
224            Method[] methods = clazz.getMethods();
225            for (int i = 0; i < methods.length; i++) {
226                Method method = methods[i];
227                Class params[] = method.getParameterTypes();
228                if (method.getName().equals(name) && params.length == 1 && isSettableType(params[0])) {
229                    return method;
230                }
231            }
232            return null;
233        }
234    
235        private static boolean isSettableType(Class clazz) {
236            if (PropertyEditorManager.findEditor(clazz) != null) {
237                return true;
238            }
239            if (clazz == URI.class) {
240                return true;
241            }
242            if (clazz == File.class) {
243                return true;
244            }
245            if (clazz == File[].class) {
246                return true;
247            }
248            if (clazz == Boolean.class) {
249                return true;
250            }
251            return false;
252        }
253    
254        public static String toString(Object target) {
255            return toString(target, Object.class);
256        }
257    
258        public static String toString(Object target, Class stopClass) {
259            LinkedHashMap<String, Object> map = new LinkedHashMap<String, Object>();
260            addFields(target, target.getClass(), stopClass, map);
261            StringBuffer buffer = new StringBuffer(simpleName(target.getClass()));
262            buffer.append(" {");
263            Set entrySet = map.entrySet();
264            boolean first = true;
265            for (Iterator iter = entrySet.iterator(); iter.hasNext();) {
266                Map.Entry entry = (Map.Entry)iter.next();
267                if (first) {
268                    first = false;
269                } else {
270                    buffer.append(", ");
271                }
272                buffer.append(entry.getKey());
273                buffer.append(" = ");
274                appendToString(buffer, entry.getValue());
275            }
276            buffer.append("}");
277            return buffer.toString();
278        }
279    
280        protected static void appendToString(StringBuffer buffer, Object value) {
281            buffer.append(value);
282        }
283    
284        public static String simpleName(Class clazz) {
285            String name = clazz.getName();
286            int p = name.lastIndexOf(".");
287            if (p >= 0) {
288                name = name.substring(p + 1);
289            }
290            return name;
291        }
292    
293        private static void addFields(Object target, Class startClass, Class<Object> stopClass, LinkedHashMap<String, Object> map) {
294    
295            if (startClass != stopClass) {
296                addFields(target, startClass.getSuperclass(), stopClass, map);
297            }
298    
299            Field[] fields = startClass.getDeclaredFields();
300            for (int i = 0; i < fields.length; i++) {
301                Field field = fields[i];
302                if (Modifier.isStatic(field.getModifiers()) || Modifier.isTransient(field.getModifiers())
303                    || Modifier.isPrivate(field.getModifiers())) {
304                    continue;
305                }
306    
307                try {
308                    field.setAccessible(true);
309                    Object o = field.get(target);
310                    if (o != null && o.getClass().isArray()) {
311                        try {
312                            o = Arrays.asList((Object[])o);
313                        } catch (Throwable e) {
314                        }
315                    }
316                    map.put(field.getName(), o);
317                } catch (Throwable e) {
318                    e.printStackTrace();
319                }
320            }
321    
322        }
323    
324    }