Skip to content

Commit

Permalink
Move Codec to ...ribose.base package
Browse files Browse the repository at this point in the history
Follow up for issue #36 (see comments in #36 for interface changes).

- make Codec accessible to effectors and include it in the javadoc
- impacts import statements only in almost all of the touched files
- javadoc updates to IEffector, IOutput
- minor edit in README

Signed-off-by: jrte <jrte.project@gmail.com>
  • Loading branch information
jrte committed Oct 9, 2023
1 parent 87f6054 commit febd0b4
Show file tree
Hide file tree
Showing 16 changed files with 82 additions and 54 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ null = (
Tintervals = (interval* null*)*;
```
Nullification can be applied similarly to subpatterns to effect fine-grained context-sensitive error handling. The general technique of flattening a transducer pattern and transforming it with an editor pattern while projecting the result back onto the original tapes can be applied in many other ways. Like [CRISPR](https://www.newscientist.com/definition/what-is-crispr/) in genetics, it can be used to inject new behaviors or alter existing behaviors in transducer patterns. The `null` expression above preserves the interleaving of input and effectors in the nullified `interval` pattern up to the first `nul` signal and replaces the remainder with a pattern that synchronizes at the opening of the next XML stanza. If no effectors are involved the same result can be expressed more succinctly as shown in the next example.
## Resolving Ambiguous Inputs (Classification)
### Resolving Ambiguous Inputs (Classification)
It is sometimes necessary to look ahead in the input, without effect, to syntactically validate a prospective feature or resolve an ambiguous pattern before selecting a course of action. The snippet below, from the `LinuxKernelStrict` transducer in the ribose test suite, demonstrates this using the `mark` and `reset` effectors. The _`header`_ and _`capture`_ subpatterns, referenced but not shown here, effect field extraction from iptables messages in Linux kernel logs.
```
#May 15 07:58:52 kb-ubuntu kernel: [ 1794.599801] DROPPED IN=eth0 OUT= MAC=01:00:5e:00:00:fb:00:13:20:c0:36:32:08:00 SRC=192.168.144.101 DST=224.0.0.251 LEN=32 TOS=0x00 PREC=0x00 TTL=1 ID=8596 OPT (94040000) PROTO=2
Expand Down
1 change: 1 addition & 0 deletions src/com/characterforming/jrte/engine/Model.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import com.characterforming.ribose.base.BaseEffector;
import com.characterforming.ribose.base.BaseParameterizedEffector;
import com.characterforming.ribose.base.Bytes;
import com.characterforming.ribose.base.Codec;
import com.characterforming.ribose.base.CompilationException;
import com.characterforming.ribose.base.EffectorException;
import com.characterforming.ribose.base.ModelException;
Expand Down
1 change: 1 addition & 0 deletions src/com/characterforming/jrte/engine/ModelCompiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import com.characterforming.ribose.IToken.Type;
import com.characterforming.ribose.base.BaseEffector;
import com.characterforming.ribose.base.Bytes;
import com.characterforming.ribose.base.Codec;
import com.characterforming.ribose.base.CompilationException;
import com.characterforming.ribose.base.DomainErrorException;
import com.characterforming.ribose.base.EffectorException;
Expand Down
1 change: 1 addition & 0 deletions src/com/characterforming/jrte/engine/ModelLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import com.characterforming.ribose.ITransductor.Metrics;
import com.characterforming.ribose.base.BaseParameterizedEffector;
import com.characterforming.ribose.base.Bytes;
import com.characterforming.ribose.base.Codec;
import com.characterforming.ribose.base.DomainErrorException;
import com.characterforming.ribose.base.EffectorException;
import com.characterforming.ribose.base.ModelException;
Expand Down
1 change: 1 addition & 0 deletions src/com/characterforming/jrte/engine/Transductor.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import com.characterforming.ribose.base.BaseEffector;
import com.characterforming.ribose.base.BaseParameterizedEffector;
import com.characterforming.ribose.base.Bytes;
import com.characterforming.ribose.base.Codec;
import com.characterforming.ribose.base.DomainErrorException;
import com.characterforming.ribose.base.EffectorException;
import com.characterforming.ribose.base.ModelException;
Expand Down
2 changes: 1 addition & 1 deletion src/com/characterforming/jrte/test/FileRunner.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@
import java.util.regex.Pattern;

import com.characterforming.jrte.engine.Base;
import com.characterforming.jrte.engine.Codec;
import com.characterforming.ribose.IModel;
import com.characterforming.ribose.ITransductor;
import com.characterforming.ribose.ITransductor.Metrics;
import com.characterforming.ribose.base.Bytes;
import com.characterforming.ribose.base.Codec;
import com.characterforming.ribose.base.Signal;

public class FileRunner {
Expand Down
2 changes: 1 addition & 1 deletion src/com/characterforming/jrte/test/TestRunner.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@
import java.util.regex.Pattern;

import com.characterforming.jrte.engine.Base;
import com.characterforming.jrte.engine.Codec;
import com.characterforming.ribose.IModel;
import com.characterforming.ribose.ITransductor;
import com.characterforming.ribose.ITransductor.Status;
import com.characterforming.ribose.base.Bytes;
import com.characterforming.ribose.base.Codec;
import com.characterforming.ribose.base.Signal;

public class TestRunner {
Expand Down
2 changes: 1 addition & 1 deletion src/com/characterforming/jrte/test/TestTarget.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

import java.nio.charset.CharacterCodingException;

import com.characterforming.jrte.engine.Codec;
import com.characterforming.ribose.IEffector;
import com.characterforming.ribose.IOutput;
import com.characterforming.ribose.ITarget;
import com.characterforming.ribose.base.BaseEffector;
import com.characterforming.ribose.base.Codec;
import com.characterforming.ribose.base.EffectorException;
import com.characterforming.ribose.base.Signal;
import com.characterforming.ribose.base.TargetBindingException;
Expand Down
90 changes: 53 additions & 37 deletions src/com/characterforming/ribose/IEffector.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,32 +22,46 @@

import com.characterforming.ribose.base.BaseEffector;
import com.characterforming.ribose.base.Bytes;
import com.characterforming.ribose.base.Codec;
import com.characterforming.ribose.base.EffectorException;

/**
* Interface for simple effectors that present only a niladic {@link #invoke()}
* method which is called on live effector instances in response to state transitions
* in a running transduction. Simple effector implementations must extend {@link
* BaseEffector} and implement {@link invoke()} and may override other base effector
* methods. They are typically implemented as anonymous inner classes within a specialized
* {@link ITarget} implementation classes. Proxy simple effectors, instantiated in model
* compilation and loding contexts, receive {@link #setOutput(IOutput)} and {@link #passivate()}
* but never receive {@link #invoke()}. They lose access to their {@link ITarget} instance
* when they are passivated, {@link #getTarget()} will return {@code null}. Live simple
* effectors instantiated in runtime contexts receive {@link #setOutput(IOutput)} once
* in a running transduction. The {@link BaseEffector} superclass provides default
* implementations for all other {@code IEffector} methods. Subclassess must implement
* {@link #invoke()} and may override other base effector methods. They are typically
* implemented as anonymous inner classes within a specialized {@link ITarget}
* mplementation classes. Conversion between Java/Unicode char and UTF-8 byte are
* supported by static {@link Codec} methods backed by thread local encoder and
* decoder bound instances. Ribose and ginr currently support only UTF-8 character
* encodings.
* <br><br>
* Proxy simple effectors, instantiated in model compilation and loding contexts,
* receive {@link #setOutput(IOutput)} when they are bound to a proxy transductor
* and target for parameter compilation. When parameter compilation completes they
* receive {@link #passivate()} and lose access to their {@link ITarget} and {@link
* IOutput} instances.
* <br><br>
* Live simple effectors instantiated in runtime contexts receive {@link #setOutput(IOutput)}
* followed by 0 or more {@link #invoke()}. Live effectors are never passivated and may
* use {@link #getTarget()} in their {@link #invoke()} methods.
* use {@link #getTarget()} in their {@link #invoke()} methods. Simple effectors that
* must access transducer fields may override {@link #setOutput(IOutput)} to look up
* localized field indexes using {@link IOutput#getLocalizedFieldIndex(String, String)}
* and retain these for subsequent use with the {@link IOutput} data transfer methods
* in {@link #invoke()}.
* <br><br>
* All effectors return an integer <a href="#field.summary">RTX</a> code, which is a bit
* map of special conditions. RTX bits are additive and accumulate as the effect vector is
* executed for a transition. Specialized effectors should return only {@code RTX_NONE}
* (to continue transduction normally) or a signal encoded using {@link IOutput#signal(int)}.
* Care should be taken to ensure that at most one effector in any effect vector may
* return an encoded signal. The built-in {@code count} and {@code signal} effectors and
* any specialized target effectors that return encoded signals should never appear in
* combination within a single effector vector, and this condition can be checked in
* the pattern domain. An {@code EffectorException} will be thrown from {@link ITransductor#run()}
* if the decoded signal is out of range, but mixed signals that remain in range will
* All {@link #invoke()} implementations return an integer <a href="#field.summary">RTX
* </a> code, which is a bit map of special conditions. RTX bits are additive and
* accumulate as an effect vector is executed for a transition. Specialized effectors
* should return only {@code RTX_NONE} (to continue transduction normally) or a signal
* encoded using {@link IOutput#signal(int)}. Care should be taken to ensure that at
* most one effector in any effect vector may return an encoded signal. The built-in
* {@code count} and {@code signal} effectors and any specialized target effectors
* that return encoded signals should never appear in combination within a single
* effector vector, and this condition can be checked in the pattern domain. An
* {@code EffectorException} will be thrown from {@link ITransductor#run()} if the
* decoded signal is out of range, but mixed signals that remain in range will
* go undetected (or force a domain error and transition on {@code nul}).
* <br><br>
* To verify that transducer <b>T</b> from a model using signalling effectors in
Expand All @@ -57,8 +71,10 @@
* must be empty. In general, range constraints on the effector set can be
* expressed as patterns to be tested against transducer patterns in the design
* stage, before they are saved to ginr FSTs for inclusion in ribose models.
*
* @param <T> The effector target type
* @see IParameterizedEffector
* @see BaseEffector
* @author Kim Briggs
*/
public interface IEffector<T extends ITarget> {
Expand Down Expand Up @@ -99,6 +115,24 @@ int invoke()
void setOutput(IOutput output)
throws EffectorException;

/**
* Called for proxy effectors after parameter compilation is
* complete. This will null out the target and output fields
* in the {@code BaseEffector} superclass. This allows the
* proxy model and transducer to be garbage collected after
* all effector parameters have been compiled. Subclasses
* may override this method to dispose of additional resources
* as well, but must also call {@code super.passivate()} in
* the overriding method.
* <br><br>
* This method is never called for effector instances that are
* bound to a live transduction. It is only called for proxy
* effectors, which are retained only to transfer compiled
* parameters to live effectors. Otherwise, proxy effectors are
* effectively zombies after parameter compilation is complete.
*/
public void passivate();

/**
* Returns the target that expresses the effector.
*
Expand Down Expand Up @@ -128,22 +162,4 @@ default boolean equivalent(final IEffector<?> other) {
return this.getClass().equals(other.getClass())
&& this.getName().equals(other.getName());
}

/**
* Called for proxy effectors after parameter compilation is
* complete. This will null out the target and output fields
* in the {@code BaseEffector} superclass. This allows the
* proxy model and transducer to be garbage collected after
* all effector parameters have been compiled. Subclasses
* may override this method to dispose of additional resources
* as well, but must also call {@code super.passivate()} in
* the overriding method.
* <br><br>
* This method is never called for effector instances that are
* bound to a live transduction. It is only called for proxy
* effectors, which are retained only to transfer compiled
* parameters to live effectors. Otherwise, proxy effectors are
* effectively zombies after parameter compilation is complete.
*/
public void passivate();
}
2 changes: 1 addition & 1 deletion src/com/characterforming/ribose/IModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@
import java.io.PrintStream;
import java.nio.charset.CharacterCodingException;

import com.characterforming.jrte.engine.Codec;
import com.characterforming.jrte.engine.ModelCompiler;
import com.characterforming.jrte.engine.ModelLoader;
import com.characterforming.ribose.base.Bytes;
import com.characterforming.ribose.base.Codec;
import com.characterforming.ribose.base.ModelException;
import com.characterforming.ribose.base.RiboseException;
import com.characterforming.ribose.base.Signal;
Expand Down
10 changes: 5 additions & 5 deletions src/com/characterforming/ribose/IOutput.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@
import com.characterforming.ribose.base.Signal;

/**
* Provides loggers, UTF-8 codecs and a view of fields (data extracted by the transduction)
* to {@link IEffector} implementations. Effectors receive their {@code IOutput} instance via
* Provides loggers and a view of fields (data extracted by the transduction) to {@link
* IEffector} implementations. Effectors receive their {@code IOutput} instance via
* {@link IEffector#setOutput(IOutput)} when they are first bound to a transductor. Transducer
* fields are local and bound to the defining transducer and can be accessed by stable
* field ordinal numbers. Every transducer has an anonymous field with ordinal number 0
* (the anonymous name token (`~`) in patterns). Ordinal numbers for named fields
* (referenced with a <b>~</b> field type prefix in transducer patterns, eg, {@code
* (the anonymous name token (`~`) in transducer patterns). Ordinal numbers for named
* fields (referenced with a <b>~</b> field type prefix in patterns, eg, {@code
* out[`~data`]}) are obtained by providing defining transducer and field names to {@link
* #getLocalizedFieldIndex(String, String)}. Effectors should obtain field ordinals in {@code
* setOutput()} and retain then for use with the data transfer methods {@link #asInteger(int)},
Expand Down Expand Up @@ -105,7 +105,7 @@ int getLocalizedFieldIndex(String transducerName, String fieldName)
throws EffectorException, CharacterCodingException;

/**
* Get the ordinal number for the current selected field. Not valid for proxy effectors.
* Get the localized ordinal number for the current selected field. Not valid for proxy effectors.
* The localized index is the offset to the field in the transducer stack frame.
*
* @return the localized index of the selected field in the current transducer stack frame
Expand Down
3 changes: 2 additions & 1 deletion src/com/characterforming/ribose/IParameterizedEffector.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
* }
* ...
* int invoke(int index) {
* SimpleDateFormat formater = super.getParameter(index);
* SimpleDateFormat formatter = super.getParameter(index);
* // get some field contents and format as date
* return RTX_NONE;
* }
Expand All @@ -97,6 +97,7 @@
* @author Kim Briggs
* @param <T> the effector target type
* @param <P> the effector parameter type, constructible from byte[][] (eg new P(byte[][]))
* @see IEffector
* @see BaseParameterizedEffector
*/
public interface IParameterizedEffector<T extends ITarget, P> extends IEffector<T> {
Expand Down
2 changes: 1 addition & 1 deletion src/com/characterforming/ribose/Ribose.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
import java.util.logging.Logger;

import com.characterforming.jrte.engine.Base;
import com.characterforming.jrte.engine.Codec;
import com.characterforming.ribose.base.Codec;
import com.characterforming.ribose.base.ModelException;
import com.characterforming.ribose.base.RiboseException;
import com.characterforming.ribose.base.Signal;
Expand Down
2 changes: 1 addition & 1 deletion src/com/characterforming/ribose/base/BaseEffector.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
package com.characterforming.ribose.base;

import java.nio.charset.CharacterCodingException;
import com.characterforming.jrte.engine.Codec;

import com.characterforming.ribose.IEffector;
import com.characterforming.ribose.IOutput;
import com.characterforming.ribose.ITarget;
Expand Down
2 changes: 0 additions & 2 deletions src/com/characterforming/ribose/base/Bytes.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@
import java.nio.charset.CharacterCodingException;
import java.util.Arrays;

import com.characterforming.jrte.engine.Codec;

/**
* Wraps an immutable array of bytes. Ribose transductions operate in the {@code byte}
* domain, and transduction input and outputs are represented as byte arrays.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
* <http://www.gnu.org/licenses/#GPL>.
*/

package com.characterforming.jrte.engine;
package com.characterforming.ribose.base;

import java.nio.ByteBuffer;
import java.nio.CharBuffer;
Expand All @@ -28,8 +28,14 @@
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CodingErrorAction;

import com.characterforming.ribose.base.Bytes;
import com.characterforming.ribose.IModel;

/**
* Thread local charset encoder/decoder. This is attached to a ribose thread on first use
* and detached when the thread closes a model (directly or implicitly via autoclose)
* or explicitly calls {@link IModel#detach()}. Static methods for encoding and decoding
* are provided.
*/
public class Codec {
private static final Charset CHARSET = Charset.forName(System.getProperty("ribose.runtime.charset", "UTF-8"));
private static final ThreadLocal<Codec> LOCAL = ThreadLocal.withInitial(Codec::new);
Expand Down Expand Up @@ -60,6 +66,9 @@ private static Codec get() {
return (codec == null) ? Codec.set() : codec;
}

/**
* Explicitly detach Codec from thread.
*/
public static void detach() {
Codec.LOCAL.remove();
}
Expand Down

0 comments on commit febd0b4

Please sign in to comment.