View Javadoc

1   /*
2      Copyright 2007 Ramon Servadei
3   
4      Licensed under the Apache License, Version 2.0 (the "License");
5      you may not use this file except in compliance with the License.
6      You may obtain a copy of the License at
7   
8          http://www.apache.org/licenses/LICENSE-2.0
9   
10     Unless required by applicable law or agreed to in writing, software
11     distributed under the License is distributed on an "AS IS" BASIS,
12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13     See the License for the specific language governing permissions and
14     limitations under the License.
15   */
16  package fulmine.model.container;
17  
18  import java.util.Map;
19  
20  import fulmine.IDomain;
21  import fulmine.IType;
22  import fulmine.Type;
23  import fulmine.context.IFrameworkContext;
24  import fulmine.model.container.impl.Record;
25  import fulmine.model.field.containerdefinition.IContainerDefinitionField;
26  import fulmine.protocol.specification.FrameReader;
27  import fulmine.util.collection.CollectionFactory;
28  import fulmine.util.log.AsyncLog;
29  
30  /**
31   * A factory that creates {@link IContainer} implementations. An
32   * {@link IContainerFactory.IContainerBuilder} is registered for each container
33   * type (see {@link IContainer#getType()}). The registered builder creates each
34   * instance. The builder is registered using the
35   * {@link #registerBuilder(IType, fulmine.model.container.ContainerFactory.IContainerBuilder)}
36   * method. By default, if there is no builder registered for a container type, a
37   * {@link Record} is created.
38   * <p>
39   * The factory is thread safe.
40   * 
41   * @author Ramon Servadei
42   */
43  public final class ContainerFactory implements IContainerFactory
44  {
45      private final static AsyncLog LOG = new AsyncLog(ContainerFactory.class);
46  
47      /**
48       * The static {@link IContainerDefinitionField} objects mapped to their
49       * {@link IType}.
50       */
51      private final Map<IType, IContainerDefinitionField> staticDefinitions;
52  
53      /**
54       * The {@link IContainerFactory.IContainerBuilder} objects mapped to their
55       * {@link IType}.
56       */
57      private final Map<IType, IContainerFactory.IContainerBuilder> builders;
58  
59      /** The default builder */
60      private final IContainerFactory.IContainerBuilder defaultBuilder;
61  
62      /**
63       * Standard constructor
64       */
65      public ContainerFactory()
66      {
67          super();
68          this.defaultBuilder = new RecordBuilder();
69          builders = CollectionFactory.newMap();
70          staticDefinitions = CollectionFactory.newMap();
71      }
72  
73      /**
74       * Register an {@link IContainerFactory.IContainerBuilder} against the
75       * {@link IContainer} type. This will overwrite any existing builder
76       * registered against the type.
77       * 
78       * @param type
79       *            the type of the {@link IContainer} the builder creates
80       * @param builder
81       *            the container builder to register
82       * @see #containsType(IType)
83       * @see IContainer#getType()
84       * @throws IllegalArgumentException
85       *             if the type {@link IType#value()} is less than
86       *             {@link Type#BASE_USER_START}
87       */
88      public synchronized void registerBuilder(IType type,
89          IContainerFactory.IContainerBuilder builder)
90      {
91          if (type.value() < Type.BASE_USER_START)
92          {
93              throw new IllegalArgumentException("Cannot register types below "
94                  + Type.BASE_USER_START);
95          }
96          final IContainerFactory.IContainerBuilder previous =
97              builders.put(type, builder);
98          if (previous != null)
99          {
100             LOG.warn("Previous builder " + previous
101                 + " has been overwritten with a new builder " + builder
102                 + " for type " + type);
103         }
104         final IContainerDefinitionField definition =
105             builder.createContainerDefinition();
106         if (definition != null)
107         {
108             if (!definition.isDynamic())
109             {
110                 staticDefinitions.put(type, definition);
111             }
112         }
113     }
114 
115     /**
116      * Does the factory contain an {@link IContainerFactory.IContainerBuilder}
117      * (and by association, an {@link IContainerDefinitionField}) registered
118      * against the {@link IContainer} type argument.
119      * 
120      * @param type
121      *            the type of the {@link IContainer} the builder creates
122      * @return <code>true</code> if there is a
123      *         {@link IContainerFactory.IContainerBuilder} registered against
124      *         the type
125      * @see IContainer#getType()
126      */
127     public synchronized boolean containsType(IType type)
128     {
129         return builders.containsKey(type);
130     }
131 
132     /**
133      * Get the {@link IContainerDefinitionField} registered against the
134      * {@link IContainer} type argument. This should not be called for dynamic
135      * container types.
136      * 
137      * @param type
138      *            the type of the {@link IContainer} the definition applies to
139      * @return the {@link IContainerDefinitionField} for the type of the
140      *         {@link IContainer}
141      * @throws IllegalArgumentException
142      *             if the {@link IContainer} is a dynamic type (there will be no
143      *             {@link IContainerDefinitionField} found)
144      * @see #containsType(IType)
145      * @see IContainer#getType()
146      */
147     public synchronized IContainerDefinitionField getDefinition(IType type)
148     {
149         if (!containsType(type))
150         {
151             throw new IllegalArgumentException("No definition registered for "
152                 + type + ", builders are=" + builders
153                 + ", is this a dynamic type?"
154                 + " (dynamic types do not register their definition)");
155         }
156         return staticDefinitions.get(type);
157     }
158 
159     /**
160      * Create an {@link IContainer} implementation from the type argument. If
161      * there is no application {@link IContainerFactory.IContainerBuilder}
162      * registered for the type, a default builder is used that creates an
163      * {@link Record}.
164      * 
165      * @param identity
166      *            the identity for the container to create
167      * @param type
168      *            the type of the {@link IContainer} implementation to create
169      * @param hostContext
170      *            the context the container will be associated with
171      * 
172      * @return an {@link IContainer} implementation
173      * @see #containsType(IType)
174      * @see IContainer#getType()
175      */
176     @SuppressWarnings("unchecked")
177     public synchronized <T extends IContainer> T createContainer(
178         String nativeContextIdentity, String identity, IType type,
179         IDomain domain, IFrameworkContext hostContext, boolean local)
180     {
181         /*
182          * This is not pretty - we need to masquerade as being in a FrameReader
183          * context to ensure we can bypass the usual checks that prevent remote
184          * containers being mutated - its the action of adding a container
185          * definition that requires this.
186          */
187         boolean alreadyInContext = FrameReader.inContext();
188         try
189         {
190             if (!local && !alreadyInContext)
191             {
192                 FrameReader.inContext.set(Boolean.TRUE);
193             }
194             IContainer container;
195             if (containsType(type))
196             {
197                 container =
198                     builders.get(type).createContainer(nativeContextIdentity,
199                         identity, type, domain, hostContext, local);
200             }
201             else
202             {
203                 container =
204                     defaultBuilder.createContainer(nativeContextIdentity,
205                         identity, type, domain, hostContext, local);
206             }
207             container.start();
208             return (T) container;
209         }
210         finally
211         {
212             if (!local && !alreadyInContext)
213             {
214                 FrameReader.inContext.remove();
215             }
216         }
217     }
218 
219     /**
220      * Builder that creates {@link Record} instances
221      * 
222      * @author Ramon Servadei
223      */
224     private static final class RecordBuilder implements
225         IContainerFactory.IContainerBuilder
226     {
227         public IContainer createContainer(String nativeContextIdentity,
228             String identity, IType type, IDomain domain,
229             IFrameworkContext hostContext, boolean local)
230         {
231             return new Record(nativeContextIdentity, identity, type, domain,
232                 hostContext, local);
233         }
234 
235         public IContainerDefinitionField createContainerDefinition()
236         {
237             return null;
238         }
239 
240         public String toString()
241         {
242             return "Builder<Record>";
243         }
244     }
245 
246     public void destroy()
247     {
248         this.builders.clear();
249         this.staticDefinitions.clear();
250     }
251 }