87 lines
3.3 KiB
Markdown
87 lines
3.3 KiB
Markdown
---
|
||
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).
|