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<E></code> where the user may manipulate the
36 * composition e.g. add, remove, sort <code>Component</code> elements, etc.</li>
37 * <li><code><E></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<E> 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 }