/* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved. * This code is licensed under the GPL 2.0 license, availible at the root * application directory. */ package org.geoserver.ows.util; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Iterator; import java.util.Map; import org.geoserver.platform.ServiceException; import org.geotools.util.SoftValueHashMap; /** * Utility class for performing reflective operations and other ows utility functions. * * @author Justin Deoliveira, The Open Planning Project * */ public class OwsUtils { /** * Reflectively sets a property on an object. * <p> * This method uses {@link #setter(Class, String, Class)} to locate teh setter * method for the property and then invokes it with teh specified <tt>value</tt>. * </p> * @param object The target object. * @param property The property to set. * @param value The value to set, may be <code>null</code>. * * @throws IllegalArgumentException If no such property exists. * @throws RuntimeException If an error occurs setting the property */ public static void set( Object object, String property, Object value ) throws IllegalArgumentException { Method s = setter( object.getClass(), property, value != null ? value.getClass() : null ); if ( s == null ) { throw new IllegalArgumentException( "No such property '" + property + "' for object " + object ); } try { s.invoke( object, value ); } catch( Exception e ) { throw new RuntimeException( e ); } } /** * Cache of reflection information about a class, keyed by class. */ static Map<Class, ClassProperties> classPropertiesCache = new SoftValueHashMap<Class, ClassProperties>(); /** * Accessor for the class to property info cache. */ static ClassProperties classProperties(Class clazz) { // SoftValueHashMap is thread safe, no need to synch ClassProperties properties = classPropertiesCache.get(clazz); if(properties == null) { properties = new ClassProperties(clazz); classPropertiesCache.put(clazz, properties); } return properties; } /** * Returns the properties object describing the properties of a class. */ public static ClassProperties getClassProperties( Class clazz ) { return classProperties(clazz); } /** * Returns a setter method for a property of java bean. * <p> * The <tt>type</tt> parameter may be <code>null</code> to indicate the * the setter for the property should be returned regardless of the type. If * not null it will be used to filter the returned method. * </p> * @param clazz The type of the bean. * @param property The property name. * @param type The type of the property, may be <code>null</code>. * * @return The setter method, or <code>null</code> if not found. */ public static Method setter(Class clazz, String property, Class type) { return classProperties(clazz).setter(property, type); } /** * Reflectively gets a property from an object. * <p> * This method uses {@link #getter(Class, String, Class)} to locate the getter * method for the property and then invokes it. * </p> * @param object The target object. * @param property The property to set. * * @throws IllegalArgumentException If no such property exists. * @throws RuntimeException If an error occurs getting the property */ public static Object get(Object object, String property) { Method g = getter( object.getClass(), property, null ); if ( g == null ) { throw new IllegalArgumentException("No such property '" + property + "' for object " + object ); } try { return g.invoke( object, null ); } catch( Exception e ) { throw new RuntimeException( e ); } } /** * Returns a getter method for a property of java bean. * * @param clazz The type of the bean. * @param property The property name. * @param type The type of the property, may be null. * * @return The setter method, or <code>null</code> if not found. */ public static Method getter(Class clazz, String property, Class type) { return classProperties(clazz).getter(property, type); } /** * Reflectivley retreives a propety from a java bean. * * @param object The java bean. * @param property The property to retreive. * @param type Teh type of the property to retreive. * * @return The property, or null if it could not be found.. */ public static Object property(Object object, String property, Class type) { Method getter = getter(object.getClass(), property, type); if (getter != null) { try { return getter.invoke(object, null); } catch (Exception e) { //TODO: log this } } return null; } /** * Returns a method with a pariticular name of a class, ignoring method * paramters. * * @param clazz The class * @param name The name of the method. * * @return The method, or <code>null</code> if it could not be found. */ public static Method method(Class clazz, String name) { return classProperties(clazz).method( name ); } /** * Returns an object of a particular type in a list of objects of * various types. * * @param parameters A list of objects, of various types. * @param type The type of paramter to be returned. * * @return The object of the specified type, or <code>null</code> */ public static Object parameter(Object[] parameters, Class type) { for (int i = 0; i < parameters.length; i++) { Object parameter = parameters[i]; if ((parameter != null) && type.isAssignableFrom(parameter.getClass())) { return parameter; } } return null; } /** * Dumps a stack of service exception messages to a string buffer. * */ public static void dumpExceptionMessages(ServiceException e, StringBuffer s, boolean xmlEscape) { Throwable ex = e; do { Throwable cause = ex.getCause(); final String message = ex.getMessage(); String lastMessage = message; if(!"".equals(message)) { if(xmlEscape) s.append(ResponseUtils.encodeXML(message)); else s.append(message); if(ex instanceof ServiceException) { for ( Iterator t = ((ServiceException) ex).getExceptionText().iterator(); t.hasNext(); ) { s.append("\n"); String msg = (String) t.next(); if(!lastMessage.equals(msg)) { if(xmlEscape) s.append(ResponseUtils.encodeXML(msg)); else s.append( t.next() ); lastMessage = msg; } } } if(cause != null) s.append("\n"); } // avoid infinite loop if someone did the very stupid thing of setting // the cause as the exception itself (I only found this situation once, but...) if(ex == cause || cause == null) break; else ex = cause; } while(true); } }