Browse Source

Initial commit

development
jens 7 months ago
commit
016dbb5406
  1. 5
      README.md
  2. 26
      RhasspyVisualConversationTool/.classpath
  3. 77
      RhasspyVisualConversationTool/.gitignore
  4. 17
      RhasspyVisualConversationTool/.project
  5. BIN
      RhasspyVisualConversationTool/lib/commons-lang3-3.9.jar
  6. BIN
      RhasspyVisualConversationTool/lib/org.eclipse.paho.client.mqttv3-1.2.1.jar
  7. 308
      RhasspyVisualConversationTool/src/com/jens/rhasspy/visualtool/GUI.java
  8. 250
      RhasspyVisualConversationTool/src/com/jens/rhasspy/visualtool/MQTT.java
  9. 1267
      RhasspyVisualConversationTool/src/com/jens/rhasspy/visualtool/Miscellaneous.java
  10. 187
      RhasspyVisualConversationTool/src/com/jens/rhasspy/visualtool/Settings.java
  11. 1541
      RhasspyVisualConversationTool/src/com/jens/rhasspy/visualtool/lib/JSONArray.java
  12. 45
      RhasspyVisualConversationTool/src/com/jens/rhasspy/visualtool/lib/JSONException.java
  13. 542
      RhasspyVisualConversationTool/src/com/jens/rhasspy/visualtool/lib/JSONML.java
  14. 2563
      RhasspyVisualConversationTool/src/com/jens/rhasspy/visualtool/lib/JSONObject.java
  15. 293
      RhasspyVisualConversationTool/src/com/jens/rhasspy/visualtool/lib/JSONPointer.java
  16. 45
      RhasspyVisualConversationTool/src/com/jens/rhasspy/visualtool/lib/JSONPointerException.java
  17. 43
      RhasspyVisualConversationTool/src/com/jens/rhasspy/visualtool/lib/JSONPropertyIgnore.java
  18. 47
      RhasspyVisualConversationTool/src/com/jens/rhasspy/visualtool/lib/JSONPropertyName.java
  19. 18
      RhasspyVisualConversationTool/src/com/jens/rhasspy/visualtool/lib/JSONString.java
  20. 79
      RhasspyVisualConversationTool/src/com/jens/rhasspy/visualtool/lib/JSONStringer.java
  21. 529
      RhasspyVisualConversationTool/src/com/jens/rhasspy/visualtool/lib/JSONTokener.java
  22. 418
      RhasspyVisualConversationTool/src/com/jens/rhasspy/visualtool/lib/JSONWriter.java
  23. 683
      RhasspyVisualConversationTool/src/com/jens/rhasspy/visualtool/lib/XML.java
  24. 407
      RhasspyVisualConversationTool/src/com/jens/rhasspy/visualtool/lib/XMLTokener.java

5
README.md

@ -0,0 +1,5 @@
# Rhasspy visual conversation helper
This application is supposed to work as a visual helper for Rhasspy conversations on setups that have a screen or even a touchscreen.
See more information and detailed instructions on https://server47.de/rhasspy/

26
RhasspyVisualConversationTool/.classpath

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Program Files/Java/jdk1.8.0_191/lib/missioncontrol/plugins/com.jrockit.mc.rjmx_5.5.2.174165/lib/mailapi.jar">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Program Files/Java/jdk1.8.0_191/lib/missioncontrol/plugins/com.jrockit.mc.rjmx_5.5.2.174165/lib/smtp.jar">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="lib/commons-lang3-3.9.jar">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="lib/org.eclipse.paho.client.mqttv3-1.2.1.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>

77
RhasspyVisualConversationTool/.gitignore

@ -0,0 +1,77 @@
# Created by https://www.toptal.com/developers/gitignore/api/eclipse
# Edit at https://www.toptal.com/developers/gitignore?templates=eclipse
### Eclipse ###
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
.recommenders
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# PyDev specific (Python IDE for Eclipse)
*.pydevproject
# CDT-specific (C/C++ Development Tooling)
.cproject
# CDT- autotools
.autotools
# Java annotation processor (APT)
.factorypath
# PDT-specific (PHP Development Tools)
.buildpath
# sbteclipse plugin
.target
# Tern plugin
.tern-project
# TeXlipse plugin
.texlipse
# STS (Spring Tool Suite)
.springBeans
# Code Recommenders
.recommenders/
# Annotation Processing
.apt_generated/
.apt_generated_test/
# Scala IDE specific (Scala & Java development for Eclipse)
.cache-main
.scala_dependencies
.worksheet
# Uncomment this line if you wish to ignore the project description file.
# Typically, this file would be tracked if it contains build/dependency configurations:
#.project
### Eclipse Patch ###
# Spring Boot Tooling
.sts4-cache/
# End of https://www.toptal.com/developers/gitignore/api/eclipse
RhasspyVisualConversationTool*8883
RhasspyVisualConversationTool*1883
keystore.jks
res
RhasspyVisualConversationTool-settings.ini

17
RhasspyVisualConversationTool/.project

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>RhasspyVisualConversationTool</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

BIN
RhasspyVisualConversationTool/lib/commons-lang3-3.9.jar

Binary file not shown.

BIN
RhasspyVisualConversationTool/lib/org.eclipse.paho.client.mqttv3-1.2.1.jar

Binary file not shown.

308
RhasspyVisualConversationTool/src/com/jens/rhasspy/visualtool/GUI.java

