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:Ali Erdem Ozcan
22   *
23   * Contributor: Matthieu Leclercq
24   */
25  
26  package org.objectweb.fractal.cecilia.adl.attributes;
27  
28  import static org.objectweb.fractal.adl.NodeUtil.castNodeError;
29  
30  import java.util.HashMap;
31  import java.util.Map;
32  
33  import org.objectweb.fractal.adl.ADLException;
34  import org.objectweb.fractal.adl.CompilerError;
35  import org.objectweb.fractal.adl.Node;
36  import org.objectweb.fractal.adl.attributes.Attribute;
37  import org.objectweb.fractal.adl.attributes.AttributeErrors;
38  import org.objectweb.fractal.adl.attributes.Attributes;
39  import org.objectweb.fractal.adl.attributes.AttributesContainer;
40  import org.objectweb.fractal.adl.error.ChainedErrorLocator;
41  import org.objectweb.fractal.adl.error.GenericErrors;
42  import org.objectweb.fractal.adl.merger.MergeException;
43  import org.objectweb.fractal.adl.merger.NodeMerger;
44  import org.objectweb.fractal.adl.xml.XMLNodeFactory;
45  import org.objectweb.fractal.api.NoSuchInterfaceException;
46  import org.objectweb.fractal.api.control.IllegalBindingException;
47  import org.objectweb.fractal.cecilia.adl.CeciliaADLConstants;
48  import org.objectweb.fractal.cecilia.adl.idl.ast.Field;
49  import org.objectweb.fractal.cecilia.adl.idl.ast.FieldContainer;
50  import org.objectweb.fractal.cecilia.adl.idl.ast.IDLDefinition;
51  import org.objectweb.fractal.cecilia.adl.idl.ast.IDLDefinitionContainer;
52  import org.objectweb.fractal.cecilia.adl.idl.ast.PrimitiveType;
53  import org.objectweb.fractal.cecilia.adl.idl.ast.RecordDefinition;
54  import org.xml.sax.SAXException;
55  
56  /**
57   * A {@link org.objectweb.fractal.adl.Loader} to check {@link Attributes} nodes
58   * in definitions. This loader checks that the Java attribute controller
59   * interfaces specified in these nodes exist, and that the attribute names and
60   * values are consistent with the methods of theses interfaces.
61   */
62  public class AttributeLoader
63      extends
64        org.objectweb.fractal.adl.attributes.AttributeLoader {
65  
66    /**
67     * The URL of the DTD that defines AST node interfaces for bridging ADL and
68     * IDL trees.
69     */
70    public static final String ADL_IDL_BRIGDE_DTD = "classpath://org/objectweb/fractal/cecilia/adl/idl/adl-idl-bridge.dtd";
71  
72    // ---------------------------------------------------------------------------
73    // Client interfaces
74    // ---------------------------------------------------------------------------
75  
76    /** The {@link NodeMerger} client interface used by this component. */
77    public NodeMerger          nodeMergerItf;
78  
79    /** The {@link XMLNodeFactory} client interface used by this component. */
80    protected XMLNodeFactory   nodeFactoryItf;
81  
82    // ---------------------------------------------------------------------------
83    // Overridden methods
84    // ---------------------------------------------------------------------------
85  
86    @Override
87    protected void checkAttributesContainer(final AttributesContainer container,
88        final Map<Object, Object> context) throws ADLException {
89      Attributes attrs = container.getAttributes();
90      if (attrs != null) {
91        final String signature = attrs.getSignature();
92        if (signature == null) {
93          throw new ADLException(AttributeErrors.SIGNATURE_MISSING, attrs);
94        }
95        if (!(attrs instanceof IDLDefinitionContainer)) {
96          // the attrs node is not an IDLDefinitionContainer
97          // - create a bridge node;
98          // - merge it with the attrs node.
99          try {
100           Node bridge = nodeFactoryItf.newXMLNode(ADL_IDL_BRIGDE_DTD, attrs
101               .astGetType());
102           bridge = nodeMergerItf.merge(attrs, bridge,
103               new HashMap<String, String>());
104           if (bridge != attrs) {
105             // replace attrs node
106             attrs = (Attributes) bridge;
107             container.setAttributes(attrs);
108           }
109         } catch (final SAXException e) {
110           throw new CompilerError(GenericErrors.INTERNAL_ERROR, e,
111               "Unable to instantiate 'attributes' node");
112         } catch (final MergeException e) {
113           throw new CompilerError(GenericErrors.INTERNAL_ERROR, e,
114               "Unable to merge 'attributes' node");
115         }
116       }
117 
118       final Attribute[] assignedAttributes = attrs.getAttributes();
119       for (final Attribute attribute : assignedAttributes) {
120         if (attribute.getName() == null) {
121           throw new ADLException(AttributeErrors.NAME_MISSING, attribute);
122         }
123         if (attribute.getValue() == null) {
124           throw new ADLException(AttributeErrors.VALUE_MISSING, attribute);
125         }
126       }
127 
128       IDLDefinition recordDefinition = ((IDLDefinitionContainer) attrs)
129           .getIDLDefinition();
130       if (recordDefinition == null) {
131         try {
132           recordDefinition = (IDLDefinition) interfaceLoaderItf.loadInterface(
133               signature, context);
134         } catch (final ADLException e) {
135           ChainedErrorLocator.chainLocator(e, attrs);
136         }
137         if (!(recordDefinition instanceof RecordDefinition)) {
138           throw new ADLException(
139               org.objectweb.fractal.cecilia.adl.attributes.AttributeErrors.INVALID_SIGNATURE,
140               container, signature);
141         }
142         // Add the record definition in the container
143         ((IDLDefinitionContainer) attrs).setIDLDefinition(recordDefinition);
144       }
145       final Field[] recordFields = ((FieldContainer) recordDefinition)
146           .getFields();
147 
148       final Attribute[] declaredAttributes = new Attribute[recordFields.length];
149       // The AST node will be replaced by the set of declared attribute to add
150       // the non-assigned attributes respecting the required order
151 
152       // Check if there are assigned attribute names which does not exist in
153       // the record
154       for (final Attribute ass : assignedAttributes) {
155         final String assName = ass.getName();
156         boolean found = false;
157         for (final Field dec : recordFields) {
158           if (dec.getName().equals(assName)) {
159             found = true;
160             break;
161           }
162         }
163         if (!found)
164           throw new ADLException(AttributeErrors.NO_SUCH_ATTRIBUTE, ass,
165               assName);
166       }
167 
168       for (int i = 0; i < declaredAttributes.length; i++) {
169         // Merge the assigned attribute values into the declared one
170         final Field field = recordFields[i];
171         final Attribute attrNode;
172         Attribute assignedAttribute = null;
173         for (final Attribute attr : assignedAttributes) {
174           if (field.getName().equals(attr.getName())) {
175             assignedAttribute = attr;
176             break;
177           }
178         }
179 
180         if (assignedAttribute == null) {
181           // Create new node.
182           try {
183             attrNode = castNodeError(nodeFactoryItf.newXMLNode(
184                 CeciliaADLConstants.CECILIA_ADL_DTD,
185                 CeciliaADLConstants.ATTRIBUTE_AST_NODE_NAME), Attribute.class);
186           } catch (final SAXException e) {
187             throw new CompilerError(GenericErrors.INTERNAL_ERROR, e, e
188                 .getMessage());
189           }
190           attrNode.setName(field.getName());
191           attrNode.setValue(getDefaultValue(field));
192         } else {
193           attrNode = assignedAttribute;
194           final PrimitiveType pt = field.getPrimitiveType();
195           if (pt != null) {
196             final String typeName = pt.getName();
197             if (typeName.equals(PrimitiveType.PrimitiveTypeEnum.STRING.name())) {
198               // If the attribute is a string and it doesn't have
199               // surrounding quotes, add them.
200               final String attrValue = attrNode.getValue();
201               if (!(attrValue.startsWith("\"") && attrValue.endsWith("\""))) {
202                 attrNode.setValue("\"" + attrValue + "\"");
203               }
204             } else if (typeName.equals(PrimitiveType.PrimitiveTypeEnum.BOOLEAN
205                 .name())) {
206               // If the attribute is a boolean, turn it into '1' or '0'.
207               final String attrValue = attrNode.getValue();
208               if (Boolean.parseBoolean(attrValue)) {
209                 attrNode.setValue("1");
210               } else {
211                 attrNode.setValue("0");
212               }
213             }
214           }
215         }
216 
217         declaredAttributes[i] = attrNode;
218       }
219 
220       // remove current attribute nodes and replace them by new ones.
221       for (final Attribute attr : assignedAttributes)
222         attrs.removeAttribute(attr);
223 
224       for (final Attribute attr : declaredAttributes)
225         attrs.addAttribute(attr);
226     }
227   }
228 
229   protected String getDefaultValue(final Field field) {
230     return "0";
231   }
232 
233   // ---------------------------------------------------------------------------
234   // Implementation of the BindingController interface
235   // ---------------------------------------------------------------------------
236 
237   @Override
238   public void bindFc(final String s, final Object o)
239       throws NoSuchInterfaceException, IllegalBindingException {
240 
241     if (s == null) {
242       throw new IllegalArgumentException("Interface name can't be null");
243     }
244 
245     if (s.equals(NodeMerger.ITF_NAME)) {
246       nodeMergerItf = (NodeMerger) o;
247     } else if (s.equals(XMLNodeFactory.ITF_NAME)) {
248       nodeFactoryItf = (XMLNodeFactory) o;
249     } else {
250       super.bindFc(s, o);
251     }
252   }
253 
254   @Override
255   public String[] listFc() {
256     final String[] superList = super.listFc();
257     final String[] list = new String[superList.length + 2];
258     list[0] = NodeMerger.ITF_NAME;
259     list[1] = XMLNodeFactory.ITF_NAME;
260     System.arraycopy(superList, 0, list, 2, superList.length);
261     return list;
262   }
263 
264   @Override
265   public Object lookupFc(final String s) throws NoSuchInterfaceException {
266 
267     if (s == null) {
268       throw new IllegalArgumentException("Interface name can't be null");
269     }
270 
271     if (s.equals(NodeMerger.ITF_NAME)) {
272       return nodeMergerItf;
273     } else if (s.equals(XMLNodeFactory.ITF_NAME)) {
274       return nodeFactoryItf;
275     } else {
276       return super.lookupFc(s);
277     }
278   }
279 
280   @Override
281   public void unbindFc(final String s) throws IllegalBindingException,
282       NoSuchInterfaceException {
283 
284     if (s == null) {
285       throw new IllegalArgumentException("Interface name can't be null");
286     }
287 
288     if (s.equals(NodeMerger.ITF_NAME)) {
289       nodeMergerItf = null;
290     } else if (s.equals(XMLNodeFactory.ITF_NAME)) {
291       nodeFactoryItf = null;
292     } else {
293       super.unbindFc(s);
294     }
295   }
296 }