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 }