@ -0,0 +1,308 @@
package com.jens.rhasspy.visualtool;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttTopic;
import com.jens.rhasspy.visualtool.lib.JSONObject;
/*
* Layout types
* https://docs.oracle.com/javase/tutorial/uiswing/layout/visual.html
*/
public class GUI
{
static JFrame mainFrame = new JFrame(Settings.programName);
static JLabel connectionStatusTextField = new JLabel();
static JTextArea mainTextField = new JTextArea();
static JScrollPane mainTextFieldHolder = new JScrollPane(mainTextField);
static JPanel optionsFrame = new JPanel();
static GUI instance = null;
Font defaultFont = new Font(Font.SANS_SERIF, Font.PLAIN, 20);
static Dimension defaultContainerDim = new Dimension(700, 250);
static Dimension zeroDim = new Dimension(0, 0);
ArrayList<String> textEntriesList = new ArrayList<>();
public static void main(String[] args)
{
if(Settings.readSettings())
{
getInstance().openWindow();
// Subscribe to MQTT topics
MQTT.getInstance().subscribeToTopic(Settings.topicNameWakewordRecognized);
MQTT.getInstance().subscribeToTopic(Settings.topicNameDisplayText);
MQTT.getInstance().subscribeToTopic(Settings.topicNameDisplayOptions);
MQTT.getInstance().subscribeToTopic(Settings.topicNameIntentsRecognized);
MQTT.getInstance().subscribeToTopic(Settings.topicNameSayText);
MQTT.getInstance().subscribeToTopic(Settings.topicNamePlaySoundFinished);
MQTT.getInstance().subscribeToTopic(Settings.topicNameSessionEnded);
}
}
public static GUI getInstance()
{
if(instance == null)
instance = new GUI();
return instance;
}
void openWindow()
{
mainFrame.setLayout(new BoxLayout(mainFrame.getContentPane(), BoxLayout.Y_AXIS));
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setSize(700, 320);
mainFrame.setLocation(50, 50);
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
Miscellaneous.logEvent(Miscellaneous.getStackTraceAsString(e), 1);
}
connectionStatusTextField.setText("Connected: " + String.valueOf(MQTT.getInstance().getClient().isConnected()));
Border border = connectionStatusTextField.getBorder();
Border margin = new EmptyBorder(10,10,10,10);
connectionStatusTextField.setBorder(new CompoundBorder(border, margin));
mainTextField.setText("Waiting for session...");
mainTextField.setFont(defaultFont);
if(mainTextField.isEditable())
mainTextField.setEditable(false);
Border borderMainTextField = mainTextField.getBorder();
Border marginMainTextField = new EmptyBorder(10,10,10,10);
mainTextField.setBorder(new CompoundBorder(borderMainTextField, marginMainTextField));
mainTextFieldHolder.setPreferredSize(defaultContainerDim);
mainTextFieldHolder.setVisible(true);
optionsFrame.setPreferredSize(defaultContainerDim);
optionsFrame.setVisible(false);
optionsFrame.setLayout(new BoxLayout(optionsFrame, BoxLayout.Y_AXIS));
mainFrame.add(connectionStatusTextField);
mainFrame.add(mainTextFieldHolder);
mainFrame.add(optionsFrame);
mainFrame.setVisible(true);
}
public void updateConnectionStatus(boolean connected)
{
if(connected)
connectionStatusTextField.setText("Connected to: " + Settings.mqttClientServerHostname);
else
connectionStatusTextField.setText("Not connected");
}
public void updateWindow()
{
if(mainTextField.isEditable())
mainTextField.setEditable(false);
mainTextField.setText(Miscellaneous.arrayImplode(Miscellaneous.lineSeparator, textEntriesList));
JScrollBar vertical = mainTextFieldHolder.getVerticalScrollBar();
vertical.setValue(vertical.getMaximum());
mainFrame.pack();
mainTextFieldHolder.setVisible(true);
optionsFrame.setVisible(false);
mainFrame.repaint();
}
public void displayOptions(String[] options)
{
optionsFrame.removeAll();
JLabel infoLabel = new JLabel("Select an option:");
infoLabel.setFont(defaultFont);
optionsFrame.add(infoLabel);
Border labelBorder = optionsFrame.getBorder();
Border labelMargin = new EmptyBorder(10,10,10,10);
optionsFrame.setBorder(new CompoundBorder(labelBorder, labelMargin));
for(String option : options)
{
JLabel optionTf = new JLabel(option);
optionTf.setFont(defaultFont);
Border border = optionTf.getBorder();
Border margin = new EmptyBorder(10,10,10,10);
optionTf.setBorder(new CompoundBorder(border, margin));
optionTf.addMouseListener(new MouseListener()
{
@Override
public void mouseReleased(MouseEvent e)
{
}
@Override
public void mousePressed(MouseEvent e)
{
}
@Override
public void mouseExited(MouseEvent e)
{
}
@Override
public void mouseEntered(MouseEvent e)
{
}
@Override
public void mouseClicked(MouseEvent e)
{
JOptionPane.showMessageDialog(mainFrame, "Option " + option + " selected.");
}
});
optionsFrame.add(optionTf);
}
// mainTextFieldHolder.setPreferredSize(zeroDim);
// optionsFrame.setPreferredSize(defaultContainerDim);
mainFrame.pack();
optionsFrame.setVisible(true);
mainTextFieldHolder.setVisible(false);
mainFrame.repaint();
}
public void handleNewMessage(Object[] messageArray)
{
/*
* Object[] object = new Object[3];
object[0] = message;
object[1] = topic;
object[2] = Calendar.getInstance();
*/
String payload = new String(((MqttMessage)messageArray[0]).getPayload());
String topic = (String)messageArray[1];
if(MqttTopic.isMatched(Settings.topicNameWakewordRecognized, topic))
{
// Turn on screen....
textEntriesList.add(getMeString() + "Hello! What can I do for you?");
updateWindow();
}
else if(MqttTopic.isMatched(Settings.topicNameIntentsRecognized, topic))
{
JSONObject jo = new JSONObject(payload);
textEntriesList.add(getYouString() + jo.getString("input"));
updateWindow();
}
else if(MqttTopic.isMatched(Settings.topicNameDisplayText, topic))
{
JSONObject jo = new JSONObject(payload);
/*
* This is deactivated only for test purposes.
* Afterwards for a conversation flow sayText needs to be used.
*/
// textEntriesList.clear();
textEntriesList.add(getMeString() + jo.getString("text"));
updateWindow();
}
else if(MqttTopic.isMatched(Settings.topicNameDisplayOptions, topic))
{
JSONObject jo = new JSONObject(payload);
/*
* This is deactivated only for test purposes.
* Afterwards for a conversation flow sayText needs to be used.
*/
// textEntriesList.clear();
String[] options = jo.getString("text").split(";");
displayOptions(options);
}
else if(MqttTopic.isMatched(Settings.topicNameSayText, topic))
{
JSONObject jo = new JSONObject(payload);
textEntriesList.add(getMeString() + jo.getString("text"));
updateWindow();
}
else if(MqttTopic.isMatched(Settings.topicNameSessionEnded, topic))
{
textEntriesList.clear();
updateWindow();
}
}
static String getYouString()
{
return "You: \t";
}
static String getMeString()
{
return "Me: \t";
}
static void turnOnScreen()
{
/*
* pi@raspberrypi11:~ $ DISPLAY=:0 xset q
Keyboard Control:
auto repeat: on key click percent: 0 LED mask: 00000000
XKB indicators:
00: Caps Lock: off 01: Num Lock: off 02: Scroll Lock: off
03: Compose: off 04: Kana: off 05: Sleep: off
06: Suspend: off 07: Mute: off 08: Misc: off
09: Mail: off 10: Charging: off 11: Shift Lock: off
12: Group 2: off 13: Mouse Keys: off
auto repeat delay: 500 repeat rate: 33
auto repeating keys: 00ffffffdffffbbf
fadfffefffedffff
9fffffffffffffff
fff7ffffffffffff
bell percent: 50 bell pitch: 400 bell duration: 100
Pointer Control:
acceleration: 20/10 threshold: 10
Screen Saver:
prefer blanking: yes allow exposures: yes
timeout: 600 cycle: 600
Colors:
default colormap: 0x20 BlackPixel: 0x0 WhitePixel: 0xffffff
Font Path:
built-ins
DPMS (Energy Star):
Standby: 600 Suspend: 600 Off: 600
DPMS is Enabled
Monitor is Off
pi@raspberrypi11:~ $
*/
}
}

