ci-server-engineer/.claude/skills/class-object-engineering/tasks/java-class.md
cliu f99490378c Extend class-object-engineering skill: language, Java, reset, opcdbg tasks
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 17:49:49 +10:00

87 lines
3.3 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.03
source: IM 36K10P11-01EN §1–§5, §10; IM 36K10L10-01EN §1; practiced with CI-Eng-Sample class CIENG_JFLOW 2026-09-30
status: verified
---
# 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. 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).