/**
* \mainpage Welcome to the OOBD Programming Manual
*
* \section Introduction
*
* This documentation is made for twopurposes: First explain the UISystem
* functionality, and second of course the general concept of how the different
* components work together.
*
* As the functionality is very specific, while the concept is very gereric, it
* will be a litte bit tricky to join these both counterparts together. Let's
* see, if it works.
*
*
* \section The Concept
*
* OOBD should be a framework for hopefully all kind of (automotive vehicle)
* diagnostics, where diagnostic in OOBD is not defined as just monitoring real
* time data, its defined as sending a question and visualize the answer.
*
* When looking more in detail into this basic requierement, you'll find five
* tasks which are nessecary to fulfill this.
*
* Each of these tasks build its own chapter. If you want to understand and
* program your own user interface, you've only to read and implement the
* chapter about \ref visualisation, how to create a own \ref scriptengine can
* be found there etc.
*
* \li coordination: Something inside must handle the fundamental things
* (dynamic module handling, message transfer, file i/o etc.). This is done by
* the \ref core \li visualisation: Finally somebody wants to see results or
* wants to do some user input. This is handled by the \ref visualisation
*
*/
package org.oobd.base;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.lang.reflect.*;
import java.io.*;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.prefs.Preferences;
import org.json.JSONException;
import org.oobd.base.archive.Archive;
import org.oobd.base.archive.Factory;
import org.oobd.base.support.Onion;
import org.oobd.base.bus.OobdBus;
import org.oobd.base.db.OobdDB;
import org.oobd.base.connector.OobdConnector;
import org.oobd.base.port.OOBDPort;
import org.oobd.base.protocol.OobdProtocol;
import org.oobd.base.scriptengine.OobdScriptengine;
import org.oobd.base.uihandler.*;
/**
* \defgroup init Initialisation during startup
*
* At startup, different objects come to live and tell each other about their
* existence and their capabilities
*
* This is mainly to create the links between the generic core functions and the
* application depending User interface and UISystem enviroment.
*
* This is done in the following steps: \li the Application class itself
* implements the Interface IFsystem \li the main class, which controls the GUI
* (like the form, the activity or whatever) implements the Interface IFsystem
*
* When the application starts, it first creates an instance of the GUI class.
* After that, it creates the (single) instance of the OOBD core
*
* myCore = new Core(this, GUI_instance)
*
*
* When the Core instance is initiated, it \li announces itself to the GUI
* object \li announces itself to the GUI object \li tells the GUI about
* available scriptengines
*
*
* \msc GUI,App,Core; App->Core [label="new Core()"]; App<-Core
* [label="registerOobdCore()", URL="\ref
* org::oobd::base::IFsystem.registerOobdCore()"]; GUI<-Core
* [label="registerOobdCore()", URL="\ref
* org::oobd::base::IFui.registerOobdCore()"]; GUI<-Core [label="1. Engine
* found", URL="\ref org::oobd::base::IFui.announceScriptengine()"]; ---
* [label="for all engines found"]; GUI<-Core [label="..n Engine found",
* URL="\ref org::oobd::base::IFui.announceScriptengine()"]; \endmsc
*
* that's already all.
*
* Now the systems waits that the user selects through the GUI one of the
* announced script engines to work with. How this works can be found in \ref
* visualisation
*/
/**
* \defgroup core Kernel, Runtime & Interprocess Functions
*/
/**
* \brief The Master Control Unit - the Core object
*
* The Core object provides all basic functionality and "glues" everything else
* together
*
*/
public class Core extends OobdPlugin implements OOBDConstants, CoreTickListener {
IFui userInterface;
IFsystem systemInterface;
OobdUIHandler uiHandler = null;
HashMap<String, OobdBus> busses; // /<stores all available busses
HashMap<String, OobdConnector> connectors; // /<stores all available
// connectors
HashMap<String, OobdProtocol> protocols; // /<stores all available protocols
HashMap<String, Class<OobdUIHandler>> uiHandlers; // /<stores all available
// UI-handlers
HashMap<String, Class<OobdScriptengine>> scriptengines; // /<stores all
// available
// scriptengine classes
HashMap<String, OobdDB> databases; // /<stores all available
// database classes
HashMap<String, OobdUIHandler> activeUIHandlers; // /<stores all active
// (instanced)
// UIHandlers objects
/**
* The assingnments - hashtable works as a poor mens registry, where
* everything, which needs to stored somehow, is kept as a string => object
* pair
*/
HashMap<String, Object> assignments;
String uiHandlerID = "";
static Core thisInstance = null; // Class variable points to only instance
CoreTick ticker;
//Preferences props;
boolean runCore = true;
final ArrayList dataPoolList = new ArrayList(DP_ARRAY_SIZE);
/**
* \brief The Application creates one single instance of the core class
* \ingroup init
*
* @param myUserInterface reference to the View - interface, which is used
* to handle all visual in- and output
* @param mySystemInterface reference to the actual application and runtime
* enviroment, on which OOBD is actual running on
* @param name of the Plugin, just for debugging
*
*/
public Core(IFui myUserInterface, IFsystem mySystemInterface, String name) {
super(name);
System.out.println("Java Runtime Version:" + System.getProperty("java.version"));
if (thisInstance != null) {
Logger.getLogger(Core.class.getName()).log(Level.SEVERE,
"Core Creator called more as once!!");
}
thisInstance = this;
id = CoreMailboxName;
userInterface = myUserInterface;
systemInterface = mySystemInterface;
// busses = new HashMap<String, OobdBus>();
busses = new HashMap<>();
connectors = new HashMap<>();
protocols = new HashMap<>();
uiHandlers = new HashMap<>();
scriptengines = new HashMap<>();
activeUIHandlers = new HashMap<>();
assignments = new HashMap<>();
databases = new HashMap<>();
// absolutely scary, but the datapool array list need to be filled once to not
// crash later when trying to (re)assign a value...
for (int i = 0; i < DP_ARRAY_SIZE; i++) {
dataPoolList.add(null);
}
systemInterface.registerOobdCore(this); // Anounce itself at the Systeminterface
userInterface.registerOobdCore(this); // Anounce itself at the Userinterface
try {
BufferedReader br;
String strLine;
br = new BufferedReader(new InputStreamReader(this.getClass().getResourceAsStream("/org/oobd/base/classloader.cfg")));
while ((strLine = br.readLine()) != null) {
if (!"".equals(strLine)) {
String[] classConfig = strLine.split(":");
boolean loadAsClass = false;
boolean loadAsInstance = false;
String result = "";
//Class<OobdScriptengine> value = (Class<OobdScriptengine>) Class.forName(classConfig[1]);
Class value = Class.forName(classConfig[1]);
String[] classNameElements = classConfig[1].split("\\.");
String element = classNameElements[classNameElements.length - 1];
OobdPlugin thisClass = null;
switch (classConfig[0]) {
case "scriptengine":
case "uihandler":
loadAsClass = true;
break;
case "oobddb":
case "protocol":
case "bus":
case "connector":
loadAsInstance = true;
break;
}
if (loadAsInstance) {
try {
thisClass = (OobdPlugin) value.newInstance();
thisClass.registerCore(this);
new Thread(thisClass).start();
} catch (InstantiationException ex) {
// Wird geworfen, wenn die Klasse nicht "instanziert" werden
// kann
Logger.getLogger(Core.class.getName()).log(
Level.WARNING,
"InstantiationException: can't instance of Database "
+ element);
} catch (IllegalAccessException ex) {
Logger.getLogger(Core.class.getName()).log(
Level.WARNING,
"IllegalAccessException: can't create instance of Database "
+ element);
}
// after creation, save results
switch (classConfig[0]) {
case "oobddb":
databases.put(element, (OobdDB) thisClass);
break;
case "protocol":
protocols.put(element, (OobdProtocol) thisClass);
break;
case "bus":
busses.put(element, (OobdBus) thisClass);
break;
case "connector":
connectors.put(element, (OobdConnector) thisClass);
break;
}
}
if (loadAsClass) {
//scriptengines.put(element, value);
// now I need to be a little bit tricky to involve the static
// class method of an untypized class
try {
java.lang.reflect.Method method = value.getMethod(
"publicName", new Class[]{}); // no parameters
Object instance = null;
result = (String) method.invoke(instance,
new Object[]{}); // no parameters
// Android: String.isEmpty() not available
// if (!result.isEmpty()) {
// if (result.length() != 0) {
// userInterface.announceScriptengine(element, result);
// }
} catch (Exception ex) {
Logger.getLogger(Core.class.getName()).log(
Level.WARNING,
"can't call static method 'publicName' of "
+ element);
ex.printStackTrace();
}
// after creation, save results
switch (classConfig[0]) {
case "scriptengine":
scriptengines.put(element, value);
if (result.length() != 0) {
userInterface.announceScriptengine(element, result);
}
break;
case "uihandler":
uiHandlers.put(element, value);
if (result.length() != 0) {
userInterface.announceUIHandler(element, result);
}
break;
}
}
}
}
} catch (ClassNotFoundException ex) {
Logger.getLogger(Core.class.getName()).log(Level.SEVERE,
"Error while trying to load class", ex);
} catch (IOException ex) {
Logger.getLogger(Core.class.getName()).log(Level.SEVERE, null, ex);
}
// ------------- start the global timer ticker -----------------
ticker = new CoreTick();
ticker.setCoreTickListener(this);
new Thread(ticker).start();
new Thread(this).start();
}// constructor
/**
* a static help routine which returns the actual running Instance of the
* Core class
*
* @return Core
*/
public static Core getSingleInstance() {
return thisInstance;
}
/**
* a help routine which returns the system Interface of the Core class
*
* @return Core
*/
public IFsystem getSystemIF() {
return systemInterface;
}
/**
* a help routine which returns the UI Interface of the Core class
*
* @return UI-Interface
*/
public IFui getUiIF() {
return userInterface;
}
/**
* a help routine which returns the UI Handler of the Core class
*
* @return Core
*/
public OobdUIHandler getUiHandler() {
return uiHandler;
}
/**
* a help routine which returns the Scriptengine of a given ID
*
* @return OobdScriptengine
*/
public OobdScriptengine getScriptEngine() {
return (OobdScriptengine) readDataPool(OOBDConstants.DP_RUNNING_SCRIPTENGINE, null);
}
/**
* supply Objects which binds to system specific hardware
*
* @param typ
* @return a hardware handle of the requested type or nil
*/
public Object supplyHardwareHandle(Onion typ) {
return systemInterface.supplyHardwareHandle(typ);
}
/**
* ends a scriptEngine call this only at end of program or when reaching the
* main page During normal operation, the engine change is handled by the
* startEngine()routine already
*
* @param id
*
*/
public void stopScriptEngine() {
OobdScriptengine thisEngine = (OobdScriptengine) readDataPool(OOBDConstants.DP_RUNNING_SCRIPTENGINE, null);
if (thisEngine != null) {
thisEngine.close();
}
}
/**
* supply list of system specific connection hardware classes
*
* @param typ
* @return a hardware handle of the requested type or nil
*/
public Hashtable<String, Class> getConnectorList() {
return systemInterface.getConnectorList();
}
@Override
public String getPluginName() {
return OOBDConstants.CoreMailboxName;
}
/**
* \brief create ScriptEngine identified by its public Name
*
* Returns a unique ID which is used from now on for all communication
* between the core and the UI
*
* @param id public name of scriptengine to be created
* @param onion additional params
* @param classtype
* @return unique id of this class, made out of its public name and counter.
* Needed to link UI canvas to this object
*
*/
public OobdScriptengine createScriptEngine(String id, Onion onion) {
Logger.getLogger(Core.class.getName()).log(Level.CONFIG,
"Core should create scriptengine: " + id);
OobdScriptengine o = null;
Class[] argsClass = new Class[3]; // first we set up an pseudo - args -
// array for the scriptengine-
// constructor
argsClass[0] = id.getClass(); // and fill it with the info of the
// arguments classes
argsClass[1] = this.getClass();
argsClass[2] = IFsystem.class;
Class classRef = scriptengines.get(id); // then we get the class of the
// wanted scriptengine
try {
Constructor con = classRef.getConstructor(argsClass); // and let
// Java find
// the
// correct
// constructor
// matching
// to the
// args
// classes
Object[] args = {id, this, systemInterface}; // creating the
// args-array
o = (OobdScriptengine) con.newInstance(args); // and finally create
// the object from
// the scriptengine
// class with its
// unique id as
// parameter
} catch (Exception e) {
e.printStackTrace();
}
writeDataPool(OOBDConstants.DP_LAST_CREATED_SCRIPTENGINE, o);
return o;
}
/**
* \brief create ScriptEngine identified by its public Name
*
* Returns a unique ID which is used from now on for all communication
* between the core and the UI
*
* @param id public name of scriptengine to be created
* @param onion additional params
* @param classtype
* @return unique id of this class, made out of its public name and counter.
* Needed to link UI canvas to this object
*
*/
public String createUIHandler(String id, Onion onion) {
Logger.getLogger(Core.class.getName()).log(Level.CONFIG,
"Core should create UIHandler: " + id);
Integer i = 1;
while (activeUIHandlers.containsKey(id + "." + i.toString())) { // searching
// for a
// free
// id
i++;
}
String seID = id + "." + i.toString();
OobdUIHandler o = null;
Class[] argsClass = new Class[3]; // first we set up an pseudo - args -
// array for the scriptengine-
// constructor
argsClass[0] = seID.getClass(); // and fill it with the info of the
// arguments classes
argsClass[1] = this.getClass();
argsClass[2] = IFsystem.class;
Class classRef = (Class) uiHandlers.get(id); // then we get the class of
// the
// wanted scriptengine
try {
Constructor con = classRef.getConstructor(argsClass); // and let
// Java find
// the
// correct
// constructor
// matching
// to the
// args
// classes
Object[] args = {seID, this, systemInterface}; // creating the
// args-array
o = (OobdUIHandler) con.newInstance(seID, this, systemInterface); // and finally create
// the object from
// the scriptengine
// class with its
// unique id as
// parameter
} catch (Exception e) {
e.printStackTrace();
}
activeUIHandlers.put(seID, o); // store the new created scriptengine
uiHandlerID = seID;
return seID;
}
/**
* \brief starts the UIHandler
*
* During startup, the core reports all available UIHandler to the User
* Interface to let the user choose with which one he wants to work with.
*
* When all initalisation is been done, it's started with startUIHandler()
* \ingroup visualisation
*
* @param onion addional param
*/
public void startUIHandler(String id, Onion onion) {
if (uiHandler == null) {
Logger.getLogger(Core.class.getName()).log(Level.CONFIG,
"Start UIHandler: " + id);
uiHandler = activeUIHandlers.get(id);
uiHandler.setStartupParameter(onion);
// uiHandler is not a thread, it's called by the UI-Thread instead,
// so we
// Thread t1 = new Thread(uiHandler);
// t1.start();
uiHandler.start();
}
}
/**
* main entry point for all actions required by the different components.
* Can be called either with a onion or with an json-String containing the
* onion data
*
* @param json string representing the onion data
* @return true if the message should be replied to sender
*/
public boolean actionRequest(String jsonString) {
try {
Logger.getLogger(Core.class.getName()).log(Level.INFO,
"required Action:" + jsonString);
return actionRequest(new Onion(jsonString.replace('\'', '"')));
} catch (org.json.JSONException ex) {
Logger.getLogger(Core.class.getName()).log(
Level.SEVERE,
"could not convert JSONstring \"" + jsonString
+ "\" into Onion", ex);
return false;
}
}
/**
* main entry point for all actions required by the different components.
* Can be called either with a onion or with an json-String containing the
* onion data
*
* @param json string representing the onion data
* @return true if the message should be replied to sender
*/
public boolean actionRequest(Onion myOnion) {
try {
if (myOnion.isType(CM_CHANNEL)) {
if ("connect".equalsIgnoreCase(myOnion.getString("command"))) {
this.getMsgPort().sendAndWait(
new Message(Core.getSingleInstance(), BusMailboxName,
new Onion("" + "{'type':'" + CM_BUSTEST + "',"
+ "'command':'" + myOnion.getString("command") + "',"
+ "'connecturl':'"
+ myOnion.getString("connecturl")
+ "'}")), 35000); // 35 secs to
// connect
// to a
// device
// (BT has
// ~30sec
// Timeout)
return true;
}
}
} catch (org.json.JSONException e) {
Logger.getLogger(Core.class.getName()).log(Level.SEVERE,
"JSON exception..");
return false;
}
return false;
}
/**
* @brief add an object to the global data pool, used for most of the
* variables used in OOBD
*
* @param id a numeric identifier, defined in OOBDConstants in DP_ (Data
* Pool) section
* @param data object reference to be stored
*/
public void writeDataPool(int id, Object data) {
synchronized (dataPoolList) {
if (id >= dataPoolList.size()) {
dataPoolList.ensureCapacity(id + 1);
}
dataPoolList.set(id, data);
}
}
/**
* @brief gets an object to the global data pool, used for most of the
* variables used in OOBD
*
* @param id a numeric identifier, defined in OOBDConstants in DP_ (Data
* Pool) section
* @param defaultObject object returned, if object is null
* @return Object
*/
public Object readDataPool(int id, Object defaultObject) {
synchronized (dataPoolList) {
try {
Object data = dataPoolList.get(id);
if (data == null) {
return defaultObject;
}
return data;
} catch (IndexOutOfBoundsException ex) {
return defaultObject;
}
}
}
/**
* @brief removes an object from the global data pool, used for most of the
* variables used in OOBD
*
* @param id a numeric identifier, defined in OOBDConstants in DP_ (Data
* Pool) section
* @return removed object
*/
public Object removeDataPool(int id, Object defaultObject) {
synchronized (dataPoolList) {
return dataPoolList.remove(id);
}
}
/**
* generic hashtable to store several relational data assignments during
* runtine
*
* @param id string identifier
* @param subclass string sub identifier
* @param data object reference to store
* @todo depreciated
*/
public void setAssign(String id, String subclass, Object data) {
assignments.put(id + ":" + subclass, data);
}
/**
* get entry from assigment
*
* @param id string identifier
* @param subclass string sub identifier
* @todo depreciated
*/
public Object getAssign(String id, String subclass) {
return assignments.get(id + ":" + subclass);
}
/**
* remove entry from assignment table
*
* @param id string identifier
* @param subclass string sub identifier
* @todo depreciated
*/
public void removeAssign(String id, String subclass) {
assignments.remove(id + ":" + subclass);
}
/**
* \brief transfer a message to the receiver
*
* @param msg a message, containing sender, receipient and the message
* itself
* @return true, if receipient was known
*
* \ingroup core
*/
public
boolean transferMsg(Message msg) {
Logger.getLogger(Core.class
.getName()).log(
Level.INFO,
"Msg: " + msg.sender + " ==> " + msg.rec + " content:"
+ msg.getContent().toString());
if (OOBDConstants.CoreMailboxName.equals(msg.rec)) { // is the core the
// receiver?
this.sendMsg(msg);
return true;
} else {// find receipient
OobdPlugin receiver = null;
OobdScriptengine scriptEngine = (OobdScriptengine) readDataPool(OOBDConstants.DP_RUNNING_SCRIPTENGINE, null);
if (scriptEngine != null && scriptEngine.getId().equals(msg.rec)) {
receiver = scriptEngine;
}
if (receiver == null
&& OOBDConstants.UIHandlerMailboxName.equals(msg.rec)) {
receiver = activeUIHandlers.get(uiHandlerID);
}
if (receiver == null) {
receiver = busses.get(msg.rec);
}
if (receiver == null) {
receiver = connectors.get(msg.rec);
}
if (receiver == null) {
receiver = protocols.get(msg.rec);
}
if (receiver == null) {
receiver = databases.get(msg.rec);
}
if (receiver != null) {
receiver.sendMsg(msg);
return true;
} else {
Logger.getLogger(Core.class.getName()).log(
Level.WARNING,
"Coudn't send msg to " + msg.rec
+ ":Receiver not in database");
return false;
}
}
}
/**
* a small help routine to output text from elements who don't have an own
* mailbox
*
* @param output the output text
*/
public void outputText(String output) {
try {
core.transferMsg(new Message(Core.getSingleInstance(),
UIHandlerMailboxName, new Onion("{" + "'type':'"
+ CM_WRITESTRING + "'," + "'owner':" + "{'name':'"
+ Core.getSingleInstance().getId() + "'},"
+ "'command':'serDisplayWrite'," + "'data':'"
+ Base64Coder.encodeString(output) + "'" + "}")));
} catch (JSONException ex) {
Logger.getLogger(Core.class
.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* forwards parameter requests to the UI to
*
* @todo extend this function to allow all type of parameter inputs + return
* values to the caller
*
* @param msg the parameter description
*/
public Onion requestParamInput(OobdPlugin sender, Onion msg) {
Onion answer = new Onion();
try {
Onion thisOnion = new Onion("{" + "'type':'" + CM_PARAM + "',"
+ "'owner':" + "{'name':'"
+ sender.getId() + "'}" + "}");
thisOnion.put(CM_PARAM, msg.get(CM_PARAM));
Message answerMsg = sender.getMsgPort().sendAndWait(
new Message(sender, UIHandlerMailboxName,
thisOnion), -1);
if (answerMsg != null) {
answer = answerMsg.getContent();
}
} catch (JSONException ex) {
Logger.getLogger(Core.class
.getName()).log(Level.SEVERE, null, ex);
}
return answer;
}
/**
* a small help routine to output text from elements who don't have an own
* mailbox
*
* @param msg the text to show
*/
public void userAlert(String msg, String windowName) {
try {
Onion msgOnion = new Onion("{'" + CM_DIALOG_INFO + "' : { "
+ "'type':'String'," + "'title':'"
+ Base64Coder.encodeString("Info") + "'," + "'default':'"
// + Base64Coder.encodeString(connectURLDefault)
+ "',"
+ "'window':'"
+ Base64Coder.encodeString(windowName)
+ "',"
+ "'tooltip':'" + Base64Coder.encodeString(msg)
+ "'" + "}}");
Onion thisOnion = new Onion("{" + "'type':'" + CM_DIALOG_INFO + "',"
+ "'owner':" + "{'name':'"
+ Core.getSingleInstance().getId() + "'}" + "}");
thisOnion.put(CM_DIALOG_INFO, msgOnion.get(CM_DIALOG_INFO));
transferMsg(new Message(Core.getSingleInstance(), UIHandlerMailboxName,
thisOnion));
} catch (JSONException ex) {
Logger.getLogger(Core.class
.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* The Central Timer
*
* in here all functions are called which needs a regular run
*
*/
public void coreTick() {
ticker.enable(false);
// updateVisualizers();
ticker.enable(true);
}
/**
* \brief the Core thread
*/
public void run() {
Message thisMsg;
while (runCore == true) {
while ((thisMsg = msgPort.getMsg(100)) != null) { // just waiting
// and handling
// messages
if (actionRequest(thisMsg.content) == true) {
try {
thisMsg.content.setValue("replyID",
thisMsg.content.getInt("msgID"));
} catch (JSONException ex) {
Logger.getLogger(Core.class
.getName()).log(
Level.SEVERE, null, ex);
}
msgPort.replyMsg(thisMsg, thisMsg.content);
}
}
// transferMsg(new Message(this, "ScriptengineTerminal.1", null));
}
}
/**
* \brief starts a scriptengine
*
* During startup, the core reports all available scriptengines to the User
* Interface to let the user choose with which one he wants to work with.
*
* This engine is then been first created with createScriptEngine(), and
* when all initalisation is been done, it's started with
* startScriptEngine() \ingroup visualisation
*
* @param onion addional param
*/
public void startScriptEngine(Onion onion) {
OobdScriptengine o = (OobdScriptengine) readDataPool(OOBDConstants.DP_LAST_CREATED_SCRIPTENGINE, null);
if (o == null) {
o = createScriptEngine("ScriptengineLua", onion);
} else {
o.close();// stop the old engine
o = createScriptEngine("ScriptengineLua", onion);
}
if (o == null) {
Logger.getLogger(Core.class.getName()).log(Level.SEVERE,
"Could not create Scriptengine! ");
return;
}
Logger.getLogger(Core.class.getName()).log(Level.CONFIG,
"Start scriptengine: " + id);
while (core.readDataPool(DP_RUNNING_SCRIPTENGINE, null) != null) {
try {
Thread.sleep(100);
System.out.println("core StartScriptEngine: Old Scriptengine not finished yet");
} catch (InterruptedException ex) {
}
}
o.setStartupParameter(onion);
Thread t1 = new Thread(o);
t1.start();
}
/*
checks, if the URL points to a lbc ActiveArchive. if yes, starts it and returns the path to the start page read out of the manifest ActiveArchive of that script
*/
public String startScriptEngineByURL(String resourceName) {
ArrayList<Archive> files = (ArrayList<Archive>) readDataPool(DP_LIST_OF_SCRIPTS, null);
Archive activeArchive = (Archive) readDataPool(DP_ACTIVE_ARCHIVE, null);
String scriptPath = "";
if (activeArchive != null && resourceName.endsWith(".lbc")) {//lets see if the innerpath points to a lbc ActiveArchive
if (activeArchive.fileExist(resourceName)) {
scriptPath = resourceName; //define the script path relative to the open Archive
//this is a lbc, so lets try to load its own manifest
activeArchive.relocateManifest(resourceName);
}
}
if (files != null && scriptPath.equals("")) { // if the resource does not point to an archive internal lbc ActiveArchive, see if it matches to another archive
for (Archive file : files) {
if (("/" + file.getID()).equalsIgnoreCase(resourceName)) {
activeArchive = file;
writeDataPool(DP_ACTIVE_ARCHIVE, file);
scriptPath = activeArchive.getProperty(OOBDConstants.MANIFEST_SCRIPTNAME, "");
if (!scriptPath.equals("") && !activeArchive.fileExist(scriptPath)) {
scriptPath = "";
}
//lets see if the archive gives us a startpage
resourceName = activeArchive.getProperty(OOBDConstants.MANIFEST_STARTPAGE, resourceName);
}
}
}
if (!scriptPath.equals("") && activeArchive != null) { //if only the root ActiveArchive name is given or the innerpath really points to a .lbc ActiveArchive
writeDataPool(DP_ACTIVE_ARCHIVE, activeArchive);
System.out.println("start scriptengine for " + scriptPath);
startScriptArchive(activeArchive);
return activeArchive.getProperty(MANIFEST_STARTPAGE, OOBDConstants.HTML_DEFAULTPAGEURL);
}
return resourceName;
}
public void startScriptArchive(Archive ActiveArchive) {
String formatURL;
String connectTypeName = (String) core.readDataPool(OOBDConstants.DP_ACTUAL_CONNECTION_TYPE, OOBDConstants.PropName_ConnectTypeBT);
Class<OOBDPort> value;
value = systemInterface.getConnectorList().get(connectTypeName);
try { // tricky: try to call a static method of an interface, where a
// interface don't have static values by definition..
java.lang.reflect.Method method = value.getMethod("getUrlFormat", new Class[]{}); // no parameters
Object instance = null;
formatURL = (String) method.invoke(instance, new Object[]{}); // no parameters
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
Logger.getLogger(Core.class.getName())
.log(Level.WARNING,
"can't call static methods 'getUrlFormat' of "
+ value.getName());
ex.printStackTrace();
return;
}
String connectURL;
String protocol = "";
String domain = "";
String connectID = (String) readDataPool(DP_ACTUAL_CONNECT_ID, "");
//\todo cancel and error message, if connect id is empty
String serverURL = (String) readDataPool(DP_ACTUAL_REMOTECONNECT_SERVER, "");
if (!"".equals(serverURL)) {
String[] parts = serverURL.split("://");
if (parts.length != 2) {
//\todo error message JOptionPane.showMessageDialog(null, "The Remote Connect URL is not a valid URL", "Wrong Format", JOptionPane.WARNING_MESSAGE);
return;
}
protocol = parts[0];
domain = parts[1];
}
if (connectTypeName.equalsIgnoreCase("Kadaver")) {
connectID = Base64Coder.encodeString(connectID); //in Kadaver the remoteId is base64 coded
if (!UIHANDLER_WS_NAME.equalsIgnoreCase((String) readDataPool(DP_ACTUAL_UIHANDLER, ""))) { // no webUI, so rquest the number from the user
try {
Onion answer = getUiIF().requestParamInput(new Onion("{" + "'" + CM_PARAM + "' : [{ " + "'type':'String',"
+ "'title':'" + Base64Coder.encodeString("Enter the Connect Number") + "',"
+ "'default':'" + Base64Coder.encodeString((String) readDataPool(OOBDConstants.DP_ACTUAL_CONNECT_ID, "")) + "',"
+ "'message':'" + Base64Coder.encodeString("Please ask the person, who's connecting the dongle to the vehicle for the Connect Number displayed by his software") + "'"
+ "}]}"));
if (answer == null) {
//\todo error message JOptionPane.showMessageDialog(null, "For Remote Connect you need to enter the Connect Number", "Missing Value", JOptionPane.WARNING_MESSAGE);
return;
}
connectID = answer.getOnionBase64String("answer");
if (connectID == null || connectID.equals("")) {
//\todo error message JOptionPane.showMessageDialog(null, "For Remote Connect you need to enter the Connect Number", "Missing Value", JOptionPane.WARNING_MESSAGE);
return;
}
writeDataPool(OOBDConstants.DP_ACTUAL_CONNECT_ID, connectID);
connectID = Base64Coder.encodeString(connectID); // in the later URL the connect
} catch (JSONException ex) {
Logger.getLogger(Core.class.getName()).log(Level.SEVERE, null, ex);
return;
}
}
}
connectURL = formatURL;
connectURL = connectURL.replace("{protocol}", protocol);
connectURL = connectURL.replace("{connectid}", connectID);
connectURL = connectURL.replace("{urlpath}", domain);
try {
Onion cmdOnion = new Onion("{" + "'scriptpath':'" + ActiveArchive.getFilePath().replace("\\", "/") + "'"
+ ",'connecturl':'" + Base64Coder.encodeString(connectURL) + "'"
+ "}");
core.writeDataPool(DP_ACTIVE_ARCHIVE, ActiveArchive);
startScriptEngine(cmdOnion);
} catch (JSONException ex) {
// TODO Auto-generated catch block
Logger.getLogger(Core.class.getName()).log(Level.WARNING, "JSON creation error with file name:" + ActiveArchive.getFilePath(), ex.getMessage());
}
}
}
/**
*
* \brief Helpclass for Core timer events
*/
class CoreTick implements Runnable {
boolean keepRunning = true;
boolean enableTicks = true;
private static final int LONG_TIME = 100; /* 0.1 Seconds */
CoreTickListener l = null; /*
* Currently only one listener. There could be
* many
*/
public void run() {
Logger.getLogger(Core.class.getName()).log(Level.CONFIG,
" Start Core tick thread");
while (keepRunning) {
try {
Thread.currentThread().sleep(LONG_TIME);
if (enableTicks) {
l.coreTick();
}
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
Logger.getLogger(Core.class.getName()).log(Level.CONFIG,
"End Core tick thread");
}
public void cancel() {
keepRunning = false;
}
public void enable(boolean allow) {
enableTicks = allow;
}
public void setCoreTickListener(CoreTickListener l) {
this.l = l;
}
}
interface CoreTickListener {
public void coreTick();
}