/************************************************************************* * Copyright 2009-2012 Eucalyptus Systems, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. * * Please contact Eucalyptus Systems, Inc., 6755 Hollister Ave., Goleta * CA 93117, USA or visit http://www.eucalyptus.com/licenses/ if you need * additional information or have any questions. * * This file may incorporate work covered under the following copyright * and permission notice: * * Software License Agreement (BSD License) * * Copyright (c) 2008, Regents of the University of California * All rights reserved. * * Redistribution and use of this software in source and binary forms, * with or without modification, are permitted provided that the * following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. USERS OF THIS SOFTWARE ACKNOWLEDGE * THE POSSIBLE PRESENCE OF OTHER OPEN SOURCE LICENSED MATERIAL, * COPYRIGHTED MATERIAL OR PATENTED MATERIAL IN THIS SOFTWARE, * AND IF ANY SUCH MATERIAL IS DISCOVERED THE PARTY DISCOVERING * IT MAY INFORM DR. RICH WOLSKI AT THE UNIVERSITY OF CALIFORNIA, * SANTA BARBARA WHO WILL THEN ASCERTAIN THE MOST APPROPRIATE REMEDY, * WHICH IN THE REGENTS' DISCRETION MAY INCLUDE, WITHOUT LIMITATION, * REPLACEMENT OF THE CODE SO IDENTIFIED, LICENSING OF THE CODE SO * IDENTIFIED, OR WITHDRAWAL OF THE CODE CAPABILITY TO THE EXTENT * NEEDED TO COMPLY WITH ANY SUCH LICENSES OR RIGHTS. ************************************************************************/ package com.eucalyptus.util; import java.lang.reflect.Constructor; import java.lang.reflect.GenericDeclaration; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.UndeclaredThrowableException; import java.util.List; import java.util.Map; import javax.annotation.Nullable; import com.eucalyptus.system.Ats; import com.eucalyptus.util.Exceptions.ErrorMessages; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; public class Classes { /** * Returns a {@link Predicate} which determines if the class or interface represented by * {@link Predicate#apply(Class input)} is either the same as, or is a * superclass or superinterface of, the class or interface represented by * {@link #assignableTo(Class type)}. It * returns true if so; otherwise it returns false. If this Class object represents a primitive * type, this * method returns true if the specified Class parameter is exactly this Class object; otherwise it * returns * false. * * @param type * @return */ public static Predicate<Class> assignableTo( final Class<?> type ) { return new Predicate<Class>( ) { @Override public boolean apply( Class input ) { return input.isAssignableFrom( type ); } }; } enum ClassNameToName implements Function<Object, String> { INSTANCE; @Override public String apply( final Object arg0 ) { return WhateverAsClass.INSTANCE.apply( arg0 ).getName( ); } } enum ClassNameToSimpleName implements Function<Object, String> { INSTANCE; @Override public String apply( final Object arg0 ) { return WhateverAsClass.INSTANCE.apply( arg0 ).getSimpleName( ); } } enum ClassNameToCanonicalName implements Function<Object, String> { INSTANCE; @Override public String apply( final Object arg0 ) { return WhateverAsClass.INSTANCE.apply( arg0 ).getCanonicalName( ); } } public static Function<Object, String> nameFunction( ) { return ClassNameToName.INSTANCE; } public static Function<Object, String> simpleNameFunction( ) { return ClassNameToSimpleName.INSTANCE; } public static Function<Object, String> canonicalNameFunction( ) { return ClassNameToCanonicalName.INSTANCE; } public static Predicate<Class<?>> subclassOf( final Class<?> target ) { return new Predicate<Class<?>>() { @Override public boolean apply( final Class<?> value ) { return value != null && target.isAssignableFrom( value ); } }; } @ErrorMessages( Classes.class ) enum ErrorMessageMap implements Function<Class, String> { INSTANCE; private static final// Map<Class, String> errorMessages = new ImmutableMap.Builder<Class, String>( ) { { this.put( IllegalAccessException.class, "Either: " + "the number of actual and formal parameters differ;" + "an unwrapping conversion for primitive arguments fails; " + "this constructor pertains to an enum type;" + "a parameter value cannot be converted to the corresponding formal parameter type by a method invocation conversion." ); this.put( NoSuchMethodException.class, "" ); this.put( SecurityException.class, "" ); this.put( ExceptionInInitializerError.class, "" ); this.put( InvocationTargetException.class, "" ); this.put( InstantiationException.class, "" ); this.put( IllegalArgumentException.class, "" ); } }.build( ); @Override public String apply( Class input ) { return errorMessages.get( input ); } } public static class InstanceBuilder<T> { private final Class<T> type; private final List<Class> argTypes = Lists.newArrayList( ); private final List<Object> args = Lists.newArrayList( ); public InstanceBuilder( Class<T> type ) { this.type = type; } public InstanceBuilder<T> arg( Object arg ) { if ( arg == null ) { throw new IllegalArgumentException( "Cannot supply a null value argument w/o specifying the type." ); } else { return arg( arg, arg.getClass( ) ); } } public InstanceBuilder<T> arg( Object arg, Class type ) { this.argTypes.add( type ); this.args.add( arg ); return this; } /** * @return * @throws UndeclaredThrowableException if the called constructor throws either: * {@link InvocationTargetException} the value of * {@link InvocationTargetException#getCause()} is rethrown as * {@link UndeclaredThrowableException#UndeclaredThrowableException(Throwable)}. * {@link NoSuchMethodException} is rethrown as * {@link UndeclaredThrowableException#UndeclaredThrowableException(Throwable)}. */ public T newInstance( ) throws UndeclaredThrowableException { if ( this.type.isEnum( ) ) { return this.type.getEnumConstants( )[0]; } else { try { Constructor<T> constructor = this.type.getConstructor( this.argTypes.toArray( new Class<?>[] {} ) ); if ( !constructor.isAccessible( ) ) { constructor.setAccessible( true ); } return ( T ) constructor.newInstance( this.args.toArray( ) ); } catch ( final InvocationTargetException ex ) { throw new UndeclaredThrowableException( ex.getCause( ), errorMessage( ex ) ); } catch ( final NoSuchMethodException ex ) { throw new UndeclaredThrowableException( ex ); } catch ( Exception ex ) { String message = errorMessage( ex, InstanceBuilder.errFstring, this.type.getClass( ), this.args, this.argTypes ); throw new InstantiationError( Exceptions.string( message, ex ) ); } } } private String errorMessage( final InvocationTargetException ex ) { return errorMessage( ex.getCause( ), errFstring, this.type.getClass( ), this.args, this.argTypes ); } private static final String errFstring = "Failed to create new instance of type %s with arguments %s (of types: %s) because of: "; public static String errorMessage( Throwable ex, String message, Object... formatArgs ) { return Exceptions.builder( Classes.class ).exception( ex ).unknownException( "An unexpected error: " ).context( errFstring, formatArgs ).append( " because of: " ).build( ); } } public static <T> InstanceBuilder<T> builder( Class<T> type ) { return new InstanceBuilder<T>( type ); } public static <T> T newInstance( final Class<T> type, final Object... args ) { try { return new InstanceBuilder<T>( type ) { { for ( Object o : args ) { this.arg( o ); } } }.newInstance( ); } catch ( UndeclaredThrowableException ex ) { throw ex; } } enum WhateverAsClass implements Function<Object, Class> { INSTANCE; @Override public Class apply( final Object o ) { return ( o instanceof Class ? ( Class ) o : ( o != null ? o.getClass( ) : null ) ); } } enum ParentClass implements Function<Class, Class> { INSTANCE; @Override public Class apply( final Class type ) { return type.getSuperclass( ); } } enum TransitiveClosureImplementedInterfaces implements Function<Class[], List<Class>> { INSTANCE; @Override public List<Class> apply( final Class[] types ) { final List<Class> ret = Lists.newArrayList( ); if ( types.length == 0 ) { return ret; } else { for ( final Class t : types ) { if ( ( t == null ) || ( t == Object.class ) ) { continue; } else if ( t.isInterface( ) ) { ret.add( t ); } if ( t.getInterfaces( ).length == 0 ) { continue; } else { final List<Class> next = TransitiveClosureImplementedInterfaces.INSTANCE.apply( t.getInterfaces( ) ); ret.addAll( next ); } } return ret; } } } enum BreadthFirstTransitiveClosure implements Function<Object, List<Class>> { INSTANCE; @Override public List<Class> apply( final Object input ) { final List<Class> ret = Lists.newArrayList( ); final Class type = WhateverAsClass.INSTANCE.apply( input ); if ( ( type == Object.class ) || ( type == null ) ) { return ret; } else if ( type.isInterface( ) ) { ret.add( type ); final List<Class> superInterfaces = TransitiveClosureImplementedInterfaces.INSTANCE.apply( new Class[] { type } ); ret.addAll( superInterfaces ); return ret; } else { ret.add( type ); final List<Class> superInterfaces = TransitiveClosureImplementedInterfaces.INSTANCE.apply( new Class[] { type } ); ret.addAll( superInterfaces ); final List<Class> next = this.apply( type.getSuperclass( ) ); ret.addAll( next ); return ret; } } } /** * Function for geting a linearized breadth-first list of classes which belong to the * transitive-closure of classes and interfaces implemented by {@code Object o}. * * @param o * @return */ public static Function<Object, List<Class>> ancestors( ) { return BreadthFirstTransitiveClosure.INSTANCE; } /** * Get a linearized breadth-first list of classes which belong to the transitive-closure of * classes and interfaces implemented by {@code Object o}. * * @param o * @return */ public static List<Class> ancestors( final Object o ) { return ancestors( ).apply( o ); } enum ClassBreadthFirstTransitiveClosure implements Function<Object, List<Class>> { INSTANCE; @Override public List<Class> apply( final Object input ) { final List<Class> ret = Lists.newArrayList( ); final Class type = WhateverAsClass.INSTANCE.apply( input ); if ( ( type == Object.class ) || ( type == null ) ) { return ret; } else if ( type.isInterface( ) ) { return ret; } else { ret.add( type ); final List<Class> next = this.apply( type.getSuperclass( ) ); ret.addAll( next ); return ret; } } } /** * Function for geting a linearized breadth-first list of classes which belong to the * transitive-closure of * classes implemented by {@code Object o}. * * @param o * @return */ public static Function<Object, List<Class>> classAncestors( ) { return ClassBreadthFirstTransitiveClosure.INSTANCE; } /** * Get a linearized breadth-first list of classes which belong to the transitive-closure of * classes implemented by {@code Object o}. * * @param o * @return */ public static List<Class> classAncestors( final Object o ) { return ClassBreadthFirstTransitiveClosure.INSTANCE.apply( o ); } enum InterfaceBreadthFirstTransitiveClosure implements Function<Object, List<Class>> { INSTANCE; @Override public List<Class> apply( final Object input ) { final List<Class> ret = Lists.newArrayList( ); final Class type = WhateverAsClass.INSTANCE.apply( input ); if ( ( type == Object.class ) || ( type == null ) ) { return ret; } else { final List<Class> superInterfaces = TransitiveClosureImplementedInterfaces.INSTANCE.apply( new Class[] { type } ); ret.addAll( superInterfaces ); final List<Class> next = this.apply( type.getSuperclass( ) ); ret.addAll( next ); return ret; } } } @SuppressWarnings( "unchecked" ) public static <T> Class<T> typeOf( final Object obj ) { return ( Class<T> ) WhateverAsClass.INSTANCE.apply( obj ); } /** * Function for getting a linearized breadth-first list of classes which belong to the * transitive-closure of * interfaces implemented by {@code Object o}. * * @param o * @return */ public static Function<Object, List<Class>> interfaceAncestors( ) { return InterfaceBreadthFirstTransitiveClosure.INSTANCE; } /** * Get a linearized breadth-first list of classes which belong to the transitive-closure of * interfaces implemented by {@code Object o}. * * @param o * @return */ public static List<Class> interfaceAncestors( final Object o ) { return interfaceAncestors( ).apply( o ); } enum GenericsBreadthFirstTransitiveClosure implements Function<Object, List<Class>> { INSTANCE; @Override public List<Class> apply( final Object input ) { final List<Class> ret = Lists.newArrayList( ); final Class inputClass = WhateverAsClass.INSTANCE.apply( input ); if ( !inputClass.isEnum( ) ) { ret.addAll( processTypeForGenerics( inputClass.getGenericSuperclass( ) ) ); } ret.addAll( processTypeForGenerics( inputClass.getGenericInterfaces( ) ) ); return ret; } private static List<Class> processTypeForGenerics( final Type... types ) { final List<Class> ret = Lists.newArrayList( ); for ( final Type t : types ) { if ( t instanceof ParameterizedType ) { final ParameterizedType pt = ( ParameterizedType ) t; for ( final Type ptType : pt.getActualTypeArguments( ) ) { if ( ptType instanceof Class ) { ret.add( ( Class ) ptType ); } } } if ( t instanceof Class ) { ret.addAll( processTypeForGenerics( ( ( Class ) t ).getGenericSuperclass( ) ) ); ret.addAll( processTypeForGenerics( ( ( Class ) t ).getGenericInterfaces( ) ) ); } } return ret; } } /** * Get a list of the classes corresponding to the actual generic parameters for the given * {@code Object o}. * * @param o * @return */ public static List<Class> genericsToClasses( final Object o ) { return genericsToClasses( ).apply( o ); } /** * Function for getting a list of the classes corresponding to the actual generic parameters for * the given {@code Object o}. * * @param o * @return */ private static Function<Object, List<Class>> genericsToClasses( ) { return GenericsBreadthFirstTransitiveClosure.INSTANCE; } }