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}