250
RhasspyVisualConversationTool/src/com/jens/rhasspy/visualtool/MQTT.java

@ -0,0 +1,250 @@
package com.jens.rhasspy.visualtool;
import java.util.Calendar;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttPersistenceException;
import com.jens.rhasspy.visualtool.lib.JSONObject;
public class MQTT implements MqttCallbackExtended
{
/*
* Connect to server
*
* raspberrypi1:1883
*
* Subscribe to topic
*
* Topic: zigbee2mqtt/0x00158d0002d72e58
* Payload: {"contact":true,"linkquality":84}
*
* Configuration file:
* /opt/zigbee2mqtt/data/configuration.yaml
*/
final static String clientId = "RhasspyVisualConversationTool";
final static int maximumReconnectionAttempts = -1;
protected static boolean forceReconnection = false;
static String getServerUri()
{
if(Settings.mqttClientUseSsl)
return "ssl://" + Settings.mqttClientServerHostname + ":" + String.valueOf(Settings.mqttClientServerPort);
else
return "tcp://" + Settings.mqttClientServerHostname + ":" + String.valueOf(Settings.mqttClientServerPort);
}
static MQTT instance = null;
static MqttClient client = null;
public static MQTT getInstance()
{
if(instance == null)
instance = new MQTT();
return instance;
}
public MqttClient getClient()
{
if(client == null)
{
try
{
/*
* Documentation of options:
* https://www.ibm.com/support/knowledgecenter/SSFKSJ_7.5.0/com.ibm.mq.javadoc.doc/WMQMQxrClasses/org/eclipse/paho/client/mqttv3/MqttConnectOptions.html#setKeepAliveInterval(int)
*/
MqttConnectOptions options = new MqttConnectOptions();
options.setCleanSession(true);
options.setAutomaticReconnect(true);
if(Settings.mqttClientUseSsl)
{
// Properties props = new Properties();
// props.put("secureProtocol", "TLSv1_method");
// options.setSSLProperties(props);
// options.setSSLProperties(props);
options.setHttpsHostnameVerificationEnabled(true);
}
if(Settings.mqttClientUseAuthentication)
{
options.setUserName(Settings.mqttClientUsername);
options.setPassword(Settings.mqttClientPassword.toCharArray());
}
client = new MqttClient(getServerUri(), clientId);
client.setCallback(this);
}
catch (MqttException e)
{
Miscellaneous.logEvent(Miscellaneous.getStackTraceAsString(e), 1);
}
}
return client;
}
protected boolean subscribeToTopic(String topic)
{
Miscellaneous.logEvent("Subscribing to topic " + topic, 3);
try
{
if(!getClient().isConnected())
{
Miscellaneous.logEvent("Connecting to MQTT server " + Settings.mqttClientServerHostname + " on port " + String.valueOf(Settings.mqttClientServerPort) + ".", 3);
// getClient().setCallback(this);
getClient().connect();
}
getClient().subscribe(topic);
return true;
}
catch (MqttException e)
{
Miscellaneous.logEvent("Error subscribing to topic " + topic + ": " + Miscellaneous.getStackTraceAsString(e), 1);
}
return false;
}
protected boolean unsubscribeFromTopic(String topic)
{
Miscellaneous.logEvent("Unsubscribing from topic " + topic, 3);
try
{
if(getClient().isConnected())
{
getClient().unsubscribe(topic);
}
return true;
}
catch (MqttException e)
{
Miscellaneous.logEvent(Miscellaneous.getStackTraceAsString(e), 1);
}
return false;
}
@Override
public void connectionLost(Throwable arg0)
{
Miscellaneous.logEvent("Connection to MQTT server lost.", 3);
Miscellaneous.logEvent("Reason for loss of MQTT connection: " + Miscellaneous.getStackTraceAsString(arg0), 5);
GUI.getInstance().updateConnectionStatus(false);
// Currently set to autoreconnect, but that doesn't always seem to work
// reconnectManually();
}
@Override
public void deliveryComplete(IMqttDeliveryToken arg0)
{
// TODO Auto-generated method stub
}
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception
{
Miscellaneous.logEvent("Received MQTT message from topic: " + topic + ", message: " + message, 3);
MqttMessageDistributor mmd = new MqttMessageDistributor(topic, message);
Thread worker = new Thread(mmd);
worker.start();
}
class MqttMessageDistributor implements Runnable
{
String topic;
MqttMessage message;
public MqttMessageDistributor(String topic, MqttMessage message)
{
this.topic = topic;
this.message = message;
}
@Override
public void run()
{
Thread.setDefaultUncaughtExceptionHandler(Miscellaneous.getUncaughtExceptionHandler(3));
try
{
Object[] object = new Object[3];
object[0] = message;
object[1] = topic;
object[2] = Calendar.getInstance();
Miscellaneous.logEvent("New message received on topic " + object[1] + Miscellaneous.lineSeparator + object[0], 2);
String message = new String(((MqttMessage)object[0]).getPayload());
// if(!StringUtils.isEmpty(message))
if(message != null && message.length() > 0)
{
JSONObject jo = new JSONObject(message);
if(jo.has(Settings.jsonObjectStringSiteId))
{
for(String ignoredSite : Settings.ignoredSatellites.split(";"))
{
if(ignoredSite.equalsIgnoreCase(jo.getString(Settings.jsonObjectStringSiteId)))
{
Miscellaneous.logEvent("Ignoring message as it's targeted to " + ignoredSite, 3);
return;
}
}
}
}
GUI.getInstance().handleNewMessage(object);
}
catch(Exception e)
{
Miscellaneous.logEvent("Error after receiving MQTT message: " + Miscellaneous.getStackTraceAsString(e), 1);
}
}
}
public boolean publish(String topic, String message)
{
try
{
getClient().publish(topic, new MqttMessage(message.getBytes()));
return true;
}
catch (MqttPersistenceException e)
{
Miscellaneous.logEvent(Miscellaneous.getStackTraceAsString(e), 1);
}
catch (MqttException e)
{
Miscellaneous.logEvent(Miscellaneous.getStackTraceAsString(e), 1);
}
return false;
}
@Override
public void connectComplete(boolean reconnect, String serverURI)
{
if(reconnect)
Miscellaneous.logEvent("Reconnected to MQTT server " + serverURI, 3);
else
Miscellaneous.logEvent("Connected to MQTT server " + serverURI, 3);
GUI.getInstance().updateConnectionStatus(true);
}
}

