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.apache.activemq.util;
018    
019    import java.beans.PropertyEditor;
020    import java.beans.PropertyEditorManager;
021    import java.lang.reflect.Array;
022    import java.lang.reflect.Field;
023    import java.lang.reflect.Method;
024    import java.lang.reflect.Modifier;
025    import java.util.Arrays;
026    import java.util.HashMap;
027    import java.util.Iterator;
028    import java.util.LinkedHashMap;
029    import java.util.Map;
030    import java.util.Set;
031    import java.util.Map.Entry;
032    
033    import org.apache.activemq.command.ActiveMQDestination;
034    
035    
036    
037    
038    public final class IntrospectionSupport {
039            
040            static {
041                    // Add Spring and ActiveMQ specific property editors
042                    String[] additionalPath = new String[] {
043                                    "org.springframework.beans.propertyeditors",
044                                    "org.apache.activemq.util" };
045                    synchronized (PropertyEditorManager.class) {
046                        String[] existingSearchPath = PropertyEditorManager.getEditorSearchPath();
047                        String[] newSearchPath = (String[]) Array.newInstance(String.class,
048                                existingSearchPath.length + additionalPath.length);
049                        System.arraycopy(existingSearchPath, 0,
050                                newSearchPath, 0,
051                                existingSearchPath.length);
052                        System.arraycopy(additionalPath, 0, 
053                                newSearchPath, existingSearchPath.length,
054                                additionalPath.length);
055                        PropertyEditorManager.setEditorSearchPath(newSearchPath);
056                    }
057            }
058        
059        private IntrospectionSupport() {
060        }
061    
062        public static boolean getProperties(Object target, Map props, String optionPrefix) {
063    
064            boolean rc = false;
065            if (target == null) {
066                throw new IllegalArgumentException("target was null.");
067            }
068            if (props == null) {
069                throw new IllegalArgumentException("props was null.");
070            }
071    
072            if (optionPrefix == null) {
073                optionPrefix = "";
074            }
075    
076            Class clazz = target.getClass();
077            Method[] methods = clazz.getMethods();
078            for (int i = 0; i < methods.length; i++) {
079                Method method = methods[i];
080                String name = method.getName();
081                Class type = method.getReturnType();
082                Class params[] = method.getParameterTypes();
083                if ((name.startsWith("is") || name.startsWith("get")) && params.length == 0 && type != null && isSettableType(type)) {
084    
085                    try {
086    
087                        Object value = method.invoke(target, new Object[] {});
088                        if (value == null) {
089                            continue;
090                        }
091    
092                        String strValue = convertToString(value, type);
093                        if (strValue == null) {
094                            continue;
095                        }
096                        if (name.startsWith("get")) {
097                            name = name.substring(3, 4).toLowerCase()
098                                    + name.substring(4);
099                        } else {
100                            name = name.substring(2, 3).toLowerCase()
101                                    + name.substring(3);
102                        }
103                        props.put(optionPrefix + name, strValue);
104                        rc = true;
105    
106                    } catch (Throwable ignore) {
107                    }
108    
109                }
110            }
111    
112            return rc;
113        }
114    
115        public static boolean setProperties(Object target, Map<String, ?> props, String optionPrefix) {
116            boolean rc = false;
117            if (target == null) {
118                throw new IllegalArgumentException("target was null.");
119            }
120            if (props == null) {
121                throw new IllegalArgumentException("props was null.");
122            }
123    
124            for (Iterator<String> iter = props.keySet().iterator(); iter.hasNext();) {
125                String name = iter.next();
126                if (name.startsWith(optionPrefix)) {
127                    Object value = props.get(name);
128                    name = name.substring(optionPrefix.length());
129                    if (setProperty(target, name, value)) {
130                        iter.remove();
131                        rc = true;
132                    }
133                }
134            }
135            return rc;
136        }
137    
138        public static Map<String, Object> extractProperties(Map props, String optionPrefix) {
139            if (props == null) {
140                throw new IllegalArgumentException("props was null.");
141            }
142    
143            HashMap<String, Object> rc = new HashMap<String, Object>(props.size());
144    
145            for (Iterator iter = props.keySet().iterator(); iter.hasNext();) {
146                String name = (String)iter.next();
147                if (name.startsWith(optionPrefix)) {
148                    Object value = props.get(name);
149                    name = name.substring(optionPrefix.length());
150                    rc.put(name, value);
151                    iter.remove();
152                }
153            }
154    
155            return rc;
156        }
157    
158        public static boolean setProperties(Object target, Map props) {
159            boolean rc = false;
160    
161            if (target == null) {
162                throw new IllegalArgumentException("target was null.");
163            }
164            if (props == null) {
165                throw new IllegalArgumentException("props was null.");
166            }
167    
168            for (Iterator iter = props.entrySet().iterator(); iter.hasNext();) {
169                Map.Entry entry = (Entry)iter.next();
170                if (setProperty(target, (String)entry.getKey(), entry.getValue())) {
171                    iter.remove();
172                    rc = true;
173                }
174            }
175    
176            return rc;
177        }
178    
179        public static boolean setProperty(Object target, String name, Object value) {
180            try {
181                Class clazz = target.getClass();
182                Method setter = findSetterMethod(clazz, name);
183                if (setter == null) {
184                    return false;
185                }
186    
187                // If the type is null or it matches the needed type, just use the
188                // value directly
189                if (value == null || value.getClass() == setter.getParameterTypes()[0]) {
190                    setter.invoke(target, new Object[] {value});
191                } else {
192                    // We need to convert it
193                    setter.invoke(target, new Object[] {convert(value, setter.getParameterTypes()[0])});
194                }
195                return true;
196            } catch (Throwable ignore) {
197                return false;
198            }
199        }
200    
201        private static Object convert(Object value, Class type) {
202            PropertyEditor editor = PropertyEditorManager.findEditor(type);
203            if (editor != null) {
204                editor.setAsText(value.toString());
205                return editor.getValue();
206            }
207            return null;
208        }
209    
210        public static String convertToString(Object value, Class type) {
211            PropertyEditor editor = PropertyEditorManager.findEditor(type);
212            if (editor != null) {
213                editor.setValue(value);
214                return editor.getAsText();
215            }
216            return null;
217        }
218    
219        private static Method findSetterMethod(Class clazz, String name) {
220            // Build the method name.
221            name = "set" + Character.toUpperCase(name.charAt(0)) + name.substring(1);
222            Method[] methods = clazz.getMethods();
223            for (int i = 0; i < methods.length; i++) {
224                Method method = methods[i];
225                Class params[] = method.getParameterTypes();
226                if (method.getName().equals(name) && params.length == 1 ) {
227                    return method;
228                }
229            }
230            return null;
231        }
232    
233        private static boolean isSettableType(Class clazz) {
234            if (PropertyEditorManager.findEditor(clazz) != null) {
235                return true;
236            }
237                    
238            return false;
239        }
240    
241        public static String toString(Object target) {
242            return toString(target, Object.class, null);
243        }
244        
245        public static String toString(Object target, Class stopClass) {
246            return toString(target, stopClass, null);
247        }
248    
249        public static String toString(Object target, Class stopClass, Map<String, Object> overrideFields) {
250            LinkedHashMap<String, Object> map = new LinkedHashMap<String, Object>();
251            addFields(target, target.getClass(), stopClass, map);
252            if (overrideFields != null) {
253                    for(String key : overrideFields.keySet()) {
254                        Object value = overrideFields.get(key);
255                        map.put(key, value);
256                    }
257    
258            }
259            StringBuffer buffer = new StringBuffer(simpleName(target.getClass()));
260            buffer.append(" {");
261            Set entrySet = map.entrySet();
262            boolean first = true;
263            for (Iterator iter = entrySet.iterator(); iter.hasNext();) {
264                Map.Entry entry = (Map.Entry)iter.next();
265                Object value = entry.getValue();
266                Object key = entry.getKey();
267                if (first) {
268                    first = false;
269                } else {
270                    buffer.append(", ");
271                }
272                buffer.append(key);
273                buffer.append(" = ");
274                
275                appendToString(buffer, key, value);
276            }
277            buffer.append("}");
278            return buffer.toString();
279        }
280    
281        protected static void appendToString(StringBuffer buffer, Object key, Object value) {
282            if (value instanceof ActiveMQDestination) {
283                ActiveMQDestination destination = (ActiveMQDestination)value;
284                buffer.append(destination.getQualifiedName());
285            } else if (key.toString().toLowerCase().contains("password")){
286                buffer.append("*****");           
287            } else {
288                buffer.append(value);
289            }
290        }
291    
292        public static String simpleName(Class clazz) {
293            String name = clazz.getName();
294            int p = name.lastIndexOf(".");
295            if (p >= 0) {
296                name = name.substring(p + 1);
297            }
298            return name;
299        }
300    
301        private static void addFields(Object target, Class startClass, Class<Object> stopClass, LinkedHashMap<String, Object> map) {
302    
303            if (startClass != stopClass) {
304                addFields(target, startClass.getSuperclass(), stopClass, map);
305            }
306    
307            Field[] fields = startClass.getDeclaredFields();
308            for (int i = 0; i < fields.length; i++) {
309                Field field = fields[i];
310                if (Modifier.isStatic(field.getModifiers()) || Modifier.isTransient(field.getModifiers())
311                    || Modifier.isPrivate(field.getModifiers())) {
312                    continue;
313                }
314    
315                try {
316                    field.setAccessible(true);
317                    Object o = field.get(target);
318                    if (o != null && o.getClass().isArray()) {
319                        try {
320                            o = Arrays.asList((Object[])o);
321                        } catch (Throwable e) {
322                        }
323                    }
324                    map.put(field.getName(), o);
325                } catch (Throwable e) {
326                    e.printStackTrace();
327                }
328            }
329    
330        }
331    
332    }