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