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 */
017package org.apache.activemq.util;
018
019import java.beans.PropertyEditor;
020import java.beans.PropertyEditorManager;
021import java.lang.reflect.Array;
022import java.lang.reflect.Field;
023import java.lang.reflect.Method;
024import java.lang.reflect.Modifier;
025import java.util.Arrays;
026import java.util.HashMap;
027import java.util.Iterator;
028import java.util.LinkedHashMap;
029import java.util.Map;
030import java.util.Set;
031import java.util.Map.Entry;
032
033import javax.net.ssl.SSLServerSocket;
034
035import org.apache.activemq.command.ActiveMQDestination;
036
037
038
039
040public 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}