View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.proxy.factory.util;
19  
20  import org.apache.commons.proxy.ProxyFactory;
21  import org.apache.commons.proxy.exception.ProxyFactoryException;
22  
23  import java.lang.reflect.Constructor;
24  import java.lang.reflect.Modifier;
25  import java.util.Collection;
26  import java.util.LinkedList;
27  import java.util.List;
28  
29  /**
30   * A useful superclass for a {@link ProxyFactory} which supports subclassing rather than merely implementing interfaces.
31   * 
32   * @author James Carman
33   * @since 1.0
34   */
35  public abstract class AbstractSubclassingProxyFactory extends ProxyFactory
36  {
37  //----------------------------------------------------------------------------------------------------------------------
38  // Static Methods
39  //----------------------------------------------------------------------------------------------------------------------
40  
41      private static boolean hasSuitableDefaultConstructor( Class superclass )
42      {
43          final Constructor[] declaredConstructors = superclass.getDeclaredConstructors();
44          for( int i = 0; i < declaredConstructors.length; i++ )
45          {
46              Constructor constructor = declaredConstructors[i];
47              if( constructor.getParameterTypes().length == 0 && ( Modifier.isPublic( constructor.getModifiers() ) ||
48                                                                   Modifier.isProtected( constructor.getModifiers() ) ) )
49              {
50                  return true;
51              }
52          }
53          return false;
54      }
55  
56      /**
57       * Returns the <code>proxyClasses</code> transformed into an array of only the interface classes.
58       *
59       * @param proxyClasses the proxy classes
60       * @return the <code>proxyClasses</code> transformed into an array of only the interface classes
61       */
62      protected static Class[] toInterfaces( Class[] proxyClasses )
63      {
64          final Collection interfaces = new LinkedList();
65          for( int i = 0; i < proxyClasses.length; i++ )
66          {
67              Class proxyInterface = proxyClasses[i];
68              if( proxyInterface.isInterface() )
69              {
70                  interfaces.add( proxyInterface );
71              }
72          }
73          return ( Class[] ) interfaces.toArray( new Class[interfaces.size()] );
74      }
75  
76      private static Class[] toNonInterfaces( Class[] proxyClasses )
77      {
78          final List superclasses = new LinkedList();
79          for( int i = 0; i < proxyClasses.length; i++ )
80          {
81              Class proxyClass = proxyClasses[i];
82              if( !proxyClass.isInterface() )
83              {
84                  superclasses.add( proxyClass );
85              }
86          }
87          return ( Class[] ) superclasses.toArray( new Class[superclasses.size()] );
88      }
89  
90  //----------------------------------------------------------------------------------------------------------------------
91  // Other Methods
92  //----------------------------------------------------------------------------------------------------------------------
93  
94      /**
95       * Returns true if a suitable superclass can be found, given the desired <code>proxyClasses</code>.
96       *
97       * @param proxyClasses the proxy classes
98       * @return true if a suitable superclass can be found, given the desired <code>proxyClasses</code>
99       */
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