View Javadoc

1   /***
2    * Cecilia ADL Compiler
3    * Copyright (C) 2006-2007 STMicroelectronics
4    *
5    * This library is free software; you can redistribute it and/or
6    * modify it under the terms of the GNU Lesser General Public
7    * License as published by the Free Software Foundation; either
8    * version 2 of the License, or (at your option) any later version.
9    *
10   * This library is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   * Lesser General Public License for more details.
14   *
15   * You should have received a copy of the GNU Lesser General Public
16   * License along with this library; if not, write to the Free Software
17   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18   *
19   * Contact: fractal@objectweb.org
20   *
21   * Author:Matthieu Leclercq
22   */
23  
24  package org.objectweb.fractal.cecilia.primitive.thinkMC.source;
25  
26  import static org.objectweb.fractal.adl.NodeUtil.castNodeError;
27  import static org.objectweb.fractal.cecilia.adl.directives.DirectiveHelper.getCFlags;
28  import static org.objectweb.fractal.cecilia.adl.directives.DirectiveHelper.getLdFlags;
29  import static org.objectweb.fractal.cecilia.adl.implementations.ImplementationDecorationUtil.getCode;
30  
31  import java.io.File;
32  import java.util.ArrayList;
33  import java.util.Collection;
34  import java.util.HashMap;
35  import java.util.HashSet;
36  import java.util.List;
37  import java.util.Map;
38  import java.util.concurrent.ExecutorService;
39  import java.util.concurrent.Future;
40  
41  import org.objectweb.fractal.adl.ADLException;
42  import org.objectweb.fractal.adl.CompilerError;
43  import org.objectweb.fractal.adl.ComponentVisitor;
44  import org.objectweb.fractal.adl.Node;
45  import org.objectweb.fractal.adl.components.ComponentContainer;
46  import org.objectweb.fractal.adl.error.GenericErrors;
47  import org.objectweb.fractal.adl.implementations.Implementation;
48  import org.objectweb.fractal.adl.implementations.ImplementationContainer;
49  import org.objectweb.fractal.api.Component;
50  import org.objectweb.fractal.api.NoSuchInterfaceException;
51  import org.objectweb.fractal.api.control.IllegalBindingException;
52  import org.objectweb.fractal.api.control.IllegalLifeCycleException;
53  import org.objectweb.fractal.cecilia.adl.compiler.CompilationTaskFactory;
54  import org.objectweb.fractal.cecilia.adl.compiler.OutputFormat;
55  import org.objectweb.fractal.cecilia.adl.compiler.OutputFormatContainer;
56  import org.objectweb.fractal.cecilia.adl.directives.Include;
57  import org.objectweb.fractal.cecilia.adl.directives.IncludeContainer;
58  import org.objectweb.fractal.cecilia.adl.file.FileCollectionProvider;
59  import org.objectweb.fractal.cecilia.adl.file.FileProvider;
60  import org.objectweb.fractal.cecilia.adl.file.FutureFileCollectionProvider;
61  import org.objectweb.fractal.cecilia.adl.file.FutureFileProvider;
62  import org.objectweb.fractal.cecilia.adl.file.SourceFile;
63  import org.objectweb.fractal.cecilia.adl.file.SourceFileProvider;
64  import org.objectweb.fractal.task.core.AbstractTaskFactoryUser;
65  import org.objectweb.fractal.task.core.TaskException;
66  import org.objectweb.fractal.task.core.primitive.annotations.ClientInterface;
67  import org.objectweb.fractal.task.core.primitive.annotations.ServerInterface;
68  import org.objectweb.fractal.task.core.primitive.annotations.ServerInterfaces;
69  import org.objectweb.fractal.task.core.primitive.annotations.TaskParameters;
70  
71  public class CompilationVisitor extends AbstractTaskFactoryUser
72      implements
73        ComponentVisitor {
74  
75    /** The name of the task composition schema used by this visitor. */
76    public static final String    COMPILATION_COMPOSITION           = "org.objectweb.fractal.cecilia.primitive.thinkMC.Compilation";
77  
78    /** The name of the {@link #compilationTaskFactoryItf} client interface. */
79    public static final String    COMPILATION_TASK_FACTORY_ITF_NAME = "compilation-task-factory";
80  
81    /** The client interface used to create compilation tasks. */
82    public CompilationTaskFactory compilationTaskFactoryItf;
83  
84    // ---------------------------------------------------------------------------
85    // Implementation of the ComponentVisitor interface
86    // ---------------------------------------------------------------------------
87  
88    /**
89     * Visits {@link ComponentContainer} nodes and creates a compilation tasks.
90     */
91    public Component visit(final List<Node> path,
92        final ComponentContainer container, final Map<Object, Object> context)
93        throws ADLException, TaskException {
94      final Implementation impl = castNodeError(container,
95          ImplementationContainer.class).getImplementation();
96      if (impl == null) {
97        throw new CompilerError(GenericErrors.INTERNAL_ERROR,
98            "This visitor is only applicable for primitive component.");
99      }
100 
101     // get cFlag list.
102     final List<String> cFlags = new ArrayList<String>();
103     cFlags.addAll(getCFlags(container));
104 
105     boolean archiveOutput = false;
106     if (container instanceof OutputFormatContainer
107         && ((OutputFormatContainer) container).getOutput() != null) {
108       final String outputFormat = ((OutputFormatContainer) container)
109           .getOutput().getFormat();
110       if (OutputFormat.ARCHIVE_OUTPUT_FORMAT.equals(outputFormat))
111         archiveOutput = true;
112     }
113 
114     final Collection<Component> tasks = new ArrayList<Component>();
115 
116     // create the task that aggregates every compiled files
117     tasks.add(createFileProviderAggregatorTask(container));
118 
119     // create the compilation task for the component source file
120     tasks.add(createComponentCompilationTask(container, cFlags, context));
121 
122     if (impl instanceof IncludeContainer
123         && ((IncludeContainer) impl).getIncludes().length != 0) {
124       final Include[] includes = ((IncludeContainer) impl).getIncludes();
125 
126       for (final Include include : includes) {
127         // if the module is an assembly, file, it should not be included.
128         final SourceFile code = (SourceFile) getCode((Node) include);
129         if ((code).isAssemblyFile()) {
130           // the module is an assembly file, must add the SourceFileProvider
131           // task for this file
132           tasks.add(createAssemblyFileProvider(container, include, code));
133         }
134         // add the compilation task
135         tasks.add(createModuleCompilationTask(include, cFlags, context));
136       }
137     }
138 
139     if (archiveOutput) {
140       tasks.add(createArchiveTask(container, null, context));
141     }
142 
143     // If the visited node is the top level node, add a link task.
144     final boolean doLink = path.isEmpty();
145     if (doLink) {
146       final List<String> ldFlags = new ArrayList<String>();
147       ldFlags.addAll(getLdFlags(container));
148       tasks.add(compilationTaskFactoryItf.newLinkTask(container, null,
149           ldFlags, context));
150     }
151 
152     return createCompilationComposition(container, tasks, archiveOutput, doLink);
153   }
154 
155   // ---------------------------------------------------------------------------
156   // Utility methods
157   // ---------------------------------------------------------------------------
158 
159   protected Component createFileProviderAggregatorTask(
160       final ComponentContainer container) throws TaskException {
161     return taskFactoryItf.newPrimitiveTask(new FileProviderAggregatorTask(),
162         container);
163   }
164 
165   protected Component createModuleCompilationTask(final Include include,
166       final List<String> cFlag, final Map<Object, Object> context)
167       throws TaskException {
168     return compilationTaskFactoryItf.newCompileTask(include, cFlag, context);
169   }
170 
171   protected Component createComponentCompilationTask(
172       final ComponentContainer container, final List<String> cFlag,
173       final Map<Object, Object> context) throws TaskException {
174     return compilationTaskFactoryItf.newCompileTask(container, cFlag, context);
175   }
176 
177   protected Component createAssemblyFileProvider(
178       final ComponentContainer container, final Include include,
179       final SourceFile code) throws TaskException {
180     return taskFactoryItf.newPrimitiveTask(new AssemblyFileProvider(code),
181         container, include);
182   }
183 
184   protected Component createArchiveTask(final ComponentContainer container,
185       final List<String> cFlag, final Map<Object, Object> context)
186       throws TaskException {
187     return compilationTaskFactoryItf.newArchiveTask(container, null, cFlag,
188         context);
189   }
190 
191   protected Component createCompilationComposition(
192       final ComponentContainer container, final Collection<Component> tasks,
193       final boolean archiveOutput, final boolean doLink) throws TaskException {
194     return taskFactoryItf.newCompositeTask(tasks, COMPILATION_COMPOSITION,
195         null, container, archiveOutput, doLink);
196   }
197 
198   // ---------------------------------------------------------------------------
199   // Task classes
200   // ---------------------------------------------------------------------------
201 
202   /**
203    * Aggregate files provided by a set of {@link FileProvider} client into a
204    * collection provided by the {@link FileCollectionProvider} server interface
205    * of this task.
206    */
207   @TaskParameters("componentNode")
208   @ServerInterfaces(@ServerInterface(name = "component-compiled-files-provider", signature = FutureFileCollectionProvider.class, record = "role:outputFiles, id:%", parameters = "componentNode"))
209   public static class FileProviderAggregatorTask
210       implements
211         FutureFileCollectionProvider {
212 
213     protected Collection<Future<File>>                     providedFiles;
214 
215     // -------------------------------------------------------------------------
216     // Task client interfaces
217     // -------------------------------------------------------------------------
218 
219     /**
220      * Client collection interface used to retrieve files provided by this task.
221      */
222     @ClientInterface(name = "file-providers", signature = FutureFileProvider.class, record = "role:aggregatorInputFile, id:%", parameters = "componentNode")
223     public final Map<String, FutureFileProvider>           clientProviderItfs            = new HashMap<String, FutureFileProvider>();
224 
225     /**
226      * Client interface used to retrieve compiled runtime implementations. This
227      * interface is used only if the component is the top-level component.
228      */
229     @ClientInterface(name = "runtime-compiled-files", signature = FutureFileProvider.class, record = "role:runtimeCompiledFile, id:%", parameters = "componentNode")
230     public final Map<String, FutureFileProvider>           runtimeProviderItfs           = new HashMap<String, FutureFileProvider>();
231 
232     /**
233      * Client interface used to retrieve compiled runtime implementations. This
234      * interface is used only if the component is the top-level component.
235      */
236     @ClientInterface(name = "runtime-compiled-file-collections", signature = FutureFileCollectionProvider.class, record = "role:runtimeCompiledFileCollection, id:%", parameters = "componentNode")
237     public final Map<String, FutureFileCollectionProvider> runtimeCollectionProviderItfs = new HashMap<String, FutureFileCollectionProvider>();
238 
239     // -------------------------------------------------------------------------
240     // Implementation of the FutureFileCollectionProvider interface
241     // -------------------------------------------------------------------------
242 
243     public synchronized Collection<Future<File>> getFiles(
244         final ExecutorService executorService) {
245       if (providedFiles == null) {
246         providedFiles = new HashSet<Future<File>>();
247         for (final FutureFileProvider fileProvider : clientProviderItfs
248             .values()) {
249           providedFiles.add(fileProvider.getFile(executorService));
250         }
251 
252         for (final FutureFileProvider fileProvider : runtimeProviderItfs
253             .values()) {
254           providedFiles.add(fileProvider.getFile(executorService));
255         }
256 
257         for (final FutureFileCollectionProvider fileCollectionProvider : runtimeCollectionProviderItfs
258             .values()) {
259           providedFiles
260               .addAll(fileCollectionProvider.getFiles(executorService));
261         }
262       }
263       return providedFiles;
264     }
265   }
266 
267   /**
268    * A {@link SourceFileProvider} task that provides {@link SourceFile} for
269    * component module written in assembly code.
270    */
271   @TaskParameters({"componentNode", "moduleNode"})
272   @ServerInterfaces(@ServerInterface(name = "assembly-file-provider", signature = SourceFileProvider.class, record = "role:componentAssemblyModuleFile, id:%, module:%", parameters = {
273       "componentNode", "moduleNode"}))
274   public static class AssemblyFileProvider implements SourceFileProvider {
275 
276     protected final SourceFile assemblyFile;
277 
278     // -------------------------------------------------------------------------
279     // Task constructor
280     // -------------------------------------------------------------------------
281 
282     /**
283      * @param assemblyFile the file provided by this task.
284      */
285     public AssemblyFileProvider(final SourceFile assemblyFile) {
286       this.assemblyFile = assemblyFile;
287     }
288 
289     // -------------------------------------------------------------------------
290     // Implementation of the SourceFileProvider interface
291     // -------------------------------------------------------------------------
292 
293     public SourceFile getSourceFile() {
294       return assemblyFile;
295     }
296   }
297 
298   // ---------------------------------------------------------------------------
299   // Implementation of the BindingController interface
300   // ---------------------------------------------------------------------------
301 
302   @Override
303   public String[] listFc() {
304     final String[] superItfs = super.listFc();
305     final String[] itfs = new String[superItfs.length + 1];
306     System.arraycopy(superItfs, 0, itfs, 0, superItfs.length);
307     itfs[superItfs.length] = COMPILATION_TASK_FACTORY_ITF_NAME;
308     return itfs;
309   }
310 
311   @Override
312   public void bindFc(final String clientItfName, final Object serverItf)
313       throws NoSuchInterfaceException, IllegalBindingException,
314       IllegalLifeCycleException {
315 
316     if (clientItfName == null) {
317       throw new IllegalArgumentException("Interface name can't be null");
318     }
319 
320     if (clientItfName.equals(COMPILATION_TASK_FACTORY_ITF_NAME))
321       compilationTaskFactoryItf = (CompilationTaskFactory) serverItf;
322     else
323       super.bindFc(clientItfName, serverItf);
324   }
325 
326   @Override
327   public Object lookupFc(final String clientItfName)
328       throws NoSuchInterfaceException {
329 
330     if (clientItfName == null) {
331       throw new IllegalArgumentException("Interface name can't be null");
332     }
333 
334     if (clientItfName.equals(COMPILATION_TASK_FACTORY_ITF_NAME))
335       return compilationTaskFactoryItf;
336     else
337       return super.lookupFc(clientItfName);
338   }
339 
340   @Override
341   public void unbindFc(final String clientItfName)
342       throws NoSuchInterfaceException, IllegalBindingException,
343       IllegalLifeCycleException {
344 
345     if (clientItfName == null) {
346       throw new IllegalArgumentException("Interface name can't be null");
347     }
348 
349     if (clientItfName.equals(COMPILATION_TASK_FACTORY_ITF_NAME))
350       compilationTaskFactoryItf = null;
351     else
352       super.unbindFc(clientItfName);
353   }
354 }