Full manual diffs (L15, C20, E30, L25, J40, C10 §2, L10, P10, P11, J20, C30, P20, R40, E10) and read-only checks on the shared R1.05 test server. Skills and summaries moved to R1.05; new skill pytools (IM 36K10P40) from docs (no Python on the test server). Issues ISS-132..181; corrections to version-differences (E10, E30, P11, dss_ath_grp_u0104); C10 summary lists the 3 new authorization actions; r105-verification V10-V17. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
114 lines
5.7 KiB
Markdown
114 lines
5.7 KiB
Markdown
---
|
||
task: Write and load a Java PROCESS Service class
|
||
version: R1.05 (first written for R1.03)
|
||
source: IM 36K10P11-01EN 4th ed. (Feb. 2026) §1–§5, §10; IM 36K10L10-01EN §1; practiced with CI-Eng-Sample class CIENG_JFLOW 2026-09-30
|
||
status: verified on R1.03 (2026-09-30); re-tested on R1.05 2026-10-08 (CIENG_JFLOW compiled on load, sPerMin 2 for inflow 120, removed). Public API of fasttools.processfast compared with javap on 2026-10-09: identical to R1.03. systemMessage() output and the reset after a change were not re-tested on R1.05
|
||
---
|
||
|
||
# Java class
|
||
|
||
Worked example: class `CIENG_JFLOW`, object `CI-Eng-Sample.TANK1.JFLOW`
|
||
(`examples/CI-Eng-Sample/06_class_df.qli`, `07_object_df.qli`). Language reference:
|
||
`knowledge/manuals/IM36K10P11-01EN.md`. Loading and removing: `load-class-object.md`.
|
||
|
||
Choose Java when you need loops, arrays of signals, inheritance, libraries, or signals that may
|
||
stay unattached; otherwise the Traditional language is simpler.
|
||
|
||
## 1. Class record
|
||
|
||
Same as a Traditional class but `PF_LANGUAGE` = `"Java"` (cannot be changed later) and Java
|
||
source in `METHOD`. The Java class name must equal the `CLASS_DF` name exactly.
|
||
|
||
```
|
||
@FIELDS
|
||
NAME,DESCRIPTION,PF_LANGUAGE,TRIGGER_1,COMPILE,LISTING_WANTED,METHOD
|
||
|
||
@CLASS_DF
|
||
"CIENG_JFLOW","Inflow per minute (Java)","Java","",1,0,@"
|
||
import fasttools.processfast.*;
|
||
|
||
public class CIENG_JFLOW extends ProcessClass {
|
||
|
||
Signal sInflow = defineDoubleSignal(Signal.Trigger.VALUE);
|
||
Signal sPerMin = defineDoubleSignal();
|
||
|
||
public void create() {
|
||
attachItemToSignal(sInflow, getSectionsPath() + ".INFLOW");
|
||
createItemForSignal(sPerMin, "CI-Eng-Sample.TEMPLATES.TPL_REAL",
|
||
"DESCRIPTION", "Tank inflow (m3/min), class CIENG_JFLOW");
|
||
}
|
||
|
||
public void signalEvent(Signal signal) {
|
||
double mInflow = sInflow.getValueAsDouble();
|
||
sPerMin.setValue(mInflow / 60.0);
|
||
systemMessage("CIENG_JFLOW " + getTag() + ": inflow " + mInflow);
|
||
}
|
||
}
|
||
"@
|
||
```
|
||
|
||
`OPCMAN` starts the Java compiler `OPCJCOM` on demand; allow ~15 s, then export the class and
|
||
check `VALID_METHOD` = 1 (as in `load-class-object.md`).
|
||
|
||
## 2. Object
|
||
|
||
```
|
||
@FIELDS
|
||
NAME,DESCRIPTION,CLASS
|
||
|
||
@OBJECT_DF
|
||
"CI-Eng-Sample.TANK1.JFLOW","Tank 1 inflow per minute (Java)","CIENG_JFLOW"
|
||
```
|
||
|
||
Prompts: `Attribute aX = defineStringAttributeForPrompt("…");` → answer in `ATTR_VALUE_n`;
|
||
refuse bad answers with `cancel("text")` in `create()`.
|
||
|
||
## 3. Results on the test system
|
||
|
||
- Signals: `sInflow` → `CI-Eng-Sample.TANK1.INFLOW`; `sPerMin` → created item
|
||
**`CI-Eng-Sample.TANK1.JFLOW.sPerMin`** — automatic names keep the identifier's case, and
|
||
`itmval` needs that exact case (`…SPERMIN` is not found). Give a `"NAME"` if you want
|
||
upper-case item names.
|
||
- `INFLOW` 120 → `sPerMin` 2; 90 → 1.5.
|
||
- `systemMessage()` appears in `umhlog.log` from `OPCJEXE` as
|
||
`UMH-I-INFO, (<object>: <text>)`.
|
||
- The first object ran without resetting the new class, although the manual asks for a reset
|
||
(ISS-029). After changing a Java class that has objects, compile **and reset** it
|
||
(`change-reset-class.md`).
|
||
- Deleting the object deleted `…JFLOW.sPerMin` and section `…TANK1.JFLOW`; `INFLOW` stayed.
|
||
|
||
## 4. Java on R1.05 (checked 2026-10-09)
|
||
|
||
- Runtime: the JDK in `%TLS_ROOT_PATH%\tls\jre` is Eclipse Temurin **11.0.28** (R1.03:
|
||
11.0.18). Same Java 11 language level; write classes for Java 11.
|
||
- API: the public classes and methods of `fasttools.processfast` (in `tls\exe\jopcsrv.jar`)
|
||
are the same as on R1.03 (`javap -public`; the jar itself was rebuilt).
|
||
- `createSection(path, description, blocked, opcVisible)` takes **four** arguments on both
|
||
versions. The manual's examples pass a fifth (an empty process-area string) and would not
|
||
compile as printed; R1.05 §10.2 now describes it correctly (ISS-154; not compile-tested).
|
||
- The API has methods that P11 does not describe (ISS-159): `getHistory(...)` (item history
|
||
as `ValueSample[]`, several overloads), `defineIntegerAttributeForPrompt` /
|
||
`defineDoubleAttributeForPrompt` (P11 only names the String version),
|
||
`sendAndReceiveMessage(...)` (BUS request/reply) and `getDssSession()` (release notes).
|
||
Their behaviour is not documented here; test before relying on them.
|
||
- Extra jars: the Java PROCESS processes (`OPCJCOM`, `OPCJACT`, `OPCJEXE`) put `tls\exe\*`
|
||
and, on R1.05, also `tls\exe\lib\*` (bundled third-party jars) on the class path.
|
||
Your own library jar still goes in `tls\exe` (P11 §9).
|
||
- OPC UA methods (R1.04+): method objects are Java (or Traditional) objects with the
|
||
attribute `MTD_KEY` and signals `MTD_TRG`, `MTD_RET`, `MTD_IN_ARG_n`, `MTD_OUT_ARG_n`. The
|
||
installed sample classes are the starting point: `UAC_MTD_JBASE` (CI Server as OPC UA
|
||
client; prompts for the method key `<station>:<method>` and for the input and output
|
||
argument lists written as `/type/description`, type f, i, s or b, at most 10 each) and
|
||
`UAS_MTD_JBASE` (method offered by the CI Server OPC UA server; your logic runs when
|
||
`MTD_TRG` becomes 1 and must set the outputs, then `MTD_RET` if needed, then `MTD_TRG` 0 =
|
||
good or 2 = bad). Use one class with its own name per method object. Procedure: skill
|
||
`data-access`, `opcua-client.md` §7, and the L45 summary (§10.6, §11.4). Not practiced.
|
||
|
||
## 5. Pitfalls (manual)
|
||
|
||
- Definitions (`define…()`) only at class level, without `public`/`private`.
|
||
- `create()`/`destroy()` run in a different process than the trigger methods: only attributes
|
||
keep values between them; no timers or signal values in `create()`.
|
||
- Never sleep or loop long in a trigger method: it blocks all objects of the same priority.
|
||
- No anonymous listener classes (fail at object start with `NoClassDefFoundError`).
|
||
- Dataset access: get the session with `getDssSession()` and never close it (release notes).
|