Skip to content

Commit 6887ddc

Browse files
committed
v0.1.6 update
updated Java release flag from 8 to 11 updated Janino dependency from 3.1.8 to 3.1.9 added optional verbose logging to some methods improved script deletion logic modified css for tables
1 parent b620436 commit 6887ddc

File tree

10 files changed

+100
-47
lines changed

10 files changed

+100
-47
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ WebCTRL is a trademark of Automated Logic Corporation. Any other trademarks ment
1212

1313
## About
1414

15-
This add-on allows WebCTRL server administrators to upload and execute scripts, which are written in the Java programming language. Scripts may be compiled and packaged into *.jar* archives (recommended), or they may be interpreted at runtime using [Janino 3.1.8](http://janino-compiler.github.io/janino/) (easy for small scripts, but note that Janino has some [limitations](#janino-limitations)). The add-on does not come prepackaged with any scripts; however, sample scripts may be found within [*./samples*](./samples). Also see the [terminal unit commissioning script](https://github.com/automatic-controls/terminal-unit-script).
15+
This add-on allows WebCTRL server administrators to upload and execute scripts, which are written in the Java programming language. Scripts may be compiled and packaged into *.jar* archives (recommended), or they may be interpreted at runtime using [Janino 3.1.9](http://janino-compiler.github.io/janino/) (easy for small scripts, but note that Janino has some [limitations](#janino-limitations)). The add-on does not come prepackaged with any scripts; however, sample scripts may be found within [*./samples*](./samples). Also see the [terminal unit commissioning script](https://github.com/automatic-controls/terminal-unit-script).
1616

1717
The original purpose of this add-on was to be a customizable alternative to the ACxelerate commissioning tool provided by Automated Logic. Semantic tagging is one concept borrowed from ACxelerate. Before execution, each script is paired with a mapping that associates control program microblock nodes to tag names referenced by the script. Primary script procedures are executed once on each control program specified by a mapping.
1818

@@ -46,13 +46,13 @@ To prevent inadvertent schedule modification, each schedule stores a hash of the
4646

4747
## Script Development
4848

49-
If a single *.java* file is uploaded as a script, then it will be interpreted using [Janino 3.1.8](http://janino-compiler.github.io/janino/) at runtime. **You do not have to configure a development environment for compiling Janino scripts.** In principle, you could develop scripts using only a text editor like *Notepad*. Another advantage of this approach is that you can easily download, edit, and re-upload script source code from any computer with a connection to the WebCTRL server.
49+
If a single *.java* file is uploaded as a script, then it will be interpreted using [Janino 3.1.9](http://janino-compiler.github.io/janino/) at runtime. **You do not have to configure a development environment for compiling Janino scripts.** In principle, you could develop scripts using only a text editor like *Notepad*. Another advantage of this approach is that you can easily download, edit, and re-upload script source code from any computer with a connection to the WebCTRL server.
5050

5151
However, it is recommended that scripts are compiled and packaged into *.jar* archives. Pre-compiled scripts do not suffer from Janino's [limitations](#janino-limitations). Essentially, just throw all your *.class* files into a *.jar* archive. The only special requirement is that a manifest file exist in the *.jar*, and that the `Main-Class` header specifies which class to use as the primary script (this class should extend `aces.webctrl.scripts.commissioning.core.Script`).
5252

5353
Be mindful to compile your script with a version of Java compatible with the target WebCTRL version of your server. For instance, you should use the build flag `--release 8` if you intend the script to run on WebCTRL7.0, and `--release 11` for WebCTRL8.0. See https://jdk.java.net/ to download the latest version of the java development kit.
5454

55-
To ease the development process, it is suggested to use an IDE (e.g, [Visual Studio Code](https://code.visualstudio.com/)), and then add the following dependencies: [CommissioningScripts-0.1.3.jar](https://github.com/automatic-controls/commissioning-scripts/releases/download/v0.1.3-beta/CommissioningScripts-0.1.3.jar) and [CommissioningScripts-0.1.3-sources.jar](https://github.com/automatic-controls/commissioning-scripts/releases/download/v0.1.3-beta/CommissioningScripts-0.1.3-sources.jar). These dependencies will provide you with intellisense and Javadocs for script development. You are also welcome to reference any other dependencies provided by WebCTRL at runtime (e.g, the add-on API, or `javax.servlet`).
55+
To ease the development process, it is suggested to use an IDE (e.g, [Visual Studio Code](https://code.visualstudio.com/)), and then add the following dependencies: [CommissioningScripts-0.1.6.jar](https://github.com/automatic-controls/commissioning-scripts/releases/download/v0.1.6-beta/CommissioningScripts-0.1.6.jar) and [CommissioningScripts-0.1.6-sources.jar](https://github.com/automatic-controls/commissioning-scripts/releases/download/v0.1.6-beta/CommissioningScripts-0.1.6-sources.jar). These dependencies will provide you with intellisense and Javadocs for script development. You are also welcome to reference any other dependencies provided by WebCTRL at runtime (e.g, the add-on API, or `javax.servlet`).
5656

5757
This add-on does not enforce any security restrictions on what scripts can do. Scripts are executed with the same privilege set as the add-on. As such, you must be careful to **use scripts at your own risk.** Note that only WebCTRL server administrators are allowed to manage scripts.
5858

config/BUILD_DETAILS

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
JDK Version:
2-
openjdk 19.0.1 2022-10-18
3-
OpenJDK Runtime Environment (build 19.0.1+10-21)
4-
OpenJDK 64-Bit Server VM (build 19.0.1+10-21, mixed mode, sharing)
2+
openjdk 21.0.2 2024-01-16
3+
OpenJDK Runtime Environment (build 21.0.2+13-58)
4+
OpenJDK 64-Bit Server VM (build 21.0.2+13-58, mixed mode, sharing)
55

66
Compilation Flags:
7-
--release 8
7+
--release 11
88

99
Runtime Dependencies:
10-
addonsupport-api-addon-1.9.0
11-
alarmmanager-api-addon-1.9.0
12-
bacnet-api-core-1.10.002-20230209.1438r
13-
directaccess-api-addon-1.9.0
14-
tomcat-embed-core-9.0.68
15-
webaccess-api-addon-1.9.0
16-
xdatabase-api-addon-1.9.0
10+
addonsupport-api-addon-1.10.0
11+
alarmmanager-api-addon-1.10.0
12+
bacnet-api-core-1.10.007-20240227.1003r
13+
directaccess-api-addon-1.10.0
14+
tomcat-embed-core-9.0.87
15+
webaccess-api-addon-1.10.0
16+
xdatabase-api-addon-1.10.0
1717
core-api-8.0.002
1818
javax.activation-1.2.0
1919
spring-context-5.2.8.RELEASE
2020

2121
Packaged Dependencies:
22-
commons-compiler-3.1.8-sources
23-
commons-compiler-3.1.8
24-
janino-3.1.8-sources
25-
janino-3.1.8
22+
commons-compiler-3.1.9-sources
23+
commons-compiler-3.1.9
24+
janino-3.1.9-sources
25+
janino-3.1.9

config/COMPILE_FLAGS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
--release 8
1+
--release 11

config/EXTERNAL_DEPS

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
url:janino-3.1.8.jar:https://repo1.maven.org/maven2/org/codehaus/janino/janino/3.1.8/janino-3.1.8.jar
2-
url:janino-3.1.8-sources.jar:https://repo1.maven.org/maven2/org/codehaus/janino/janino/3.1.8/janino-3.1.8-sources.jar
3-
url:commons-compiler-3.1.8.jar:https://repo1.maven.org/maven2/org/codehaus/janino/commons-compiler/3.1.8/commons-compiler-3.1.8.jar
4-
url:commons-compiler-3.1.8-sources.jar:https://repo1.maven.org/maven2/org/codehaus/janino/commons-compiler/3.1.8/commons-compiler-3.1.8-sources.jar
1+
url:janino-3.1.9.jar:https://repo1.maven.org/maven2/org/codehaus/janino/janino/3.1.9/janino-3.1.9.jar
2+
url:janino-3.1.9-sources.jar:https://repo1.maven.org/maven2/org/codehaus/janino/janino/3.1.9/janino-3.1.9-sources.jar
3+
url:commons-compiler-3.1.9.jar:https://repo1.maven.org/maven2/org/codehaus/janino/commons-compiler/3.1.9/commons-compiler-3.1.9.jar
4+
url:commons-compiler-3.1.9-sources.jar:https://repo1.maven.org/maven2/org/codehaus/janino/commons-compiler/3.1.9/commons-compiler-3.1.9-sources.jar

root/info.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<extension version="1">
2-
<name>ACES_Tech_Tool_Belt</name>
2+
<name>CommissioningScripts</name>
33
<description>Executes scripts concurrently on groups of equipment to evaluate performance and detect faults.</description>
4-
<version>0.1.4</version>
4+
<version>0.1.6</version>
55
<vendor>Automatic Controls Equipment Systems, Inc.</vendor>
66
</extension>

src/aces/webctrl/scripts/commissioning/core/Initializer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ public void execute(WritableSystemAccess sys){
198198
t.kill();
199199
}
200200
for (Test t:tests){
201-
t.waitForDeath();
201+
t.waitForDeath(-1);
202202
}
203203
kill = true;
204204
dataQueryThread.interrupt();

src/aces/webctrl/scripts/commissioning/core/ResolvedTestingUnit.java

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ public class ResolvedTestingUnit {
3434
public volatile int tries = 3;
3535
/** Specifies how long to wait after failing to read or write a node value. */
3636
public volatile long failedAttemptTimeout = 300L;
37+
/** More error messages will be logged when this is true. */
38+
public volatile boolean verbose = false;
3739
/**
3840
* Constructs a resolved testing unit based on a few relevant pieces of information.
3941
* @param tu is the testing unit to resolve.
@@ -120,7 +122,7 @@ public boolean setValue(final String tag, final Object value) throws Interrupted
120122
* Sets the value of the given node.
121123
* @return {@code true} if the node value was set successfully; {@code false} otherwise.
122124
*/
123-
public static boolean setValue(final Node n, final Object value, final int tries, final long failedAttemptTimeout) throws InterruptedException {
125+
public boolean setValue(final Node n, final Object value, final int tries, final long failedAttemptTimeout) throws InterruptedException {
124126
if (n==null){
125127
return false;
126128
}
@@ -142,6 +144,9 @@ public void execute(WritableSystemAccess sys){
142144
ret.setResult(true);
143145
}catch(Throwable t){
144146
ret.setResult(false);
147+
if (verbose){
148+
Initializer.log(t);
149+
}
145150
}
146151
}
147152
});
@@ -187,6 +192,9 @@ public void execute(WritableSystemAccess sys){
187192
ret.setResult(val.x);
188193
}catch(Throwable t){
189194
ret.setResult(null);
195+
if (verbose){
196+
Initializer.log(t);
197+
}
190198
}
191199
}
192200
});
@@ -232,7 +240,7 @@ public String getValue(String tag) throws InterruptedException {
232240
/**
233241
* @return the value of the node, or {@code null} if the value could not be retrieved.
234242
*/
235-
public static String getValue(Node n, final int tries, final long failedAttemptTimeout) throws InterruptedException {
243+
public String getValue(Node n, final int tries, final long failedAttemptTimeout) throws InterruptedException {
236244
if (n==null){
237245
return null;
238246
}else if (n instanceof LiteralNode){
@@ -251,6 +259,9 @@ public void execute(SystemAccess sys){
251259
ret.setResult(n.getValue());
252260
}catch(Throwable t){
253261
ret.setResult(null);
262+
if (verbose){
263+
Initializer.log(t);
264+
}
254265
}
255266
}
256267
});
@@ -269,7 +280,7 @@ public String getDisplayValue(String tag) throws InterruptedException {
269280
/**
270281
* @return the display value of the node, or {@code null} if the value could not be retrieved.
271282
*/
272-
public static String getDisplayValue(Node n, final int tries, final long failedAttemptTimeout) throws InterruptedException {
283+
public String getDisplayValue(Node n, final int tries, final long failedAttemptTimeout) throws InterruptedException {
273284
if (n==null){
274285
return null;
275286
}else if (n instanceof LiteralNode){
@@ -288,6 +299,9 @@ public void execute(SystemAccess sys){
288299
ret.setResult(n.getDisplayValue());
289300
}catch(Throwable t){
290301
ret.setResult(null);
302+
if (verbose){
303+
Initializer.log(t);
304+
}
291305
}
292306
}
293307
});
@@ -336,6 +350,9 @@ public void execute(WritableSystemAccess sys){
336350
ret.setResult(true);
337351
}catch(Throwable t){
338352
ret.setResult(false);
353+
if (verbose){
354+
Initializer.log(t);
355+
}
339356
}
340357
}
341358
});

src/aces/webctrl/scripts/commissioning/core/Test.java

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,21 @@ public Test(Path scriptFile){
4747
@Override public int hashCode(){
4848
return hash;
4949
}
50-
public void delete(){
50+
public boolean delete(){
5151
if (reserved){
52-
return;
52+
return false;
5353
}
5454
try{
55-
instances.remove(ID);
5655
kill();
57-
Files.deleteIfExists(scriptFile);
56+
if (!waitForDeath(5000L)){
57+
return false;
58+
}
59+
try{
60+
Files.deleteIfExists(scriptFile);
61+
}catch(Throwable t){
62+
return false;
63+
}
64+
instances.remove(ID);
5865
final Path scripts = Initializer.getScriptFolder();
5966
Iterator<ScheduledTest> iter = ScheduledTest.instances.values().iterator();
6067
ScheduledTest st;
@@ -68,9 +75,11 @@ public void delete(){
6875
Initializer.log(t);
6976
}
7077
}
78+
return true;
7179
}catch(Throwable t){
7280
Initializer.log(t);
7381
}
82+
return false;
7483
}
7584
/**
7685
* @return the output of the test, or {@code null} if there is no output.
@@ -163,10 +172,29 @@ public boolean isRunning(){
163172
}
164173
/**
165174
* Waits for this test to terminate.
175+
* @param timeout in milliseconds specifies the maximum duration to wait for death. -1 means wait forever.
176+
* @return whether the test died within the specified timeout
166177
*/
167-
public void waitForDeath() throws InterruptedException {
168-
while (running.get()){
169-
Thread.sleep(500L);
178+
public boolean waitForDeath(long timeout) throws InterruptedException {
179+
if (!running.get()){
180+
return true;
181+
}
182+
if (timeout==-1){
183+
while (running.get()){
184+
Thread.sleep(500L);
185+
}
186+
return true;
187+
}else{
188+
final long x = System.currentTimeMillis()+timeout;
189+
long d;
190+
while (running.get()){
191+
d = x-System.currentTimeMillis();
192+
if (d<=0){
193+
break;
194+
}
195+
Thread.sleep(Math.min(500L,d));
196+
}
197+
return !running.get();
170198
}
171199
}
172200
/**

src/aces/webctrl/scripts/commissioning/html/main.css

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,13 @@ th {
9696
background-color:darkslategray;
9797
}
9898
table {
99-
border-collapse:collapse;
99+
border-collapse:separate;
100+
border-spacing:0;
100101
margin:0 auto;
101102
}
103+
tr {
104+
border-collapse:collapse;
105+
}
102106
thead {
103107
border:solid 3px white;
104108
}

src/aces/webctrl/scripts/commissioning/web/ScriptPage.java

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,17 @@ public class ScriptPage extends ServletBase {
5757
}
5858
final Path script = Initializer.getScriptFolder().resolve(fileName);
5959
Test newTest = null;
60-
for (Test te:Test.instances.values()){
61-
if (Files.isSameFile(script,te.getScriptFile())){
62-
if (te.reserved){
63-
Initializer.log(new FileAlreadyExistsException("Cannot overwrite permanent script: "+fileName));
64-
res.setStatus(400);
65-
return;
60+
if (Files.exists(script)){
61+
for (Test te:Test.instances.values()){
62+
if (Files.isSameFile(script,te.getScriptFile())){
63+
if (te.reserved){
64+
Initializer.log(new FileAlreadyExistsException("Cannot overwrite permanent script: "+fileName));
65+
res.setStatus(400);
66+
return;
67+
}
68+
newTest = te;
69+
break;
6670
}
67-
newTest = te;
68-
break;
6971
}
7072
}
7173
{
@@ -215,8 +217,10 @@ public class ScriptPage extends ServletBase {
215217
String err = "Cannot delete permanent script.";
216218
res.sendError(400, err);
217219
Initializer.log(new IllegalAccessError(err));
218-
}else{
219-
t.delete();
220+
}else if (!t.delete()){
221+
String err = "Script could not be deleted. Please try again in a few moments.";
222+
res.sendError(400, err);
223+
Initializer.log(new IllegalAccessError(err));
220224
}
221225
break;
222226
}

0 commit comments

Comments
 (0)