View Javadoc
1   /*******************************************************************************
2    * jArduino: Arduino C++ Code Generation From Java
3    * Copyright 2020 Tony Washer
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License");
6    * you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   ******************************************************************************/
17  package net.sourceforge.jarduino.message;
18  
19  import java.util.ArrayList;
20  import java.util.HashMap;
21  import java.util.List;
22  import java.util.Map;
23  import java.util.Objects;
24  
25  import net.sourceforge.jarduino.ArduinoException;
26  import net.sourceforge.jarduino.message.ArduinoAttribute.ArduinoAttrObject;
27  import net.sourceforge.jarduino.message.ArduinoParser.ArduinoParserException;
28  
29  /**
30   * ArduinoNode.
31   */
32  public class ArduinoNode
33          implements ArduinoNamedObject, ArduinoAttrObject {
34      /**
35       * The Marker.
36       */
37      static final String MARKER = "BU_";
38  
39      /**
40       * The Marker.
41       */
42      static final String MARKER_TX = ArduinoMessage.MARKER + "TX_" + MARKER;
43  
44      /**
45       * The null node.
46       */
47      public static final String NULL_NODE = "Vector__XXX";
48  
49      /**
50       * The owning system.
51       */
52      private final ArduinoSystem theOwner;
53  
54      /**
55       * The name of the Node.
56       */
57      private final String theName;
58  
59      /**
60       * The list of messages sent by this node.
61       */
62      private final List<ArduinoMessage> theMessages;
63  
64      /**
65       * The list of messages sent but not owned by this node.
66       */
67      private final List<ArduinoMessage> theBorrowed;
68  
69      /**
70       * the Map of explicit attributes.
71       */
72      private final Map<ArduinoAttribute, Object> theAttributes;
73  
74      /**
75       * the Map of relation attributes.
76       */
77      private final Map<ArduinoAttribute, Map<ArduinoAttrObject, Object>> theRelations;
78  
79      /**
80       * Constructor.
81       * @param pOwner the owner
82       * @param pName the name.
83       */
84      ArduinoNode(final ArduinoSystem pOwner,
85                  final String pName) {
86          /* Store parameters */
87          theOwner = pOwner;
88          theName = pName;
89  
90          /* Create lists/maps */
91          theMessages = new ArrayList<>();
92          theBorrowed = new ArrayList<>();
93          theAttributes = new HashMap<>();
94          theRelations = new HashMap<>();
95      }
96  
97      /**
98       * Obtain the owner.
99       * @return the owner
100      */
101     public ArduinoSystem getOwner() {
102         return theOwner;
103     }
104 
105     @Override
106     public String getName() {
107         return theName;
108     }
109 
110     /**
111      * Add message to list.
112      * @param pMessage the message
113      */
114     void addMessage(final ArduinoMessage pMessage) {
115         theMessages.add(pMessage);
116     }
117 
118     /**
119      * Obtain the messages sent by this node.
120      * @return the messages
121      */
122     public List<ArduinoMessage> getMessages() {
123         return theMessages;
124     }
125 
126     /**
127      * Add potentially borrowed message to list.
128      * @param pMessage the message
129      */
130     void addBorrowedMessage(final ArduinoMessage pMessage) {
131         /* Only add to borrowed if it is not owned by this node */
132         if (!theMessages.contains(pMessage)) {
133             theBorrowed.add(pMessage);
134         }
135     }
136 
137     /**
138      * Obtain the borrowed messages sent by this node.
139      * @return the borrowed messages
140      */
141     public List<ArduinoMessage> getBorrowed() {
142         return theBorrowed;
143     }
144 
145     /**
146      * Set value for attribute.
147      * @param pAttr the attribute
148      * @param pValue the value
149      * @throws ArduinoParserException on error
150      */
151     void setAttrValue(final ArduinoAttribute pAttr,
152                       final Object pValue) throws ArduinoParserException {
153         /* Check that this is not a duplicate */
154         if (theAttributes.containsKey(pAttr)) {
155             throw new ArduinoParserException("Duplicate Attribute", pAttr.getName());
156         }
157 
158         /* Store the value */
159         theAttributes.put(pAttr, pValue);
160     }
161 
162     @Override
163     public Object getAttrValue(final ArduinoAttribute pAttr) {
164         final Object myValue = theAttributes.get(pAttr);
165         return myValue == null ? pAttr.getDefault() : myValue;
166     }
167 
168     /**
169      * Set value for relation attribute.
170      * @param pAttr the attribute
171      * @param pRelation the relation
172      * @param pValue the value
173      * @throws ArduinoParserException on error
174      */
175     void setRelationValue(final ArduinoAttribute pAttr,
176                           final ArduinoAttrObject pRelation,
177                           final Object pValue) throws ArduinoParserException {
178         /* Access the map for this attribute and creat if it doesn't exist */
179         final Map<ArduinoAttrObject, Object> myMap = theRelations.computeIfAbsent(pAttr, a -> new HashMap<>());
180 
181         /* Check that this is not a duplicate */
182         if (myMap.containsKey(pRelation)) {
183             throw new ArduinoParserException("Duplicate Relation Attribute", pAttr.getName());
184         }
185 
186         /* Store the value */
187         myMap.put(pRelation, pValue);
188     }
189 
190     /**
191      * Obtain value for relation attribute.
192      * @param pAttr the attribute
193      * @param pRelation the relation
194      * @return the value
195      */
196     public Object getRelationValue(final ArduinoAttribute pAttr,
197                                    final ArduinoAttrObject pRelation) {
198         final Map<ArduinoAttrObject, Object> myMap = theRelations.get(pAttr);
199         final Object myValue = myMap == null ? null : myMap.get(pRelation);
200         return myValue == null ? pAttr.getDefault() : myValue;
201     }
202 
203     /**
204      * find message by id.
205      * @param pId the message Id.
206      * @return the message
207      */
208     ArduinoMessage findMessageById(final String pId) {
209         /* Loop through the list */
210         for (ArduinoMessage myMessage : theMessages) {
211             if (myMessage.getId().equals(pId)) {
212                 return myMessage;
213             }
214         }
215         return null;
216     }
217 
218     /**
219      * does the node send the message?
220      * @param pMessage the message
221      * @return true/false
222      */
223     public boolean sendsMessage(final ArduinoMessage pMessage) {
224         /* Message must be owned or borrowed by node */
225         return theMessages.contains(pMessage)
226                 || theBorrowed.contains(pMessage);
227     }
228 
229     /**
230      * does the node send the signal?
231      * @param pSignal the signal
232      * @return true/false
233      */
234     public boolean sendsSignal(final ArduinoSignal pSignal) {
235         /* sends signal if it sends the owning message */
236         final ArduinoMessage myMessage = pSignal.getOwner();
237         return sendsMessage(myMessage);
238     }
239 
240     /**
241      * does the receive the message?
242      * @param pMessage the message
243      * @return true/false
244      */
245     public boolean receivesMessage(final ArduinoMessage pMessage) {
246         /* Loop through the signals */
247         for (ArduinoSignal mySignal : pMessage.getAllSignals()) {
248             /* receives message if it receives any signal */
249             if (receivesSignal(mySignal)) {
250                 return true;
251             }
252         }
253 
254         /* Doesn't receive it */
255         return false;
256     }
257 
258     /**
259      * does the node receive the signal?
260      * @param pSignal the signal
261      * @return true/false
262      */
263     public boolean receivesSignal(final ArduinoSignal pSignal) {
264         /* receives signal if it is the list of receivers */
265         return pSignal.getReceivers().contains(this);
266     }
267 
268     /**
269      * Parse transmitters.
270      * @param pSystem the system
271      * @param pXmitDef the message representation
272      * @throws ArduinoException on error
273      */
274     static void parseXmitNodes(final ArduinoSystem pSystem,
275                                final String pXmitDef) throws ArduinoException {
276         /* Split out header/xmitters */
277         int myIndex = pXmitDef.indexOf(ArduinoChar.COLON);
278         if (myIndex == -1) {
279             throw new ArduinoException("Missing " + ArduinoChar.COLON + " separator", pXmitDef);
280         }
281         final String myHdr = pXmitDef.substring(0, myIndex);
282         String myXmitters = pXmitDef.substring(myIndex + 1).trim();
283 
284         /* Marker is first token in header, id is remaining token */
285         final String myMarker = ArduinoParser.nextToken(myHdr);
286         final String myMsgId = ArduinoParser.stripToken(myHdr, myMarker);
287         if (!myMarker.equals(MARKER_TX)) {
288             throw new ArduinoException("Invalid marker", pXmitDef);
289         }
290 
291         /* Check that the end character is semicolon */
292         final int myLen = myXmitters.length();
293         if (myXmitters.length() == 0 || myXmitters.charAt(myLen - 1) != ArduinoChar.SEMICOLON) {
294             throw new ArduinoException("Missing Attr terminator", pXmitDef);
295         }
296         myXmitters = myXmitters.substring(0, myLen - 1);
297 
298         /* Protect against exceptions */
299         try {
300             /* Locate the message */
301             final ArduinoMessage myMessage = pSystem.findMessageById(myMsgId);
302 
303             /* Loop through the tokens */
304             while (myXmitters.length() > 0) {
305                 /* Split on comma separator */
306                 myIndex = myXmitters.indexOf(ArduinoChar.COMMA);
307                 if (myIndex == -1) {
308                     pSystem.findNodeByName(myXmitters.trim()).addBorrowedMessage(myMessage);
309                     return;
310                 }
311                 final String myNode = myXmitters.substring(0, myIndex).trim();
312                 pSystem.findNodeByName(myNode).addBorrowedMessage(myMessage);
313                 myXmitters = myXmitters.substring(myIndex + 1);
314             }
315 
316             /* Handle parser exceptions */
317         } catch (ArduinoParserException e) {
318             throw new ArduinoException(e.getMessage() + ArduinoChar.COLON + e.getDetail(), pXmitDef);
319         }
320     }
321 
322     @Override
323     public boolean equals(final Object pThat) {
324         /* Handle trivial cases */
325         if (pThat == this) {
326             return true;
327         } else if (!(pThat instanceof ArduinoNode)) {
328             return false;
329         }
330 
331         /* Access correctly */
332         final ArduinoNode/../../net/sourceforge/jarduino/message/ArduinoNode.html#ArduinoNode">ArduinoNode myThat = (ArduinoNode) pThat;
333 
334         /* Check name and owner */
335         return theName.equals(myThat.getName())
336                 && theOwner.equals(myThat.getOwner());
337     }
338 
339     @Override
340     public int hashCode() {
341         return Objects.hash(theName, theOwner);
342     }
343 
344     @Override
345     public String toString() {
346         return theName;
347     }
348 }