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 018 package org.apache.commons.proxy.factory.util; 019 020 import org.apache.commons.proxy.ProxyFactory; 021 import org.apache.commons.proxy.exception.ProxyFactoryException; 022 023 import java.lang.reflect.Constructor; 024 import java.lang.reflect.Modifier; 025 import java.util.Collection; 026 import java.util.LinkedList; 027 import java.util.List; 028 029 /** 030 * A useful superclass for a {@link ProxyFactory} which supports subclassing rather than merely implementing interfaces. 031 * 032 * @author James Carman 033 * @since 1.0 034 */ 035 public abstract class AbstractSubclassingProxyFactory extends ProxyFactory 036 { 037 //---------------------------------------------------------------------------------------------------------------------- 038 // Static Methods 039 //---------------------------------------------------------------------------------------------------------------------- 040 041 private static boolean hasSuitableDefaultConstructor( Class superclass ) 042 { 043 final Constructor[] declaredConstructors = superclass.getDeclaredConstructors(); 044 for( int i = 0; i < declaredConstructors.length; i++ ) 045 { 046 Constructor constructor = declaredConstructors[i]; 047 if( constructor.getParameterTypes().length == 0 && ( Modifier.isPublic( constructor.getModifiers() ) || 048 Modifier.isProtected( constructor.getModifiers() ) ) ) 049 { 050 return true; 051 } 052 } 053 return false; 054 } 055 056 /** 057 * Returns the <code>proxyClasses</code> transformed into an array of only the interface classes. 058 * 059 * @param proxyClasses the proxy classes 060 * @return the <code>proxyClasses</code> transformed into an array of only the interface classes 061 */ 062 protected static Class[] toInterfaces( Class[] proxyClasses ) 063 { 064 final Collection interfaces = new LinkedList(); 065 for( int i = 0; i < proxyClasses.length; i++ ) 066 { 067 Class proxyInterface = proxyClasses[i]; 068 if( proxyInterface.isInterface() ) 069 { 070 interfaces.add( proxyInterface ); 071 } 072 } 073 return ( Class[] ) interfaces.toArray( new Class[interfaces.size()] ); 074 } 075 076 private static Class[] toNonInterfaces( Class[] proxyClasses ) 077 { 078 final List superclasses = new LinkedList(); 079 for( int i = 0; i < proxyClasses.length; i++ ) 080 { 081 Class proxyClass = proxyClasses[i]; 082 if( !proxyClass.isInterface() ) 083 { 084 superclasses.add( proxyClass ); 085 } 086 } 087 return ( Class[] ) superclasses.toArray( new Class[superclasses.size()] ); 088 } 089 090 //---------------------------------------------------------------------------------------------------------------------- 091 // Other Methods 092 //---------------------------------------------------------------------------------------------------------------------- 093 094 /** 095 * Returns true if a suitable superclass can be found, given the desired <code>proxyClasses</code>. 096 * 097 * @param proxyClasses the proxy classes 098 * @return true if a suitable superclass can be found, given the desired <code>proxyClasses</code> 099 */ 100 public boolean canProxy( Class[] proxyClasses ) 101 { 102 try 103 { 104 getSuperclass( proxyClasses ); 105 return true; 106 } 107 catch( ProxyFactoryException e ) 108 { 109 return false; 110 } 111 } 112 113 /** 114 * Returns either {@link Object} if all of the <code>proxyClasses</code> are interfaces or the single non-interface 115 * class from <code>proxyClasses</code>. 116 * 117 * @param proxyClasses the proxy classes 118 * @return either {@link Object} if all of the <code>proxyClasses</code> are interfaces or the single non-interface 119 * class from <code>proxyClasses</code> 120 * @throws ProxyFactoryException if multiple non-interface classes are contained in <code>proxyClasses</code> or any 121 * of the non-interface classes are final 122 */ 123 public static Class getSuperclass( Class[] proxyClasses ) 124 { 125 final Class[] superclasses = toNonInterfaces( proxyClasses ); 126 switch( superclasses.length ) 127 { 128 case 0: 129 return Object.class; 130 case 1: 131 final Class superclass = superclasses[0]; 132 if( Modifier.isFinal( superclass.getModifiers() ) ) 133 { 134 throw new ProxyFactoryException( 135 "Proxy class cannot extend " + superclass.getName() + " as it is final." ); 136 } 137 if( !hasSuitableDefaultConstructor( superclass ) ) 138 { 139 throw new ProxyFactoryException( "Proxy class cannot extend " + superclass.getName() + 140 ", because it has no visible \"default\" constructor." ); 141 } 142 return superclass; 143 default: 144 final StringBuffer errorMessage = new StringBuffer( "Proxy class cannot extend " ); 145 for( int i = 0; i < superclasses.length; i++ ) 146 { 147 Class c = superclasses[i]; 148 errorMessage.append( c.getName() ); 149 if( i != superclasses.length - 1 ) 150 { 151 errorMessage.append( ", " ); 152 } 153 } 154 errorMessage.append( "; multiple inheritance not allowed." ); 155 throw new ProxyFactoryException( errorMessage.toString() ); 156 } 157 } 158 } 159