1267
RhasspyVisualConversationTool/src/com/jens/rhasspy/visualtool/Miscellaneous.java

File diff suppressed because it is too large

187
RhasspyVisualConversationTool/src/com/jens/rhasspy/visualtool/Settings.java

@ -0,0 +1,187 @@
package com.jens.rhasspy.visualtool;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;
public class Settings
{
/*
* Unchangable stuff:
*/
public static final String programName = "RhasspyVisualConversationTool";
final static String logFileName = programName + "LogFile.txt";
final static int logFilesAmount = 1;
final static int maxLogSize = Settings.logMaxSize * 1024 * 1024;
final static boolean logAppend = true;
public static final String settingsFileName = programName + "-settings.ini";
public final static String settingsTtsLedStateVariable = "<state>";
public final static String settingsTtsSoundFileVariable = "<soundFilePath>";
public final static long notificationWaitPeriod = 60*60*24;
public final static int programVersion = 1;
public final static String jsonObjectStringSiteId = "siteId";
public final static String jsonObjectStringSessionId = "sessionId";
public final static String topicNameWakewordRecognized = "hermes/hotword/+/detected";
public final static String topicNameDisplayText = "hermes/tts/displayText";
public final static String topicNameDisplayOptions = "hermes/tts/displayOptions";
public final static String topicNameIntentsRecognized = "hermes/intent/#";
public final static String topicNameSayText = "hermes/tts/say";
public final static String topicNameSayFinished = "hermes/tts/sayFinished";
public static String topicNamePlaySoundFinished = "hermes/audioServer/" + jsonObjectStringSiteId + "/playFinished";
public final static String topicNameSessionEnded = "hermes/dialogueManager/sessionEnded";
/*
* Unchangable stuff:
*/
public static final boolean default_sslDebug = false;
public static final String default_keystoreFilename = "keystore.jks";
public static final String default_keystorePassword = "keystorePassword";
public static final String default_dateFormat = "dd.MM.yyyy HH:mm:ss:SSSS";
public static final boolean default_logFileEnabled = false;
public static final String default_logFolderPath = "/var/log/homecontrol";
public static final int default_logLevel = 3;
public static final int default_logMaxSize = 5;
public static final String default_encryptionKey="choose_a_password";
public static final String default_language = "en-US";
public static final String default_intentMqttPath = "hermes/intent/#";
public static final boolean default_notificationsEnabled = true;
public static final int default_notificationVerbosity = 2;
public static final String default_notificationFromAddress = "admin@localhost.com";
public static final String default_notificationToAddress = "admin@localhost.com";
public static final String default_notificationMailServer = "smtp.host.com";
public static final int default_notificationMailServerPort = 25;
public static final String default_notificationEncryptionType = "starttls";
public static final boolean default_notificationAuthenticate = false;
public static final String default_notificationUsername = "smtpUsername";
public static final String default_notificationPassword = "smtpPassword";
public static final String default_mqttClientServerHostname = "";
public static final int default_mqttClientServerPort = 1883;
public static final boolean default_mqttClientUseSsl = false;
public static final boolean default_mqttClientUseAuthentication = false;
public static final String default_mqttClientUsername = "";
public static final String default_mqttClientPassword = "";
public static final String default_ignoredSatellites = "master";
public static final String default_siteId = "unknown";
public static String intentMqttPath;
public static String language;
public static boolean sslDebug;
public static String keystoreFilename;
public static String keystorePassword;
public static String dateFormat = default_dateFormat;
public static boolean logFileEnabled;
public static String logFolderPath;
public static int logLevel = 5; // Set a default value as logging is performed before settings can be loaded.
public static int logMaxSize = 5; // Set a default value as logging is performed before settings can be loaded.
public static String scriptsPath;
public static boolean notificationsEnabled;
public static int notificationVerbosity;
public static String notificationFromAddress;
public static String notificationToAddress;
public static String notificationMailServer;
public static int notificationMailServerPort;
public static String notificationEncryptionType;
public static boolean notificationAuthenticate;
public static String notificationUsername;
public static String notificationPassword;
public static String mqttClientServerHostname;
public static int mqttClientServerPort;
public static boolean mqttClientUseSsl;
public static boolean mqttClientUseAuthentication;
public static String mqttClientUsername;
public static String mqttClientPassword;
public static String ignoredSatellites;
public static String siteId;
public static boolean readSettings()
{
File sFile = new File(settingsFileName);
Miscellaneous.logEvent("Loading settings from " + sFile.getAbsolutePath(), 3);
Properties prop = new Properties();
try
{
// Local settings from settings file
prop.load(new FileInputStream(sFile));
intentMqttPath = prop.getProperty("intentMqttPath", default_intentMqttPath);
language = prop.getProperty("language", default_language);
sslDebug = Boolean.parseBoolean(prop.getProperty("sslDebug", String.valueOf(default_sslDebug)));
keystoreFilename = prop.getProperty("keystoreFilename", default_keystoreFilename);
keystorePassword = prop.getProperty("keystorePassword", default_keystorePassword);
logFileEnabled = Boolean.parseBoolean(prop.getProperty("logFileEnabled", String.valueOf(default_logFileEnabled)));
logFolderPath = prop.getProperty("logFolderPath", String.valueOf(default_logFolderPath));
logLevel = Integer.parseInt(prop.getProperty("logLevel", String.valueOf(default_logLevel)));
logMaxSize = Integer.parseInt(prop.getProperty("logMaxSize", String.valueOf(default_logMaxSize)));
notificationsEnabled = Boolean.parseBoolean(prop.getProperty("notificationsEnabled", String.valueOf(default_notificationsEnabled)));
notificationVerbosity = Integer.parseInt(prop.getProperty("notificationVerbosity", String.valueOf(default_notificationVerbosity)));
notificationFromAddress = prop.getProperty("notificationFromAddress", default_notificationFromAddress);
notificationToAddress = prop.getProperty("notificationToAddress", default_notificationToAddress);
notificationMailServer = prop.getProperty("notificationMailServer", default_notificationMailServer);
notificationMailServerPort = Integer.parseInt(prop.getProperty("notificationMailServerPort", String.valueOf(default_notificationMailServerPort)));
notificationEncryptionType = prop.getProperty("notificationEncryptionType", default_notificationEncryptionType);
notificationAuthenticate = Boolean.parseBoolean(prop.getProperty("notificationAuthenticate", String.valueOf(default_notificationAuthenticate)));
notificationUsername = prop.getProperty("notificationUsername", default_notificationUsername);
notificationPassword = prop.getProperty("notificationPassword", default_notificationPassword);
mqttClientServerHostname = prop.getProperty("mqttClientServerHostname", default_mqttClientServerHostname);
mqttClientServerPort = Integer.parseInt(prop.getProperty("mqttClientServerPort", String.valueOf(default_mqttClientServerPort)));
mqttClientUseSsl = Boolean.parseBoolean(prop.getProperty("mqttClientUseSsl", String.valueOf(default_mqttClientUseSsl)));
mqttClientUseAuthentication = Boolean.parseBoolean(prop.getProperty("mqttClientUseAuthentication", String.valueOf(default_mqttClientUseAuthentication)));
mqttClientUsername = prop.getProperty("mqttClientUsername", default_mqttClientUsername);
mqttClientPassword = prop.getProperty("mqttClientPassword", default_mqttClientPassword);
ignoredSatellites = prop.getProperty("ignoredSatellites", default_ignoredSatellites);
siteId = prop.getProperty("siteId", default_siteId);
topicNamePlaySoundFinished = topicNamePlaySoundFinished.replace(jsonObjectStringSiteId, siteId);
if(mqttClientUseSsl)
loadKeystore();
}
catch (FileNotFoundException e)
{
Miscellaneous.logEvent(Miscellaneous.getStackTraceAsString(e), 1);
}
catch (IOException e)
{
Miscellaneous.logEvent(Miscellaneous.getStackTraceAsString(e), 1);
}
return true;
}
static void loadKeystore()
{
if((new File(Settings.keystoreFilename).exists()))
{
Miscellaneous.logEvent("Loading keystore " + Settings.keystoreFilename, 3);
System.setProperty("javax.net.ssl.keyStore", Settings.keystoreFilename);
System.setProperty("javax.net.ssl.keyStorePassword", Settings.keystorePassword);
System.setProperty("javax.net.ssl.trustStore", Settings.keystoreFilename);
System.setProperty("javax.net.ssl.trustStorePassword", Settings.keystorePassword);
// System.setProperty("javax.net.ssl.trustStoreType","JCEKS");
}
else
{
Miscellaneous.logEvent("Could not load keystore, file does not exist.", 3);
System.exit(1);
}
}
}

