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