View Javadoc

1   /***
2    * Cecilia ADL Compiler
3    * Copyright (C) 2006-2008 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   * Contributor: Alessio Pace
23   */
24  
25  package org.objectweb.fractal.cecilia.adl.bindings;
26  
27  import static org.objectweb.fractal.adl.types.TypeInterfaceUtil.isCollection;
28  import static org.objectweb.fractal.adl.types.TypeInterfaceUtil.isServer;
29  import static org.objectweb.fractal.adl.types.TypeInterfaceUtil.isSingleton;
30  import static org.objectweb.fractal.cecilia.adl.bindings.BindingDecorationUtil.getServerInterface;
31  import static org.objectweb.fractal.cecilia.adl.bindings.BindingDecorationUtil.isStaticallyBoundFalse;
32  import static org.objectweb.fractal.cecilia.adl.bindings.BindingDecorationUtil.setClientInterface;
33  import static org.objectweb.fractal.cecilia.adl.bindings.BindingDecorationUtil.setServerInterface;
34  import static org.objectweb.fractal.cecilia.adl.bindings.BindingDecorationUtil.setStaticallyBound;
35  import static org.objectweb.fractal.cecilia.adl.interfaces.InterfaceDecorationUtil.getContainer;
36  import static org.objectweb.fractal.cecilia.adl.interfaces.InterfaceDecorationUtil.isNoStaticBinding;
37  import static org.objectweb.fractal.cecilia.adl.interfaces.InterfaceDecorationUtil.setBoundTo;
38  import static org.objectweb.fractal.cecilia.adl.interfaces.InterfaceDecorationUtil.setContainer;
39  
40  import java.util.ArrayList;
41  import java.util.HashMap;
42  import java.util.List;
43  import java.util.Map;
44  
45  import org.objectweb.fractal.adl.ADLException;
46  import org.objectweb.fractal.adl.Definition;
47  import org.objectweb.fractal.adl.NodeUtil;
48  import org.objectweb.fractal.adl.bindings.Binding;
49  import org.objectweb.fractal.adl.bindings.TypeBindingLoader;
50  import org.objectweb.fractal.adl.components.Component;
51  import org.objectweb.fractal.adl.components.ComponentContainer;
52  import org.objectweb.fractal.adl.error.NodeErrorLocator;
53  import org.objectweb.fractal.adl.implementations.ImplementationContainer;
54  import org.objectweb.fractal.adl.interfaces.Interface;
55  import org.objectweb.fractal.adl.interfaces.InterfaceContainer;
56  import org.objectweb.fractal.adl.types.TypeInterface;
57  import org.objectweb.fractal.adl.util.FractalADLLogManager;
58  import org.objectweb.fractal.cecilia.adl.idl.ast.IDLDefinition;
59  import org.objectweb.fractal.cecilia.adl.idl.ast.IDLDefinitionContainer;
60  import org.objectweb.fractal.cecilia.adl.interfaces.InterfaceDecorationUtil;
61  
62  /**
63   * A Loader which "resolves" bindings. It adds to client interfaces of primitive
64   * components the {@link InterfaceDecorationUtil#BOUND_TO_DECORATION}
65   * decoration. The value of this decoration is the server interface of the
66   * primitive component the client interface is bound to. Moreover, this
67   * component adds the following decorations :
68   * <ul>
69   * <li> {@link BindingDecorationUtil#CLIENT_INTERFACE_DECORATION} on each binding
70   * node. It is set to the client interface node designated by the
71   * {@link Binding#getFrom() client} attribute.</li>
72   * <li> {@link BindingDecorationUtil#SERVER_INTERFACE_DECORATION} on each binding
73   * node. It is set to the server interface node designated by the
74   * {@link Binding#getTo() server} attribute.</li>
75   * <li> {@link BindingDecorationUtil#STATICALLY_BOUND_DECORATION} is set to
76   * <code>true</code> on each binding node that has to be bound statically.</li>
77   * <li> {@link InterfaceDecorationUtil#CONTAINER_DECORATION} on each interface
78   * node. It is set to the interface container node (i.e. the component node that
79   * contains this interface node).</li>
80   * </ul>
81   */
82  public class BindingResolverLoader extends TypeBindingLoader {
83  
84    /**
85     * Map associating client interface node to the list of binding nodes it is
86     * the client.
87     */
88    protected Map<TypeInterface, List<Binding>> clientInterfaceBindings;
89  
90    // --------------------------------------------------------------------------
91    // Implementation of the Loader interface
92    // --------------------------------------------------------------------------
93  
94    @Override
95    public Definition load(final String name, final Map<Object, Object> context)
96        throws ADLException {
97  
98      clientInterfaceBindings = new HashMap<TypeInterface, List<Binding>>();
99  
100     final Definition d = super.load(name, context);
101     addDecoration(d, context);
102     resolvBinding(d, d, context);
103 
104     // set to null to allow GC
105     clientInterfaceBindings = null;
106 
107     return d;
108   }
109 
110   // --------------------------------------------------------------------------
111   // Overridden BindingLoader methods
112   // --------------------------------------------------------------------------
113 
114   @Override
115   protected boolean ignoreBinding(final Binding binding,
116       final String fromCompName, final String fromItfName,
117       final String toCompName, final String toItfName) {
118     return false;
119   }
120 
121   // --------------------------------------------------------------------------
122   // Overridden TypeBindingloader methods
123   // --------------------------------------------------------------------------
124 
125   @Override
126   protected void checkBinding(final Binding binding, final Interface fromItf,
127       final String fromCompName, final String fromItfName,
128       final Interface toItf, final String toCompName, final String toItfName,
129       final Map<Object, Object> context) throws ADLException {
130 
131     NodeUtil.castNodeError(fromItf, TypeInterface.class);
132     NodeUtil.castNodeError(toItf, TypeInterface.class);
133 
134     super.checkBinding(binding, fromItf, fromCompName, fromItfName, toItf,
135         toCompName, toItfName, context);
136 
137     /* verifies that the binding is between compatible signatures */
138     checkBindingSignaturesCompatibility(binding, fromItf, toItf);
139 
140     setClientInterface(binding, fromItf);
141     setServerInterface(binding, toItf);
142 
143     if (toCompName.equals("this") && isCollection(toItf)) {
144       // the given binding export a client collection interface through a
145       // composite. Currently this is allowed only if interfaces have the same
146       // name
147       if (!fromItfName.equals(toItfName)) {
148         throw new ADLException(BindingErrors.COMPOSITE_CLIENT_COLLECTION,
149             binding);
150       }
151     }
152 
153     List<Binding> bindings = clientInterfaceBindings.get(fromItf);
154     if (bindings == null) {
155       bindings = new ArrayList<Binding>();
156       clientInterfaceBindings.put((TypeInterface) fromItf, bindings);
157     }
158     bindings.add(binding);
159   }
160 
161   // --------------------------------------------------------------------------
162   // Utility methods
163   // --------------------------------------------------------------------------
164 
165   protected void checkBindingSignaturesCompatibility(final Binding binding,
166       final Interface clientItf, final Interface serverItf) throws ADLException {
167 
168     if (!(clientItf instanceof IDLDefinitionContainer)
169         || !(serverItf instanceof IDLDefinitionContainer)) return;
170 
171     final IDLDefinition clientIDLDefinition = ((IDLDefinitionContainer) clientItf)
172         .getIDLDefinition();
173 
174     if (clientIDLDefinition != null
175         && InterfaceDecorationUtil
176             .isInheritancePathDecorationPresent(clientIDLDefinition)) {
177 
178       final String clientItfSignature = InterfaceDecorationUtil
179           .getInheritancePathDecoration(clientIDLDefinition).get(0);
180 
181       final IDLDefinition serverIDLDefinition = ((IDLDefinitionContainer) serverItf)
182           .getIDLDefinition();
183 
184       final List<String> serverItfInheritancePath = InterfaceDecorationUtil
185           .getInheritancePathDecoration(serverIDLDefinition);
186 
187       if (!serverItfInheritancePath.contains(clientItfSignature)) {
188 
189         throw new ADLException(
190             org.objectweb.fractal.adl.bindings.BindingErrors.INVALID_SIGNATURE,
191             binding, new NodeErrorLocator(clientItf), new NodeErrorLocator(
192                 serverItf));
193       }
194     } else {
195       FractalADLLogManager.STEP
196           .warning("WARNING: the "
197               + InterfaceDecorationUtil.INHERITANCE_PATH_DECORATION
198               + " is not set, so binding signature compatibility check is not performed");
199     }
200 
201   }
202 
203   protected void addDecoration(final Object node,
204       final Map<Object, Object> context) {
205     if (node instanceof InterfaceContainer) {
206       final InterfaceContainer interfaceContainer = (InterfaceContainer) node;
207       for (final Interface itf : interfaceContainer.getInterfaces())
208         setContainer(itf, interfaceContainer);
209     }
210     if (node instanceof ComponentContainer) {
211       for (final Component component : ((ComponentContainer) node)
212           .getComponents())
213         addDecoration(component, context);
214     }
215   }
216 
217   private void resolvBinding(final Object node, final Object topLevelNode,
218       final Map<Object, Object> context) throws ADLException {
219     if (isPrimitive(node)) {
220       // primitive component
221       if (!(node instanceof InterfaceContainer)) return;
222       final InterfaceContainer itfContainer = (InterfaceContainer) node;
223       for (final Interface itf : itfContainer.getInterfaces()) {
224         if (isServer(itf)) continue;
225 
226         // for each client interface of primitive component.
227         final TypeInterface clientItf = (TypeInterface) itf;
228 
229         // static binding is allows if:
230         // the NO_STATIC_BINDING_DECORATION is not set
231         // AND the client interface is a singleton.
232         final boolean staticBindingAllowed = (!isNoStaticBinding(clientItf))
233             && isSingleton(clientItf);
234 
235         final List<Binding> bindings = clientInterfaceBindings.get(clientItf);
236 
237         // if the client interface is not bound
238         if (bindings == null) {
239           continue;
240         }
241 
242         // for each binding of this client interface
243         for (final Binding binding : bindings) {
244           // set client interface properties on binding node
245           if (staticBindingAllowed) setStaticallyBound(binding, true);
246 
247           walkBindingGraph(clientItf, binding, staticBindingAllowed);
248         }
249       }
250     } else if (node instanceof ComponentContainer) {
251       for (final Component comp : ((ComponentContainer) node).getComponents()) {
252         resolvBinding(comp, topLevelNode, context);
253       }
254     }
255   }
256 
257   protected void walkBindingGraph(final TypeInterface clientItf,
258       final Binding binding, final boolean staticBindingAllowed)
259       throws ADLException {
260     final TypeInterface serverItf = (TypeInterface) getServerInterface(binding);
261     final InterfaceContainer serverComponent = getContainer(serverItf);
262 
263     // if the serverItf belongs to a composite
264     if (!isPrimitive(serverComponent)) {
265       // if serverItf is a control interface stop here.
266       if (isServer(serverItf)
267           && (serverItf.getName().endsWith("controller")
268               || serverItf.getName().equals("component") || serverItf.getName()
269               .equals("factory"))) {
270         setBoundTo(clientItf, serverItf);
271         return;
272       }
273 
274       final List<Binding> serverBindings = clientInterfaceBindings
275           .get(serverItf);
276 
277       if (serverBindings == null) {
278         return;
279       }
280 
281       // If there is more than one binding
282       if (serverBindings.size() > 1 && isServer(serverItf)) {
283         throw new ADLException(BindingErrors.COMPOSITE_SERVER_COLLECTION,
284             serverItf);
285       }
286 
287       for (final Binding b : serverBindings) {
288 
289         // propagate the staticallybound property
290         // the property is propagated only if the "statically-bound"
291         // decoration is not already set to false.
292         if (staticBindingAllowed && !isStaticallyBoundFalse(b))
293           setStaticallyBound(b, true);
294         else
295           // if the static binding is not allowed, set the property to false
296           // This avoid the property to be set latter for another client
297           // interface exported through the same binding
298           setStaticallyBound(b, false);
299 
300         // Since the serverItf node belongs to a composite, get the server
301         // interface it is bound to and recheck if this new serverItf
302         // belongs to a composite.
303         walkBindingGraph(clientItf, b, staticBindingAllowed);
304       }
305     } else {
306       // the serverItf node does not belong to a composite,
307       // set the "bound-to" decoration.
308       setBoundTo(clientItf, serverItf);
309     }
310   }
311 
312   protected static boolean isPrimitive(final Object component) {
313     return component instanceof ImplementationContainer
314         && ((ImplementationContainer) component).getImplementation() != null;
315   }
316 }