139 lines
8.3 KiB
Markdown
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.
|