View Javadoc

1   // 
2   // Copyright (c) 2003, Caltha - Gajda, Krzewski, Mach, Potempski Sp.J. 
3   // All rights reserved. 
4   //   
5   // Redistribution and use in source and binary forms, with or without modification,  
6   // are permitted provided that the following conditions are met: 
7   //   
8   // * Redistributions of source code must retain the above copyright notice,  
9   //   this list of conditions and the following disclaimer. 
10  // * Redistributions in binary form must reproduce the above copyright notice,  
11  //   this list of conditions and the following disclaimer in the documentation  
12  //   and/or other materials provided with the distribution. 
13  // * Neither the name of the Caltha - Gajda, Krzewski, Mach, Potempski Sp.J.  
14  //   nor the names of its contributors may be used to endorse or promote products  
15  //   derived from this software without specific prior written permission. 
16  // 
17  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"  
18  // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED  
19  // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
20  // IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,  
21  // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,  
22  // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
23  // OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
24  // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)  
25  // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE  
26  // POSSIBILITY OF SUCH DAMAGE. 
27  //
28  
29  package org.objectledge.pico;
30  
31  import java.lang.reflect.Array;
32  import java.lang.reflect.Constructor;
33  import java.util.Arrays;
34  import java.util.Collection;
35  
36  import org.picocontainer.ComponentAdapter;
37  import org.picocontainer.Parameter;
38  import org.picocontainer.PicoContainer;
39  import org.picocontainer.PicoException;
40  import org.picocontainer.PicoInitializationException;
41  import org.picocontainer.PicoIntrospectionException;
42  import org.picocontainer.PicoVisitor;
43  
44  /***
45   * Allows hinting the component's constructor arguments of aggregated types.
46   * 
47   * <p>
48   * Both Java arrays and <code>java.util.Collection</code> objects are supported.
49   * The elements of the sequence are <code>org.picocontainer.Parameter</code> objects
50   * - they may resolve to constants, component references, or nested sequences.
51   * </p>
52   *
53   * @author <a href="Rafal.Krzewski">rafal@caltha.pl</a>
54   * @version $Id: SequenceParameter.java,v 1.6 2005/07/07 08:30:04 zwierzem Exp $
55   */
56  public class SequenceParameter implements Parameter
57  {
58      private Parameter[] elements;
59      private Class implClass;
60      
61      /***
62       * Creates a sequence parameter.
63       * 
64       * @param elements the sequence elements.
65       * @param implClass collection implementation class, may be null.
66       */
67      public SequenceParameter(Parameter[] elements, Class implClass)
68      {
69          this.elements = elements;
70          this.implClass = implClass;
71      }
72  
73      /***
74       * {@inheritDoc}
75       */
76      public Object resolveInstance(PicoContainer container, ComponentAdapter adapter, 
77          Class expectedType)
78          throws PicoInitializationException
79      {
80          Class elementType = getElementType(expectedType);
81          Object[] items = new Object[elements.length];
82          for(int i = 0; i < elements.length; i++)
83          {
84              items[i] = elements[i].resolveInstance(container, adapter, elementType);
85          }
86          if(expectedType.getComponentType() != null)
87          {
88              return toArray(items, expectedType);
89          }
90          if(Collection.class.isAssignableFrom(expectedType))
91          {
92              if(implClass != null)
93              {
94                  return toCollection(items, implClass);
95              }
96              else
97              {
98                  return toCollection(items, expectedType);
99              }
100         }
101         throw new PicoIntrospectionException("not a collection nor array type");
102     }
103 
104     /***
105      * {@inheritDoc}
106      */
107     public boolean isResolvable(PicoContainer container, ComponentAdapter adapter, 
108         Class expectedType)
109     {
110         try
111         {
112             Class elementType = getElementType(expectedType);
113             for(Parameter element : elements)
114             {
115                 if(!element.isResolvable(container, adapter, elementType))
116                 {
117                     return false;
118                 }
119             }
120             return true;
121         }
122         catch(PicoIntrospectionException e)
123         {
124             // non array or collection type
125             return false;
126         }
127     }
128 
129     /***
130      * {@inheritDoc}
131      */
132     public void verify(PicoContainer container, ComponentAdapter adapter, Class expectedType)
133         throws PicoIntrospectionException
134     {
135         Class elementType = getElementType(expectedType);
136         for(Parameter element : elements)
137         {
138             element.verify(container, adapter, expectedType);
139         }
140     }
141 
142     /***
143      * {@inheritDoc}
144      */
145     public void accept(PicoVisitor visitor)
146     {
147         visitor.visitParameter(this);
148         for(Parameter element : elements)
149         {
150             visitor.visitParameter(element);
151         }
152     }
153     
154     private Class getElementType(Class expectedType)
155     {
156         if(expectedType.getComponentType() != null)
157         {
158             return expectedType.getComponentType();
159         }
160         if(Collection.class.isAssignableFrom(expectedType))
161         {
162             // Cannot determine actual type parameters from a Class object. This is not supported
163             // Java5. We could determine the type parameter from the constructor though - we
164             // would have to be passed java.lang.reflect.ParametrizedType, which can be obtained
165             // from Constructor.getGenericParameterTypes()
166             return Object.class;
167         }
168         throw new PicoIntrospectionException("not a collection nor array type");
169     }
170     
171     private Object toArray(Object[] source, Class targetType)
172     {
173         Object target = Array.newInstance(targetType.getComponentType(), source.length);
174         System.arraycopy(source, 0, target, 0, source.length);
175         return target;
176     }
177     
178     private Object toCollection(Object[] source, Class targetType)
179     {
180         Collection target;
181         try
182         {
183             try
184             {
185                 Constructor ctor = targetType.getConstructor(new Class[] { Integer.TYPE });
186                 target = (Collection)ctor.newInstance(new Object[] { new Integer(source.length) });
187             }
188             catch(NoSuchMethodException e)
189             {
190                 try
191                 {
192                     Constructor ctor = targetType.getConstructor(new Class[0]);
193                     target = (Collection)ctor.newInstance(new Object[0]);
194                 }
195                 catch(NoSuchMethodException ee)
196                 {
197                     throw new CollectionInstantiationException("cannot instantiate Collection "
198                         + targetType.getName() + " no supported constructors found", ee);
199                 }
200             }
201         }
202         catch(Exception e)
203         {
204             if(e instanceof PicoException)
205             {
206                 throw (PicoException)e;
207             }
208             else
209             {
210                 throw new CollectionInstantiationException("cannot instantiate Collection "
211                     + targetType.getName(), e);
212             }
213         }
214         target.addAll(Arrays.asList(source));
215         return target;
216     }
217 }