View Javadoc

1   /***
2    * Fractal ADL Parser
3    * Copyright (C) 2002-2004 France Telecom R&D
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: Eric.Bruneton@rd.francetelecom.com
20   *
21   * Author: Ali Erdem Ozcan
22   */
23  
24  package org.objectweb.fractal.adl;
25  
26  import static java.util.Arrays.asList;
27  
28  import java.util.ArrayList;
29  import java.util.LinkedHashMap;
30  import java.util.List;
31  import java.util.Map;
32  
33  import org.objectweb.fractal.api.Component;
34  import org.objectweb.fractal.api.NoSuchInterfaceException;
35  import org.objectweb.fractal.api.control.IllegalBindingException;
36  import org.objectweb.fractal.api.control.IllegalLifeCycleException;
37  import org.objectweb.fractal.task.core.AbstractTaskFactoryUser;
38  import org.objectweb.fractal.task.core.TaskException;
39  import org.objectweb.fractal.task.core.composition.CompositeTaskFactory;
40  
41  /**
42   * An abstract and generic visitor implementation that is intended to dispatch
43   * visit requests on a collection of client visitors. This visitor returns a
44   * composite task that contains the tasks returned by each client visitor. This
45   * composite task is created using the composition schema specified by the
46   * {@link #getTaskCompositionFileName() taskCompositionFileName} attribute. <br>
47   * This class is abstract because it has a generic parameters. A sub-class must
48   * be written for each type of visited node (see
49   * {@link ComponentVisitorDispatcher} for instance). This ensure type safetyness
50   * since this class is intended to be instantiated dynamically through
51   * reflexivity.
52   * 
53   * @param <T> the type of the visited nodes.
54   */
55  public abstract class VisitorDispatcher<T> extends AbstractTaskFactoryUser
56      implements
57        Visitor<T>,
58        TaskCompositionAttribute {
59  
60    // ---------------------------------------------------------------------------
61    // Client interfaces
62    // ---------------------------------------------------------------------------
63  
64    /** The name of the {@link Compiler} client interface of this component. */
65    public static final String     CLIENT_VISITOR          = "client-visitor";
66  
67    /** The builders client interfaces. */
68    // use a LinkedHashMap to ensure the iteration order which improves
69    // stability when debugging
70    public Map<String, Visitor<T>> visitorsItf             = new LinkedHashMap<String, Visitor<T>>();
71  
72    // ---------------------------------------------------------------------------
73    // Attributes
74    // ---------------------------------------------------------------------------
75  
76    protected String               taskCompositionFileName = null;
77  
78    // ---------------------------------------------------------------------------
79    // Abstract methods
80    // ---------------------------------------------------------------------------
81  
82    /**
83     * This method is used by {@link #bindFc(String, Object) bindFc} to cast the
84     * given <code>serverItf</code> to a correct type. Sub-classes must
85     * implements this method to guaranty type safety.
86     */
87    protected abstract Visitor<T> castVisitorInterface(Object serverItf);
88  
89    /**
90     * Returns the parameter to be passed to the
91     * {@link CompositeTaskFactory#newCompositeTask newCompositeTask} method.
92     * Cannot return <code>null</code>.
93     */
94    protected abstract Object[] getCompositionParameters(final List<Node> path,
95        final T node, final Map<Object, Object> context);
96  
97    // --------------------------------------------------------------------------
98    // Implementation of the Visitor interface
99    // --------------------------------------------------------------------------
100 
101   public Component visit(final List<Node> path, final T node,
102       final Map<Object, Object> context) throws ADLException, TaskException {
103     final List<Component> taskComponents = new ArrayList<Component>();
104     for (final Visitor<T> visitorItf : visitorsItf.values()) {
105       final Component task = visitorItf.visit(path, node, context);
106       if (task != null) taskComponents.add(task);
107     }
108     // Create the composite task by applying the composition file to the task
109     // component list.
110     if (taskCompositionFileName == null)
111       throw new TaskException(
112           "No task composition file is specified as attribute.");
113     return createTask(path, node, context, taskComponents);
114   }
115 
116   // --------------------------------------------------------------------------
117   // Utility methods
118   // --------------------------------------------------------------------------
119 
120   /**
121    * Retrieves the composition parameters using the
122    * {@link #getCompositionParameters getCompositionParameters} method, then
123    * creates and returns the composite task using the
124    * {@link CompositeTaskFactory#newCompositeTask newCompositeTask} method.
125    */
126   protected Component createTask(final List<Node> path, final T node,
127       final Map<Object, Object> context, final List<Component> taskComponents)
128       throws ADLException, TaskException {
129     return taskFactoryItf.newCompositeTask(taskComponents,
130         taskCompositionFileName, null, getCompositionParameters(path, node,
131             context));
132   }
133 
134   /**
135    * Utility method that can be used to implements the
136    * {@link #getCompositionParameters getCompositionParameters} method. It
137    * allows to creates an array of object in a concise way.
138    */
139   protected static Object[] toArray(final Object... parameters) {
140     return parameters;
141   }
142 
143   // --------------------------------------------------------------------------
144   // Implementation of the BindingController interface
145   // --------------------------------------------------------------------------
146 
147   @Override
148   public String[] listFc() {
149     final List<String> interfaceList = new ArrayList<String>(visitorsItf
150         .keySet());
151     interfaceList.addAll(asList(super.listFc()));
152     return interfaceList.toArray(new String[interfaceList.size()]);
153   }
154 
155   @Override
156   public void bindFc(final String clientItfName, final Object serverItf)
157       throws NoSuchInterfaceException, IllegalBindingException,
158       IllegalLifeCycleException {
159 
160     if (clientItfName == null) {
161       throw new IllegalArgumentException("Interface name can't be null");
162     }
163 
164     if (clientItfName.startsWith(CLIENT_VISITOR))
165       visitorsItf.put(clientItfName, castVisitorInterface(serverItf));
166     else
167       super.bindFc(clientItfName, serverItf);
168   }
169 
170   @Override
171   public Object lookupFc(final String clientItfName)
172       throws NoSuchInterfaceException {
173 
174     if (clientItfName == null) {
175       throw new IllegalArgumentException("Interface name can't be null");
176     }
177 
178     if (clientItfName.startsWith(CLIENT_VISITOR))
179       return visitorsItf.get(clientItfName);
180     else
181       return super.lookupFc(clientItfName);
182   }
183 
184   @Override
185   public void unbindFc(final String clientItfName)
186       throws NoSuchInterfaceException, IllegalBindingException,
187       IllegalLifeCycleException {
188 
189     if (clientItfName == null) {
190       throw new IllegalArgumentException("Interface name can't be null");
191     }
192 
193     if (clientItfName.startsWith(CLIENT_VISITOR)) {
194       if (visitorsItf.remove(clientItfName) == null) {
195         throw new NoSuchInterfaceException("There is no interface named '"
196             + clientItfName + "'");
197       }
198     } else
199       super.unbindFc(clientItfName);
200   }
201 
202   // --------------------------------------------------------------------------
203   // Implementation of the Attribute Controller interface
204   // --------------------------------------------------------------------------
205 
206   public String getTaskCompositionFileName() {
207     return this.taskCompositionFileName;
208   }
209 
210   public void setTaskCompositionFileName(final String fileName) {
211     this.taskCompositionFileName = fileName;
212   }
213 }