3.3 KiB
| task | version | source | status |
|---|---|---|---|
| Write and load a Java PROCESS Service class | R1.03 | IM 36K10P11-01EN §1–§5, §10; IM 36K10L10-01EN §1; practiced with CI-Eng-Sample class CIENG_JFLOW 2026-09-30 | 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 itemCI-Eng-Sample.TANK1.JFLOW.sPerMin— automatic names keep the identifier's case, anditmvalneeds that exact case (…SPERMINis not found). Give a"NAME"if you want upper-case item names. INFLOW120 →sPerMin2; 90 → 1.5.systemMessage()appears inumhlog.logfromOPCJEXEasUMH-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.sPerMinand section…TANK1.JFLOW;INFLOWstayed.
4. Pitfalls (manual)
- Definitions (
define…()) only at class level, withoutpublic/private. create()/destroy()run in a different process than the trigger methods: only attributes keep values between them; no timers or signal values increate().- 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).