ci-server-engineer/.claude/skills/class-object-engineering/tasks/java-class.md
cliu 516729ff24 R1.05 findings from a user project (tested only)
Tested on the R1.05 test server 2026-10-09..12 with a user project (own
objects only); not yet on CI-Eng-Sample (ISS-188). Only results that
were tested are included; inferences, code-only and manual-only points
and the untested sample layout change were left out.
- layouts: 'logout' is a secondary logout, always disabled on the R1.05
  web client; 'exit' closes the window and ends the session (ISS-182).
- create-display: R1.05 web client table (String items in text vs
  textField, fixed text alignment, start-hidden limits ISS-183, two
  visibility conditions, On entry display actions, rectangle blinking,
  verified connections, first load).
- java-class 4a: signal arrays at scale, write on change, attribute
  arrays, offline javac/javap check; change-reset-class: new signals need
  the object recreated, attributes lost (ISS-185); opcdbg reset in cmd,
  TRIGGER_1 via dssqld -m.
- string-items (ISS-187), users-groups, modbus-station (400 registers,
  comm loss), export-dataset (NAME range filter), item-alarming.
- new task system-management/package-project.md; tools/ModbusSim.java
  (tested on R1.05: FC03/04/06/16, exceptions, modes); AMSI (ISS-186).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 21:57:08 +11:00

138 lines
7.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
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.
## 4a. Large classes on R1.05 (verified 2026-10-12, user project on the R1.05 test server, 2026-10-09 to 10-12)
A Java class with about 1,600 signals ran on R1.05 every second without problems:
- **Signal arrays**: `Signal[] t = defineDoubleSignalArray(400);` (also `defineIntegerSignalArray`,
`defineStringSignalArray`), attached in a loop in `create()`:
`for (int k = 0; k < 400; k++) attachItemToSignal(t[k], "<Section>.TEMP." + name(k));`.
Signals without a trigger, plus `TRIGGER_1` = a trigger group and `triggerGroupEvent(TriggerGroup tg)`,
give one run per second for all inputs.
- **Write only on change**: the class compared with `getValueAsDouble()` / `getValueAsString()`
before `setValue()` (and also wrote when `getStatusNumber() == Signal.Status.NOT_INIT`).
- **String signals**: `setValue(String)` on a String item works.
- **Attribute arrays** (`defineDoubleAttributeArray(Attribute.Scope.OBJECT, n)`) keep their values
over a class reset; Java fields do not (initialise them in the first trigger run, not in
`create()`). Attributes are **lost when the object is deleted** (verified: after remove and
insert the new object found them empty and logged that it rebuilt the data from items; see
`change-reset-class.md` §3).
- **Compile check before loading** (no CI Server change):
`"%TLS_ROOT_PATH%\tls\jre\bin\javac.exe" -Xlint:all -cp "%TLS_ROOT_PATH%\tls\exe\jopcsrv.jar" -d cls <Class>.java`.
The exact API: `javap -cp %TLS_ROOT_PATH%\tls\exe\jopcsrv.jar fasttools.processfast.ProcessClass`
(also `Signal`, `Attribute$Scope`, `Signal$Trigger`, `Signal$Status` constants, e.g. `NOT_INIT` 13).
- **Keep quick load lines short**: put long generated arrays (tables in the class source) on several
lines; the class loaded with lines up to 233 characters.
## 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).