--- 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, (: )`. - 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).