View Javadoc

1   //----------------------------------------------------------------------
2   // 
3   // PerfectJPattern: "Design patterns are good but components are better!" 
4   // AbstractComposite.java Copyright (c) 2009 Giovanni Azua Garcia
5   // bravegag@hotmail.com
6   //  
7   // This program is free software; you can redistribute it and/or
8   // modify it under the terms of the GNU General Public License
9   // as published by the Free Software Foundation; either version 3
10  // of the License, or (at your option) any later version.
11  //
12  // This program is distributed in the hope that it will be useful,
13  // but WITHOUT ANY WARRANTY; without even the implied warranty of
14  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  // GNU General Public License for more details.
16  //
17  // You should have received a copy of the GNU General Public License
18  // along with this program; if not, see <http://www.gnu.org/licenses/>.
19  //
20  //----------------------------------------------------------------------
21  package org.perfectjpattern.core.structural.composite;
22  
23  import java.lang.reflect.*;
24  import java.util.*;
25  
26  import org.apache.commons.lang.*;
27  import org.perfectjpattern.core.api.structural.composite.*;
28  
29  
30  /**
31   * Componentized implementation of <code>IComposite</code> interface. Creates
32   * composition of strongly type interfaces giving the user the dual view of this
33   * instance:<br/>
34   * <ul>
35   * <li><code>IComposite&lt;E&gt;</code> where the user may manipulate the 
36   * composition e.g. add, remove, sort <code>Component</code> elements, etc.</li>
37   * <li><code>&lt;E&gt;</code> type view of this composite 
38   * {@link #getComponent()} so all <code>Component</code> operations will be 
39   * transparently applied to the entire composition</li>
40   * </ul>
41   * <br/>
42   * Composite type also provides an overridable method {@link #aggregate(Method, 
43   * Object[])} that defines how to aggregate multiple result for a function 
44   * call i.e. it defines how to aggregate the results providuced from a function
45   * call for the complete composition.
46   * <br/><br/>
47   * @see IComposite
48   * 
49   * @param <C> Component element type.
50   * 
51   * @author <a href="mailto:bravegag@hotmail.com">Giovanni Azua</a>
52   * @version $Revision: 1.0 $ $Date: Nov 18, 2007 10:01:11 PM $
53   */
54  public final
55  class Composite<C>
56  extends ArrayList<C>
57  implements IComposite<C>, InvocationHandler
58  {
59      //------------------------------------------------------------------------
60      // public
61      //------------------------------------------------------------------------
62      /**
63       * Creates a Composite&lt;E&gt; from the Component type interface.
64       * 
65       * @param anInterface The Component interface to create Composite types of.
66       * @throws IllegalArgumentException 'anInterface' must not be null.
67       * @throws IllegalArgumentException 'anInterface' must be an interface type.
68       */
69      @SuppressWarnings("unchecked")
70      public 
71      Composite(Class<C> anInterface)
72      throws IllegalArgumentException
73      {
74          Validate.notNull(anInterface, "'anInterface' must not be null");
75          Validate.isTrue(anInterface.isInterface(), 
76              "'anInterface' must be an interface type.");
77          
78          final ClassLoader myClassLoader = anInterface.getClassLoader(); 
79          theComponent = (C) Proxy.newProxyInstance(myClassLoader, new Class[] {
80              anInterface }, this);        
81      }
82  
83      //------------------------------------------------------------------------
84      public Object 
85      invoke(Object aProxy, Method aMethod, Object[] anArguments)
86      throws Throwable
87      {        
88          // nothing to do?
89          if (size() == 0)
90          {
91              return null;
92          }
93  
94          Object[] myResults = new Object[this.size()];
95          
96          // execute target method over the collection of Elements
97          int i = 0;
98          for (C myElement : this)
99          {
100             myResults[i++] = aMethod.invoke(myElement, anArguments);
101         }
102         
103         return aggregate(aMethod, myResults);
104     }    
105     
106     //------------------------------------------------------------------------
107     /** 
108      * {@inheritDoc}
109      */
110     public C 
111     getComponent()
112     {
113         return theComponent;
114     }
115 
116     //------------------------------------------------------------------------
117     /** 
118      * {@inheritDoc}
119      */
120     public boolean
121     addAll(C ... anElements)
122     throws IllegalArgumentException
123     {
124         Validate.notNull(anElements, "'anElements' must not be null");
125         Validate.notEmpty(anElements, "'anElements' must not be empty.");
126         Validate.noNullElements(anElements, 
127             "'anElements' must not contain null Elements.");
128         
129         return super.addAll(Arrays.asList(anElements));
130     }    
131     
132     //------------------------------------------------------------------------
133     // protected
134     //------------------------------------------------------------------------
135     /**
136      * Returns aggregation of all results returned by each of the Component in 
137      * this composition. Default implementation just returns null but provides
138      * a means to define specialized ways to aggregate results.
139      * 
140      * @param aMethod Method that was called, relevant to discern and aggregate
141      *        differently for different methods. 
142      * @param aResults Array of all results produced by all Components.
143      * @return aggregation of all results returned by each of the Component in 
144      *         this composition.
145      */
146     protected Object 
147     aggregate(Method aMethod, Object[] aResults)
148     {
149         Object myResult = null;
150         
151         return myResult;
152     }
153     
154     //------------------------------------------------------------------------
155     // members
156     //------------------------------------------------------------------------
157     /**
158      * Reference to the Component type implemented by this Composite instance.
159      */
160     private final C theComponent;
161     
162     /**
163      * Default serial version ID.
164      */
165     private static final long serialVersionUID = 1L;    
166 }