ArduinoNode.java
/*******************************************************************************
* jArduino: Arduino C++ Code Generation From Java
* Copyright 2020 Tony Washer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package net.sourceforge.jarduino.message;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import net.sourceforge.jarduino.ArduinoException;
import net.sourceforge.jarduino.message.ArduinoAttribute.ArduinoAttrObject;
import net.sourceforge.jarduino.message.ArduinoParser.ArduinoParserException;
/**
* ArduinoNode.
*/
public class ArduinoNode
implements ArduinoNamedObject, ArduinoAttrObject {
/**
* The Marker.
*/
static final String MARKER = "BU_";
/**
* The Marker.
*/
static final String MARKER_TX = ArduinoMessage.MARKER + "TX_" + MARKER;
/**
* The null node.
*/
public static final String NULL_NODE = "Vector__XXX";
/**
* The owning system.
*/
private final ArduinoSystem theOwner;
/**
* The name of the Node.
*/
private final String theName;
/**
* The list of messages sent by this node.
*/
private final List<ArduinoMessage> theMessages;
/**
* The list of messages sent but not owned by this node.
*/
private final List<ArduinoMessage> theBorrowed;
/**
* the Map of explicit attributes.
*/
private final Map<ArduinoAttribute, Object> theAttributes;
/**
* the Map of relation attributes.
*/
private final Map<ArduinoAttribute, Map<ArduinoAttrObject, Object>> theRelations;
/**
* Constructor.
* @param pOwner the owner
* @param pName the name.
*/
ArduinoNode(final ArduinoSystem pOwner,
final String pName) {
/* Store parameters */
theOwner = pOwner;
theName = pName;
/* Create lists/maps */
theMessages = new ArrayList<>();
theBorrowed = new ArrayList<>();
theAttributes = new HashMap<>();
theRelations = new HashMap<>();
}
/**
* Obtain the owner.
* @return the owner
*/
public ArduinoSystem getOwner() {
return theOwner;
}
@Override
public String getName() {
return theName;
}
/**
* Add message to list.
* @param pMessage the message
*/
void addMessage(final ArduinoMessage pMessage) {
theMessages.add(pMessage);
}
/**
* Obtain the messages sent by this node.
* @return the messages
*/
public List<ArduinoMessage> getMessages() {
return theMessages;
}
/**
* Add potentially borrowed message to list.
* @param pMessage the message
*/
void addBorrowedMessage(final ArduinoMessage pMessage) {
/* Only add to borrowed if it is not owned by this node */
if (!theMessages.contains(pMessage)) {
theBorrowed.add(pMessage);
}
}
/**
* Obtain the borrowed messages sent by this node.
* @return the borrowed messages
*/
public List<ArduinoMessage> getBorrowed() {
return theBorrowed;
}
/**
* Set value for attribute.
* @param pAttr the attribute
* @param pValue the value
* @throws ArduinoParserException on error
*/
void setAttrValue(final ArduinoAttribute pAttr,
final Object pValue) throws ArduinoParserException {
/* Check that this is not a duplicate */
if (theAttributes.containsKey(pAttr)) {
throw new ArduinoParserException("Duplicate Attribute", pAttr.getName());
}
/* Store the value */
theAttributes.put(pAttr, pValue);
}
@Override
public Object getAttrValue(final ArduinoAttribute pAttr) {
final Object myValue = theAttributes.get(pAttr);
return myValue == null ? pAttr.getDefault() : myValue;
}
/**
* Set value for relation attribute.
* @param pAttr the attribute
* @param pRelation the relation
* @param pValue the value
* @throws ArduinoParserException on error
*/
void setRelationValue(final ArduinoAttribute pAttr,
final ArduinoAttrObject pRelation,
final Object pValue) throws ArduinoParserException {
/* Access the map for this attribute and creat if it doesn't exist */
final Map<ArduinoAttrObject, Object> myMap = theRelations.computeIfAbsent(pAttr, a -> new HashMap<>());
/* Check that this is not a duplicate */
if (myMap.containsKey(pRelation)) {
throw new ArduinoParserException("Duplicate Relation Attribute", pAttr.getName());
}
/* Store the value */
myMap.put(pRelation, pValue);
}
/**
* Obtain value for relation attribute.
* @param pAttr the attribute
* @param pRelation the relation
* @return the value
*/
public Object getRelationValue(final ArduinoAttribute pAttr,
final ArduinoAttrObject pRelation) {
final Map<ArduinoAttrObject, Object> myMap = theRelations.get(pAttr);
final Object myValue = myMap == null ? null : myMap.get(pRelation);
return myValue == null ? pAttr.getDefault() : myValue;
}
/**
* find message by id.
* @param pId the message Id.
* @return the message
*/
ArduinoMessage findMessageById(final String pId) {
/* Loop through the list */
for (ArduinoMessage myMessage : theMessages) {
if (myMessage.getId().equals(pId)) {
return myMessage;
}
}
return null;
}
/**
* does the node send the message?
* @param pMessage the message
* @return true/false
*/
public boolean sendsMessage(final ArduinoMessage pMessage) {
/* Message must be owned or borrowed by node */
return theMessages.contains(pMessage)
|| theBorrowed.contains(pMessage);
}
/**
* does the node send the signal?
* @param pSignal the signal
* @return true/false
*/
public boolean sendsSignal(final ArduinoSignal pSignal) {
/* sends signal if it sends the owning message */
final ArduinoMessage myMessage = pSignal.getOwner();
return sendsMessage(myMessage);
}
/**
* does the receive the message?
* @param pMessage the message
* @return true/false
*/
public boolean receivesMessage(final ArduinoMessage pMessage) {
/* Loop through the signals */
for (ArduinoSignal mySignal : pMessage.getAllSignals()) {
/* receives message if it receives any signal */
if (receivesSignal(mySignal)) {
return true;
}
}
/* Doesn't receive it */
return false;
}
/**
* does the node receive the signal?
* @param pSignal the signal
* @return true/false
*/
public boolean receivesSignal(final ArduinoSignal pSignal) {
/* receives signal if it is the list of receivers */
return pSignal.getReceivers().contains(this);
}
/**
* Parse transmitters.
* @param pSystem the system
* @param pXmitDef the message representation
* @throws ArduinoException on error
*/
static void parseXmitNodes(final ArduinoSystem pSystem,
final String pXmitDef) throws ArduinoException {
/* Split out header/xmitters */
int myIndex = pXmitDef.indexOf(ArduinoChar.COLON);
if (myIndex == -1) {
throw new ArduinoException("Missing " + ArduinoChar.COLON + " separator", pXmitDef);
}
final String myHdr = pXmitDef.substring(0, myIndex);
String myXmitters = pXmitDef.substring(myIndex + 1).trim();
/* Marker is first token in header, id is remaining token */
final String myMarker = ArduinoParser.nextToken(myHdr);
final String myMsgId = ArduinoParser.stripToken(myHdr, myMarker);
if (!myMarker.equals(MARKER_TX)) {
throw new ArduinoException("Invalid marker", pXmitDef);
}
/* Check that the end character is semicolon */
final int myLen = myXmitters.length();
if (myXmitters.length() == 0 || myXmitters.charAt(myLen - 1) != ArduinoChar.SEMICOLON) {
throw new ArduinoException("Missing Attr terminator", pXmitDef);
}
myXmitters = myXmitters.substring(0, myLen - 1);
/* Protect against exceptions */
try {
/* Locate the message */
final ArduinoMessage myMessage = pSystem.findMessageById(myMsgId);
/* Loop through the tokens */
while (myXmitters.length() > 0) {
/* Split on comma separator */
myIndex = myXmitters.indexOf(ArduinoChar.COMMA);
if (myIndex == -1) {
pSystem.findNodeByName(myXmitters.trim()).addBorrowedMessage(myMessage);
return;
}
final String myNode = myXmitters.substring(0, myIndex).trim();
pSystem.findNodeByName(myNode).addBorrowedMessage(myMessage);
myXmitters = myXmitters.substring(myIndex + 1);
}
/* Handle parser exceptions */
} catch (ArduinoParserException e) {
throw new ArduinoException(e.getMessage() + ArduinoChar.COLON + e.getDetail(), pXmitDef);
}
}
@Override
public boolean equals(final Object pThat) {
/* Handle trivial cases */
if (pThat == this) {
return true;
} else if (!(pThat instanceof ArduinoNode)) {
return false;
}
/* Access correctly */
final ArduinoNode myThat = (ArduinoNode) pThat;
/* Check name and owner */
return theName.equals(myThat.getName())
&& theOwner.equals(myThat.getOwner());
}
@Override
public int hashCode() {
return Objects.hash(theName, theOwner);
}
@Override
public String toString() {
return theName;
}
}