ci-server-engineer/knowledge/manuals/IM36K10P11-01EN.md
cliu f9f6bf59db Add phase 6 PROCESS Service manual summaries (L10, P10, P11)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 17:49:49 +10:00

139 lines
8.3 KiB
Markdown

---
manual: IM 36K10P11-01EN
title: Class Description Language - Java
edition: 3rd Edition, Sep. 2023
version: R1.03
status: from docs; a Java class (attachItemToSignal, createItemForSignal with automatic name, Signal.Trigger.VALUE, signalEvent, systemMessage) compiled on quick load and run on the test system with CI-Eng-Sample class CIENG_JFLOW on 2026-09-30; everything else from docs
---
# Java PROCESS Service language (R1.03)
Summary in own words; section numbers refer to the manual. Engineering: `IM36K10L10-01EN.md`,
skill `class-object-engineering`. The full API reference is only in the Engineering Module
class editor (F1).
## 1. What Java adds (§1)
Arrays of signals/attributes, loops, inheritance (`extends` another PROCESS class), any Java
library (TCP/IP, files, web services), and signals that need not be attached. Java and
Traditional classes cannot contain each other. Compiled by `OPCJCOM`, created by `OPCJACT`, run
by `OPCJEXE` (see L10 summary).
## 2. Class layout (§1.1, §3)
```java
import fasttools.processfast.*; // the framework; import other packages as usual
public class CIENG_JFLOW extends ProcessClass { // name = class name in CLASS_DF, exactly
// definitions: class level only, no public/protected modifiers
Signal sInflow = defineDoubleSignal(Signal.Trigger.VALUE);
Signal sPerMin = defineDoubleSignal();
Attribute aCapacity = defineDoubleAttribute(Attribute.Scope.OBJECT);
Timer tCheck = defineTimer();
public void create() { /* object created: attach or create items */ }
public void destroy() { /* object deleted (items are detached automatically) */ }
public void start() { /* object starts: after create and at every CI Server start */ }
public void stop() { /* CI Server stops (not guaranteed, e.g. HA switch) */ }
public void signalEvent(Signal signal) { }
public void timerEvent(Timer timer) { }
public void triggerGroupEvent(TriggerGroup triggerGroup) { }
}
```
Naming advice: `s…` signals, `a…` attributes, `t…` timers, `c…` containments, `m…` locals;
identifiers max 15 characters. Omit methods you do not need.
**Two environments** (§3.4, important): `create()`/`destroy()` run in the *creation*
environment (`OPCJACT`), everything else in the *runtime* environment (`OPCJEXE`). Signals have
items only at runtime; timers only at runtime; plain Java fields and objects set in `create()`
are gone at runtime — only **attributes** carry values across. Static fields are not shared
between objects of different priorities. Share data through class-scope attributes or items.
## 3. Signals (§4)
- `defineIntegerSignal()`, `defineDoubleSignal()`, `defineStringSignal()` (string max 79
characters); `…SignalArray(n)` or `…SignalArray(trigger, n)`; max 4095 signals per class.
- Triggers: `Signal.Trigger.VALUE | STATUS | OPTION | UPDATE | FIRST | PIT | LIMIT | QUALITY`
as argument of `define…Signal()`. Without it the signal never triggers.
- In `create()`:
- `attachItemToSignal(sig, "<item>")` — the item must exist, else creation is cancelled and
rolled back.
- `createItemForSignal(sig, "<template>[;<station>:<template point>]", "FIELD", value, …)` —
any `ITEM_DF` field; `"STORAGE_GROUP", "<group>"` followed by `ITEM_HIS_DF` fields (order
matters, max 4 groups); with a point, prefix shared names: `"ITEM'DESCRIPTION"`,
`"POINT'DESCRIPTION"`, and use the station's point dataset fields (`STATION`,
`IO_ADDRESS` …). Sub-items: template must be a sub-item, main item must exist, name required.
- Without `"NAME"` the framework names the item `<object>.<signal identifier>` and creates
the sections; **the identifier's case is kept** (verified: `CI-Eng-Sample.TANK1.JFLOW.sPerMin`;
item names are case-sensitive for `itmval`). Framework-created items and sections are
deleted with the object (verified) unless *Leave items* is set.
- `createSection(path, description, process areas, blocked, opcVisible)` creates sections
you name yourself; the framework cannot always undo these — prefer automatic names.
- Name helpers: `getTag()`, `getSectionsPath()`, `getSections()`, `getFullIdentifierPath(x)`,
`getContainerIdentifierName()`, `getContainerIdentifierPath()`, `getNode()`.
- Unattached signals: `sig.isAttached()`; most methods throw on an unattached signal.
- Handling: override `signalEvent(Signal signal)` and compare with `==`, or add a named inner
class implementing `SignalListener` in `start()` (`addSignalListener`); **anonymous listeners
compile but fail at start** (`NoClassDefFoundError` in the log).
- The signal passed to the handler holds the attribute values of the moment of the trigger.
- Common methods: `getValueAsDouble/Integer/String()`, `getOldValueAs…()`, `setValue(x)`,
`setValueAndStatus(x, Signal.Status.MANUAL)`, `setStatusNumber(Signal.Status.FAILED)`,
limits `get/setHighLimit()` … (throw when the item has no such limit — catch it),
`isOffline()`, `setOffline()`, `isBlocked()`, `getQuality()`, `getUpdateTime()`,
`getValueAsDoubleAndReset()` (sub-items), `setValueAndTime()`.
- Control item: `hasControlSignal()`, `getControlSignal()`; blocked control item = triggers
ignored.
## 4. Attributes (§5)
`defineIntegerAttribute(scope)`, `defineDoubleAttribute(scope)`, `defineStringAttribute(scope)`
(string max 255), `…AttributeArray(scope, n)`; scope `Attribute.Scope.OBJECT` or `.CLASS`.
Prompts: `defineStringAttributeForPrompt("Question:")` (always OBJECT scope; max 100 prompts);
read it in `create()` and call `cancel("message")` to refuse the object (rolls back). Attributes
survive restarts and are visible in the Engineering Module, but writing them is heavy (disk,
and for CLASS scope every runtime) — use them for settings, not process values.
## 5. Timers and trigger groups (§6, §7)
- `defineTimer()` (no arrays; not usable in `create()`/`destroy()`); `t.start(10)` or
`setTime(10)` + `start()`; `setRepeat(true)`; `cancel()`; resolution 1 s. Handle in
`timerEvent()` or with a named `TimerListener`.
- Trigger groups are assigned in engineering (class or object), not in code; handled in
`triggerGroupEvent(tg)` (`tg.getName()`, `tg.getInterval()`, `TriggerGroup.Interval.…`).
Use a trigger group for periodic work, a timer for "check again after a while". ONCE groups
are unnecessary: use `start()`.
## 6. Containment and inheritance (§8, §9)
- `VALVE cGas = (VALVE)defineContainment("VALVE");` — never `new VALVE()`. Prompts of a
contained class become normal attributes: set them in the container's `create()`
(`cGas.aStation.setValue(…)`).
- `create()`/`destroy()` of contained classes are called automatically after the container's
(`call(cX).create()` to force order); `start()`/`stop()` and the `…Event()` methods are **not**
— call or forward them yourself, or use listeners in the contained class.
- Inheritance: `public class BOILER_MIXER extends BOILER`; call `super.create()`,
`super.signalEvent(signal)` etc.; prompts of the super class are kept. A shared base class
(e.g. `BASE_CLASS extends ProcessClass`) holds helper methods; each subclass loads its own
copy (no shared statics). Plain Java code can go in a jar in `%TLS_ROOT_PATH%\tls\exe`; its
classes must have a package name.
## 7. Runtime behaviour (§10)
- Keep trigger methods short, never sleep: one object holds up all objects **of the same
priority** (one thread per priority). Give slow objects their own priority, or extra
executors per priority range.
- Exceptions in `create()` cancel the creation; in a trigger method they abort that trigger and
are logged. Use `try/catch`.
- `systemMessage("text")` writes to the message log (`umhlog.log`, sender `OPCJEXE`, prefixed
with the object name — verified); `cancel("text")` also stops the current trigger.
- `getStatistics()` → processed/lost/queued events, execution times.
- The manual says a changed class must be compiled **and reset**, and a new class reset before
its first object. On the test system a new class compiled by quick load ran its first object
without a reset (ISS-029); after changing a class with objects, reset it (skill task
`change-reset-class.md`).
- Release notes (IM 36K01A50): Java classes that use datasets must get the session with
`getDssSession()` and never close it.
## 8. Examples in the manual (Appendix 1)
Valve, boiler (containment), twin boiler, mixer boiler (inheritance), city temperature.