1541
RhasspyVisualConversationTool/src/com/jens/rhasspy/visualtool/lib/JSONArray.java

File diff suppressed because it is too large

45
RhasspyVisualConversationTool/src/com/jens/rhasspy/visualtool/lib/JSONException.java

@ -0,0 +1,45 @@
package com.jens.rhasspy.visualtool.lib;
/**
* The JSONException is thrown by the JSON.org classes when things are amiss.
*
* @author JSON.org
* @version 2015-12-09
*/
public class JSONException extends RuntimeException {
/** Serialization ID */
private static final long serialVersionUID = 0;
/**
* Constructs a JSONException with an explanatory message.
*
* @param message
* Detail about the reason for the exception.
*/
public JSONException(final String message) {
super(message);
}
/**
* Constructs a JSONException with an explanatory message and cause.
*
* @param message
* Detail about the reason for the exception.
* @param cause
* The cause.
*/
public JSONException(final String message, final Throwable cause) {
super(message, cause);
}
/**
* Constructs a new JSONException with the specified cause.
*
* @param cause
* The cause.
*/
public JSONException(final Throwable cause) {
super(cause.getMessage(), cause);
}
}

542
RhasspyVisualConversationTool/src/com/jens/rhasspy/visualtool/lib/JSONML.java

@ -0,0 +1,542 @@
package com.jens.rhasspy.visualtool.lib;
/*
Copyright (c) 2008 JSON.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The Software shall be used for Good, not Evil.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* This provides static methods to convert an XML text into a JSONArray or
* JSONObject, and to covert a JSONArray or JSONObject into an XML text using
* the JsonML transform.
*
* @author JSON.org
* @version 2016-01-30
*/
public class JSONML {
/**
* Parse XML values and store them in a JSONArray.
* @param x The XMLTokener containing the source string.
* @param arrayForm true if array form, false if object form.
* @param ja The JSONArray that is containing the current tag or null
* if we are at the outermost level.
* @param keepStrings Don't type-convert text nodes and attribute values
* @return A JSONArray if the value is the outermost tag, otherwise null.
* @throws JSONException
*/
private static Object parse(
XMLTokener x,
boolean arrayForm,
JSONArray ja,
boolean keepStrings
) throws JSONException {
String attribute;
char c;
String closeTag = null;
int i;
JSONArray newja = null;
JSONObject newjo = null;
Object token;
String tagName = null;
// Test for and skip past these forms:
// <!-- ... -->
// <![ ... ]]>
// <! ... >
// <? ... ?>
while (true) {
if (!x.more()) {
throw x.syntaxError("Bad XML");
}
token = x.nextContent();
if (token == XML.LT) {
token = x.nextToken();
if (token instanceof Character) {
if (token == XML.SLASH) {
// Close tag </
token = x.nextToken();
if (!(token instanceof String)) {
throw new JSONException(
"Expected a closing name instead of '" +
token + "'.");
}
if (x.nextToken() != XML.GT) {
throw x.syntaxError("Misshaped close tag");
}
return token;
} else if (token == XML.BANG) {
// <!
c = x.next();
if (c == '-') {
if (x.next() == '-') {
x.skipPast("-->");
} else {
x.back();
}
} else if (c == '[') {
token = x.nextToken();
if (token.equals("CDATA") && x.next() == '[') {
if (ja != null) {
ja.put(x.nextCDATA());
}
} else {
throw x.syntaxError("Expected 'CDATA['");
}
} else {
i = 1;
do {
token = x.nextMeta();
if (token == null) {
throw x.syntaxError("Missing '>' after '<!'.");
} else if (token == XML.LT) {
i += 1;
} else if (token == XML.GT) {
i -= 1;
}
} while (i > 0);
}
} else if (token == XML.QUEST) {
// <?
x.skipPast("?>");
} else {
throw x.syntaxError("Misshaped tag");
}
// Open tag <
} else {
if (!(token instanceof String)) {
throw x.syntaxError("Bad tagName '" + token + "'.");
}
tagName = (String)token;
newja = new JSONArray();
newjo = new JSONObject();
if (arrayForm) {
newja.put(tagName);
if (ja != null) {
ja.put(newja);
}
} else {
newjo.put("tagName", tagName);
if (ja != null) {
ja.put(newjo);
}
}
token = null;
for (;;) {
if (token == null) {
token = x.nextToken();
}
if (token == null) {
throw x.syntaxError("Misshaped tag");
}
if (!(token instanceof String)) {
break;
}
// attribute = value
attribute = (String)token;
if (!arrayForm && ("tagName".equals(attribute) || "childNode".equals(attribute))) {
throw x.syntaxError("Reserved attribute.");
}
token = x.nextToken();
if (token == XML.EQ) {
token = x.nextToken();
if (!(token instanceof String)) {
throw x.syntaxError("Missing value");
}
newjo.accumulate(attribute, keepStrings ? ((String)token) :XML.stringToValue((String)token));
token = null;
} else {
newjo.accumulate(attribute, "");
}
}
if (arrayForm && newjo.length() > 0) {
newja.put(newjo);
}
// Empty tag <.../>
if (token == XML.SLASH) {
if (x.nextToken() != XML.GT) {
throw x.syntaxError("Misshaped tag");
}
if (ja == null) {
if (arrayForm) {
return newja;
}
return newjo;
}
// Content, between <...> and </...>
} else {
if (token != XML.GT) {
throw x.syntaxError("Misshaped tag");
}
closeTag = (String)parse(x, arrayForm, newja, keepStrings);
if (closeTag != null) {
if (!closeTag.equals(tagName)) {
throw x.syntaxError("Mismatched '" + tagName +
"' and '" + closeTag + "'");
}
tagName = null;
if (!arrayForm && newja.length() > 0) {
newjo.put("childNodes", newja);
}
if (ja == null) {
if (arrayForm) {
return newja;
}
return newjo;
}
}
}
}
} else {
if (ja != null) {
ja.put(token instanceof String
? keepStrings ? XML.unescape((String)token) :XML.stringToValue((String)token)
: token);
}
}
}
}
/**
* Convert a well-formed (but not necessarily valid) XML string into a
* JSONArray using the JsonML transform. Each XML tag is represented as
* a JSONArray in which the first element is the tag name. If the tag has
* attributes, then the second element will be JSONObject containing the
* name/value pairs. If the tag contains children, then strings and
* JSONArrays will represent the child tags.
* Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
* @param string The source string.
* @return A JSONArray containing the structured data from the XML string.
* @throws JSONException Thrown on error converting to a JSONArray
*/
public static JSONArray toJSONArray(String string) throws JSONException {
return (JSONArray)parse(new XMLTokener(string), true, null, false);
}
/**
* Convert a well-formed (but not necessarily valid) XML string into a
* JSONArray using the JsonML transform. Each XML tag is represented as
* a JSONArray in which the first element is the tag name. If the tag has
* attributes, then the second element will be JSONObject containing the
* name/value pairs. If the tag contains children, then strings and
* JSONArrays will represent the child tags.
* As opposed to toJSONArray this method does not attempt to convert
* any text node or attribute value to any type
* but just leaves it as a string.
* Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
* @param string The source string.
* @param keepStrings If true, then values will not be coerced into boolean
* or numeric values and will instead be left as strings
* @return A JSONArray containing the structured data from the XML string.
* @throws JSONException Thrown on error converting to a JSONArray
*/
public static JSONArray toJSONArray(String string, boolean keepStrings) throws JSONException {
return (JSONArray)parse(new XMLTokener(string), true, null, keepStrings);
}
/**
* Convert a well-formed (but not necessarily valid) XML string into a
* JSONArray using the JsonML transform. Each XML tag is represented as
* a JSONArray in which the first element is the tag name. If the tag has
* attributes, then the second element will be JSONObject containing the
* name/value pairs. If the tag contains children, then strings and
* JSONArrays will represent the child content and tags.
* As opposed to toJSONArray this method does not attempt to convert
* any text node or attribute value to any type
* but just leaves it as a string.
* Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
* @param x An XMLTokener.
* @param keepStrings If true, then values will not be coerced into boolean
* or numeric values and will instead be left as strings
* @return A JSONArray containing the structured data from the XML string.
* @throws JSONException Thrown on error converting to a JSONArray
*/
public static JSONArray toJSONArray(XMLTokener x, boolean keepStrings) throws JSONException {
return (JSONArray)parse(x, true, null, keepStrings);
}
/**
* Convert a well-formed (but not necessarily valid) XML string into a
* JSONArray using the JsonML transform. Each XML tag is represented as
* a JSONArray in which the first element is the tag name. If the tag has
* attributes, then the second element will be JSONObject containing the
* name/value pairs. If the tag contains children, then strings and
* JSONArrays will represent the child content and tags.
* Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
* @param x An XMLTokener.
* @return A JSONArray containing the structured data from the XML string.
* @throws JSONException Thrown on error converting to a JSONArray
*/
public static JSONArray toJSONArray(XMLTokener x) throws JSONException {
return (JSONArray)parse(x, true, null, false);
}
/**
* Convert a well-formed (but not necessarily valid) XML string into a
* JSONObject using the JsonML transform. Each XML tag is represented as
* a JSONObject with a "tagName" property. If the tag has attributes, then
* the attributes will be in the JSONObject as properties. If the tag
* contains children, the object will have a "childNodes" property which
* will be an array of strings and JsonML JSONObjects.
* Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
* @param string The XML source text.
* @return A JSONObject containing the structured data from the XML string.
* @throws JSONException Thrown on error converting to a JSONObject
*/
public static JSONObject toJSONObject(String string) throws JSONException {
return (JSONObject)parse(new XMLTokener(string), false, null, false);
}
/**
* Convert a well-formed (but not necessarily valid) XML string into a
* JSONObject using the JsonML transform. Each XML tag is represented as
* a JSONObject with a "tagName" property. If the tag has attributes, then
* the attributes will be in the JSONObject as properties. If the tag
* contains children, the object will have a "childNodes" property which
* will be an array of strings and JsonML JSONObjects.
* Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
* @param string The XML source text.
* @param keepStrings If true, then values will not be coerced into boolean
* or numeric values and will instead be left as strings
* @return A JSONObject containing the structured data from the XML string.
* @throws JSONException Thrown on error converting to a JSONObject
*/
public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException {
return (JSONObject)parse(new XMLTokener(string), false, null, keepStrings);
}
/**
* Convert a well-formed (but not necessarily valid) XML string into a
* JSONObject using the JsonML transform. Each XML tag is represented as
* a JSONObject with a "tagName" property. If the tag has attributes, then
* the attributes will be in the JSONObject as properties. If the tag
* contains children, the object will have a "childNodes" property which
* will be an array of strings and JsonML JSONObjects.
* Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
* @param x An XMLTokener of the XML source text.
* @return A JSONObject containing the structured data from the XML string.
* @throws JSONException Thrown on error converting to a JSONObject
*/
public static JSONObject toJSONObject(XMLTokener x) throws JSONException {
return (JSONObject)parse(x, false, null, false);
}
/**
* Convert a well-formed (but not necessarily valid) XML string into a
* JSONObject using the JsonML transform. Each XML tag is represented as
* a JSONObject with a "tagName" property. If the tag has attributes, then
* the attributes will be in the JSONObject as properties. If the tag
* contains children, the object will have a "childNodes" property which
* will be an array of strings and JsonML JSONObjects.
* Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
* @param x An XMLTokener of the XML source text.
* @param keepStrings If true, then values will not be coerced into boolean
* or numeric values and will instead be left as strings
* @return A JSONObject containing the structured data from the XML string.
* @throws JSONException Thrown on error converting to a JSONObject
*/
public static JSONObject toJSONObject(XMLTokener x, boolean keepStrings) throws JSONException {
return (JSONObject)parse(x, false, null, keepStrings);
}
/**
* Reverse the JSONML transformation, making an XML text from a JSONArray.
* @param ja A JSONArray.
* @return An XML string.
* @throws JSONException Thrown on error converting to a string
*/
public static String toString(JSONArray ja) throws JSONException {
int i;
JSONObject jo;
int length;
Object object;
StringBuilder sb = new StringBuilder();
String tagName;
// Emit <tagName
tagName = ja.getString(0);
XML.noSpace(tagName);
tagName = XML.escape(tagName);
sb.append('<');
sb.append(tagName);
object = ja.opt(1);
if (object instanceof JSONObject) {
i = 2;
jo = (JSONObject)object;
// Emit the attributes
// Don't use the new entrySet API to maintain Android support
for (final String key : jo.keySet()) {
final Object value = jo.opt(key);
XML.noSpace(key);
if (value != null) {
sb.append(' ');
sb.append(XML.escape(key));
sb.append('=');
sb.append('"');
sb.append(XML.escape(value.toString()));
sb.append('"');
}
}
} else {
i = 1;
}
// Emit content in body
length = ja.length();
if (i >= length) {
sb.append('/');
sb.append('>');
} else {
sb.append('>');
do {
object = ja.get(i);
i += 1;
if (object != null) {
if (object instanceof String) {
sb.append(XML.escape(object.toString()));
} else if (object instanceof JSONObject) {
sb.append(toString((JSONObject)object));
} else if (object instanceof JSONArray) {
sb.append(toString((JSONArray)object));
} else {
sb.append(object.toString());
}
}
} while (i < length);
sb.append('<');
sb.append('/');
sb.append(tagName);
sb.append('>');
}
return sb.toString();
}
/**
* Reverse the JSONML transformation, making an XML text from a JSONObject.
* The JSONObject must contain a "tagName" property. If it has children,
* then it must have a "childNodes" property containing an array of objects.
* The other properties are attributes with string values.
* @param jo A JSONObject.
* @return An XML string.
* @throws JSONException Thrown on error converting to a string
*/
public static String toString(JSONObject jo) throws JSONException {
StringBuilder sb = new StringBuilder();
int i;
JSONArray ja;
int length;
Object object;
String tagName;
Object value;
//Emit <tagName
tagName = jo.optString("tagName");
if (tagName == null) {
return XML.escape(jo.toString());
}
XML.noSpace(tagName);
tagName = XML.escape(tagName);
sb.append('<');
sb.append(tagName);
//Emit the attributes
// Don't use the new entrySet API to maintain Android support
for (final String key : jo.keySet()) {
if (!"tagName".equals(key) && !"childNodes".equals(key)) {
XML.noSpace(key);
value = jo.opt(key);
if (value != null) {
sb.append(' ');
sb.append(XML.escape(key));
sb.append('=');
sb.append('"');
sb.append(XML.escape(value.toString()));
sb.append('"');
}
}
}
//Emit content in body
ja = jo.optJSONArray("childNodes");
if (ja == null) {
sb.append('/');
sb.append('>');
} else {
sb.append('>');
length = ja.length();
for (i = 0; i < length; i += 1) {
object = ja.get(i);
if (object != null) {
if (object instanceof String) {
sb.append(XML.escape(object.toString()));
} else if (object instanceof JSONObject) {
sb.append(toString((JSONObject)object));
} else if (object instanceof JSONArray) {
sb.append(toString((JSONArray)object));
} else {
sb.append(object.toString());
}
}
}
sb.append('<');
sb.append('/');
sb.append(tagName);
sb.append('>');
}
return sb.toString();
}
}

2563
RhasspyVisualConversationTool/src/com/jens/rhasspy/visualtool/lib/JSONObject.java

File diff suppressed because it is too large

293
RhasspyVisualConversationTool/src/com/jens/rhasspy/visualtool/lib/JSONPointer.java

@ -0,0 +1,293 @@
package com.jens.rhasspy.visualtool.lib;
import static java.lang.String.format;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/*
Copyright (c) 2002 JSON.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The Software shall be used for Good, not Evil.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* A JSON Pointer is a simple query language defined for JSON documents by
* <a href="https://tools.ietf.org/html/rfc6901">RFC 6901</a>.
*
* In a nutshell, JSONPointer allows the user to navigate into a JSON document
* using strings, and retrieve targeted objects, like a simple form of XPATH.
* Path segments are separated by the '/' char, which signifies the root of
* the document when it appears as the first char of the string. Array
* elements are navigated using ordinals, counting from 0. JSONPointer strings
* may be extended to any arbitrary number of segments. If the navigation
* is successful, the matched item is returned. A matched item may be a
* JSONObject, a JSONArray, or a JSON value. If the JSONPointer string building
* fails, an appropriate exception is thrown. If the navigation fails to find
* a match, a JSONPointerException is thrown.
*
* @author JSON.org
* @version 2016-05-14
*/
public class JSONPointer {
// used for URL encoding and decoding
private static final String ENCODING = "utf-8";
/**
* This class allows the user to build a JSONPointer in steps, using
* exactly one segment in each step.
*/
public static class Builder {
// Segments for the eventual JSONPointer string
private final List<String> refTokens = new ArrayList<String>();
/**
* Creates a {@code JSONPointer} instance using the tokens previously set using the
* {@link #append(String)} method calls.
*/
public JSONPointer build() {
return new JSONPointer(this.refTokens);
}
/**