blob: e3f57f52e857900468689150358fb6b058984adc [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.uima.cas.impl;
import static java.lang.String.format;
import static java.lang.System.identityHashCode;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.MutableCallSite;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Spliterator;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Predicate;
import org.apache.uima.UIMAFramework;
import org.apache.uima.UIMARuntimeException;
import org.apache.uima.UimaSerializable;
import org.apache.uima.cas.AbstractCas_ImplBase;
import org.apache.uima.cas.ArrayFS;
import org.apache.uima.cas.BooleanArrayFS;
import org.apache.uima.cas.ByteArrayFS;
import org.apache.uima.cas.CAS;
import org.apache.uima.cas.CASException;
import org.apache.uima.cas.CASRuntimeException;
import org.apache.uima.cas.CasOwner;
import org.apache.uima.cas.CommonArrayFS;
import org.apache.uima.cas.ComponentInfo;
import org.apache.uima.cas.ConstraintFactory;
import org.apache.uima.cas.DoubleArrayFS;
import org.apache.uima.cas.FSIndex;
import org.apache.uima.cas.FSIndexRepository;
import org.apache.uima.cas.FSIterator;
import org.apache.uima.cas.FSMatchConstraint;
import org.apache.uima.cas.Feature;
import org.apache.uima.cas.FeaturePath;
import org.apache.uima.cas.FeatureStructure;
import org.apache.uima.cas.FeatureValuePath;
import org.apache.uima.cas.FloatArrayFS;
import org.apache.uima.cas.IntArrayFS;
import org.apache.uima.cas.LongArrayFS;
import org.apache.uima.cas.Marker;
import org.apache.uima.cas.SerialFormat;
import org.apache.uima.cas.ShortArrayFS;
import org.apache.uima.cas.SofaFS;
import org.apache.uima.cas.SofaID;
import org.apache.uima.cas.StringArrayFS;
import org.apache.uima.cas.Type;
import org.apache.uima.cas.TypeSystem;
import org.apache.uima.cas.admin.CASAdminException;
import org.apache.uima.cas.admin.CASFactory;
import org.apache.uima.cas.admin.CASMgr;
import org.apache.uima.cas.admin.FSIndexComparator;
import org.apache.uima.cas.admin.FSIndexRepositoryMgr;
import org.apache.uima.cas.admin.TypeSystemMgr;
import org.apache.uima.cas.impl.FSsTobeAddedback.FSsTobeAddedbackSingle;
import org.apache.uima.cas.impl.SlotKinds.SlotKind;
import org.apache.uima.cas.text.AnnotationFS;
import org.apache.uima.cas.text.AnnotationIndex;
import org.apache.uima.cas.text.Language;
import org.apache.uima.internal.util.IntVector;
import org.apache.uima.internal.util.Misc;
import org.apache.uima.internal.util.PositiveIntSet;
import org.apache.uima.internal.util.PositiveIntSet_impl;
import org.apache.uima.internal.util.UIMAClassLoader;
import org.apache.uima.jcas.JCas;
import org.apache.uima.jcas.cas.AnnotationBase;
import org.apache.uima.jcas.cas.BooleanArray;
import org.apache.uima.jcas.cas.ByteArray;
import org.apache.uima.jcas.cas.DoubleArray;
import org.apache.uima.jcas.cas.EmptyFSList;
import org.apache.uima.jcas.cas.EmptyFloatList;
import org.apache.uima.jcas.cas.EmptyIntegerList;
import org.apache.uima.jcas.cas.EmptyList;
import org.apache.uima.jcas.cas.EmptyStringList;
import org.apache.uima.jcas.cas.FSArray;
import org.apache.uima.jcas.cas.FloatArray;
import org.apache.uima.jcas.cas.IntegerArray;
import org.apache.uima.jcas.cas.LongArray;
import org.apache.uima.jcas.cas.ShortArray;
import org.apache.uima.jcas.cas.Sofa;
import org.apache.uima.jcas.cas.StringArray;
import org.apache.uima.jcas.cas.TOP;
import org.apache.uima.jcas.impl.JCasHashMap;
import org.apache.uima.jcas.impl.JCasImpl;
import org.apache.uima.jcas.tcas.Annotation;
import org.apache.uima.util.AutoCloseableNoException;
import org.apache.uima.util.Level;
/**
* Implements the CAS interfaces. This class must be public because we need to be able to create
* instance of it from outside the package. Use at your own risk. May change without notice.
*
*/
public class CASImpl extends AbstractCas_ImplBase
implements CAS, CASMgr, LowLevelCAS, TypeSystemConstants {
private static final String DISABLE_SUBTYPE_FSARRAY_CREATION = "uima.disable_subtype_fsarray_creation";
static final boolean IS_DISABLE_SUBTYPE_FSARRAY_CREATION = Misc
.getNoValueSystemProperty(DISABLE_SUBTYPE_FSARRAY_CREATION);
private static final String TRACE_FSS = "uima.trace_fs_creation_and_updating";
// public static final boolean IS_USE_V2_IDS = false; // if false, ids increment by 1
private static final boolean trace = false; // debug
public static final boolean traceFSs = // false; // debug - trace FS creation and update
Misc.getNoValueSystemProperty(TRACE_FSS);
public static final boolean traceCow = false; // debug - trace copy on write actions, index adds /
// deletes
private static final String traceFile = "traceFSs.log.txt";
private static final PrintStream traceOut;
static {
try {
if (traceFSs) {
System.out.println("Creating traceFSs file in directory " + System.getProperty("user.dir"));
traceOut = traceFSs
? new PrintStream(new BufferedOutputStream(new FileOutputStream(traceFile, false)))
: null;
} else {
traceOut = null;
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static final boolean MEASURE_SETINT = false;
// debug
static final AtomicInteger casIdProvider = new AtomicInteger(0);
// Notes on the implementation
// ---------------------------
// Floats are handled by casting them to ints when they are stored
// in the heap. Conveniently, 0 casts to 0.0f, which is the default
// value.
public static final int NULL = 0;
// Boolean scalar values are stored as ints in the fs heap.
// TRUE is 1 and false is 0.
public static final int TRUE = 1;
public static final int FALSE = 0;
public static final int DEFAULT_INITIAL_HEAP_SIZE = 500_000;
public static final int DEFAULT_RESET_HEAP_SIZE = 5_000_000;
/**
* The UIMA framework detects (unless disabled, for high performance) updates to indexed FS which
* update key values used as keys in indexes. Normally the framework will protect against index
* corruption by temporarily removing the FS from the indexes, then do the update to the feature
* value, and then addback the changed FS.
* <p>
* Users can use the protectIndexes() methods to explicitly control this remove - add back cycle,
* for instance to "batch" together several updates to multiple features in a FS.
* <p>
* Some build processes may want to FAIL if any unprotected updates of this kind occur, instead of
* having the framework silently recover them. This is enabled by having the framework throw an
* exception; this is controlled by this global JVM property, which, if defined, causes the
* framework to throw an exception rather than recover.
*
*/
public static final String THROW_EXCEPTION_FS_UPDATES_CORRUPTS = "uima.exception_when_fs_update_corrupts_index";
// public for test case use
public static boolean IS_THROW_EXCEPTION_CORRUPT_INDEX = Misc
.getNoValueSystemProperty(THROW_EXCEPTION_FS_UPDATES_CORRUPTS);
/**
* Define this JVM property to enable checking for invalid updates to features which are used as
* keys by any index.
* <ul>
* <li>The following are the same: -Duima.check_invalid_fs_updates and
* -Duima.check_invalid_fs_updates=true</li>
* </ul>
*/
public static final String REPORT_FS_UPDATES_CORRUPTS = "uima.report_fs_update_corrupts_index";
private static final boolean IS_REPORT_FS_UPDATE_CORRUPTS_INDEX = IS_THROW_EXCEPTION_CORRUPT_INDEX
|| Misc.getNoValueSystemProperty(REPORT_FS_UPDATES_CORRUPTS);
/**
* Set this JVM property to false for high performance, (no checking); insure you don't have the
* report flag (above) turned on - otherwise it will force this to "true".
*/
public static final String DISABLE_PROTECT_INDEXES = "uima.disable_auto_protect_indexes";
/**
* the protect indexes flag is on by default, but may be turned of via setting the property.
*
* This is overridden if a report is requested or the exception detection is on.
*/
private static final boolean IS_DISABLED_PROTECT_INDEXES = Misc
.getNoValueSystemProperty(DISABLE_PROTECT_INDEXES) && !IS_REPORT_FS_UPDATE_CORRUPTS_INDEX
&& !IS_THROW_EXCEPTION_CORRUPT_INDEX;
public static final String ALWAYS_HOLD_ONTO_FSS = "uima.default_v2_id_references";
static final boolean IS_ALWAYS_HOLD_ONTO_FSS = // debug and users of low-level cas apis with
// deserialization
Misc.getNoValueSystemProperty(ALWAYS_HOLD_ONTO_FSS);
// private static final int REF_DATA_FOR_ALLOC_SIZE = 1024;
// private static final int INT_DATA_FOR_ALLOC_SIZE = 1024;
//
// this next seemingly non-sensical static block
// is to force the classes needed by Eclipse debugging to load
// otherwise, you get a com.sun.jdi.ClassNotLoadedException when
// the class is used as part of formatting debugging messages
static {
new DebugNameValuePair(null, null);
new DebugFSLogicalStructure();
}
private final static ThreadLocal<Boolean> defaultV2IdRefs = InheritableThreadLocal
.withInitial(() -> null);
public static ThreadLocal<Boolean> getDefaultV2IdRefs() {
return defaultV2IdRefs;
}
// Static classes representing shared instance data
// - shared data is computed once for all views
/**
* Journaling changes for computing delta cas. Each instance represents one or more changes for
* one feature structure A particular Feature Structure may have multiple FsChange instances but
* we attempt to minimize this
*/
public static class FsChange {
/** ref to the FS being modified */
final TOP fs;
/**
* which feature (by offset) is modified
*/
final BitSet featuresModified;
final PositiveIntSet arrayUpdates;
FsChange(TOP fs) {
this.fs = fs;
TypeImpl ti = fs._getTypeImpl();
featuresModified = (ti.highestOffset == -1) ? null : new BitSet(ti.highestOffset + 1);
arrayUpdates = (ti.isArray()) ? new PositiveIntSet_impl() : null;
}
void addFeatData(int v) {
featuresModified.set(v);
}
void addArrayData(int v, int nbrOfConsecutive) {
for (int i = 0; i < nbrOfConsecutive; i++) {
arrayUpdates.add(v++);
}
}
void addArrayData(PositiveIntSet indexesPlus1) {
indexesPlus1.forAllInts(i -> arrayUpdates.add(i - 1));
}
@Override
public int hashCode() {
return 31 + ((fs == null) ? 0 : fs._id);
}
@Override
public boolean equals(Object obj) {
if (obj == null || !(obj instanceof FsChange)) {
return false;
}
return ((FsChange) obj).fs._id == fs._id;
}
}
/**
* Instances are put into a Stack, to remember previous state to switch back to, when switching
* class loaders and locking the CAS
*
* https://issues.apache.org/jira/browse/UIMA-6057
*/
static class SwitchControl {
final boolean wasLocked;
boolean wasSwitched = false;
SwitchControl(boolean wasLocked) {
this.wasLocked = wasLocked;
}
}
// fields shared among all CASes belong to views of a common base CAS
static class SharedViewData {
/**
* map from FS ids to FSs.
*/
final private Id2FS id2fs;
/** set to > 0 to reuse an id, 0 otherwise */
private int reuseId = 0;
// Base CAS for all views
final private CASImpl baseCAS;
/**
* These fields are here, not in TypeSystemImpl, because different CASes may have different
* indexes but share the same type system They hold the same data (constant per CAS) but are
* accessed with different indexes
*/
private final BitSet featureCodesInIndexKeys = new BitSet(1024); // 128 bytes
// private final BitSet featureJiInIndexKeys = new BitSet(1024); // indexed by JCas Feature
// Index, not feature code.
// A map from SofaNumbers which are also view numbers to IndexRepositories.
// these numbers are dense, and start with 1. 1 is the initial view. 0 is the base cas
ArrayList<FSIndexRepositoryImpl> sofa2indexMap;
// @formatter:off
/**
* A map from Sofa numbers to CAS views.
* number 0 - not used
* number 1 - used for view named "_InitialView"
* number 2-n used for other views
*
* Note: this is not reset with "Cas Reset" because views (really, their associated index repos)
* take a lot of setup for the indexes.
* However, the maximum view count is reset; so creation of new views "reuses" these pre-setup indexRepos
* associated with these views.
*/
// @formatter:on
ArrayList<CASImpl> sofaNbr2ViewMap;
/**
* a set of instantiated sofaNames
*/
private Set<String> sofaNameSet;
// Flag that initial Sofa has been created
private boolean initialSofaCreated = false;
// Count of Views created in this cas
// equals count of sofas except if initial view has no sofa.
int viewCount;
// The ClassLoader that should be used by the JCas to load the generated
// FS cover classes for this CAS. Defaults to the ClassLoader used
// to load the CASImpl class.
private ClassLoader jcasClassLoader = this.getClass().getClassLoader();
/*****************************
* PEAR Support
*****************************/
/**
* Only support one level of PEAR nesting; for more general approach, make this a deque
*/
private ClassLoader previousJCasClassLoader = null;
/**
* Save area for suspending this while we create a base instance
*/
private ClassLoader suspendPreviousJCasClassLoader;
/**
* A map from IDs to already created trampoline FSs for the base FS with that id. These are used
* when in a Pear and retrieving a FS (via index or deref) and you want the Pear version for
* that ID. There are potentially multiple maps - one per PEAR Classpath
*/
private JCasHashMap id2tramp = null;
/**
* a map from IDs of FSs that have a Pear version, to the base (non-Pear) version used to locate
* the base version for adding to indexes
*/
private JCasHashMap id2base = null;
private final Map<ClassLoader, JCasHashMap> cl2id2tramp = new IdentityHashMap<>();
// @formatter:off
/**
* The current (active, switches at Pear boundaries) FsGenerators (excluding array-generators)
* key = type code
* read-only, unsynchronized for this CAS
* Cache for setting this kept in TypeSystemImpl, by classloader
* - shared among all CASs that use that Type System and class loader
* -- in turn, initialized from FSClassRegistry, once per classloader / typesystem combo
*
* Pear generators are mostly null except for instances where the PEAR has redefined the JCas
* cover class
*/
// @formatter:on
private FsGenerator3[] generators;
// @formatter:off
/**
* When generating a new instance of a FS in a PEAR where there's an alternate JCas class impl,
* generate the base version, and make the alternate a trampoline to it.
* Note: in future, if it is known that this FS is never used outside of this PEAR, then can
* skip generating the double version
*/
// @formatter:on
private FsGenerator3[] baseGenerators;
// If this CAS can be flushed (reset) or not.
// often, the framework disables this before calling users code
private boolean flushEnabled = true;
// not final because set with reinit deserialization
private TypeSystemImpl tsi;
private ComponentInfo componentInfo;
/**
* This tracks the changes for delta cas May also in the future support Journaling by component,
* allowing determination of which component in a flow created/updated a FeatureStructure (not
* implmented)
*
* TrackingMarkers are held on to by things outside of the Cas, to support switching from one
* tracking marker to another (currently not used, but designed to support Component
* Journaling).
*
* We track changes on a granularity of features and for features which are arrays, which
* element of the array (This last to enable efficient delta serializations of giant arrays of
* things, where you've only updated a few items)
*
* The FsChange doesn't store the changed data, only stores the ref info needed to get to what
* was changed.
*/
private MarkerImpl trackingMark;
/**
* Track modified preexistingFSs Note this is a map, keyed by the FS, so all changes are merged
* when added
*/
private Map<TOP, FsChange> modifiedPreexistingFSs;
/**
* This list currently only contains at most 1 element. If Journaling is implemented, it may
* contain an element per component being journaled.
*/
private List<MarkerImpl> trackingMarkList;
/**
* This stack corresponds to nested protectIndexes contexts. Normally should be very shallow.
*/
private final ArrayList<FSsTobeAddedback> fssTobeAddedback = new ArrayList<>();
/**
* This version is for single fs use, by binary deserializers and by automatic mode Only one
* user at a time is allowed.
*/
private final FSsTobeAddedbackSingle fsTobeAddedbackSingle = (FSsTobeAddedbackSingle) FSsTobeAddedback
.createSingle();
/**
* Set to true while this is in use.
*/
boolean fsTobeAddedbackSingleInUse = false;
/**
* temporarily set to true by deserialization routines doing their own management of this check
*/
boolean disableAutoCorruptionCheck = false;
// used to generate FSIDs, increments by 1 for each use. First id == 1
/**
* The fsId of the last created FS used to generate FSIDs, increments by 1 for each use. First
* id == 1
*/
private int fsIdGenerator = 0;
/**
* The version 2 size on the main heap of the last created FS
*/
private int lastFsV2Size = 1;
/**
* used to "capture" the fsIdGenerator value for a read-only CAS to be visible in other threads
*/
AtomicInteger fsIdLastValue = new AtomicInteger(0);
// mostly for debug - counts # times cas is reset
private final AtomicInteger casResets = new AtomicInteger(0);
// unique ID for a created CAS view, not updated if CAS is reset and reused
private final String casId = String.valueOf(casIdProvider.incrementAndGet());
// shared singltons, created at type system commit
private EmptyFSList emptyFSList;
private EmptyFloatList emptyFloatList;
private EmptyIntegerList emptyIntegerList;
private EmptyStringList emptyStringList;
private FloatArray emptyFloatArray;
private final Map<Type, FSArray> emptyFSArrayMap = new HashMap<>();
private IntegerArray emptyIntegerArray;
private StringArray emptyStringArray;
private DoubleArray emptyDoubleArray;
private LongArray emptyLongArray;
private ShortArray emptyShortArray;
private ByteArray emptyByteArray;
private BooleanArray emptyBooleanArray;
/**
* Created at startup time, lives as long as the CAS lives Serves to reference code for binary
* cas ser/des that used to live in this class, but was moved out
*/
private final BinaryCasSerDes bcsd;
/**
* Created when doing binary or form4 non-delta (de)serialization, used in subsequent delta
* ser/deserialization Created when doing binary or form4 non-delta ser/deserialization, used in
* subsequent delta (de)serialization Reset with CasReset or deltaMergesComplete API call
*/
private CommonSerDesSequential csds;
/*************************************************
* VERSION 2 LOW_LEVEL_API COMPATIBILITY SUPPORT *
*************************************************/
// @formatter:off
/**
* A StringSet used only to support ll_get/setInt api
* get adds string to this and returns the int handle
* set retrieves the string, given the handle
* lazy initialized
*/
// @formatter:on
private StringSet llstringSet = null;
// @formatter:off
/**
* A LongSet used only to support v2 ll_get/setInt api
* get adds long to this and returns the int handle
* set retrieves the long, given the handle
* lazy initialized
*/
// @formatter:on
private LongSet lllongSet = null;
// For tracing FS creation and updating, normally disabled
private final StringBuilder traceFScreationSb = traceFSs ? new StringBuilder() : null;
private final StringBuilder traceCowSb = traceCow ? new StringBuilder() : null;
private int traceFSid = 0;
private boolean traceFSisCreate;
private final IntVector id2addr = traceFSs ? new IntVector() : null;
private int nextId2Addr = 1; // only for tracing, to convert id's to v2 addresses
final private int initialHeapSize;
// @formatter:off
/** if true,
* modify fs creation to save in id2fs map
* modify deserializers to create fss with ids the same as the serialized form (
* or the V2 "address" imputed from that)
* modify serializers to include reachables only found via id2fs table
*
* not static because is updated (see ll_enableV2IdRefs)
*/
// @formatter:on
private boolean isId2Fs;
/**
* a stack used to remember and restore previous state of cas lock and class loaders when
* switching classloaders and locking the cas https://issues.apache.org/jira/browse/UIMA-6057
*/
private final Deque<SwitchControl> switchControl = new ArrayDeque<>();
// @formatter:off
/******************************************************************************************
* C A S S T A T E management *
* Cas state is implemented in a way to allow the Java to efficiently *
* access the state test without synchronization or "voliatile" memory accessing, *
* while at the same time, allowing for an occasional cross-thread memory invalidation *
* when the state is changed. This is done using a MutableCallSite plus that *
* objects "syncAll" method. *
******************************************************************************************/
// @formatter:on
private final EnumSet<CasState> casState = EnumSet.noneOf(CasState.class);
private static final MethodType noArgBoolean = MethodType.methodType(boolean.class);
private static final MethodHandle mh_return_false;
private static final MethodHandle mh_return_true;
static {
try {
mh_return_false = MethodHandles.lookup().findStatic(CasState.class, "return_false",
noArgBoolean);
mh_return_true = MethodHandles.lookup().findStatic(CasState.class, "return_true",
noArgBoolean);
} catch (NoSuchMethodException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
private final MutableCallSite is_updatable_callsite = new MutableCallSite(mh_return_true);
private final MutableCallSite is_readable_callsite = new MutableCallSite(mh_return_true);
private final MethodHandle is_updatable = is_updatable_callsite.dynamicInvoker();
private final MethodHandle is_readable = is_readable_callsite.dynamicInvoker();
private final MutableCallSite[] is_updatable_callsites = new MutableCallSite[] {
is_updatable_callsite };
private final MutableCallSite[] is_readable_callsites = new MutableCallSite[] {
is_readable_callsite };
private volatile Thread current_one_thread_access = null;
private void updateCallSite(boolean desired_state, MethodHandle tester, MutableCallSite c,
MethodHandle mh, MutableCallSite[] cs) {
try {
if (((boolean) tester.invokeExact()) != desired_state) {
c.setTarget(mh);
MutableCallSite.syncAll(cs);
}
} catch (Throwable e) {
Misc.internalError(e);
}
}
private synchronized boolean setCasState(CasState state, Thread thread) {
boolean wasAdded = casState.add(state);
if (wasAdded || (state == CasState.NO_ACCESS && thread != current_one_thread_access)) {
switch (state) {
case READ_ONLY:
if (casState.contains(CasState.NO_ACCESS)) {
break; // ignore readonly if no-access is set
}
updateCallSite(false, is_updatable, is_updatable_callsite, mh_return_false,
is_updatable_callsites);
break;
case NO_ACCESS:
current_one_thread_access = thread;
MethodHandle mh = CasState.produce_one_thread_access_test(thread);
boolean b = true; // value ignored, needed to avoid compile warning
try {
b = (boolean) mh.invokeExact();
} catch (Throwable e) {
Misc.internalError(e);
}
updateCallSite(b, is_updatable, is_updatable_callsite, mh, is_updatable_callsites);
updateCallSite(b, is_readable, is_readable_callsite, mh, is_readable_callsites);
break;
default:
}
}
return wasAdded;
}
private synchronized boolean clearCasState(CasState state) {
boolean wasRemoved = casState.remove(state);
if (wasRemoved) {
switch (state) {
case READ_ONLY:
if (casState.contains(CasState.NO_ACCESS)) {
break;
}
updateCallSite(true, is_updatable, is_updatable_callsite, mh_return_true,
is_updatable_callsites);
break;
case NO_ACCESS:
current_one_thread_access = null;
updateCallSite(true, is_updatable, is_updatable_callsite, mh_return_true,
is_updatable_callsites);
updateCallSite(true, is_readable, is_readable_callsite, mh_return_true,
is_readable_callsites);
break;
default:
}
}
return wasRemoved;
}
private SharedViewData(CASImpl baseCAS, int initialHeapSize, TypeSystemImpl tsi) {
this.baseCAS = baseCAS;
this.tsi = tsi;
this.initialHeapSize = initialHeapSize;
bcsd = new BinaryCasSerDes(baseCAS);
id2fs = new Id2FS(initialHeapSize);
if (traceFSs) {
id2addr.add(0);
}
Boolean v = getDefaultV2IdRefs().get();
isId2Fs = (v == null) ? IS_ALWAYS_HOLD_ONTO_FSS : v;
}
void clearCasReset() {
// fss
fsIdGenerator = 0;
lastFsV2Size = 1;
id2fs.clear();
// pear caches
id2tramp = null;
id2base = null;
for (Iterator<Entry<ClassLoader, JCasHashMap>> it = cl2id2tramp.entrySet().iterator(); it
.hasNext();) {
Entry<ClassLoader, JCasHashMap> e = it.next();
ClassLoader cl = e.getKey();
e.getValue().clear();
if (cl instanceof UIMAClassLoader) { // https://issues.apache.org/jira/browse/UIMA-5801
if (((UIMAClassLoader) cl).isClosed()) {
it.remove();
}
}
}
// index corruption avoidance
fssTobeAddedback.clear();
fsTobeAddedbackSingle.clear();
fsTobeAddedbackSingleInUse = false;
disableAutoCorruptionCheck = false;
// misc
flushEnabled = true;
componentInfo = null;
bcsd.clear();
csds = null;
llstringSet = null;
traceFSid = 0;
if (traceFSs) {
traceFScreationSb.setLength(0);
id2addr.removeAllElements();
id2addr.add(0);
nextId2Addr = 1;
}
emptyFloatList = null; // these cleared in case new ts redefines?
emptyFSList = null;
emptyIntegerList = null;
emptyStringList = null;
emptyFloatArray = null;
emptyFSArrayMap.clear();
emptyIntegerArray = null;
emptyStringArray = null;
emptyDoubleArray = null;
emptyLongArray = null;
emptyShortArray = null;
emptyByteArray = null;
emptyBooleanArray = null;
current_one_thread_access = null;
updateCallSite(true, is_updatable, is_updatable_callsite, mh_return_true,
is_updatable_callsites);
updateCallSite(true, is_readable, is_readable_callsite, mh_return_true,
is_readable_callsites);
clearNonSharedInstanceData();
}
/**
* called by resetNoQuestions and cas complete reinit
*/
void clearSofaInfo() {
sofaNameSet.clear();
initialSofaCreated = false;
}
// @formatter:off
/**
* Called from CasComplete deserialization (reinit).
*
* Skips the resetNoQuestions operation of flushing the indexes, since these will be
* reinitialized with potentially new definitions.
*
* Clears additional data related to having the
* - type system potentially change
* - the features belonging to indexes change
*/
// @formatter:on
void clear() {
resetNoQuestions(false); // false - skip flushing the index repos
// type system + index spec
tsi = null;
featureCodesInIndexKeys.clear();
// featureJiInIndexKeys.clear();
/**
* Clear the existing views, except keep the info for the initial view so that the cas
* complete deserialization after setting up the new index repository in the base cas can
* "refresh" the existing initial view (if present; if not present, a new one is created).
*/
if (sofaNbr2ViewMap.size() >= 1) {
// have initial view - preserve it
CASImpl localInitialView = sofaNbr2ViewMap.get(1);
sofaNbr2ViewMap.clear();
Misc.setWithExpand(sofaNbr2ViewMap, 1, localInitialView);
viewCount = 1;
} else {
sofaNbr2ViewMap.clear();
viewCount = 0;
}
}
private void resetNoQuestions(boolean flushIndexRepos) {
casResets.incrementAndGet();
if (trace) {
System.out.println("CAS Reset in thread " + Thread.currentThread().getName()
+ " for CasId = " + casId + ", new reset count = " + casResets.get());
}
clearCasReset(); // also clears cached FSs
if (flushIndexRepos) {
flushIndexRepositoriesAllViews();
}
clearTrackingMarks();
clearSofaInfo(); // but keep initial view, and other views
// because setting up the index infrastructure is expensive
viewCount = 1; // initial view
traceFSid = 0;
if (traceFSs) {
traceFScreationSb.setLength(0);
}
componentInfo = null; // https://issues.apache.org/jira/browse/UIMA-5097
switchControl.clear(); // https://issues.apache.org/jira/browse/UIMA-6057
}
private void flushIndexRepositoriesAllViews() {
int numViews = viewCount;
for (int view = 1; view <= numViews; view++) {
CASImpl tcas = (CASImpl) ((view == 1) ? getInitialView() : getViewFromSofaNbr(view));
if (tcas != null) {
tcas.indexRepository.flush();
}
}
// safety : in case this public method is called on other than the base cas
baseCAS.indexRepository.flush(); // for base view, other views flushed above
}
private void clearNonSharedInstanceData() {
int numViews = viewCount;
for (int view = 1; view <= numViews; view++) {
CASImpl tcas = (CASImpl) ((view == 1) ? getInitialView() : getViewFromSofaNbr(view));
if (tcas != null) {
tcas.mySofaRef = null; // was in v2: (1 == view) ? -1 : 0;
tcas.docAnnotIter = null;
}
}
}
private void clearTrackingMarks() {
// resets all markers that might be held by things outside the Cas
// Currently (2009) this list has a max of 1 element
// Future impl may have one element per component for component Journaling
if (trackingMarkList != null) {
for (int i = 0; i < trackingMarkList.size(); i++) {
trackingMarkList.get(i).isValid = false;
}
}
trackingMark = null;
if (null != modifiedPreexistingFSs) {
modifiedPreexistingFSs.clear();
}
trackingMarkList = null;
}
// switches ClassLoader but does not lock CAS
void switchClassLoader(ClassLoader newClassLoader, boolean wasLocked) {
// https://issues.apache.org/jira/browse/UIMA-6057
SwitchControl switchControlInstance = new SwitchControl(wasLocked);
switchControl.push(switchControlInstance);
if (null == newClassLoader) { // is null if no cl set
return;
}
if (!(newClassLoader instanceof UIMAClassLoader)) {
UIMAFramework.getLogger()
.debug("Calling switchClassLoader with a classloader of type [{}] that is not "
+ "a UIMAClassLoader may cause JCas wrappers to be loaded from the wrong "
+ "classloader.", newClassLoader.getClass().getName());
}
if (newClassLoader != jcasClassLoader) {
if (null != previousJCasClassLoader) {
/**
* Multiply nested classloaders not supported. Original base loader: {0}, current nested
* loader: {1}, trying to switch to loader: {2}.
*/
throw new CASRuntimeException(CASRuntimeException.SWITCH_CLASS_LOADER_NESTED,
previousJCasClassLoader, jcasClassLoader, newClassLoader);
}
// System.out.println("Switching to new class loader");
previousJCasClassLoader = jcasClassLoader;
jcasClassLoader = newClassLoader;
switchControlInstance.wasSwitched = true;
generators = tsi.getGeneratorsForClassLoader(newClassLoader, true); // true - isPear
assert null == id2tramp; // is null outside of a pear
id2tramp = cl2id2tramp.get(newClassLoader);
if (null == id2tramp) {
cl2id2tramp.put(newClassLoader, id2tramp = new JCasHashMap(32));
}
if (id2base == null) {
id2base = new JCasHashMap(32);
}
}
}
void restoreClassLoader(boolean empty_switchControl, SwitchControl switchControlInstance) {
if (null == previousJCasClassLoader) {
return;
}
if ((empty_switchControl || switchControlInstance.wasSwitched)
&& previousJCasClassLoader != jcasClassLoader) {
// System.out.println("Switching back to previous class loader");
jcasClassLoader = previousJCasClassLoader;
previousJCasClassLoader = null;
generators = baseGenerators;
id2tramp = null;
}
}
// @formatter:off
/**
* The logic for this is:
* - normal - add 1 to the value of the previous
* which is kept in fsIdGenerator
* Update fsIdGenerator to be this id.
* (maybe) set lastFsV2Size to the size of this FS in v2
* - pear trampolines: use the exact same id as the main fs.
* This value is in reuseId.
* In this case, no computation of "next" is done
* - isId2Fs This is set if in special mode to emulate v2 addresses.
* - used for backwards compatibility when LowLevelCas getFSForRef calls in use
* - used for debugging v2 vs v3 runs
* - causes fsId to be set to a value which should match the v2 address
* Side effect: when doing v2 emulation, updates the lastFsV2Size
* @param fs - the fs, used to compute its "size" on the v2 heap when emulating v2 addresses
* @return the id to use
*/
// @formatter:on
private int getNextFsId(TOP fs) {
if (reuseId != 0) { // for pear use
// l.setStrongRef(fs, reuseId);
int r = reuseId;
reuseId = 0;
return r; // reuseId reset to 0 by callers' try/finally block
}
// l.add(fs);
// if (id2fs.size() != (2 + fsIdGenerator.get())) {
// System.out.println("debug out of sync id generator and id2fs size");
// }
// assert(l.size() == (2 + fsIdGenerator));
final int p = fsIdGenerator;
final int r = fsIdGenerator = peekNextFsId();
if (r < p) {
throw new RuntimeException("UIMA Cas Internal id value overflowed maximum int value");
}
if (isId2Fs) {
// this computation is partial - misses length of arrays stored on heap
// because that info not yet available
// It is added later via call to adjustLastFsV2size(int)
lastFsV2Size = fs._getTypeImpl().getFsSpaceReq();
}
return r;
}
/**
* @return the lastUsedFsId + the size of that or 1
*/
int peekNextFsId() {
return fsIdGenerator + lastFsV2IdIncr();
}
int lastFsV2IdIncr() {
return (isId2Fs ? lastFsV2Size : 1);
}
private CASImpl getViewFromSofaNbr(int nbr) {
final ArrayList<CASImpl> sn2v = sofaNbr2ViewMap;
if (nbr < sn2v.size()) {
return sn2v.get(nbr);
}
return null;
}
// For internal platform use only
CASImpl getInitialView() {
CASImpl couldBeThis = getViewFromSofaNbr(1);
if (couldBeThis != null) {
return couldBeThis;
}
// create the initial view, without a Sofa
CASImpl aView = new CASImpl(baseCAS, (SofaFS) null);
setViewForSofaNbr(1, aView);
assert (viewCount <= 1);
viewCount = 1;
return aView;
}
void setViewForSofaNbr(int nbr, CASImpl view) {
Misc.setWithExpand(sofaNbr2ViewMap, nbr, view);
}
}
/**********************************************
* C A S S T A T E m a n a g e m e n t *
**********************************************/
/**
* @param state
* to add to the set
* @return true if the set changed as a result of this operation
*/
public boolean setCasState(CasState state) {
return setCasState(state, null);
}
/**
* @param state
* to add to the set
* @param thread
* null or the thread to permit access to
* @return true if the set changed as a result of this operation
*/
public boolean setCasState(CasState state, Thread thread) {
return svd.setCasState(state, thread);
}
/**
* @param state
* to see if it is among the items in this set
* @return true if the set contains that state
*/
public boolean containsCasState(CasState state) {
return svd.casState.contains(state);
}
/**
* @param state
* to be removed
* @return true if it was present, and is now removed
*/
public boolean clearCasState(CasState state) {
return svd.clearCasState(state);
}
boolean is_updatable() {
try {
return (boolean) svd.is_updatable.invokeExact();
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
boolean is_readable() {
try {
return (boolean) svd.is_readable.invokeExact();
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
/*****************************************************************
* Non-shared instance data kept per CAS view incl base CAS
*****************************************************************/
// package protected to let other things share this info
final SharedViewData svd; // shared view data
// public only for cross package access
public boolean isCasLocked() {
return !svd.flushEnabled;
}
/** The index repository. Referenced by XmiCasSerializer */
FSIndexRepositoryImpl indexRepository;
// private Object[] currentRefDataForAlloc = new Object[REF_DATA_FOR_ALLOC_SIZE];
// private Object[] returnRefDataForAlloc;
// private int[] currentIntDataForAlloc = new int[INT_DATA_FOR_ALLOC_SIZE];
// private int[] returnIntDataForAlloc;
// private int nextRefDataOffsetForAlloc = 0;
// private int nextIntDataOffsetForAlloc = 0;
// @formatter:off
/**
* The Feature Structure for the sofa FS for this view, or
* null
* //-1 if the sofa FS is for the initial view, or
* // 0 if there is no sofa FS - for instance, in the "base cas"
*/
// @formatter:on
private Sofa mySofaRef = null;
/** the corresponding JCas object */
JCasImpl jcas = null;
// @formatter:off
/**
* Copies of frequently accessed data pulled up for
* locality of reference - only an optimization
* - each value needs to be reset appropriately
* - getters check for null, and if null, do the get.
*/
// @formatter:on
private TypeSystemImpl tsi_local;
/**
* for Pear generation - set this to the base FS not in SharedViewData to reduce object traversal
* when generating FSs
*/
FeatureStructureImplC pearBaseFs = null;
// @formatter:off
/**
* Optimization - keep a documentAnnotationIterator handy for getting a ref to the doc annot
* Initialized lazily, synchronized
* One per cas view
*/
// @formatter:on
private volatile FSIterator<Annotation> docAnnotIter = null;
// UIMA-6199 provides access to non-indexed doc annot
// to allow sofa setting to set the "length" of the local sofa data string
// @see updateDocumentAnnotation() updateDocumentAnnotation.
private volatile Annotation deserialized_doc_annot_not_indexed = null;
// private StackTraceElement[] addbackSingleTrace = null; // for debug use only, normally
// commented out
// CASImpl(TypeSystemImpl typeSystem) {
// this(typeSystem, DEFAULT_INITIAL_HEAP_SIZE);
// }
// // Reference existing CAS
// // For use when creating views of the CAS
// CASImpl(CAS cas) {
// this.setCAS(cas);
// this.useFSCache = false;
// initTypeVariables();
// }
/*
* Configure a new (base view) CASImpl, **not a new view** typeSystem can be null, in which case a
* new instance of TypeSystemImpl is set up, but not committed. If typeSystem is not null, it is
* committed (locked). ** Note: it is assumed that the caller of this will always set up the
* initial view ** by calling
*/
public CASImpl(TypeSystemImpl typeSystem, int initialHeapSize) {
TypeSystemImpl ts;
final boolean externalTypeSystem = (typeSystem != null);
if (externalTypeSystem) {
ts = typeSystem;
} else {
ts = (TypeSystemImpl) CASFactory.createTypeSystem(); // creates also new CASMetadata and
// FSClassRegistry instances
}
this.svd = new SharedViewData(this, initialHeapSize, ts);
// this.svd.baseCAS = this;
// this.svd.heap = new Heap(initialHeapSize);
if (externalTypeSystem) {
commitTypeSystem();
}
this.svd.sofa2indexMap = new ArrayList<>();
this.svd.sofaNbr2ViewMap = new ArrayList<>();
this.svd.sofaNameSet = new HashSet<>();
this.svd.initialSofaCreated = false;
this.svd.viewCount = 0;
this.svd.clearTrackingMarks();
}
public CASImpl() {
this((TypeSystemImpl) null, DEFAULT_INITIAL_HEAP_SIZE);
}
// In May 2007, appears to have 1 caller, createCASMgr in Serialization class,
// could have out-side the framework callers because it is public.
public CASImpl(CASMgrSerializer ser) {
this(ser.getTypeSystem(), DEFAULT_INITIAL_HEAP_SIZE);
checkInternalCodes(ser);
// assert(ts != null);
// assert(getTypeSystem() != null);
this.indexRepository = ser.getIndexRepository(this);
}
// Use this when creating a CAS view
CASImpl(CASImpl cas, SofaFS aSofa) {
// these next fields are final and must be set in the constructor
this.svd = cas.svd;
this.mySofaRef = (Sofa) aSofa;
// get the indexRepository for this Sofa
this.indexRepository = (this.mySofaRef == null)
? (FSIndexRepositoryImpl) cas.getSofaIndexRepository(1)
: (FSIndexRepositoryImpl) cas.getSofaIndexRepository(aSofa);
if (null == this.indexRepository) {
// create the indexRepository for this CAS
// use the baseIR to create a lightweight IR copy
FSIndexRepositoryImpl baseIndexRepo = (FSIndexRepositoryImpl) cas.getBaseIndexRepository();
this.indexRepository = new FSIndexRepositoryImpl(this, baseIndexRepo);
// the index creation depends on "indexRepository" already being set
baseIndexRepo.name2indexMap.keySet().stream()
.forEach(key -> this.indexRepository.createIndex(baseIndexRepo, key));
this.indexRepository.commit();
// save new sofa index
if (this.mySofaRef == null) {
cas.setSofaIndexRepository(1, this.indexRepository);
} else {
cas.setSofaIndexRepository(aSofa, this.indexRepository);
}
}
}
// Use this when creating a CAS view
void refreshView(CAS cas, SofaFS aSofa) {
if (aSofa != null) {
// save address of SofaFS
this.mySofaRef = (Sofa) aSofa;
} else {
// this is the InitialView
this.mySofaRef = null;
}
// toss the JCas, if it exists
this.jcas = null;
// create the indexRepository for this Sofa
final FSIndexRepositoryImpl baseIndexRepo = (FSIndexRepositoryImpl) ((CASImpl) cas)
.getBaseIndexRepository();
this.indexRepository = new FSIndexRepositoryImpl(this, baseIndexRepo);
// the index creation depends on "indexRepository" already being set
baseIndexRepo.name2indexMap.keySet().stream()
.forEach(key -> this.indexRepository.createIndex(baseIndexRepo, key));
this.indexRepository.commit();
// save new sofa index
if (this.mySofaRef == null) {
((CASImpl) cas).setSofaIndexRepository(1, this.indexRepository);
} else {
((CASImpl) cas).setSofaIndexRepository(aSofa, this.indexRepository);
}
}
private void checkInternalCodes(CASMgrSerializer ser) throws CASAdminException {
if ((ser.topTypeCode > 0) && (ser.topTypeCode != topTypeCode)) {
throw new CASAdminException(CASAdminException.DESERIALIZATION_ERROR);
}
if (ser.featureOffsets == null) {
return;
}
// if (ser.featureOffsets.length != this.svd.casMetadata.featureOffset.length) {
// throw new CASAdminException(CASAdminException.DESERIALIZATION_ERROR);
// }
TypeSystemImpl tsi = getTypeSystemImpl();
for (int i = 1; i < ser.featureOffsets.length; i++) {
FeatureImpl fi = tsi.getFeatureForCode_checked(i);
int adjOffset = fi.isInInt ? 0 : fi.getRangeImpl().nbrOfUsedIntDataSlots;
if (ser.featureOffsets[i] != (fi.getOffset() + adjOffset)) {
throw new CASAdminException(CASAdminException.DESERIALIZATION_ERROR);
}
}
}
// ----------------------------------------
// accessors for data in SharedViewData
// ----------------------------------------
public boolean isId2Fs() {
return svd.isId2Fs;
}
Id2FS getId2FSs() {
return svd.id2fs;
}
void set_id2fs(TOP fs) {
svd.id2fs.put(fs);
}
void set_reuseId(int id) {
svd.reuseId = id;
}
void setLastUsedFsId(int id) {
svd.fsIdGenerator = id;
}
void setLastFsV2Size(int size) {
svd.lastFsV2Size = size;
}
void addSofaViewName(String id) {
svd.sofaNameSet.add(id);
}
void setViewCount(int n) {
svd.viewCount = n;
}
void addbackSingle(TOP fs) {
if (!svd.fsTobeAddedbackSingleInUse) {
Misc.internalError();
}
svd.fsTobeAddedbackSingle.addback(fs);
svd.fsTobeAddedbackSingleInUse = false;
}
void addbackSingleIfWasRemoved(boolean wasRemoved, TOP fs) {
if (wasRemoved) {
addbackSingle(fs);
}
svd.fsTobeAddedbackSingleInUse = false;
}
private FSsTobeAddedback getAddback(int size) {
if (svd.fsTobeAddedbackSingleInUse) {
Misc.internalError();
}
return svd.fssTobeAddedback.get(size - 1);
}
FSsTobeAddedbackSingle getAddbackSingle() {
if (svd.fsTobeAddedbackSingleInUse) {
// System.out.println(Misc.dumpCallers(addbackSingleTrace, 2, 100));
Misc.internalError();
}
// addbackSingleTrace = Thread.currentThread().getStackTrace();
svd.fsTobeAddedbackSingleInUse = true;
svd.fsTobeAddedbackSingle.clear(); // safety
return svd.fsTobeAddedbackSingle;
}
void featureCodes_inIndexKeysAdd(int featCode/* , int registryIndex */) {
svd.featureCodesInIndexKeys.set(featCode);
// skip adding if no JCas registry entry for this feature
// if (registryIndex >= 0) {
// svd.featureJiInIndexKeys.set(registryIndex);
// }
}
@Override
public void enableReset(boolean flag) {
this.svd.flushEnabled = flag;
}
@Override
public final TypeSystem getTypeSystem() {
return getTypeSystemImpl();
}
public final TypeSystemImpl getTypeSystemImpl() {
if (tsi_local == null) {
tsi_local = this.svd.tsi;
}
return this.tsi_local;
}
/**
* Set the shared svd type system ref, in all views
*
* @param ts
*/
void installTypeSystemInAllViews(TypeSystemImpl ts) {
this.svd.tsi = ts;
final List<CASImpl> sn2v = this.svd.sofaNbr2ViewMap;
if (sn2v.size() > 0) {
for (CASImpl view : sn2v.subList(1, sn2v.size())) {
view.tsi_local = ts;
}
}
this.getBaseCAS().tsi_local = ts;
}
@Override
public ConstraintFactory getConstraintFactory() {
return ConstraintFactory.instance();
}
/**
* Create the appropriate Feature Structure Java instance - from whatever the generator for this
* type specifies.
*
* @param type
* the type to create
* @return a Java object representing the FeatureStructure impl in Java.
*/
@Override
public <T extends FeatureStructure> T createFS(Type type) {
final TypeImpl ti = (TypeImpl) type;
if (!ti.isCreatableAndNotBuiltinArray()) {
throw new CASRuntimeException(CASRuntimeException.NON_CREATABLE_TYPE, type.getName(),
"CAS.createFS()");
}
return (T) createFSAnnotCheck(ti);
}
private <T extends FeatureStructureImplC> T createFSAnnotCheck(TypeImpl ti) {
if (ti.isAnnotationBaseType()) {
// not here, will be checked later in AnnotationBase constructor
// if (this.isBaseCas()) {
// throw new CASRuntimeException(CASRuntimeException.DISALLOW_CREATE_ANNOTATION_IN_BASE_CAS,
// ti.getName());
// }
getSofaRef(); // materialize this if not present; required for setting the sofa ref
// must happen before the annotation is created, for compressed form 6
// serialization order
// to insure sofa precedes the ref of it
}
assertTypeBelongsToCasTypesystem(ti);
FsGenerator3 g = svd.generators[ti.getCode()]; // get generator or null
return (g != null) ? (T) g.createFS(ti, this)
// pear case, with no overriding pear - use base
: (T) createFsFromGenerator(svd.baseGenerators, ti);
//
//
// // not pear or no special cover class for this
//
//
// TOP fs = createFsFromGenerator(svd.baseGenerators, ti);
//
// FsGenerator g = svd.generators[ti.getCode()]; // get pear generator or null
// return (g != null)
// ? (T) pearConvert(fs, g)
// : (T) fs;
// }
//
// return (T) createFsFromGenerator(svd.generators, ti);
}
private static final AtomicInteger strictTypeSourceCheckMessageCount = new AtomicInteger(0);
private void assertTypeBelongsToCasTypesystem(TypeImpl ti) {
if (tsi_local != null && ti.getTypeSystem() != tsi_local) {
String message = String.format(
"Creating a feature structure of type [%s](%d) from type system [%s] in CAS with "
+ "different type system [%s] is not supported.",
ti.getName(), ti.getCode(), format("<%,d>", identityHashCode(ti.getTypeSystem())),
format("<%,d>", identityHashCode(tsi_local)));
if (TypeSystemImpl.IS_ENABLE_STRICT_TYPE_SOURCE_CHECK) {
throw new IllegalArgumentException(message);
} else {
Misc.decreasingWithTrace(strictTypeSourceCheckMessageCount, message,
UIMAFramework.getLogger());
}
}
}
/**
* Called during construction of FS. For normal FS "new" operators, if in PEAR context, make the
* base version
*
* @param fs
* @param ti
* @return true if made a base for a trampoline
*/
boolean maybeMakeBaseVersionForPear(FeatureStructureImplC fs, TypeImpl ti) {
if (!inPearContext()) {
return false;
}
FsGenerator3 g = svd.generators[ti.getCode()]; // get pear generator or null
if (g == null) {
return false;
}
TOP baseFs;
try {
suspendPearContext();
assertTypeBelongsToCasTypesystem(ti);
svd.reuseId = fs._id;
baseFs = createFsFromGenerator(svd.baseGenerators, ti);
} finally {
restorePearContext();
svd.reuseId = 0;
}
svd.id2base.put(baseFs);
svd.id2tramp.put(baseFs._id, (TOP) fs);
pearBaseFs = baseFs;
return true;
}
private TOP createFsFromGenerator(FsGenerator3[] gs, TypeImpl ti) {
return gs[ti.getCode()].createFS(ti, this);
}
public TOP createArray(TypeImpl array_type, int arrayLength) {
TypeImpl_array tia = (TypeImpl_array) array_type;
TypeImpl componentType = tia.getComponentType();
if (componentType.isPrimitive()) {
checkArrayPreconditions(arrayLength);
switch (componentType.getCode()) {
case intTypeCode:
return new IntegerArray(array_type, this, arrayLength);
case floatTypeCode:
return new FloatArray(array_type, this, arrayLength);
case booleanTypeCode:
return new BooleanArray(array_type, this, arrayLength);
case byteTypeCode:
return new ByteArray(array_type, this, arrayLength);
case shortTypeCode:
return new ShortArray(array_type, this, arrayLength);
case longTypeCode:
return new LongArray(array_type, this, arrayLength);
case doubleTypeCode:
return new DoubleArray(array_type, this, arrayLength);
case stringTypeCode:
return new StringArray(array_type, this, arrayLength);
default:
throw Misc.internalError();
}
}
// return (TOP) createArrayFS(/* array_type, */ arrayLength); // for backwards compat w/ v2,
// don't create typed arrays
if (IS_DISABLE_SUBTYPE_FSARRAY_CREATION) {
return (TOP) createArrayFS(arrayLength);
} else {
return (TOP) createArrayFS(array_type, arrayLength);
}
}
/*
* =============== These methods might be deprecated in favor of new FSArray(jcas, length) etc.
* except that these run with the CAS, not JCas (non-Javadoc)
*
* @see org.apache.uima.cas.CAS#createArrayFS(int)
*/
@Override
public ArrayFS createArrayFS(int length) {
return createArrayFS(getTypeSystemImpl().fsArrayType, length);
}
private ArrayFS createArrayFS(TypeImpl type, int length) {
checkArrayPreconditions(length);
return new FSArray(type, this, length);
}
@Override
public IntArrayFS createIntArrayFS(int length) {
checkArrayPreconditions(length);
return new IntegerArray(getTypeSystemImpl().intArrayType, this, length);
}
@Override
public FloatArrayFS createFloatArrayFS(int length) {
checkArrayPreconditions(length);
return new FloatArray(getTypeSystemImpl().floatArrayType, this, length);
}
@Override
public StringArrayFS createStringArrayFS(int length) {
checkArrayPreconditions(length);
return new StringArray(getTypeSystemImpl().stringArrayType, this, length);
}
// return true if only one sofa and it is the default text sofa
public boolean isBackwardCompatibleCas() {
// check that there is exactly one sofa
if (this.svd.viewCount != 1) {
return false;
}
if (!this.svd.initialSofaCreated) {
return false;
}
Sofa sofa = this.getInitialView().getSofa();
// check for mime type exactly equal to "text"
String sofaMime = sofa.getMimeType();
if (!"text".equals(sofaMime)) {
return false;
}
// check that sofaURI and sofaArray are not set
String sofaUri = sofa.getSofaURI();
if (sofaUri != null) {
return false;
}
TOP sofaArray = sofa.getSofaArray();
if (sofaArray != null) {
return false;
}
// check that name is NAME_DEFAULT_SOFA
String sofaname = sofa.getSofaID();
return NAME_DEFAULT_SOFA.equals(sofaname);
}
int getViewCount() {
return this.svd.viewCount;
}
FSIndexRepository getSofaIndexRepository(SofaFS aSofa) {
return getSofaIndexRepository(aSofa.getSofaRef());
}
FSIndexRepositoryImpl getSofaIndexRepository(int aSofaRef) {
if (aSofaRef >= this.svd.sofa2indexMap.size()) {
return null;
}
return this.svd.sofa2indexMap.get(aSofaRef);
}
void setSofaIndexRepository(SofaFS aSofa, FSIndexRepositoryImpl indxRepos) {
setSofaIndexRepository(aSofa.getSofaRef(), indxRepos);
}
void setSofaIndexRepository(int aSofaRef, FSIndexRepositoryImpl indxRepos) {
Misc.setWithExpand(this.svd.sofa2indexMap, aSofaRef, indxRepos);
}
@Override
@Deprecated
public SofaFS createSofa(SofaID sofaID, String mimeType) {
// extract absolute SofaName string from the ID
SofaFS aSofa = createSofa(sofaID.getSofaID(), mimeType);
getView(aSofa); // will create the view, needed to make the
// resetNoQuestions and other things that
// iterate over views work.
return aSofa;
}
Sofa createSofa(String sofaName, String mimeType) {
return createSofa(++this.svd.viewCount, sofaName, mimeType);
}
Sofa createSofa(int sofaNum, String sofaName, String mimeType) {
if (this.svd.sofaNameSet.contains(sofaName)) {
throw new CASRuntimeException(CASRuntimeException.SOFANAME_ALREADY_EXISTS, sofaName);
}
final boolean viewAlreadyExists = sofaNum == this.svd.viewCount;
if (!viewAlreadyExists) {
if (sofaNum == 1) { // skip the test for sofaNum == 1 - this can be set "later"
if (this.svd.viewCount == 0) {
this.svd.viewCount = 1;
} // else it is == or higher, so don't reset it down
} else { // sofa is not initial sofa - is guaranteed to be set when view created
// if (sofaNum != this.svd.viewCount + 1) {
// System.out.println("debug");
// }
assert (sofaNum == this.svd.viewCount + 1);
this.svd.viewCount = sofaNum;
}
}
Sofa sofa = new Sofa(getTypeSystemImpl().sofaType, this.getBaseCAS(), // view for a sofa is the
// base cas to correspond
// to where it gets
// indexed
sofaNum, sofaName, mimeType);
this.getBaseIndexRepository().addFS(sofa);
this.svd.sofaNameSet.add(sofaName);
if (!viewAlreadyExists) {
getView(sofa); // create the view that goes with this Sofa
}
return sofa;
}
boolean hasView(String name) {
return this.svd.sofaNameSet.contains(name);
}
Sofa createInitialSofa(String mimeType) {
Sofa sofa = createSofa(1, CAS.NAME_DEFAULT_SOFA, mimeType);
registerInitialSofa();
this.mySofaRef = sofa;
return sofa;
}
void registerInitialSofa() {
this.svd.initialSofaCreated = true;
}
boolean isInitialSofaCreated() {
return this.svd.initialSofaCreated;
}
/**
* @deprecated
*/
@Override
@Deprecated
public SofaFS getSofa(SofaID sofaID) {
// extract absolute SofaName string from the ID
return getSofa(sofaID.getSofaID());
}
private SofaFS getSofa(String sofaName) {
FSIterator<Sofa> iterator = this.svd.baseCAS.getSofaIterator();
while (iterator.hasNext()) {
SofaFS sofa = iterator.next();
if (sofaName.equals(sofa.getSofaID())) {
return sofa;
}
}
throw new CASRuntimeException(CASRuntimeException.SOFANAME_NOT_FOUND, sofaName);
}
SofaFS getSofa(int sofaRef) {
SofaFS aSofa = (SofaFS) this.ll_getFSForRef(sofaRef);
if (aSofa == null) {
CASRuntimeException e = new CASRuntimeException(CASRuntimeException.SOFAREF_NOT_FOUND);
throw e;
}
return aSofa;
}
public int ll_getSofaNum(int sofaRef) {
return ((Sofa) getFsFromId_checked(sofaRef)).getSofaNum();
}
public String ll_getSofaID(int sofaRef) {
return ((Sofa) getFsFromId_checked(sofaRef)).getSofaID();
}
public String ll_getSofaDataString(int sofaAddr) {
return ((Sofa) getFsFromId_checked(sofaAddr)).getSofaString();
}
public CASImpl getBaseCAS() {
return this.svd.baseCAS;
}
@Override
public <T extends SofaFS> FSIterator<T> getSofaIterator() {
FSIndex<T> sofaIndex = this.svd.baseCAS.indexRepository.<T> getIndex(CAS.SOFA_INDEX_NAME);
return sofaIndex.iterator();
}
// For internal use only
public Sofa getSofaRef() {
if (this.mySofaRef == null) {
// create the SofaFS for _InitialView ...
// ... and reset mySofaRef to point to it
this.mySofaRef = this.createInitialSofa(null);
}
return this.mySofaRef;
}
// For internal use only
public InputStream getSofaDataStream(SofaFS aSofa) {
Sofa sofa = (Sofa) aSofa;
String sd = sofa.getLocalStringData();
if (null != sd) {
ByteArrayInputStream bis;
bis = new ByteArrayInputStream(sd.getBytes(StandardCharsets.UTF_8));
return bis;
} else if (null != aSofa.getLocalFSData()) {
TOP fs = (TOP) sofa.getLocalFSData();
ByteBuffer buf = null;
switch (fs._getTypeCode()) {
case stringArrayTypeCode: {
StringBuilder sb = new StringBuilder();
final String[] theArray = ((StringArray) fs)._getTheArray();
for (int i = 0; i < theArray.length; i++) {
if (i != 0) {
sb.append('\n');
}
sb.append(theArray[i]);
}
return new ByteArrayInputStream(sb.toString().getBytes(StandardCharsets.UTF_8));
}
case intArrayTypeCode: {
final int[] theArray = ((IntegerArray) fs)._getTheArray();
(buf = ByteBuffer.allocate(theArray.length * 4)).asIntBuffer().put(theArray, 0,
theArray.length);
break;
}
case floatArrayTypeCode: {
final float[] theArray = ((FloatArray) fs)._getTheArray();
(buf = ByteBuffer.allocate(theArray.length * 4)).asFloatBuffer().put(theArray, 0,
theArray.length);
break;
}
case byteArrayTypeCode: {
final byte[] theArray = ((ByteArray) fs)._getTheArray();
buf = ByteBuffer.wrap(theArray);
break;
}
case shortArrayTypeCode: {
final short[] theArray = ((ShortArray) fs)._getTheArray();
(buf = ByteBuffer.allocate(theArray.length * 2)).asShortBuffer().put(theArray, 0,
theArray.length);
break;
}
case longArrayTypeCode: {
final long[] theArray = ((LongArray) fs)._getTheArray();
(buf = ByteBuffer.allocate(theArray.length * 8)).asLongBuffer().put(theArray, 0,
theArray.length);
break;
}
case doubleArrayTypeCode: {
final double[] theArray = ((DoubleArray) fs)._getTheArray();
(buf = ByteBuffer.allocate(theArray.length * 8)).asDoubleBuffer().put(theArray, 0,
theArray.length);
break;
}
default:
throw Misc.internalError();
}
ByteArrayInputStream bis = new ByteArrayInputStream(buf.array());
return bis;
} else if (null != aSofa.getSofaURI()) {
URL url;
try {
url = new URL(aSofa.getSofaURI());
return url.openStream();
} catch (IOException exc) {
throw new CASRuntimeException(CASRuntimeException.SOFADATASTREAM_ERROR, exc.getMessage());
}
}
return null;
}
@Override
public <T extends FeatureStructure> FSIterator<T> createFilteredIterator(FSIterator<T> it,
FSMatchConstraint cons) {
return new FilteredIterator<>(it, cons);
}
public TypeSystemImpl commitTypeSystem(boolean skip_loading_user_jcas) {
TypeSystemImpl ts = getTypeSystemImpl();
// For CAS pools, the type system could have already been committed
// Skip the initFSClassReg if so, because it may have been updated to a JCas
// version by another CAS processing in the pool
// @see org.apache.uima.cas.impl.FSClassRegistry
// avoid race: two instances of a CAS from a pool attempting to commit the
// ts
// at the same time
final ClassLoader cl = getJCasClassLoader();
synchronized (ts) {
// //debug
// System.out.format("debug committing ts %s classLoader %s%n", ts.hashCode(), cl);
if (!ts.isCommitted()) {
ts.set_skip_loading_user_jcas(skip_loading_user_jcas);
TypeSystemImpl tsc = ts.commit(cl);
if (tsc != ts) {
installTypeSystemInAllViews(tsc);
ts = tsc;
}
}
}
svd.baseGenerators = svd.generators = ts.getGeneratorsForClassLoader(cl, false); // false - not
// PEAR
createIndexRepository();
return ts;
}
public TypeSystemImpl commitTypeSystem() {
return commitTypeSystem(false);
}
private void createIndexRepository() {
if (!this.getTypeSystemMgr().isCommitted()) {
throw new CASAdminException(CASAdminException.MUST_COMMIT_TYPE_SYSTEM);
}
if (this.indexRepository == null) {
this.indexRepository = new FSIndexRepositoryImpl(this);
}
}
@Override
public FSIndexRepositoryMgr getIndexRepositoryMgr() {
// assert(this.cas.getIndexRepository() != null);
return this.indexRepository;
}
@Deprecated
public void commitFS(FeatureStructure fs) {
getIndexRepository().addFS(fs);
}
@Override
public FeaturePath createFeaturePath() {
return new FeaturePathImpl();
}
// Implement the ConstraintFactory interface.
/**
* @see org.apache.uima.cas.admin.CASMgr#getTypeSystemMgr()
*/
@Override
public TypeSystemMgr getTypeSystemMgr() {
return getTypeSystemImpl();
}
@Override
public void reset() {
if (isCasLocked()) {
throw new CASAdminException(CASAdminException.FLUSH_DISABLED);
}
if (this == this.svd.baseCAS) {
resetNoQuestions();
return;
}
// called from a CAS view.
// clear CAS ...
this.svd.baseCAS.resetNoQuestions();
}
public void resetNoQuestions() {
svd.resetNoQuestions(true);
}
/**
* @deprecated Use {@link #reset reset()}instead.
*/
@Override
@Deprecated
public void flush() {
reset();
}
@Override
public FSIndexRepository getIndexRepository() {
if (this == this.svd.baseCAS) {
// BaseCas has no indexes for users
return null;
}
if (this.indexRepository.isCommitted()) {
return this.indexRepository;
}
return null;
}
FSIndexRepository getBaseIndexRepository() {
if (this.svd.baseCAS.indexRepository.isCommitted()) {
return this.svd.baseCAS.indexRepository;
}
return null;
}
FSIndexRepositoryImpl getBaseIndexRepositoryImpl() {
return this.svd.baseCAS.indexRepository;
}
void addSofaFsToIndex(SofaFS sofa) {
this.svd.baseCAS.getBaseIndexRepository().addFS(sofa);
}
void registerView(Sofa aSofa) {
this.mySofaRef = aSofa;
}
/**
* @see org.apache.uima.cas.CAS#fs2listIterator(FSIterator)
*/
@Override
public <T extends FeatureStructure> ListIterator<T> fs2listIterator(FSIterator<T> it) {
// return new FSListIteratorImpl<T>(it);
return it; // in v3, FSIterator extends listIterator
}
/**
* @see org.apache.uima.cas.admin.CASMgr#getCAS()
*/
@Override
public CAS getCAS() {
if (this.indexRepository.isCommitted()) {
return this;
}
throw new CASAdminException(CASAdminException.MUST_COMMIT_INDEX_REPOSITORY);
}
// public void setFSClassRegistry(FSClassRegistry fsClassReg) {
// this.svd.casMetadata.fsClassRegistry = fsClassReg;
// }
// JCasGen'd cover classes use this to add their generators to the class
// registry
// Note that this now (June 2007) a no-op for JCasGen'd generators
// Also previously (but not now) used in JCas initialization to copy-down super generators to
// subtypes
// as needed
public FSClassRegistry getFSClassRegistry() {
return null;
// return getTypeSystemImpl().getFSClassRegistry();
}
/**
* @param fs
* the Feature Structure being updated
* @param fi
* the Feature of fs being updated, or null if fs is an array
* @param arrayIndexStart
* @param nbrOfConsecutive
*/
private void logFSUpdate(TOP fs, FeatureImpl fi, int arrayIndexStart, int nbrOfConsecutive) {
// log the FS
final Map<TOP, FsChange> changes = this.svd.modifiedPreexistingFSs;
// create or use last FsChange element
FsChange change = changes.computeIfAbsent(fs, key -> new FsChange(key));
if (fi == null) {
Misc.assertUie(arrayIndexStart >= 0);
change.addArrayData(arrayIndexStart, nbrOfConsecutive);
} else {
change.addFeatData(fi.getOffset());
}
}
/**
* @param fs
* the Feature Structure being updated
* @param arrayIndexStart
* @param nbrOfConsecutive
*/
private void logFSUpdate(TOP fs, PositiveIntSet indexesPlus1) {
// log the FS
final Map<TOP, FsChange> changes = this.svd.modifiedPreexistingFSs;
// create or use last FsChange element
FsChange change = changes.computeIfAbsent(fs, key -> new FsChange(key));
change.addArrayData(indexesPlus1);
}
private void logFSUpdate(TOP fs, FeatureImpl fi) {
logFSUpdate(fs, fi, -1, -1); // indicate non-array call
}
/**
* This is your link from the low-level API to the high-level API. Use this method to create a
* FeatureStructure object from an address. Note that the reverse is not supported by public APIs
* (i.e., there is currently no way to get at the address of a FeatureStructure. Maybe we will
* need to change that.
*
* The "create" in "createFS" is a misnomer - the FS must already be created.
*
* @param id
* The id of the feature structure to be created.
* @param <T>
* The Java class associated with this feature structure
* @return A FeatureStructure object.
*/
public <T extends TOP> T createFS(int id) {
return getFsFromId_checked(id);
}
public int getArraySize(CommonArrayFS fs) {
return fs.size();
}
@Override
public int ll_getArraySize(int id) {
return getArraySize(getFsFromId_checked(id));
}
final void setWithCheckAndJournal(TOP fs, FeatureImpl fi, Runnable setter) {
if (fs._inSetSortedIndex()) {
boolean wasRemoved = checkForInvalidFeatureSetting(fs, fi.getCode());
setter.run();
if (wasRemoved) {
maybeAddback(fs);
}
} else {
setter.run();
}
maybeLogUpdate(fs, fi);
}
final public void setWithCheckAndJournal(TOP fs, int featCode, Runnable setter) {
if (fs._inSetSortedIndex()) {
boolean wasRemoved = checkForInvalidFeatureSetting(fs, featCode);
setter.run();
if (wasRemoved) {
maybeAddback(fs);
}
} else {
setter.run();
}
maybeLogUpdate(fs, featCode);
}
// public void setWithCheck(FeatureStructureImplC fs, FeatureImpl feat, Runnable setter) {
// boolean wasRemoved = checkForInvalidFeatureSetting(fs, feat);
// setter.run();
// if (wasRemoved) {
// maybeAddback(fs);
// }
// }
/**
* This method called by setters in JCas gen'd classes when the setter must check for journaling
*
* @param fs
* -
* @param fi
* -
* @param setter
* -
*/
public final void setWithJournal(FeatureStructureImplC fs, FeatureImpl fi, Runnable setter) {
setter.run();
maybeLogUpdate(fs, fi);
}
public final boolean isLoggingNeeded(FeatureStructureImplC fs) {
return this.svd.trackingMark != null && !this.svd.trackingMark.isNew(fs._id);
}
/**
* @param fs
* the Feature Structure being updated
* @param feat
* the feature of fs being updated, or null if fs is a primitive array
* @param i
* the index being updated
*/
final public void maybeLogArrayUpdate(FeatureStructureImplC fs, FeatureImpl feat, int i) {
if (isLoggingNeeded(fs)) {
this.logFSUpdate((TOP) fs, feat, i, 1);
}
}
/**
* @param fs
* the Feature Structure being updated
* @param indexesPlus1
* - a set of indexes (plus 1) that have been update
*/
final public void maybeLogArrayUpdates(FeatureStructureImplC fs, PositiveIntSet indexesPlus1) {
if (isLoggingNeeded(fs)) {
this.logFSUpdate((TOP) fs, indexesPlus1);
}
}
/**
* @param fs
* a primitive array FS
* @param startingIndex
* -
* @param length
* number of consequtive items
*/
public final void maybeLogArrayUpdates(FeatureStructureImplC fs, int startingIndex, int length) {
if (isLoggingNeeded(fs)) {
this.logFSUpdate((TOP) fs, null, startingIndex, length);
}
}
final public void maybeLogUpdate(FeatureStructureImplC fs, FeatureImpl feat) {
if (isLoggingNeeded(fs)) {
this.logFSUpdate((TOP) fs, feat);
}
}
final public void maybeLogUpdate(FeatureStructureImplC fs, int featCode) {
if (isLoggingNeeded(fs)) {
this.logFSUpdate((TOP) fs, getFeatFromCode_checked(featCode));
}
}
final public boolean isLogging() {
return this.svd.trackingMark != null;
}
// /**
// * Common setter code for features in Feature Structures
// *
// * These come in two styles: one with int values, one with Object values
// * Object values are FS or Strings or JavaObjects
// */
//
// /**
// * low level setter
// *
// * @param fs the feature structure
// * @param feat the feature to set
// * @param value -
// */
//
// public void setFeatureValue(FeatureStructureImplC fs, FeatureImpl feat, int value) {
// fs.setIntValue(feat, value);
//// boolean wasRemoved = checkForInvalidFeatureSetting(fs, feat.getCode());
//// fs._intData[feat.getAdjustedOffset()] = value;
//// if (wasRemoved) {
//// maybeAddback(fs);
//// }
//// maybeLogUpdate(fs, feat);
// }
/**
* version for longs, uses two slots Only called from FeatureStructureImplC after determining
* there is no local field to use Is here because of 3 calls to things in this class
*
* @param fsIn
* the feature structure
* @param feat
* the feature to set
* @param v
* -
*/
public void setLongValue(FeatureStructureImplC fsIn, FeatureImpl feat, long v) {
TOP fs = (TOP) fsIn;
if (fs._inSetSortedIndex()) {
boolean wasRemoved = checkForInvalidFeatureSetting(fs, feat.getCode());
fs._setLongValueNcNj(feat, v);
if (wasRemoved) {
maybeAddback(fs);
}
} else {
fs._setLongValueNcNj(feat, v);
}
maybeLogUpdate(fs, feat);
}
void setFeatureValue(int fsRef, int featureCode, TOP value) {
getFsFromId_checked(fsRef).setFeatureValue(getFeatFromCode_checked(featureCode), value);
}
/**
* internal use - special setter for setting feature values, including special handling if the
* feature is for the sofaArray, when deserializing
*
* @param fs
* -
* @param feat
* -
* @param value
* -
*/
public static void setFeatureValueMaybeSofa(TOP fs, FeatureImpl feat, TOP value) {
if (fs instanceof Sofa) {
assert feat.getCode() == sofaArrayFeatCode;
((Sofa) fs).setLocalSofaData(value);
} else {
fs.setFeatureValue(feat, value);
}
}
/**
* Internal use, for cases where deserializing - special case setting sofString to skip updating
* the document annotation
*
* @param fs
* -
* @param feat
* -
* @param s
* -
*/
public static void setFeatureValueFromStringNoDocAnnotUpdate(FeatureStructureImplC fs,
FeatureImpl feat, String s) {
if (fs instanceof Sofa && feat.getCode() == sofaStringFeatCode) {
((Sofa) fs).setLocalSofaDataNoDocAnnotUpdate(s);
} else {
setFeatureValueFromString(fs, feat, s);
}
}
/**
* Supports setting slots to "0" for null values
*
* @param fs
* The feature structure to update
* @param feat
* the feature to update-
* @param s
* the string representation of the value, could be null
*/
public static void setFeatureValueFromString(FeatureStructureImplC fs, FeatureImpl feat,
String s) {
final TypeImpl range = feat.getRangeImpl();
if (fs instanceof Sofa) {
// sofa has special setters
Sofa sofa = (Sofa) fs;
switch (feat.getCode()) {
case sofaMimeFeatCode:
sofa.setMimeType(s);
break;
case sofaStringFeatCode:
sofa.setLocalSofaData(s);
break;
case sofaUriFeatCode:
sofa.setRemoteSofaURI(s);
break;
default: // left empty - ignore trying to set final fields
}
return;
}
if (feat.isInInt) {
switch (range.getCode()) {
case floatTypeCode:
fs.setFloatValue(feat, (s == null) ? 0F : Float.parseFloat(s));
break;
case booleanTypeCode:
fs.setBooleanValue(feat, (s == null) ? false : Boolean.parseBoolean(s));
break;
case longTypeCode:
fs.setLongValue(feat, (s == null) ? 0L : Long.parseLong(s));
break;
case doubleTypeCode:
fs.setDoubleValue(feat, (s == null) ? 0D : Double.parseDouble(s));
break;
case byteTypeCode:
fs.setByteValue(feat, (s == null) ? 0 : Byte.parseByte(s));
break;
case shortTypeCode:
fs.setShortValue(feat, (s == null) ? 0 : Short.parseShort(s));
break;
case intTypeCode:
fs.setIntValue(feat, (s == null) ? 0 : Integer.parseInt(s));
break;
default:
fs.setIntValue(feat, (s == null) ? 0 : Integer.parseInt(s));
}
} else if (range.isRefType) {
if (s == null) {
fs.setFeatureValue(feat, null);
} else {
// Setting a reference value "{0}" from a string is not supported.
throw new CASRuntimeException(CASRuntimeException.SET_REF_FROM_STRING_NOT_SUPPORTED,
feat.getName());
}
} else if (range.isStringOrStringSubtype()) { // includes TypeImplSubString
// is String or Substring
fs.setStringValue(feat, (s == null) ? null : s);
// } else if (range == getTypeSystemImpl().javaObjectType) {
// fs.setJavaObjectValue(feat, (s == null) ? null : deserializeJavaObject(s));
} else {
Misc.internalError();
}
}
// private Object deserializeJavaObject(String s) {
// throw new UnsupportedOperationException("Deserializing JavaObjects not yet implemented");
// }
//
// static String serializeJavaObject(Object s) {
// throw new UnsupportedOperationException("Serializing JavaObjects not yet implemented");
// }
/*
* This should be the only place where the encoding of floats and doubles in terms of ints is
* specified Someday we may want to preserve NAN things using "raw" versions
*/
public static final float int2float(int i) {
return Float.intBitsToFloat(i);
}
public static final int float2int(float f) {
return Float.floatToIntBits(f);
}
public static final double long2double(long l) {
return Double.longBitsToDouble(l);
}
public static final long double2long(double d) {
return Double.doubleToLongBits(d);
}
// Type access methods.
public final boolean isStringType(Type type) {
return type instanceof TypeImpl_string;
}
public final boolean isAbstractArrayType(Type type) {
return isArrayType(type);
}
public final boolean isArrayType(Type type) {
return ((TypeImpl) type).isArray();
}
public final boolean isPrimitiveArrayType(Type type) {
return (type instanceof TypeImpl_array) && !type.getComponentType().isPrimitive();
}
public final boolean isIntArrayType(Type type) {
return (type == getTypeSystemImpl().intArrayType);
}
public final boolean isFloatArrayType(Type type) {
return ((TypeImpl) type).getCode() == floatArrayTypeCode;
}
public final boolean isStringArrayType(Type type) {
return ((TypeImpl) type).getCode() == stringArrayTypeCode;
}
public final boolean isBooleanArrayType(Type type) {
return ((TypeImpl) type).getCode() == booleanArrayTypeCode;
}
public final boolean isByteArrayType(Type type) {
return ((TypeImpl) type).getCode() == byteArrayTypeCode;
}
public final boolean isShortArrayType(Type type) {
return ((TypeImpl) type).getCode() == byteArrayTypeCode;
}
public final boolean isLongArrayType(Type type) {
return ((TypeImpl) type).getCode() == longArrayTypeCode;
}
public final boolean isDoubleArrayType(Type type) {
return ((TypeImpl) type).getCode() == doubleArrayTypeCode;
}
public final boolean isFSArrayType(Type type) {
return ((TypeImpl) type).getCode() == fsArrayTypeCode;
}
public final boolean isIntType(Type type) {
return ((TypeImpl) type).getCode() == intTypeCode;
}
public final boolean isFloatType(Type type) {
return ((TypeImpl) type).getCode() == floatTypeCode;
}
public final boolean isByteType(Type type) {
return ((TypeImpl) type).getCode() == byteTypeCode;
}
public final boolean isBooleanType(Type type) {
return ((TypeImpl) type).getCode() == floatTypeCode;
}
public final boolean isShortType(Type type) {
return ((TypeImpl) type).getCode() == shortTypeCode;
}
public final boolean isLongType(Type type) {
return ((TypeImpl) type).getCode() == longTypeCode;
}
public final boolean isDoubleType(Type type) {
return ((TypeImpl) type).getCode() == doubleTypeCode;
}
/*
* Only called on base CAS
*/
/**
* @see org.apache.uima.cas.admin.CASMgr#initCASIndexes()
*/
@Override
public void initCASIndexes() throws CASException {
final TypeSystemImpl ts = getTypeSystemImpl();
if (!ts.isCommitted()) {
throw new CASException(CASException.MUST_COMMIT_TYPE_SYSTEM);
}
FSIndexComparator comp = this.indexRepository.createComparator();
comp.setType(ts.sofaType);
comp.addKey(ts.sofaNum, FSIndexComparator.STANDARD_COMPARE);
this.indexRepository.createIndex(comp, CAS.SOFA_INDEX_NAME, FSIndex.BAG_INDEX);
comp = this.indexRepository.createComparator();
comp.setType(ts.annotType);
comp.addKey(ts.startFeat, FSIndexComparator.STANDARD_COMPARE);
comp.addKey(ts.endFeat, FSIndexComparator.REVERSE_STANDARD_COMPARE);
comp.addKey(this.indexRepository.getDefaultTypeOrder(), FSIndexComparator.STANDARD_COMPARE);
this.indexRepository.createIndex(comp, CAS.STD_ANNOTATION_INDEX);
}
// ///////////////////////////////////////////////////////////////////////////
// CAS support ... create CAS view of aSofa
// For internal use only
public CAS getView(int sofaNum) {
return svd.getViewFromSofaNbr(sofaNum);
}
@Override
public CAS getCurrentView() {
return getView(CAS.NAME_DEFAULT_SOFA);
}
// ///////////////////////////////////////////////////////////////////////////
// JCas support
@Override
public JCas getJCas() {
if (this.jcas == null) {
this.jcas = JCasImpl.getJCas(this);
}
return this.jcas;
}
@Override
public JCasImpl getJCasImpl() {
if (this.jcas == null) {
this.jcas = JCasImpl.getJCas(this);
}
return this.jcas;
}
// /**
// * Internal use only
// *
// * @return corresponding JCas, assuming it exists
// */
// public JCas getExistingJCas() {
// return this.jcas;
// }
//
// Create JCas view of aSofa
@Override
public JCas getJCas(SofaFS aSofa) throws CASException {
// Create base JCas, if needed
this.svd.baseCAS.getJCas();
return getView(aSofa).getJCas();
/*
* // If a JCas already exists for this Sofa, return it JCas aJCas = (JCas)
* this.svd.baseCAS.sofa2jcasMap.get(Integer.valueOf(aSofa.getSofaRef())); if (null != aJCas) {
* return aJCas; } // Get view of aSofa CASImpl view = (CASImpl) getView(aSofa); // wrap in JCas
* aJCas = view.getJCas(); this.sofa2jcasMap.put(Integer.valueOf(aSofa.getSofaRef()), aJCas);
* return aJCas;
*/
}
@Override
@Deprecated
public JCas getJCas(SofaID aSofaID) throws CASException {
SofaFS sofa = getSofa(aSofaID);
// sofa guaranteed to be non-null by above method.
return getJCas(sofa);
}
// For internal platform use only
CASImpl getInitialView() {
return svd.getInitialView();
}
@Override
public CAS createView(String aSofaID) {
// do sofa mapping for current component
String absoluteSofaName = null;
if (getCurrentComponentInfo() != null) {
absoluteSofaName = getCurrentComponentInfo().mapToSofaID(aSofaID);
}
if (absoluteSofaName == null) {
absoluteSofaName = aSofaID;
}
// Can't use name of Initial View
if (CAS.NAME_DEFAULT_SOFA.equals(absoluteSofaName)) {
throw new CASRuntimeException(CASRuntimeException.SOFANAME_ALREADY_EXISTS, aSofaID);
}
Sofa newSofa = createSofa(absoluteSofaName, null);
CAS newView = getView(newSofa);
((CASImpl) newView).registerView(newSofa);
return newView;
}
@Override
public CAS getView(String aSofaID) {
// do sofa mapping for current component
String absoluteSofaName = null;
if (getCurrentComponentInfo() != null) {
absoluteSofaName = getCurrentComponentInfo().mapToSofaID(aSofaID);
}
if (absoluteSofaName == null) {
absoluteSofaName = aSofaID;
}
// if this resolves to the Initial View, return view(1)...
// ... as the Sofa for this view may not exist yet
if (CAS.NAME_DEFAULT_SOFA.equals(absoluteSofaName)) {
return getInitialView();
}
// get Sofa and switch to view
SofaFS sofa = getSofa(absoluteSofaName);
// sofa guaranteed to be non-null by above method
// unless sofa doesn't exist, which will cause a throw.
return getView(sofa);
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.cas.CAS#getView(org.apache.uima.cas.SofaFS)
*
* Callers of this can have created Sofas in the CAS without views: using the old deprecated
* createSofa apis (this is being fixed so these will create the views) via deserialization, which
* will put the sofaFSs into the CAS without creating the views, and then call this to create the
* views. - for deserialization: there are 2 kinds: 1 is xmi the other is binary. - for xmi: there
* is 1.4.x compatible and 2.1 compatible. The older format can have sofaNbrs in the order 2, 3,
* 4, 1 (initial sofa), 5, 6, 7 The newer format has them in order. For deserialized sofas, we
* insure here that there are no duplicates. This is not done in the deserializers - they use
* either heap dumping (binary) or generic fs creators (xmi).
*
* Goal is to detect case where check is needed (sofa exists, but view not yet created). This is
* done by looking for cases where sofaNbr &gt; curViewCount. This only works if the sofaNbrs go
* up by 1 (except for the initial sofa) in the input sequence of calls.
*/
@Override
public CASImpl getView(SofaFS aSofa) {
Sofa sofa = (Sofa) aSofa;
final int sofaNbr = sofa.getSofaRef();
// final Integer sofaNbrInteger = Integer.valueOf(sofaNbr);
CASImpl aView = svd.getViewFromSofaNbr(sofaNbr);
if (null == aView) {
// This is the deserializer case, or the case where an older API created a
// sofa,
// which is now creating the associated view
// create a new CAS view
aView = new CASImpl(this.svd.baseCAS, sofa);
svd.setViewForSofaNbr(sofaNbr, aView);
verifySofaNameUniqueIfDeserializedViewAdded(sofaNbr, sofa);
return aView;
}
// for deserialization - might be reusing a view, and need to tie new Sofa
// to old View
if (null == aView.mySofaRef) {
aView.mySofaRef = sofa;
}
verifySofaNameUniqueIfDeserializedViewAdded(sofaNbr, aSofa);
return aView;
}
// boolean isSofaView(int sofaAddr) {
// if (mySofaRef == null) {
// // don't create initial sofa
// return false;
// }
// return mySofaRef == sofaAddr;
// }
/*
* for Sofas being added (determined by sofaNbr &gt; curViewCount): verify sofa name is not
* already present, and record it for future tests
*
* Only should do the name test & update in the case of deserialized new sofas coming in. These
* will come in, in order. Exception is "_InitialView" which could come in the middle. If it comes
* in the middle, no test will be done for duplicates, and it won't be added to set of known
* names. This is ok because the createVIew special cases this test. Users could corrupt an xmi
* input, which would make this logic fail.
*/
private void verifySofaNameUniqueIfDeserializedViewAdded(int sofaNbr, SofaFS aSofa) {
final int curViewCount = this.svd.viewCount;
if (curViewCount < sofaNbr) {
// Only true for deserialized sofas with new views being either created,
// or
// hooked-up from CASes that were freshly reset, which have multiple
// views.
// Assume sofa numbers are incrementing by 1
assert (sofaNbr == curViewCount + 1);
this.svd.viewCount = sofaNbr;
String id = aSofa.getSofaID();
// final Feature idFeat =
// getTypeSystem().getFeatureByFullName(CAS.FEATURE_FULL_NAME_SOFAID);
// String id =
// ll_getStringValue(((FeatureStructureImpl)aSofa).getAddress(),
// ((FeatureImpl) idFeat).getCode());
Misc.assertUie(this.svd.sofaNameSet.contains(id));
// this.svd.sofaNameSet.add(id);
}
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.cas.impl.LowLevelCAS#ll_getTypeSystem()
*/
@Override
public LowLevelTypeSystem ll_getTypeSystem() {
return getTypeSystemImpl().getLowLevelTypeSystem();
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.cas.impl.LowLevelCAS#ll_getIndexRepository()
*/
@Override
public LowLevelIndexRepository ll_getIndexRepository() {
return this.indexRepository;
}
/**
*
* @param fs
* @param domType
* @param featCode
*/
private final void checkLowLevelParams(TOP fs, TypeImpl domType, int featCode) {
checkFeature(featCode);
checkTypeHasFeature(domType, featCode);
}
/**
* Check that the featCode is a feature of the domain type
*
* @param domTypeCode
* @param featCode
*/
private final void checkTypeHasFeature(TypeImpl domainType, int featureCode) {
checkTypeHasFeature(domainType, getFeatFromCode_checked(featureCode));
}
private final void checkTypeHasFeature(TypeImpl domainType, FeatureImpl feature) {
if (!domainType.isAppropriateFeature(feature)) {
throw new LowLevelException(LowLevelException.FEAT_DOM_ERROR, domainType.getCode(),
domainType.getName(), feature.getCode(), feature.getName());
}
}
/**
* Check the range is appropriate for this type/feature. Throws LowLevelException if it isn't.
*
* @param domType
* domain type
* @param ranType
* range type
* @param feat
* feature
*/
public final void checkTypingConditions(Type domType, Type ranType, Feature feat) {
TypeImpl domainTi = (TypeImpl) domType;
FeatureImpl fi = (FeatureImpl) feat;
checkTypeHasFeature(domainTi, fi);
if (!((TypeImpl) fi.getRange()).subsumes((TypeImpl) ranType)) {
throw new LowLevelException(LowLevelException.FEAT_RAN_ERROR, fi.getCode(), feat.getName(),
((TypeImpl) ranType).getCode(), ranType.getName());
}
}
/**
* Validate a feature's range is a ref to a feature structure
*
* @param featCode
* @throws LowLevelException
*/
private final void checkFsRan(FeatureImpl fi) throws LowLevelException {
if (!fi.getRangeImpl().isRefType) {
throw new LowLevelException(LowLevelException.FS_RAN_TYPE_ERROR, fi.getCode(), fi.getName(),
fi.getRange().getName());
}
}
private final void checkFeature(int featureCode) {
if (!getTypeSystemImpl().isFeature(featureCode)) {
throw new LowLevelException(LowLevelException.INVALID_FEATURE_CODE, featureCode);
}
}
private TypeImpl getTypeFromCode(int typeCode) {
return getTypeSystemImpl().getTypeForCode(typeCode);
}
private TypeImpl getTypeFromCode_checked(int typeCode) {
return getTypeSystemImpl().getTypeForCode_checked(typeCode);
}
private FeatureImpl getFeatFromCode_checked(int featureCode) {
return getTypeSystemImpl().getFeatureForCode_checked(featureCode);
}
public final <T extends TOP> T getFsFromId_checked(int fsRef) {
T r = getFsFromId(fsRef);
if (r == null) {
if (fsRef == 0) {
return null;
}
LowLevelException e = new LowLevelException(LowLevelException.INVALID_FS_REF, fsRef);
// this form to enable seeing this even if the
// throwable is silently handled.
// System.err.println("debug " + e);
throw e;
}
return r;
}
@Override
public final boolean ll_isRefType(int typeCode) {
return getTypeFromCode(typeCode).isRefType;
}
@Override
public final int ll_getTypeClass(int typeCode) {
return TypeSystemImpl.getTypeClass(getTypeFromCode(typeCode));
}
// backwards compatibility only
@Override
public final int ll_createFS(int typeCode) {
return ll_createFS(typeCode, true);
}
@Override
public final int ll_createFS(int typeCode, boolean doCheck) {
TypeImpl ti = (TypeImpl) getTypeSystemImpl().ll_getTypeForCode(typeCode);
if (doCheck) {
if (ti == null || !ti.isCreatableAndNotBuiltinArray()) {
throw new LowLevelException(LowLevelException.CREATE_FS_OF_TYPE_ERROR, typeCode);
}
}
TOP fs = (TOP) createFS(ti);
if (!fs._isPearTrampoline()) {
setId2FsMaybeUnconditionally(fs);
}
return fs._id;
}
/**
* used for ll_setIntValue which changes type code
*
* @param ti
* - the type of the created FS
* @param id
* - the id to use
* @return the FS
*/
private TOP createFsWithExistingId(TypeImpl ti, int id) {
svd.reuseId = id;
try {
TOP fs = createFS(ti);
svd.id2fs.putChange(id, fs);
return fs;
} finally {
svd.reuseId = 0;
}
}
/*
* /**
*
* @param arrayLength
*
* @return the id of the created array
*
* @see org.apache.uima.cas.impl.LowLevelCAS#ll_createArray(int, int)
*/
@Override
public int ll_createArray(int typeCode, int arrayLength) {
TOP fs = createArray(getTypeFromCode_checked(typeCode), arrayLength);
setId2FsMaybeUnconditionally(fs);
return fs._id;
}
/**
* (for backwards compatibility with V2 CASImpl) Create a temporary (i.e., per document) array FS
* on the heap.
*
* @param type
* The type code of the array to be created.
* @param len
* The length of the array to be created.
* @return -
* @exception ArrayIndexOutOfBoundsException
* If <code>type</code> is not a type.
*/
public int createTempArray(int type, int len) {
return ll_createArray(type, len);
}
/**
* @param arrayLength
* -
* @return the id of the created array
*/
@Override
public int ll_createByteArray(int arrayLength) {
TOP fs = createArray(getTypeSystemImpl().byteArrayType, arrayLength);
set_id2fs(fs);
return fs._id;
}
/**
* @param arrayLength
* -
* @return the id of the created array
*/
@Override
public int ll_createBooleanArray(int arrayLength) {
TOP fs = createArray(getTypeSystemImpl().booleanArrayType, arrayLength);
set_id2fs(fs);
return fs._id;
}
/**
* @param arrayLength
* -
* @return the id of the created array
*/
@Override
public int ll_createShortArray(int arrayLength) {
TOP fs = createArray(getTypeSystemImpl().shortArrayType, arrayLength);
set_id2fs(fs);
return fs._id;
}
/**
* @param arrayLength
* -
* @return the id of the created array
*/
@Override
public int ll_createLongArray(int arrayLength) {
TOP fs = createArray(getTypeSystemImpl().longArrayType, arrayLength);
set_id2fs(fs);
return fs._id;
}
/**
* @param arrayLength
* -
* @return the id of the created array
*/
@Override
public int ll_createDoubleArray(int arrayLength) {
TOP fs = createArray(getTypeSystemImpl().doubleArrayType, arrayLength);
set_id2fs(fs);
return fs._id;
}
/**
* @param arrayLength
* -
* @return the id of the created array
*/
@Override
public int ll_createArray(int typeCode, int arrayLength, boolean doChecks) {
TypeImpl ti = getTypeFromCode_checked(typeCode);
if (doChecks) {
if (!ti.isArray()) {
throw new LowLevelException(LowLevelException.CREATE_ARRAY_OF_TYPE_ERROR, typeCode,
ti.getName());
}
if (arrayLength < 0) {
throw new LowLevelException(LowLevelException.ILLEGAL_ARRAY_LENGTH, arrayLength);
}
}
TOP fs = createArray(ti, arrayLength);
set_id2fs(fs);
return fs._id;
}
public void validateArraySize(int length) {
if (length < 0) {
/** Array size must be &gt;= 0. */
throw new CASRuntimeException(CASRuntimeException.ILLEGAL_ARRAY_SIZE);
}
}
/**
* Safety - any time the low level API to a FS is requested, hold on to that FS until CAS reset to
* mimic how v2 works.
*/
@Override
public final int ll_getFSRef(FeatureStructure fs) {
if (null == fs) {
return NULL;
}
TOP fst = (TOP) fs;
if (fst._isPearTrampoline()) {
return fst._id; // no need to hold on to this one - it's in jcas hash maps
}
// uncond. because this method can be called multiple times
svd.id2fs.putUnconditionally(fst); // hold on to it
return ((FeatureStructureImplC) fs)._id;
}
@Override
public <T extends TOP> T ll_getFSForRef(int id) {
return getFsFromId_checked(id);
}
// @formatter:off
/**
* Handle some unusual backwards compatibility cases
* featureCode = 0 - implies getting the type code
* feature range is int - normal
* feature range is a fs reference, return the id
* feature range is a string: add the string if not already present to the string heap, return the int handle.
* @param fsRef -
* @param featureCode -
* @return -
*/
// @formatter:on
@Override
public final int ll_getIntValue(int fsRef, int featureCode) {
TOP fs = getFsFromId_checked(fsRef);
if (featureCode == 0) {
return fs._getTypeImpl().getCode(); // case where the type is being requested
}
FeatureImpl fi = getFeatFromCode_checked(featureCode);
SlotKind kind = fi.getSlotKind();
switch (kind) {
case Slot_HeapRef:
return fs.getFeatureValue(fi)._id;
case Slot_Boolean:
case Slot_Byte:
case Slot_Short:
case Slot_Int:
case Slot_Float:
return fs._getIntValueNc(fi);
case Slot_StrRef:
return getCodeForString(fs._getStringValueNc(fi));
case Slot_LongRef:
return getCodeForLong(fs._getLongValueNc(fi));
case Slot_DoubleRef:
return getCodeForLong(CASImpl.double2long(fs._getDoubleValueNc(fi)));
default:
throw new CASRuntimeException(CASRuntimeException.INAPPROP_RANGE, fi.getName(), "int",
fi.getRange().getName());
}
}
// public final int ll_getIntValueFeatOffset(int fsRef, int featureOffset) {
// return ll_getFSForRef(fsRef)._intData[featureOffset];
// }
@Override
public final float ll_getFloatValue(int fsRef, int featureCode) {
return getFsFromId_checked(fsRef).getFloatValue(getFeatFromCode_checked(featureCode));
}
@Override
public final String ll_getStringValue(int fsRef, int featureCode) {
return getFsFromId_checked(fsRef).getStringValue(getFeatFromCode_checked(featureCode));
}
// public final String ll_getStringValueFeatOffset(int fsRef, int featureOffset) {
// return (String) getFsFromId_checked(fsRef)._refData[featureOffset];
// }
@Override
public final int ll_getRefValue(int fsRef, int featureCode) {
return getFsFromId_checked(fsRef).getFeatureValue(getFeatFromCode_checked(featureCode))._id();
}
// public final int ll_getRefValueFeatOffset(int fsRef, int featureOffset) {
// return ((FeatureStructureImplC)getFsFromId_checked(fsRef)._refData[featureOffset]).id();
// }
@Override
public final int ll_getIntValue(int fsRef, int featureCode, boolean doTypeChecks) {
if (doTypeChecks) {
checkNonArrayConditions(fsRef, featureCode);
}
return ll_getIntValue(fsRef, featureCode);
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.cas.impl.LowLevelCAS#ll_getFloatValue(int, int, boolean)
*/
@Override
public final float ll_getFloatValue(int fsRef, int featureCode, boolean doTypeChecks) {
if (doTypeChecks) {
checkNonArrayConditions(fsRef, featureCode);
}
return ll_getFloatValue(fsRef, featureCode);
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.cas.impl.LowLevelCAS#ll_getStringValue(int, int, boolean)
*/
@Override
public final String ll_getStringValue(int fsRef, int featureCode, boolean doTypeChecks) {
if (doTypeChecks) {
checkNonArrayConditions(fsRef, featureCode);
}
return ll_getStringValue(fsRef, featureCode);
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.cas.impl.LowLevelCAS#ll_getRefValue(int, int, boolean)
*/
@Override
public final int ll_getRefValue(int fsRef, int featureCode, boolean doTypeChecks) {
if (doTypeChecks) {
checkFsRefConditions(fsRef, featureCode);
}
return getFsFromId_checked(fsRef).getFeatureValue(getFeatFromCode_checked(featureCode))._id();
}
/**
* This is the method all normal FS feature "setters" call before doing the set operation on
* values where the range could be used as an index key.
* <p>
* If enabled, it will check if the update may corrupt any index in any view. The check tests
* whether the feature is being used as a key in one or more indexes and if the FS is in one or
* more corruptable view indexes.
* <p>
* If true, then:
* <ul>
* <li>it may remove and remember (for later adding-back) the FS from all corruptable indexes (bag
* indexes are not corruptable via updating, so these are skipped). The addback occurs later
* either via an explicit call to do so, or the end of a protectIndex block, or. (if
* autoIndexProtect is enabled) after the individual feature update is completed.</li>
* <li>it may give a WARN level message to the log. This enables users to implement their own
* optimized handling of this for "high performance" applications which do not want the overhead
* of runtime checking.</li>
* </ul>
* <p>
*
* @param fs
* - the FS to test if it is in the indexes
* @param featCode
* - the feature being tested
* @return true if something may need to be added back
*/
private boolean checkForInvalidFeatureSetting(TOP fs, int featCode) {
if (doInvalidFeatSettingCheck(fs)) {
if (!svd.featureCodesInIndexKeys.get(featCode)) { // skip if no index uses this feature
return false;
}
boolean wasRemoved = checkForInvalidFeatureSetting2(fs);
if (wasRemoved && doCorruptReport()) {
featModWhileInIndexReport(fs, featCode);
}
return wasRemoved;
}
return false;
}
/**
* version for deserializers, and for set document language, using their own store for toBeAdded
* Doesn't report updating of corruptable slots.
*
* @param fs
* -
* @param featCode
* -
* @param toBeAdded
* -
* @return -
*/
boolean checkForInvalidFeatureSetting(TOP fs, int featCode, FSsTobeAddedback toBeAdded) {
if (doInvalidFeatSettingCheck(fs)) {
if (!svd.featureCodesInIndexKeys.get(featCode)) { // skip if no index uses this feature
return false;
}
boolean wasRemoved = removeFromCorruptableIndexAnyView(fs, toBeAdded);
// if (wasRemoved && doCorruptReport()) {
// featModWhileInIndexReport(fs, featCode);
// }
return wasRemoved;
}
return false;
}
/**
* version for deserializers, using their own store for toBeAdded and not bothering to check for
* particular features Doesn't report updating of corruptable slots.
*
* @param fs
* -
* @param featCode
* -
* @param toBeAdded
* -
* @return -
*/
boolean checkForInvalidFeatureSetting(TOP fs, FSsTobeAddedback toBeAdded) {
if (doInvalidFeatSettingCheck(fs)) {
boolean wasRemoved = removeFromCorruptableIndexAnyView(fs, toBeAdded);
// if (wasRemoved && doCorruptReport()) {
// featModWhileInIndexReport(fs, null);
// }
return wasRemoved;
}
return false;
}
// // version of above, but using jcasFieldRegistryIndex
// private boolean checkForInvalidFeatureSettingJFRI(TOP fs, int jcasFieldRegistryIndex) {
// if (doInvalidFeatSettingCheck(fs) &&
// svd.featureJiInIndexKeys.get(jcasFieldRegistryIndex)) {
//
// boolean wasRemoved = checkForInvalidFeatureSetting2(fs);
//
//// if (wasRemoved && doCorruptReport()) {
//// featModWhileInIndexReport(fs, getFeatFromRegistry(jcasFieldRegistryIndex));
//// }
// return wasRemoved;
// }
// return false;
// }
private boolean checkForInvalidFeatureSetting2(TOP fs) {
final int ssz = svd.fssTobeAddedback.size();
// next method skips if the fsRef is not in the index (cache)
boolean wasRemoved = removeFromCorruptableIndexAnyView(fs, (ssz > 0) ? getAddback(ssz) : // validates
// single
// not
// in
// use
getAddbackSingle() // validates single usage at a time
);
if (!wasRemoved && svd.fsTobeAddedbackSingleInUse) {
svd.fsTobeAddedbackSingleInUse = false;
}
return wasRemoved;
}
// public FeatureImpl getFeatFromRegistry(int jcasFieldRegistryIndex) {
// return getFSClassRegistry().featuresFromJFRI[jcasFieldRegistryIndex];
// }
private boolean doCorruptReport() {
return
// skip message if wasn't removed
// skip message if protected in explicit block
IS_REPORT_FS_UPDATE_CORRUPTS_INDEX && svd.fssTobeAddedback.size() == 0;
}
/**
*
* @param fs
* -
* @return false if the fs is not in a set or sorted index (bit in fs), or the auto protect is
* disabled and we're not in an explicit protect block
*/
private boolean doInvalidFeatSettingCheck(TOP fs) {
if (!fs._inSetSortedIndex()) {
return false;
}
final int ssz = svd.fssTobeAddedback.size();
// skip if protection is disabled, and no explicit protection block
if (IS_DISABLED_PROTECT_INDEXES && ssz == 0) {
return false;
}
return true;
}
private void featModWhileInIndexReport(FeatureStructure fs, int featCode) {
featModWhileInIndexReport(fs, getFeatFromCode_checked(featCode));
}
private void featModWhileInIndexReport(FeatureStructure fs, FeatureImpl fi) {
// prepare a message which includes the feature which is a key, the fs, and
// the call stack.
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
new Throwable().printStackTrace(pw);
pw.close();
String msg = String.format(
"While FS was in the index, the feature \"%s\""
+ ", which is used as a key in one or more indexes, "
+ "was modified\n FS = \"%s\"\n%s%n",
(fi == null) ? "for-all-features" : fi.getName(), fs.toString(), sw.toString());
UIMAFramework.getLogger().log(Level.WARNING, msg);
if (IS_THROW_EXCEPTION_CORRUPT_INDEX) {
throw new UIMARuntimeException(UIMARuntimeException.ILLEGAL_FS_FEAT_UPDATE, new Object[] {});
}
}
// @formatter:off
/**
* Only called if there was something removed that needs to be added back
*
* skip the addback (to defer it until later) if:
* - running in block mode (you can tell this if svd.fssTobeAddedback.size() &gt; 0) or
* if running in block mode, the add back is delayed until the end of the block
*
* @param fs
* the fs to add back
*/
// @formatter:on
public void maybeAddback(TOP fs) {
if (svd.fssTobeAddedback.size() == 0) {
assert (svd.fsTobeAddedbackSingleInUse);
svd.fsTobeAddedbackSingle.addback(fs);
svd.fsTobeAddedbackSingleInUse = false;
}
}
boolean removeFromCorruptableIndexAnyView(final TOP fs, FSsTobeAddedback toBeAdded) {
return removeFromIndexAnyView(fs, toBeAdded, FSIndexRepositoryImpl.SKIP_BAG_INDEXES);
}
/**
* This might be called from low level set int value, if we support switching types, and we want
* to remove the old type from all indexes.
*
* @param fs
* the fs to maybe remove
* @param toBeAdded
* a place to record the removal so we can add it back later
* @param isSkipBagIndexes
* is true usually, we don't need to remove/readd to bag indexes (except for the case of
* supporting switching types via low level set int for v2 backwards compatibility)
* @return true if was removed from one or more indexes
*/
boolean removeFromIndexAnyView(final TOP fs, FSsTobeAddedback toBeAdded,
boolean isSkipBagIndexes) {
final TypeImpl ti = ((FeatureStructureImplC) fs)._getTypeImpl();
if (ti.isAnnotationBaseType()) {
boolean r = removeAndRecord(fs, (FSIndexRepositoryImpl) fs._casView.getIndexRepository(),
toBeAdded, isSkipBagIndexes);
fs._resetInSetSortedIndex();
return r;
}
// not a subtype of AnnotationBase, need to check all views (except base)
// sofas indexed in the base view are not corruptable.
final Iterator<CAS> viewIterator = getViewIterator();
boolean wasRemoved = false;
while (viewIterator.hasNext()) {
wasRemoved |= removeAndRecord(fs,
(FSIndexRepositoryImpl) viewIterator.next().getIndexRepository(), toBeAdded,
isSkipBagIndexes);
}
fs._resetInSetSortedIndex();
return wasRemoved;
}
/**
* remove a FS from all indexes in this view (except bag indexes, if isSkipBagIndex is true)
*
* @param fs
* the fs to be removed
* @param ir
* the view
* @param toBeAdded
* the place to record how many times it was in the index, per view
* @param isSkipBagIndex
* set to true for corruptable removes, false for remove in all cases from all indexes
* @return true if it was removed, false if it wasn't in any corruptable index.
*/
private boolean removeAndRecord(TOP fs, FSIndexRepositoryImpl ir, FSsTobeAddedback toBeAdded,
boolean isSkipBagIndex) {
boolean wasRemoved = ir.removeFS_ret(fs, isSkipBagIndex);
if (wasRemoved) {
toBeAdded.recordRemove(fs, ir, 1);
}
return wasRemoved;
}
// @formatter:off
/**
* Special considerations:
* Interface with corruption checking
* For backwards compatibility:
* handle cases where feature is:
* int - normal
* 0 - change type code
* a ref: treat int as FS "addr"
* not an int: handle like v2 where reasonable
*/
// @formatter:on
@Override
public final void ll_setIntValue(int fsRef, int featureCode, int value) {
TOP fs = getFsFromId_checked(fsRef);
if (featureCode == 0) {
switchFsType(fs, value);
return;
}
FeatureImpl fi = getFeatFromCode_checked(featureCode);
if (fs._getTypeImpl().isArray()) {
throw new UnsupportedOperationException(
"ll_setIntValue not permitted to set a feature of an array");
}
SlotKind kind = fi.getSlotKind();
switch (kind) {
case Slot_HeapRef:
if (fi.getCode() == annotBaseSofaFeatCode) {
// setting the sofa ref of an annotationBase
// can't change this so just verify it's the same
TOP sofa = fs.getFeatureValue(fi);
if (sofa._id != value) {
throw new UnsupportedOperationException(
"ll_setIntValue not permitted to change a sofaRef feature");
}
return; // if the same, just ignore, already set
}
TOP ref = fs._casView.getFsFromId_checked(value);
fs.setFeatureValue(fi, ref); // does the right feature check, too
return;
case Slot_Boolean:
case Slot_Byte:
case Slot_Short:
case Slot_Int:
case Slot_Float:
fs._setIntValueCJ(fi, value);
break;
case Slot_StrRef:
String s = getStringForCode(value);
if (s == null && value != 0) {
Misc.internalError(
new Exception("ll_setIntValue got null string for non-0 handle: " + value));
}
fs._setRefValueNfcCJ(fi, getStringForCode(value));
break;
case Slot_LongRef:
case Slot_DoubleRef:
Long lng = getLongForCode(value);
if (lng == null) {
Misc.internalError(
new Exception("ll_setIntValue got null Long/Double for handle: " + value));
}
fs._setLongValueNfcCJ(fi, lng);
break;
default:
CASRuntimeException e = new CASRuntimeException(CASRuntimeException.INAPPROP_RANGE,
fi.getName(), "int", fi.getRange().getName());
// System.err.println("debug " + e);
throw e;
}
}
private String getStringForCode(int i) {
if (null == svd.llstringSet) {
return null;
}
return svd.llstringSet.getStringForCode(i);
}
private int getCodeForString(String s) {
if (null == svd.llstringSet) {
svd.llstringSet = new StringSet();
}
return svd.llstringSet.getCodeForString(s); // avoids adding duplicates
}
private Long getLongForCode(int i) {
if (null == svd.lllongSet) {
return null;
}
return svd.lllongSet.getLongForCode(i);
}
private int getCodeForLong(long s) {
if (null == svd.lllongSet) {
svd.lllongSet = new LongSet();
}
return svd.lllongSet.getCodeForLong(s); // avoids adding duplicates
}
private void switchFsType(TOP fs, int value) {
// throw new UnsupportedOperationException();
// case where the type is being changed
// if the new type is a sub/super type of the existing type,
// some field data may be copied
// if not, no data is copied.
//
// Item is removed from index and re-indexed
// to emulate what V2 did,
// the indexing didn't change
// all the slots were the same
//
boolean wasRemoved = removeFromIndexAnyView(fs, getAddbackSingle(),
FSIndexRepositoryImpl.INCLUDE_BAG_INDEXES);
if (!wasRemoved) {
svd.fsTobeAddedbackSingleInUse = false;
}
TypeImpl newType = getTypeFromCode_checked(value);
Class<?> newClass = newType.getJavaClass();
if ((fs instanceof UimaSerializable) || UimaSerializable.class.isAssignableFrom(newClass)) {
throw new UnsupportedOperationException("can't switch type to/from UimaSerializable");
}
// Measurement - record which type gets switched to which other type
// count how many times
// record which JCas cover class goes with each type
// key = old type, new type, old jcas cover class, new jcas cover class
// value = count
MeasureSwitchType mst = null;
if (MEASURE_SETINT) {
MeasureSwitchType key = new MeasureSwitchType(fs._getTypeImpl(), newType);
synchronized (measureSwitches) { // map access / updating must be synchronized
mst = measureSwitches.get(key);
if (null == mst) {
measureSwitches.put(key, key);
mst = key;
}
mst.count++;
mst.newSubsumesOld = newType.subsumes(fs._getTypeImpl());
mst.oldSubsumesNew = fs._getTypeImpl().subsumes(newType);
}
}
if (newClass == fs._getTypeImpl().getJavaClass() || newType.subsumes(fs._getTypeImpl())) {
// switch in place
fs._setTypeImpl(newType);
return;
}
// if types don't subsume each other, we
// deviate a bit from V2 behavior
// and skip copying the feature slots
boolean isOkToCopyFeatures = // true || // debug
fs._getTypeImpl().subsumes(newType) || newType.subsumes(fs._getTypeImpl());
// throw new CASRuntimeException(CASRuntimeException.ILLEGAL_TYPE_CHANGE, newType.getName(),
// fs._getTypeImpl().getName());
TOP newFs = createFsWithExistingId(newType, fs._id); // updates id -> fs map
// initialize fields:
if (isOkToCopyFeatures) {
newFs._copyIntAndRefArraysFrom(fs);
}
// if (wasRemoved) {
// addbackSingle(newFs);
// }
// replace refs in existing FSs with new
// will miss any fs's held by user code - no way to fix that without
// universal indirection - very inefficient, so just accept for now
long st = System.nanoTime();
walkReachablePlusFSsSorted(fsItem -> {
if (fsItem._getTypeImpl().hasRefFeature) {
if (fsItem instanceof FSArray) {
TOP[] a = ((FSArray) fsItem)._getTheArray();
for (int i = 0; i < a.length; i++) {
if (fs == a[i]) {
a[i] = newFs;
}
}
return;
}
final int sz = fsItem._getTypeImpl().nbrOfUsedRefDataSlots;
for (int i = 0; i < sz; i++) {
Object o = fsItem._getRefValueCommon(i);
if (o == fs) {
fsItem._setRefValueCommon(i, newFs);
// fsItem._refData[i] = newFs;
}
}
}
}, null, // mark
null, // null or predicate for filtering what gets added
null); // null or type mapper, skips if not in other ts
if (MEASURE_SETINT) {
mst.scantime += System.nanoTime() - st;
}
}
@Override
public final void ll_setFloatValue(int fsRef, int featureCode, float value) {
getFsFromId_checked(fsRef).setFloatValue(getFeatFromCode_checked(featureCode), value);
}
// public final void ll_setFloatValueNoIndexCorruptionCheck(int fsRef, int featureCode, float
// value) {
// setFeatureValueNoIndexCorruptionCheck(fsRef, featureCode, float2int(value));
// }
@Override
public final void ll_setStringValue(int fsRef, int featureCode, String value) {
getFsFromId_checked(fsRef).setStringValue(getFeatFromCode_checked(featureCode), value);
}
@Override
public final void ll_setRefValue(int fsRef, int featureCode, int value) {
// no index check because refs can't be keys
setFeatureValue(fsRef, featureCode, getFsFromId_checked(value));
}
@Override
public final void ll_setIntValue(int fsRef, int featureCode, int value, boolean doTypeChecks) {
if (doTypeChecks) {
checkNonArrayConditions(fsRef, featureCode);
}
ll_setIntValue(fsRef, featureCode, value);
}
@Override
public final void ll_setFloatValue(int fsRef, int featureCode, float value,
boolean doTypeChecks) {
if (doTypeChecks) {
checkNonArrayConditions(fsRef, featureCode);
}
ll_setFloatValue(fsRef, featureCode, value);
}
@Override
public final void ll_setStringValue(int fsRef, int featureCode, String value,
boolean doTypeChecks) {
if (doTypeChecks) {
checkNonArrayConditions(fsRef, featureCode);
}
ll_setStringValue(fsRef, featureCode, value);
}
@Override
public final void ll_setCharBufferValue(int fsRef, int featureCode, char[] buffer, int start,
int length, boolean doTypeChecks) {
if (doTypeChecks) {
checkNonArrayConditions(fsRef, featureCode);
}
ll_setCharBufferValue(fsRef, featureCode, buffer, start, length);
}
@Override
public final void ll_setCharBufferValue(int fsRef, int featureCode, char[] buffer, int start,
int length) {
ll_setStringValue(fsRef, featureCode, new String(buffer, start, length));
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.cas.impl.LowLevelCAS#ll_copyCharBufferValue(int, int, char, int)
*/
@Override
public int ll_copyCharBufferValue(int fsRef, int featureCode, char[] buffer, int start) {
String str = ll_getStringValue(fsRef, featureCode);
if (str == null) {
return -1;
}
final int len = str.length();
final int requestedMax = start + len;
// Check that the buffer is long enough to copy the whole string. If it isn't long enough, we
// copy up to buffer.length - start characters.
final int max = (buffer.length < requestedMax) ? (buffer.length - start) : len;
for (int i = 0; i < max; i++) {
buffer[start + i] = str.charAt(i);
}
return len;
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.cas.impl.LowLevelCAS#ll_getCharBufferValueSize(int, int)
*/
@Override
public int ll_getCharBufferValueSize(int fsRef, int featureCode) {
String str = ll_getStringValue(fsRef, featureCode);
return str.length();
}
@Override
public final void ll_setRefValue(int fsRef, int featureCode, int value, boolean doTypeChecks) {
if (doTypeChecks) {
checkFsRefConditions(fsRef, featureCode);
}
ll_setRefValue(fsRef, featureCode, value);
}
public final int getIntArrayValue(IntegerArray array, int i) {
return array.get(i);
}
public final float getFloatArrayValue(FloatArray array, int i) {
return array.get(i);
}
public final String getStringArrayValue(StringArray array, int i) {
return array.get(i);
}
public final FeatureStructure getRefArrayValue(FSArray array, int i) {
return array.get(i);
}
@Override
public final int ll_getIntArrayValue(int fsRef, int position) {
return getIntArrayValue(((IntegerArray) getFsFromId_checked(fsRef)), position);
}
@Override
public final float ll_getFloatArrayValue(int fsRef, int position) {
return getFloatArrayValue(((FloatArray) getFsFromId_checked(fsRef)), position);
}
@Override
public final String ll_getStringArrayValue(int fsRef, int position) {
return getStringArrayValue(((StringArray) getFsFromId_checked(fsRef)), position);
}
@Override
public final int ll_getRefArrayValue(int fsRef, int position) {
return ((TOP) getRefArrayValue(((FSArray) getFsFromId_checked(fsRef)), position))._id();
}
private void throwAccessTypeError(int fsRef, int typeCode) {
throw new LowLevelException(LowLevelException.ACCESS_TYPE_ERROR, fsRef, typeCode,
getTypeSystemImpl().ll_getTypeForCode(typeCode).getName(),
getTypeSystemImpl().ll_getTypeForCode(ll_getFSRefType(fsRef)).getName());
}
public final void checkArrayBounds(int fsRef, int pos) {
final int arrayLength = ll_getArraySize(fsRef);
if ((pos < 0) || (pos >= arrayLength)) {
throw new ArrayIndexOutOfBoundsException(pos);
// LowLevelException e = new LowLevelException(
// LowLevelException.ARRAY_INDEX_OUT_OF_RANGE);
// e.addArgument(Integer.toString(pos));
// throw e;
}
}
public final void checkArrayBounds(int arrayLength, int pos, int length) {
if ((pos < 0) || (length < 0) || ((pos + length) > arrayLength)) {
throw new LowLevelException(LowLevelException.ARRAY_INDEX_LENGTH_OUT_OF_RANGE,
Integer.toString(pos), Integer.toString(length));
}
}
// @formatter:off
/**
* Check that the fsRef is valid.
* Check that the fs is featureCode belongs to the fs
* Check that the featureCode is one of the features of the domain type of the fsRef
* feat could be primitive, string, ref to another feature
*
* @param fsRef
* @param typeCode
* @param featureCode
*/
// @formatter:on
private final void checkNonArrayConditions(int fsRef, int featureCode) {
TOP fs = getFsFromId_checked(fsRef);
final TypeImpl domainType = (TypeImpl) fs.getType();
// checkTypeAt(domType, fs); // since the type is from the FS, it's always OK
checkFeature(featureCode); // checks that the featureCode is in the range of all feature codes
TypeSystemImpl tsi = getTypeSystemImpl();
FeatureImpl fi = tsi.getFeatureForCode_checked(featureCode);
checkTypeHasFeature(domainType, fi); // checks that the feature code is one of the features of
// the type
// checkFsRan(fi);
}
private final void checkFsRefConditions(int fsRef, int featureCode) {
TOP fs = getFsFromId_checked(fsRef);
checkLowLevelParams(fs, fs._getTypeImpl(), featureCode); // checks type has feature
TypeSystemImpl tsi = getTypeSystemImpl();
FeatureImpl fi = tsi.getFeatureForCode_checked(featureCode);
checkFsRan(fi);
// next not needed because checkFsRan already validates this
// checkFsRef(fsRef + this.svd.casMetadata.featureOffset[featureCode]);
}
// private final void checkArrayConditions(int fsRef, int typeCode,
// int position) {
// checkTypeSubsumptionAt(fsRef, typeCode);
// // skip this next test because
// // a) it's done implicitly in the bounds check and
// // b) it fails for arrays stored outside of the main heap (e.g.,
// byteArrays, etc.)
// // checkFsRef(getArrayStartAddress(fsRef) + position);
// checkArrayBounds(fsRef, position);
// }
private final void checkPrimitiveArrayConditions(int fsRef, int typeCode, int position) {
if (typeCode != ll_getFSRefType(fsRef)) {
throwAccessTypeError(fsRef, typeCode);
}
checkArrayBounds(fsRef, position);
}
@Override
public final int ll_getIntArrayValue(int fsRef, int position, boolean doTypeChecks) {
if (doTypeChecks) {
checkPrimitiveArrayConditions(fsRef, intArrayTypeCode, position);
}
return ll_getIntArrayValue(fsRef, position);
}
@Override
public float ll_getFloatArrayValue(int fsRef, int position, boolean doTypeChecks) {
if (doTypeChecks) {
checkPrimitiveArrayConditions(fsRef, floatArrayTypeCode, position);
}
return ll_getFloatArrayValue(fsRef, position);
}
@Override
public String ll_getStringArrayValue(int fsRef, int position, boolean doTypeChecks) {
if (doTypeChecks) {
checkPrimitiveArrayConditions(fsRef, stringArrayTypeCode, position);
}
return ll_getStringArrayValue(fsRef, position);
}
@Override
public int ll_getRefArrayValue(int fsRef, int position, boolean doTypeChecks) {
if (doTypeChecks) {
checkPrimitiveArrayConditions(fsRef, fsArrayTypeCode, position);
}
return ll_getRefArrayValue(fsRef, position);
}
@Override
public void ll_setIntArrayValue(int fsRef, int position, int value, boolean doTypeChecks) {
if (doTypeChecks) {
checkPrimitiveArrayConditions(fsRef, intArrayTypeCode, position);
}
ll_setIntArrayValue(fsRef, position, value);
}
@Override
public void ll_setFloatArrayValue(int fsRef, int position, float value, boolean doTypeChecks) {
if (doTypeChecks) {
checkPrimitiveArrayConditions(fsRef, floatArrayTypeCode, position);
}
ll_setFloatArrayValue(fsRef, position, value);
}
@Override
public void ll_setStringArrayValue(int fsRef, int position, String value, boolean doTypeChecks) {
if (doTypeChecks) {
checkPrimitiveArrayConditions(fsRef, stringArrayTypeCode, position);
}
ll_setStringArrayValue(fsRef, position, value);
}
@Override
public void ll_setRefArrayValue(int fsRef, int position, int value, boolean doTypeChecks) {
if (doTypeChecks) {
checkPrimitiveArrayConditions(fsRef, fsArrayTypeCode, position);
}
ll_setRefArrayValue(fsRef, position, value);
}
// ************************
// Low Level Array Setters
// ************************
@Override
public void ll_setIntArrayValue(int fsRef, int position, int value) {
IntegerArray array = getFsFromId_checked(fsRef);
array.set(position, value); // that set operation does required journaling
}
@Override
public void ll_setFloatArrayValue(int fsRef, int position, float value) {
FloatArray array = getFsFromId_checked(fsRef);
array.set(position, value); // that set operation does required journaling
}
@Override
public void ll_setStringArrayValue(int fsRef, int position, String value) {
StringArray array = getFsFromId_checked(fsRef);
array.set(position, value); // that set operation does required journaling
}
@Override
public void ll_setRefArrayValue(int fsRef, int position, int value) {
FSArray array = getFsFromId_checked(fsRef);
array.set(position, getFsFromId_checked(value)); // that set operation does required journaling
}
/**
* @param fsRef
* an id for a FS
* @return the type code for this FS
*/
@Override
public int ll_getFSRefType(int fsRef) {
return getFsFromId_checked(fsRef)._getTypeCode();
}
@Override
public int ll_getFSRefType(int fsRef, boolean doChecks) {
// type code is always valid
return ll_getFSRefType(fsRef);
}
@Override
public LowLevelCAS getLowLevelCAS() {
return this;
}
@Override
public int size() {
throw new UIMARuntimeException(UIMARuntimeException.INTERNAL_ERROR);
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.cas.admin.CASMgr#getJCasClassLoader()
*/
@Override
public ClassLoader getJCasClassLoader() {
return this.svd.jcasClassLoader;
}
/*
* Called to set the overall jcas class loader to use.
*
* @see org.apache.uima.cas.admin.CASMgr#setJCasClassLoader(java.lang.ClassLoader)
*/
@Override
public void setJCasClassLoader(ClassLoader classLoader) {
this.svd.jcasClassLoader = classLoader;
}
public void switchClassLoader(ClassLoader newClassLoader, boolean wasLocked) {
this.svd.switchClassLoader(newClassLoader, wasLocked);
}
// Internal use only, public for cross package use
// Assumes: The JCasClassLoader for a CAS is set up initially when the CAS is
// created
// and not switched (other than by this code) once it is set.
// Callers of this method always code the "restoreClassLoaderUnlockCAS" in
// pairs,
// protected as needed with try - finally blocks.
//
// Special handling is needed for CAS Mulipliers - they can modify a cas up to
// the point they no longer "own" it.
// So the try / finally approach doesn't fit
public void switchClassLoaderLockCas(Object userCode) {
switchClassLoaderLockCasCL(userCode.getClass().getClassLoader());
}
public void switchClassLoaderLockCasCL(ClassLoader newClassLoader) {
boolean wasLocked = isCasLocked();
// lock out CAS functions to which annotator should not have access
enableReset(false);
svd.switchClassLoader(newClassLoader, wasLocked);
}
// // internal use, public for cross-package ref
// public boolean usingBaseClassLoader() {
// return (this.svd.jcasClassLoader == this.svd.previousJCasClassLoader);
// }
public void restoreClassLoaderUnlockCas() {
boolean empty_switchControl = this.svd.switchControl.isEmpty();
SwitchControl switchControlInstance = empty_switchControl ? null : this.svd.switchControl.pop();
if (empty_switchControl || !switchControlInstance.wasLocked) {
// unlock CAS functions
enableReset(true);
}
// this might be called without the switch ever being called
svd.restoreClassLoader(empty_switchControl, switchControlInstance);
}
@Override
public FeatureValuePath createFeatureValuePath(String featureValuePath)
throws CASRuntimeException {
return FeatureValuePathImpl.getFeaturePath(featureValuePath);
}
@Override
public void setOwner(CasOwner aCasOwner) {
CASImpl baseCas = getBaseCAS();
if (baseCas != this) {
baseCas.setOwner(aCasOwner);
} else {
super.setOwner(aCasOwner);
}
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.cas.AbstractCas_ImplBase#release()
*/
@Override
public void release() {
CASImpl baseCas = getBaseCAS();
if (baseCas != this) {
baseCas.release();
} else {
super.release();
}
}
// **********************************
// A R R A Y C R E A T I O N
// **********************************
@Override
public ByteArrayFS createByteArrayFS(int length) throws CASRuntimeException {
checkArrayPreconditions(length);
return new ByteArray(this.getJCas(), length);
}
@Override
public BooleanArrayFS createBooleanArrayFS(int length) throws CASRuntimeException {
checkArrayPreconditions(length);
return new BooleanArray(this.getJCas(), length);
}
@Override
public ShortArrayFS createShortArrayFS(int length) throws CASRuntimeException {
checkArrayPreconditions(length);
return new ShortArray(this.getJCas(), length);
}
@Override
public LongArrayFS createLongArrayFS(int length) throws CASRuntimeException {
checkArrayPreconditions(length);
return new LongArray(this.getJCas(), length);
}
@Override
public DoubleArrayFS createDoubleArrayFS(int length) throws CASRuntimeException {
checkArrayPreconditions(length);
return new DoubleArray(this.getJCas(), length);
}
@Override
public byte ll_getByteValue(int fsRef, int featureCode) {
return getFsFromId_checked(fsRef).getByteValue(getFeatFromCode_checked(featureCode));
}
@Override
public byte ll_getByteValue(int fsRef, int featureCode, boolean doTypeChecks) {
if (doTypeChecks) {
checkNonArrayConditions(fsRef, featureCode);
}
return ll_getByteValue(fsRef, featureCode);
}
@Override
public boolean ll_getBooleanValue(int fsRef, int featureCode) {
return getFsFromId_checked(fsRef).getBooleanValue(getFeatFromCode_checked(featureCode));
}
@Override
public boolean ll_getBooleanValue(int fsRef, int featureCode, boolean doTypeChecks) {
if (doTypeChecks) {
checkNonArrayConditions(fsRef, featureCode);
}
return ll_getBooleanValue(fsRef, featureCode);
}
@Override
public short ll_getShortValue(int fsRef, int featureCode) {
return getFsFromId_checked(fsRef).getShortValue(getFeatFromCode_checked(featureCode));
}
@Override
public short ll_getShortValue(int fsRef, int featureCode, boolean doTypeChecks) {
if (doTypeChecks) {
checkNonArrayConditions(fsRef, featureCode);
}
return ll_getShortValue(fsRef, featureCode);
}
// impossible to implement in v3; change callers
// public long ll_getLongValue(int offset) {
// return this.getLongHeap().getHeapValue(offset);
// }
@Override
public long ll_getLongValue(int fsRef, int featureCode) {
return getFsFromId_checked(fsRef).getLongValue(getFeatFromCode_checked(featureCode));
}
// public long ll_getLongValueFeatOffset(int fsRef, int offset) {
// TOP fs = getFsFromId_checked(fsRef);
// return fs.getLongValueOffset(offset);
// }
@Override
public long ll_getLongValue(int fsRef, int featureCode, boolean doTypeChecks) {
if (doTypeChecks) {
checkNonArrayConditions(fsRef, featureCode);
}
return ll_getLongValue(fsRef, featureCode);
}
@Override
public double ll_getDoubleValue(int fsRef, int featureCode) {
return getFsFromId_checked(fsRef).getDoubleValue(getFeatFromCode_checked(featureCode));
}
// public double ll_getDoubleValueFeatOffset(int fsRef, int offset) {
// TOP fs = getFsFromId_checked(fsRef);
// return fs.getDoubleValueOffset(offset);
// }
@Override
public double ll_getDoubleValue(int fsRef, int featureCode, boolean doTypeChecks) {
if (doTypeChecks) {
checkNonArrayConditions(fsRef, featureCode);
}
return ll_getDoubleValue(fsRef, featureCode);
}
@Override
public void ll_setBooleanValue(int fsRef, int featureCode, boolean value) {
getFsFromId_checked(fsRef).setBooleanValue(getFeatFromCode_checked(featureCode), value);
}
@Override
public void ll_setBooleanValue(int fsRef, int featureCode, boolean value, boolean doTypeChecks) {
if (doTypeChecks) {
checkNonArrayConditions(fsRef, featureCode);
}
ll_setBooleanValue(fsRef, featureCode, value);
}
@Override
public final void ll_setByteValue(int fsRef, int featureCode, byte value) {
getFsFromId_checked(fsRef).setByteValue(getFeatFromCode_checked(featureCode), value);
}
@Override
public void ll_setByteValue(int fsRef, int featureCode, byte value, boolean doTypeChecks) {
if (doTypeChecks) {
checkNonArrayConditions(fsRef, featureCode);
}
ll_setByteValue(fsRef, featureCode, value);
}
@Override
public final void ll_setShortValue(int fsRef, int featureCode, short value) {
getFsFromId_checked(fsRef).setShortValue(getFeatFromCode_checked(featureCode), value);
}
@Override
public void ll_setShortValue(int fsRef, int featureCode, short value, boolean doTypeChecks) {
if (doTypeChecks) {
checkNonArrayConditions(fsRef, featureCode);
}
ll_setShortValue(fsRef, featureCode, value);
}
@Override
public void ll_setLongValue(int fsRef, int featureCode, long value) {
getFsFromId_checked(fsRef).setLongValue(getFeatFromCode_checked(featureCode), value);
}
@Override
public void ll_setLongValue(int fsRef, int featureCode, long value, boolean doTypeChecks) {
if (doTypeChecks) {
checkNonArrayConditions(fsRef, featureCode);
}
ll_setLongValue(fsRef, featureCode, value);
}
@Override
public void ll_setDoubleValue(int fsRef, int featureCode, double value) {
getFsFromId_checked(fsRef).setDoubleValue(getFeatFromCode_checked(featureCode), value);
}
@Override
public void ll_setDoubleValue(int fsRef, int featureCode, double value, boolean doTypeChecks) {
if (doTypeChecks) {
checkNonArrayConditions(fsRef, featureCode);
}
ll_setDoubleValue(fsRef, featureCode, value);
}
@Override
public byte ll_getByteArrayValue(int fsRef, int position) {
return ((ByteArray) getFsFromId_checked(fsRef)).get(position);
}
@Override
public byte ll_getByteArrayValue(int fsRef, int position, boolean doTypeChecks) {
return ll_getByteArrayValue(fsRef, position);
}
@Override
public boolean ll_getBooleanArrayValue(int fsRef, int position) {
return ((BooleanArray) getFsFromId_checked(fsRef)).get(position);
}
@Override
public boolean ll_getBooleanArrayValue(int fsRef, int position, boolean doTypeChecks) {
return ll_getBooleanArrayValue(fsRef, position);
}
@Override
public short ll_getShortArrayValue(int fsRef, int position) {
return ((ShortArray) getFsFromId_checked(fsRef)).get(position);
}
@Override
public short ll_getShortArrayValue(int fsRef, int position, boolean doTypeChecks) {
return ll_getShortArrayValue(fsRef, position);
}
@Override
public long ll_getLongArrayValue(int fsRef, int position) {
return ((LongArray) getFsFromId_checked(fsRef)).get(position);
}
@Override
public long ll_getLongArrayValue(int fsRef, int position, boolean doTypeChecks) {
return ll_getLongArrayValue(fsRef, position);
}
@Override
public double ll_getDoubleArrayValue(int fsRef, int position) {
return ((DoubleArray) getFsFromId_checked(fsRef)).get(position);
}
@Override
public double ll_getDoubleArrayValue(int fsRef, int position, boolean doTypeChecks) {
return ll_getDoubleArrayValue(fsRef, position);
}
@Override
public void ll_setByteArrayValue(int fsRef, int position, byte value) {
((ByteArray) getFsFromId_checked(fsRef)).set(position, value);
}
@Override
public void ll_setByteArrayValue(int fsRef, int position, byte value, boolean doTypeChecks) {
ll_setByteArrayValue(fsRef, position, value);
}
@Override
public void ll_setBooleanArrayValue(int fsRef, int position, boolean b) {
((BooleanArray) getFsFromId_checked(fsRef)).set(position, b);
}
@Override
public void ll_setBooleanArrayValue(int fsRef, int position, boolean value,
boolean doTypeChecks) {
ll_setBooleanArrayValue(fsRef, position, value);
}
@Override
public void ll_setShortArrayValue(int fsRef, int position, short value) {
((ShortArray) getFsFromId_checked(fsRef)).set(position, value);
}
@Override
public void ll_setShortArrayValue(int fsRef, int position, short value, boolean doTypeChecks) {
ll_setShortArrayValue(fsRef, position, value);
}
@Override
public void ll_setLongArrayValue(int fsRef, int position, long value) {
((LongArray) getFsFromId_checked(fsRef)).set(position, value);
}
@Override
public void ll_setLongArrayValue(int fsRef, int position, long value, boolean doTypeChecks) {
ll_setLongArrayValue(fsRef, position, value);
}
@Override
public void ll_setDoubleArrayValue(int fsRef, int position, double d) {
((DoubleArray) getFsFromId_checked(fsRef)).set(position, d);
}
@Override
public void ll_setDoubleArrayValue(int fsRef, int position, double value, boolean doTypeChecks) {
ll_setDoubleArrayValue(fsRef, position, value);
}
public boolean isAnnotationType(Type t) {
return ((TypeImpl) t).isAnnotationType();
}
/**
* @param t
* the type code to test
* @return true if that type is subsumed by AnnotationBase type
*/
public boolean isSubtypeOfAnnotationBaseType(int t) {
TypeImpl ti = getTypeFromCode(t);
return (ti == null) ? false : ti.isAnnotationBaseType();
}
public boolean isBaseCas() {
return this == getBaseCAS();
}
@Override
public Annotation createAnnotation(Type type, int begin, int end) {
// duplicates a later check
// if (this.isBaseCas()) {
// // Can't create annotation on base CAS
// throw new CASRuntimeException(CASRuntimeException.INVALID_BASE_CAS_METHOD,
// "createAnnotation(Type, int, int)");
// }
Annotation fs = (Annotation) createFS(type);
fs.setBegin(begin);
fs.setEnd(end);
return fs;
}
public int ll_createAnnotation(int typeCode, int begin, int end) {
TOP fs = createAnnotation(getTypeFromCode(typeCode), begin, end);
set_id2fs(fs); // to prevent gc from reclaiming
return fs._id();
}
/**
* The generic spec T extends AnnotationFS (rather than AnnotationFS) allows the method JCasImpl
* getAnnotationIndex to return Annotation instead of AnnotationFS
*
* @param <T>
* the Java class associated with the annotation index
* @return the annotation index
*/
@Override
public <T extends AnnotationFS> AnnotationIndex<T> getAnnotationIndex() {
return (AnnotationIndex<T>) indexRepository.getAnnotationIndex(getTypeSystemImpl().annotType);
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.cas.CAS#getAnnotationIndex(org.apache.uima.cas.Type)
*/
@Override
public <T extends AnnotationFS> AnnotationIndex<T> getAnnotationIndex(Type type)
throws CASRuntimeException {
return (AnnotationIndex<T>) indexRepository.getAnnotationIndex((TypeImpl) type);
}
/**
* @see org.apache.uima.cas.CAS#getAnnotationType()
*/
@Override
public Type getAnnotationType() {
return getTypeSystemImpl().annotType;
}
/**
* @see org.apache.uima.cas.CAS#getEndFeature()
*/
@Override
public Feature getEndFeature() {
return getTypeSystemImpl().endFeat;
}
/**
* @see org.apache.uima.cas.CAS#getBeginFeature()
*/
@Override
public Feature getBeginFeature() {
return getTypeSystemImpl().startFeat;
}
private <T extends AnnotationFS> T createDocumentAnnotation(int length) {
final TypeSystemImpl ts = getTypeSystemImpl();
// Remove any existing document annotations.
FSIterator<T> it = this.<T> getAnnotationIndex(ts.docType).iterator();
List<T> list = new ArrayList<>();
while (it.isValid()) {
list.add(it.get());
it.moveToNext();
}
for (int i = 0; i < list.size(); i++) {
getIndexRepository().removeFS(list.get(i));
}
return (T) createDocumentAnnotationNoRemove(length);
}
private <T extends Annotation> T createDocumentAnnotationNoRemove(int length) {
T docAnnot = createDocumentAnnotationNoRemoveNoIndex(length);
addFsToIndexes(docAnnot);
return docAnnot;
}
public <T extends Annotation> T createDocumentAnnotationNoRemoveNoIndex(int length) {
final TypeSystemImpl ts = getTypeSystemImpl();
AnnotationFS docAnnot = createAnnotation(ts.docType, 0, length);
docAnnot.setStringValue(ts.langFeat, CAS.DEFAULT_LANGUAGE_NAME);
return (T) docAnnot;
}
public int ll_createDocumentAnnotation(int length) {
final int fsRef = ll_createDocumentAnnotationNoIndex(0, length);
ll_getIndexRepository().ll_addFS(fsRef);
return fsRef;
}
public int ll_createDocumentAnnotationNoIndex(int begin, int end) {
final TypeSystemImpl ts = getTypeSystemImpl();
int fsRef = ll_createAnnotation(ts.docType.getCode(), begin, end);
ll_setStringValue(fsRef, ts.langFeat.getCode(), CAS.DEFAULT_LANGUAGE_NAME);
return fsRef;
}
// For the "built-in" instance of Document Annotation, set the
// "end" feature to be the length of the sofa string
// @formatter:off
/**
* updates the document annotation (only if the sofa's local string data != null)
* setting the end feature to be the length of the sofa string, if any.
* creates the document annotation if not present
* only works if not in the base cas
*
*/
// @formatter:on
public void updateDocumentAnnotation() {
if (!mySofaIsValid() || this == this.svd.baseCAS) {
return;
}
String newDoc = this.mySofaRef.getLocalStringData();
if (null != newDoc) {
Annotation docAnnot = getDocumentAnnotationNoCreate();
if (docAnnot != null) {
// use a local instance of the add-back memory because this may be called as a side effect
// of updating a sofa
FSsTobeAddedback tobeAddedback = FSsTobeAddedback.createSingle();
boolean wasRemoved = this.checkForInvalidFeatureSetting(docAnnot,
getTypeSystemImpl().endFeat.getCode(), tobeAddedback);
docAnnot._setIntValueNfc(endFeatAdjOffset, newDoc.length());
if (wasRemoved) {
tobeAddedback.addback(docAnnot);
}
} else if (deserialized_doc_annot_not_indexed != null) {
// UIMA-6199 provides access to non-indexed doc annot
// to allow sofa setting to set the "length" of the local sofa data string
// @see updateDocumentAnnotation() updateDocumentAnnotation.
deserialized_doc_annot_not_indexed._setIntValueNfc(endFeatAdjOffset, newDoc.length());
} else {
// not in the index (yet)
createDocumentAnnotation(newDoc.length());
}
}
return;
}
/**
* Generic issue: The returned document annotation could be either an instance of
* DocumentAnnotation or a subclass of it, or an instance of Annotation - the Java cover class
* used for annotations when JCas is not being used.
*/
@Override
public <T extends AnnotationFS> T getDocumentAnnotation() {
T docAnnot = (T) getDocumentAnnotationNoCreate();
if (null == docAnnot) {
return (T) createDocumentAnnotationNoRemove(0);
} else {
return docAnnot;
}
}
public <T extends AnnotationFS> T getDocumentAnnotationNoCreate() {
if (this == this.svd.baseCAS) {
// base CAS has no document
return null;
}
FSIterator<Annotation> it = getDocAnnotIter();
it.moveToFirst(); // revalidate in case index updated
if (it.isValid()) {
Annotation r = it.get();
return (T) (inPearContext() ? pearConvert(r) : r);
}
return null;
}
private FSIterator<Annotation> getDocAnnotIter() {
if (docAnnotIter != null) {
return docAnnotIter;
}
synchronized (this) {
if (docAnnotIter == null) {
docAnnotIter = this.<Annotation> getAnnotationIndex(getTypeSystemImpl().docType).iterator();
}
return docAnnotIter;
}
}
/**
*
* @return the fs addr of the document annotation found via the index, or 0 if not there
*/
public int ll_getDocumentAnnotation() {
AnnotationFS r = getDocumentAnnotationNoCreate();
return (r == null) ? 0 : r._id();
}
@Override
public String getDocumentLanguage() {
if (this == this.svd.baseCAS) {
// base CAS has no document
return null;
}
return getDocumentAnnotation().getStringValue(getTypeSystemImpl().langFeat);
}
@Override
public String getDocumentText() {
return this.getSofaDataString();
}
@Override
public String getSofaDataString() {
if (this == this.svd.baseCAS) {
// base CAS has no document
return null;
}
return mySofaIsValid() ? mySofaRef.getLocalStringData() : null;
}
@Override
public FeatureStructure getSofaDataArray() {
if (this == this.svd.baseCAS) {
// base CAS has no Sofa
return null;
}
return mySofaIsValid() ? mySofaRef.getLocalFSData() : null;
}
@Override
public String getSofaDataURI() {
if (this == this.svd.baseCAS) {
// base CAS has no Sofa
return null;
}
return mySofaIsValid() ? mySofaRef.getSofaURI() : null;
}
@Override
public InputStream getSofaDataStream() {
if (this == this.svd.baseCAS) {
// base CAS has no Sofa nothin
return null;
}
// return mySofaRef.getSofaDataStream(); // this just goes to the next method
return mySofaIsValid() ? this.getSofaDataStream(mySofaRef) : null;
}
@Override
public String getSofaMimeType() {
if (this == this.svd.baseCAS) {
// base CAS has no Sofa
return null;
}
return mySofaIsValid() ? mySofaRef.getSofaMime() : null;
}
@Override
public Sofa getSofa() {
return mySofaRef;
}
/**
* @return the addr of the sofaFS associated with this view, or 0
*/
@Override
public int ll_getSofa() {
return mySofaIsValid() ? mySofaRef._id() : 0;
}
@Override
public String getViewName() {
return (this == svd.getViewFromSofaNbr(1)) ? CAS.NAME_DEFAULT_SOFA
: mySofaIsValid() ? mySofaRef.getSofaID() : null;
}
private boolean mySofaIsValid() {
return this.mySofaRef != null;
}
void setDocTextFromDeserializtion(String text) {
if (mySofaIsValid()) {
Sofa sofa = getSofaRef(); // creates sofa if doesn't already exist
sofa.setLocalSofaDataNoDocAnnotUpdate(text);
}
}
@Override
public void setDocumentLanguage(String languageCode) {
if (this == this.svd.baseCAS) {
throw new CASRuntimeException(CASRuntimeException.INVALID_BASE_CAS_METHOD,
"setDocumentLanguage(String)");
}
Annotation docAnnot = getDocumentAnnotation();
FeatureImpl languageFeature = getTypeSystemImpl().langFeat;
languageCode = Language.normalize(languageCode);
boolean wasRemoved = this.checkForInvalidFeatureSetting(docAnnot, languageFeature.getCode(),
this.getAddbackSingle());
docAnnot.setStringValue(getTypeSystemImpl().langFeat, languageCode);
addbackSingleIfWasRemoved(wasRemoved, docAnnot);
}
private void setSofaThingsMime(Consumer<Sofa> c, String msg) {
if (this == this.svd.baseCAS) {
throw new CASRuntimeException(CASRuntimeException.INVALID_BASE_CAS_METHOD, msg);
}
Sofa sofa = getSofaRef();
c.accept(sofa);
}
@Override
public void setDocumentText(String text) {
setSofaDataString(text, "text");
}
@Override
public void setSofaDataString(String text, String mime) throws CASRuntimeException {
setSofaThingsMime(sofa -> sofa.setLocalSofaData(text, mime), "setSofaDataString(text, mime)");
}
@Override
public void setSofaDataArray(FeatureStructure array, String mime) {
setSofaThingsMime(sofa -> sofa.setLocalSofaData(array, mime),
"setSofaDataArray(FeatureStructure, mime)");
}
@Override
public void setSofaDataURI(String uri, String mime) throws CASRuntimeException {
setSofaThingsMime(sofa -> sofa.setRemoteSofaURI(uri, mime), "setSofaDataURI(String, String)");
}
@Override
public void setCurrentComponentInfo(ComponentInfo info) {
// always store component info in base CAS
this.svd.componentInfo = info;
}
ComponentInfo getCurrentComponentInfo() {
return this.svd.componentInfo;
}
/**
* @see org.apache.uima.cas.CAS#addFsToIndexes(FeatureStructure fs)
*/
@Override
public void addFsToIndexes(FeatureStructure fs) {
// if (fs instanceof AnnotationBaseFS) {
// final CAS sofaView = ((AnnotationBaseFS) fs).getView();
// if (sofaView != this) {
// CASRuntimeException e = new CASRuntimeException(
// CASRuntimeException.ANNOTATION_IN_WRONG_INDEX, new String[] { fs.toString(),
// sofaView.getSofa().getSofaID(), this.getSofa().getSofaID() });
// throw e;
// }
// }
this.indexRepository.addFS(fs);
}
/**
* @see org.apache.uima.cas.CAS#removeFsFromIndexes(FeatureStructure fs)
*/
@Override
public void removeFsFromIndexes(FeatureStructure fs) {
this.indexRepository.removeFS(fs);
}
/**
* @param fs
* the AnnotationBase instance
* @return the view associated with this FS where it could be indexed
*/
public CASImpl getSofaCasView(AnnotationBase fs) {
return fs._casView;
// Sofa sofa = fs.getSofa();
//
// if (null != sofa && sofa != this.getSofa()) {
// return (CASImpl) this.getView(sofa.getSofaNum());
// }
//
// /* Note: sofa == null means annotation created from low-level APIs, without setting sofa
// feature
// * Ignore this for backwards compatibility */
// return this;
}
@Override
public CASImpl ll_getSofaCasView(int id) {
return getSofaCasView(getFsFromId_checked(id));
}
// public Iterator<CAS> getViewIterator() {
// List<CAS> viewList = new ArrayList<CAS>();
// // add initial view if it has no sofa
// if (!((CASImpl) getInitialView()).mySofaIsValid()) {
// viewList.add(getInitialView());
// }
// // add views with Sofas
// FSIterator<SofaFS> sofaIter = getSofaIterator();
// while (sofaIter.hasNext()) {
// viewList.add(getView(sofaIter.next()));
// }
// return viewList.iterator();
// }
/**
* Creates the initial view (without a sofa) if not present
*
* @return the number of views, excluding the base view, including the initial view (even if not
* initially present or no sofa)
*/
public int getNumberOfViews() {
CASImpl initialView = getInitialView(); // creates one if not existing, w/o sofa
int nbrSofas = this.svd.baseCAS.indexRepository.getIndex(CAS.SOFA_INDEX_NAME).size();
return initialView.mySofaIsValid() ? nbrSofas : 1 + nbrSofas;
}
public int getNumberOfSofas() {
return this.svd.baseCAS.indexRepository.getIndex(CAS.SOFA_INDEX_NAME).size();
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.cas.CAS#getViewIterator()
*/
@Override
public <T extends CAS> Iterator<T> getViewIterator() {
return new Iterator<T>() {
final CASImpl initialView = getInitialView(); // creates one if not existing, w/o sofa
boolean isInitialView_but_noSofa = !initialView.mySofaIsValid(); // true if has no Sofa in
// initial view
// but is reset to false once iterator moves
// off of initial view.
// if initial view has a sofa, we just use the
// sofa iterator instead.
final FSIterator<Sofa> sofaIter = getSofaIterator();
@Override
public boolean hasNext() {
if (isInitialView_but_noSofa) {
return true;
}
return sofaIter.hasNext();
}
@Override
public T next() {
if (isInitialView_but_noSofa) {
isInitialView_but_noSofa = false; // no incr of sofa iterator because it was missing
// initial view
return (T) initialView;
}
return (T) getView(sofaIter.next());
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
/**
* excludes initial view if its sofa is not valid
*
* @return iterator over all views except the base view
*/
public Iterator<CASImpl> getViewImplIterator() {
return new Iterator<CASImpl>() {
final CASImpl initialView = getInitialView(); // creates one if not existing, w/o sofa
boolean isInitialView_but_noSofa = !initialView.mySofaIsValid(); // true if has no Sofa in
// initial view
// but is reset to false once iterator moves
// off of initial view.
// if initial view has a sofa, we just use the
// sofa iterator instead.
final FSIterator<Sofa> sofaIter = getSofaIterator();
@Override
public boolean hasNext() {
if (isInitialView_but_noSofa) { // set to false once iterator moves off of first value
return true;
}
return sofaIter.hasNext();
}
@Override
public CASImpl next() {
if (isInitialView_but_noSofa) {
isInitialView_but_noSofa = false; // no incr of sofa iterator because it was missing
// initial view
return initialView;
}
return getView(sofaIter.next());
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
/**
* iterate over all views in view order (by view number)
*
* @param processViews
* action to perform on the views.
*/
public void forAllViews(Consumer<CASImpl> processViews) {
final int numViews = this.getNumberOfViews();
for (int viewNbr = 1; viewNbr <= numViews; viewNbr++) {
CASImpl view = (viewNbr == 1) ? getInitialView() : (CASImpl) getView(viewNbr);
processViews.accept(view);
}
//
// Iterator<CASImpl> it = getViewImplIterator();
// while (it.hasNext()) {
// processViews.accept(it.next());
// }
}
void forAllSofas(Consumer<Sofa> processSofa) {
FSIterator<Sofa> it = getSofaIterator();
while (it.hasNext()) {
processSofa.accept(it.nextNvc());
}
}
/**
* Excludes base view's ir, Includes the initial view's ir only if it has a sofa defined
*
* @param processIr
* the code to execute
*/
void forAllIndexRepos(Consumer<FSIndexRepositoryImpl> processIr) {
final int numViews = this.getViewCount();
for (int viewNum = 1; viewNum <= numViews; viewNum++) {
processIr.accept(this.getSofaIndexRepository(viewNum));
}
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.cas.CAS#getViewIterator(java.lang.String)
*/
@Override
public Iterator<CAS> getViewIterator(String localViewNamePrefix) {
// do sofa mapping for current component
String absolutePrefix = null;
if (getCurrentComponentInfo() != null) {
absolutePrefix = getCurrentComponentInfo().mapToSofaID(localViewNamePrefix);
}
if (absolutePrefix == null) {
absolutePrefix = localViewNamePrefix;
}
// find Sofas with this prefix
List<CAS> viewList = new ArrayList<>();
FSIterator<Sofa> sofaIter = getSofaIterator();
while (sofaIter.hasNext()) {
SofaFS sofa = sofaIter.next();
String sofaId = sofa.getSofaID();
if (sofaId.startsWith(absolutePrefix)) {
if ((sofaId.length() == absolutePrefix.length())
|| (sofaId.charAt(absolutePrefix.length()) == '.')) {
viewList.add(getView(sofa));
}
}
}
return viewList.iterator();
}
/**
* protectIndexes
*
* Within the scope of protectIndexes, feature updates are checked, and if found to be a key, and
* the FS is in a corruptible index, then the FS is removed from the indexes (in all necessary
* views) (perhaps multiple times if the FS was added to the indexes multiple times), and this
* removal is recorded on an new instance of FSsTobeReindexed appended to fssTobeAddedback.
*
* Later, when the protectIndexes is closed, the tobe items are added back to the indexes.
*/
@Override
public AutoCloseableNoException protectIndexes() {
FSsTobeAddedback r = FSsTobeAddedback.createMultiple(this);
svd.fssTobeAddedback.add(r);
return r;
}
void dropProtectIndexesLevel() {
if (svd.fssTobeAddedback.isEmpty()) {
return;
}
svd.fssTobeAddedback.remove(svd.fssTobeAddedback.size() - 1);
}
// @formatter:off
/**
* This design is to support normal operations where the
* addbacks could be nested
* It also handles cases where nested ones were inadvertently left open
* Three cases:
* 1) the addbacks are the last element in the stack
* - remove it from the stack
* 2) the addbacks are (no longer) in the list
* - leave stack alone
* 3) the addbacks are in the list but not at the end
* - remove it and all later ones, calling addback on each
*
* If the "withProtectedindexes" approach is used, it guarantees proper
* nesting, but the Runnable can't throw checked exceptions.
*
* You can do your own try-finally blocks (or use the try with resources
* form in Java 8 to do a similar thing with no restrictions on what the
* body can contain.
*
* @param addbacks
* -
*/
// @formatter:on
void addbackModifiedFSs(FSsTobeAddedback addbacks) {
final List<FSsTobeAddedback> listOfAddbackInfos = svd.fssTobeAddedback;
// case 1: the addbacks are the last in the stack:
if (listOfAddbackInfos.get(listOfAddbackInfos.size() - 1) == addbacks) {
listOfAddbackInfos.remove(listOfAddbackInfos.size() - 1);
addbacks.addback();
return;
}
int pos = listOfAddbackInfos.indexOf(addbacks);
// case 2: the addbacks are in the stack, but there are others following it
if (pos >= 0) {
for (int i = listOfAddbackInfos.size() - 1; i >= pos; i--) {
FSsTobeAddedback toAddBack = listOfAddbackInfos.remove(i);
toAddBack.addback();
}
return;
}
// case 3: the addbacks are not in the list - just remove them, ignore the list
addbacks.addback();
}
/**
*
* @param r
* an inner block of code to be run with
*/
@Override
public void protectIndexes(Runnable r) {
AutoCloseable addbacks = protectIndexes();
try {
r.run();
} finally {
addbackModifiedFSs((FSsTobeAddedback) addbacks);
}
}
/**
* The current implementation only supports 1 marker call per CAS. Subsequent calls will throw an
* error.
*
* The design is intended to support (at some future point) multiple markers; for this to work,
* the intent is to extend the MarkerImpl to keep track of indexes into these IntVectors
* specifying where that marker starts/ends.
*/
@Override
public Marker createMarker() {
if (isCasLocked()) {
throw new CASAdminException(CASAdminException.FLUSH_DISABLED);
}
this.svd.trackingMark = new MarkerImpl(this.getLastUsedFsId() + 1, this);
if (this.svd.modifiedPreexistingFSs == null) {
this.svd.modifiedPreexistingFSs = new IdentityHashMap<>();
}
if (this.svd.modifiedPreexistingFSs.size() > 0) {
errorMultipleMarkers();
}
if (this.svd.trackingMarkList == null) {
this.svd.trackingMarkList = new ArrayList<>();
} else {
errorMultipleMarkers();
}
this.svd.trackingMarkList.add(this.svd.trackingMark);
return this.svd.trackingMark;
}
private void errorMultipleMarkers() {
throw new CASRuntimeException(CASRuntimeException.MULTIPLE_CREATE_MARKER);
}
// made public https://issues.apache.org/jira/browse/UIMA-2478
public MarkerImpl getCurrentMark() {
return this.svd.trackingMark;
}
/**
*
* @return an array of FsChange items, one per modified Fs, sorted in order of fs._id
*/
FsChange[] getModifiedFSList() {
final Map<TOP, FsChange> mods = this.svd.modifiedPreexistingFSs;
FsChange[] r = mods.values().toArray(new FsChange[mods.size()]);
Arrays.sort(r, 0, mods.size(), (c1, c2) -> Integer.compare(c1.fs._id, c2.fs._id));
return r;
}
boolean isInModifiedPreexisting(TOP fs) {
return this.svd.modifiedPreexistingFSs.containsKey(fs);
}
@Override
public String toString() {
String sofa = (mySofaRef == null) ? (isBaseCas() ? "Base CAS" : "_InitialView or no Sofa")
: mySofaRef.getSofaID();
// (mySofaRef == 0) ? "no Sofa" :
return this.getClass().getSimpleName() + ":" + getCasId() + "[view: " + sofa + "]";
}
public int getCasResets() {
return svd.casResets.get();
}
/**
* @return an identifier for this CAS, globally unique within the classloader
*/
public String getCasId() {
return svd.casId;
}
final public int getNextFsId(TOP fs) {
return svd.getNextFsId(fs);
}
public void adjustLastFsV2Size_arrays(int arrayLength) {
svd.lastFsV2Size += 1 + arrayLength; // 1 is for array length value
}
public void adjustLastFsV2size_nonHeapStoredArrays() {
svd.lastFsV2Size += 2; // length and index into other special heap
}
/**
* Test case use
*
* @param fss
* the FSs to include in the id 2 fs map
*/
public void setId2FSsMaybeUnconditionally(FeatureStructure... fss) {
for (FeatureStructure fs : fss) {
setId2FsMaybeUnconditionally((TOP) fs);
}
}
private void setId2FsMaybeUnconditionally(TOP fs) {
if (svd.isId2Fs) {
svd.id2fs.putUnconditionally(fs);
} else {
set_id2fs(fs);
}
}
// Not currently used
// public Int2ObjHashMap<TOP, TOP> getId2FSs() {
// return svd.id2fs.getId2fs();
// }
// final private int getNextFsId() {
// return ++ svd.fsIdGenerator;
// }
final public int getLastUsedFsId() {
return svd.fsIdGenerator;
}
final public int peekNextFsId() {
return svd.peekNextFsId();
}
final public int lastV2IdIncr() {
return svd.lastFsV2IdIncr();
}
/**
* Call this to capture the current value of fsIdGenerator and make it available to other threads.
*
* Must be called on a thread that has been synchronized with the thread used for creating FSs for
* this CAS.
*/
final public void captureLastFsIdForOtherThread() {
svd.fsIdLastValue.set(svd.fsIdGenerator);
}
public <T extends TOP> T getFsFromId(int id) {
return (T) this.svd.id2fs.get(id);
}
// /**
// * plus means all reachable, plus maybe others not reachable but not yet gc'd
// * @param action -
// */
// public void walkReachablePlusFSsSorted(Consumer<TOP> action) {
// this.svd.id2fs.walkReachablePlusFSsSorted(action);
// }
// /**
// * called for delta serialization - walks just the new items above the line
// * @param action -
// * @param fromId - the id of the first item to walk from
// */
// public void walkReachablePlusFSsSorted(Consumer<TOP> action, int fromId) {
// this.svd.id2fs.walkReachablePlueFSsSorted(action, fromId);
// }
/**
* find all of the FSs via the indexes plus what's reachable. sort into order by id,
*
* Apply the action to those Return the list of sorted FSs
*
* @param action_filtered
* action to perform on each item after filtering
* @param mark
* null or the mark
* @param includeFilter
* null or a filter (exclude items not in other type system)
* @param typeMapper
* null or how to map to other type system, used to skip things missing in other type
* system
* @return sorted list of all found items (ignoring mark)
*/
public List<TOP> walkReachablePlusFSsSorted(Consumer<TOP> action_filtered, MarkerImpl mark,
Predicate<TOP> includeFilter, CasTypeSystemMapper typeMapper) {
List<TOP> all = new AllFSs(this, mark, includeFilter, typeMapper)
.getAllFSsAllViews_sofas_reachable().getAllFSsSorted();
List<TOP> filtered = filterAboveMark(all, mark);
if (action_filtered != null) {
for (TOP fs : filtered) {
action_filtered.accept(fs);
}
}
return all;
}
static List<TOP> filterAboveMark(List<TOP> all, MarkerImpl mark) {
if (null == mark) {
return all;
}
int c = Collections.binarySearch(all, TOP._createSearchKey(mark.nextFSId),
(fs1, fs2) -> Integer.compare(fs1._id, fs2._id));
if (c < 0) {
c = (-c) - 1;
}
return all.subList(c, all.size());
}
// /**
// * Get the Java class corresponding to a particular type
// * Only valid after type system commit
// *
// * @param type
// * @return
// */
// public <T extends FeatureStructure> Class<T> getClass4Type(Type type) {
// TypeSystemImpl tsi = getTypeSystemImpl();
// if (!tsi.isCommitted()) {
// throw new CASRuntimeException(CASRuntimeException.GET_CLASS_FOR_TYPE_BEFORE_TS_COMMIT);
// }
//
// }
public final static boolean isSameCAS(CAS c1, CAS c2) {
CASImpl ci1 = (CASImpl) c1.getLowLevelCAS();
CASImpl ci2 = (CASImpl) c2.getLowLevelCAS();
return ci1.getBaseCAS() == ci2.getBaseCAS();
}
public boolean isInCAS(FeatureStructure fs) {
return ((TOP) fs)._casView.getBaseCAS() == this.getBaseCAS();
}
// /**
// *
// * @param typecode -
// * @return Object that can be cast to either a 2 or 3 arg createFs functional interface
// * FsGenerator or FsGeneratorArray
// */
// private Object getFsGenerator(int typecode) {
// return getTypeSystemImpl().getGenerator(typecode);
// }
public final void checkArrayPreconditions(int len) throws CASRuntimeException {
// Check array size.
if (len < 0) {
throw new CASRuntimeException(CASRuntimeException.ILLEGAL_ARRAY_SIZE);
}
}
@Override
public <T extends TOP> EmptyFSList<T> emptyFSList() {
if (null == svd.emptyFSList) {
svd.emptyFSList = new EmptyFSList<>(getTypeSystemImpl().fsEListType, this);
}
return svd.emptyFSList;
}
/*
* @see org.apache.uima.cas.CAS#emptyFloatList()
*/
@Override
public EmptyFloatList emptyFloatList() {
if (null == svd.emptyFloatList) {
svd.emptyFloatList = new EmptyFloatList(getTypeSystemImpl().floatEListType, this);
}
return svd.emptyFloatList;
}
@Override
public EmptyIntegerList emptyIntegerList() {
if (null == svd.emptyIntegerList) {
svd.emptyIntegerList = new EmptyIntegerList(getTypeSystemImpl().intEListType, this);
}
return svd.emptyIntegerList;
}
@Override
public EmptyStringList emptyStringList() {
if (null == svd.emptyStringList) {
svd.emptyStringList = new EmptyStringList(getTypeSystemImpl().stringEListType, this);
}
return svd.emptyStringList;
}
public CommonArrayFS emptyArray(Type type) {
switch (((TypeImpl) type).getCode()) {
case TypeSystemConstants.booleanArrayTypeCode:
return emptyBooleanArray();
case TypeSystemConstants.byteArrayTypeCode:
return emptyByteArray();
case TypeSystemConstants.shortArrayTypeCode:
return emptyShortArray();
case TypeSystemConstants.intArrayTypeCode:
return emptyIntegerArray();
case TypeSystemConstants.floatArrayTypeCode:
return emptyFloatArray();
case TypeSystemConstants.longArrayTypeCode:
return emptyLongArray();
case TypeSystemConstants.doubleArrayTypeCode:
return emptyDoubleArray();
case TypeSystemConstants.stringArrayTypeCode:
return emptyStringArray();
default: // TypeSystemConstants.fsArrayTypeCode or any other type
return emptyFSArray();
}
}
@Override
public FloatArray emptyFloatArray() {
if (null == svd.emptyFloatArray) {
svd.emptyFloatArray = new FloatArray(this.getJCas(), 0);
}
return svd.emptyFloatArray;
}
@Override
public <T extends FeatureStructure> FSArray<T> emptyFSArray() {
return emptyFSArray(null);
}
@Override
public <T extends FeatureStructure> FSArray<T> emptyFSArray(Type type) {
return svd.emptyFSArrayMap.computeIfAbsent(type,
t -> (t == null) ? new FSArray(this.getJCas(), 0)
: new FSArray((TypeImpl) getTypeSystemImpl().getArrayType(type), this, 0));
}
@Override
public IntegerArray emptyIntegerArray() {
if (null == svd.emptyIntegerArray) {
svd.emptyIntegerArray = new IntegerArray(this.getJCas(), 0);
}
return svd.emptyIntegerArray;
}
@Override
public StringArray emptyStringArray() {
if (null == svd.emptyStringArray) {
svd.emptyStringArray = new StringArray(this.getJCas(), 0);
}
return svd.emptyStringArray;
}
@Override
public DoubleArray emptyDoubleArray() {
if (null == svd.emptyDoubleArray) {
svd.emptyDoubleArray = new DoubleArray(this.getJCas(), 0);
}
return svd.emptyDoubleArray;
}
@Override
public LongArray emptyLongArray() {
if (null == svd.emptyLongArray) {
svd.emptyLongArray = new LongArray(this.getJCas(), 0);
}
return svd.emptyLongArray;
}
@Override
public ShortArray emptyShortArray() {
if (null == svd.emptyShortArray) {
svd.emptyShortArray = new ShortArray(this.getJCas(), 0);
}
return svd.emptyShortArray;
}
@Override
public ByteArray emptyByteArray() {
if (null == svd.emptyByteArray) {
svd.emptyByteArray = new ByteArray(this.getJCas(), 0);
}
return svd.emptyByteArray;
}
@Override
public BooleanArray emptyBooleanArray() {
if (null == svd.emptyBooleanArray) {
svd.emptyBooleanArray = new BooleanArray(this.getJCas(), 0);
}
return svd.emptyBooleanArray;
}
/**
* @param rangeCode
* special codes for serialization use only
* @return the empty list (shared) corresponding to the type
*/
public EmptyList emptyList(int rangeCode) {
return (rangeCode == CasSerializerSupport.TYPE_CLASS_INTLIST) ? emptyIntegerList()
: (rangeCode == CasSerializerSupport.TYPE_CLASS_FLOATLIST) ? emptyFloatList()
: (rangeCode == CasSerializerSupport.TYPE_CLASS_STRINGLIST) ? emptyStringList()
: emptyFSList();
}
/**
* Get an empty list from the type code of a list
*
* @param typeCode
* -
* @return -
*/
public EmptyList emptyListFromTypeCode(int typeCode) {
switch (typeCode) {
case fsListTypeCode:
case fsEListTypeCode:
case fsNeListTypeCode:
return emptyFSList();
case floatListTypeCode:
case floatEListTypeCode:
case floatNeListTypeCode:
return emptyFloatList();
case intListTypeCode:
case intEListTypeCode:
case intNeListTypeCode:
return emptyIntegerList();
case stringListTypeCode:
case stringEListTypeCode:
case stringNeListTypeCode:
return emptyStringList();
default:
throw new IllegalArgumentException();
}
}
// /**
// * Copies a feature, from one fs to another
// * FSs may belong to different CASes, but must have the same type system
// * Features must have compatible ranges
// * The target must not be indexed
// * The target must be a "new" (above the "mark") FS
// * @param fsSrc source FS
// * @param fi Feature to copy
// * @param fsTgt target FS
// */
// public static void copyFeature(TOP fsSrc, FeatureImpl fi, TOP fsTgt) {
// if (!copyFeatureExceptFsRef(fsSrc, fi, fsTgt, fi)) {
// if (!fi.isAnnotBaseSofaRef) {
// fsTgt._setFeatureValueNcNj(fi, fsSrc._getFeatureValueNc(fi));
// }
// }
// }
/**
* Copies a feature from one fs to another FSs may be in different type systems Doesn't copy a
* feature ref, but instead returns false. This is because feature refs can't cross CASes
*
* @param fsSrc
* source FS
* @param fiSrc
* feature in source to copy
* @param fsTgt
* target FS
* @param fiTgt
* feature in target to set
* @return false if feature is an fsRef
*/
public static boolean copyFeatureExceptFsRef(TOP fsSrc, FeatureImpl fiSrc, TOP fsTgt,
FeatureImpl fiTgt) {
switch (fiSrc.getRangeImpl().getCode()) {
case booleanTypeCode:
fsTgt._setBooleanValueNcNj(fiTgt, fsSrc._getBooleanValueNc(fiSrc));
break;
case byteTypeCode:
fsTgt._setByteValueNcNj(fiTgt, fsSrc._getByteValueNc(fiSrc));
break;
case shortTypeCode:
fsTgt._setShortValueNcNj(fiTgt, fsSrc._getShortValueNc(fiSrc));
break;
case intTypeCode:
fsTgt._setIntValueNcNj(fiTgt, fsSrc._getIntValueNc(fiSrc));
break;
case longTypeCode:
fsTgt._setLongValueNcNj(fiTgt, fsSrc._getLongValueNc(fiSrc));
break;
case floatTypeCode:
fsTgt._setFloatValueNcNj(fiTgt, fsSrc._getFloatValueNc(fiSrc));
break;
case doubleTypeCode:
fsTgt._setDoubleValueNcNj(fiTgt, fsSrc._getDoubleValueNc(fiSrc));
break;
case stringTypeCode:
fsTgt._setStringValueNcNj(fiTgt, fsSrc._getStringValueNc(fiSrc));
break;
// case javaObjectTypeCode : fsTgt._setJavaObjectValueNcNj(fiTgt,
// fsSrc.getJavaObjectValue(fiSrc)); break;
// skip setting sofaRef - it's final and can't be set
default:
if (fiSrc.getRangeImpl().isStringSubtype()) {
fsTgt._setStringValueNcNj(fiTgt, fsSrc._getStringValueNc(fiSrc));
break; // does substring range check
}
return false;
} // end of switch
return true;
}
public static CommonArrayFS copyArray(TOP srcArray) {
CommonArrayFS srcCA = (CommonArrayFS) srcArray;
CommonArrayFS copy = (CommonArrayFS) srcArray._casView.createArray(srcArray._getTypeImpl(),
srcCA.size());
copy.copyValuesFrom(srcCA);
return copy;
}
public BinaryCasSerDes getBinaryCasSerDes() {
return svd.bcsd;
}
/**
* @return the saved CommonSerDesSequential info
*/
CommonSerDesSequential getCsds() {
return svd.csds;
}
void setCsds(CommonSerDesSequential csds) {
svd.csds = csds;
}
CommonSerDesSequential newCsds() {
return svd.csds = new CommonSerDesSequential(this.getBaseCAS());
}
/**
* A space-freeing optimization for use cases where (multiple) delta CASes are being deserialized
* into this CAS and merged.
*/
public void deltaMergesComplete() {
svd.csds = null;
}
// @formatter:off
/******************************************
* PEAR support
* Don't modify the type system because it is in use on multiple threads
*
* Handling of id2fs for low level APIs:
* FSs in id2fs map are the outer non-pear ones
* Any gets do pear conversion if needed.
*
******************************************/
/**
* Convert base FS to Pear equivalent
* 3 cases:
* 1) no trampoline needed, no conversion, return the original fs
* 2) trampoline already exists - return that one
* 3) create new trampoline
* @param aFs
* @return
*/
// @formatter:on
static <T extends FeatureStructure> T pearConvert(T aFs) {
if (null == aFs) {
return null;
}
final TOP fs = (TOP) aFs;
final CASImpl view = fs._casView;
final TypeImpl ti = fs._getTypeImpl();
final FsGenerator3 generator = view.svd.generators[ti.getCode()];
if (null == generator) {
return aFs;
}
return (T) view.pearConvert(fs, generator);
}
/**
* Inner method - after determining there is a generator First see if already have generated the
* pear version, and if so, use that. Otherwise, create the pear version and save in trampoline
* table
*
* @param fs
* @param g
* @return
*/
private TOP pearConvert(TOP fs, FsGenerator3 g) {
return svd.id2tramp.putIfAbsent(fs._id, k -> {
svd.reuseId = k; // create new FS using base FS's ID
pearBaseFs = fs;
TOP r;
// createFS below is modified because of pearBaseFs non-null to
// "share" the int and data arrays
try {
r = g.createFS(fs._getTypeImpl(), this);
} finally {
svd.reuseId = 0;
pearBaseFs = null;
}
assert r != null;
if (r instanceof UimaSerializable) {
throw new UnsupportedOperationException(
"Pears with Alternate implementations of JCas classes implementing UimaSerializable not supported.");
// ((UimaSerializable) fs)._save_to_cas_data(); // updates in r too
// ((UimaSerializable) r)._init_from_cas_data();
}
return r;
});
}
/**
* Given a trampoline FS, return the corresponding base Fs Supports adding Fs (which must be a
* non-trampoline version) to indexes
*
* @param fs
* trampoline fs
* @return the corresponding base fs
*/
<T extends TOP> T getBaseFsFromTrampoline(T fs) {
TOP r = svd.id2base.get(fs._id);
assert r != null;
return (T) r;
}
// *****************************************
// DEBUGGING and TRACING
// *****************************************
public void traceFSCreate(FeatureStructureImplC fs) {
StringBuilder b = svd.traceFScreationSb;
if (b.length() > 0) {
traceFSflush();
}
// normally commented-out for matching with v2
// // mark annotations created by subiterator
// if (fs._getTypeCode() == TypeSystemConstants.annotTypeCode) {
// StackTraceElement[] stktr = Thread.currentThread().getStackTrace();
// if (stktr.length > 7 &&
// stktr[6].getClassName().equals("org.apache.uima.cas.impl.Subiterator")) {
// b.append('*');
// }
// }
svd.id2addr.add(svd.nextId2Addr);
svd.nextId2Addr += fs._getTypeImpl().getFsSpaceReq((TOP) fs);
traceFSfs(fs);
svd.traceFSisCreate = true;
if (fs._getTypeImpl().isArray()) {
b.append(" l:").append(((CommonArrayFS) fs).size());
}
}
void traceFSfs(FeatureStructureImplC fs) {
StringBuilder b = svd.traceFScreationSb;
svd.traceFSid = fs._id;
b.append("c:").append(String.format("%-3s", getCasId()));
String viewName = fs._casView.getViewName();
if (null == viewName) {
viewName = "base";
}
b.append(" v:").append(Misc.elide(viewName, 8));
b.append(" i:").append(String.format("%-5s", geti2addr(fs._id)));
b.append(" t:").append(Misc.elide(fs._getTypeImpl().getShortName(), 10));
}
void traceIndexMod(boolean isAdd, TOP fs, boolean isAddbackOrSkipBag) {
StringBuilder b = svd.traceCowSb;
b.setLength(0);
b.append(isAdd ? (isAddbackOrSkipBag ? "abk_idx " : "add_idx ")
: (isAddbackOrSkipBag ? "rmv_auto_idx " : "rmv_norm_idx "));
// b.append(fs.toString());
b.append(fs._getTypeImpl().getShortName()).append(":").append(fs._id);
if (fs instanceof Annotation) {
Annotation ann = (Annotation) fs;
b.append(" begin: ").append(ann.getBegin());
b.append(" end: ").append(ann.getEnd());
b.append(" txt: \"").append(Misc.elide(ann.getCoveredText(), 10)).append("\"");
}
traceOut.println(b);
}
void traceCowCopy(FsIndex_singletype<?> index) {
StringBuilder b = svd.traceCowSb;
b.setLength(0);
b.append("cow-copy:");
b.append(" i: ").append(index);
traceOut.println(b);
}
void traceCowCopyUse(FsIndex_singletype<?> index) {
StringBuilder b = svd.traceCowSb;
b.setLength(0);
b.append("cow-copy-used:");
b.append(" i: ").append(index);
traceOut.println(b);
}
void traceCowReinit(String kind, FsIndex_singletype<?> index) {
StringBuilder b = svd.traceCowSb;
b.setLength(0);
b.append("cow-redo: ");
b.append(kind);
b.append(" i: ").append(index);
b.append(" c: ");
b.append(Misc.getCaller());
traceOut.println(b);
}
/** only used for tracing, enables tracing 2 slots for long/double */
private FeatureImpl prevFi;
void traceFSfeat(FeatureStructureImplC fs, FeatureImpl fi, Object v) {
// debug
FeatureImpl originalFi = fi;
StringBuilder b = svd.traceFScreationSb;
assert (b.length() > 0);
if (fs._id != svd.traceFSid) {
traceFSfeatUpdate(fs);
}
if (fi == null) { // happens on 2nd setInt call from cas copier copyfeatures for Long / Double
switch (prevFi.getSlotKind()) {
case Slot_DoubleRef:
v = fs._getDoubleValueNc(prevFi);
break; // correct double and long
case Slot_LongRef:
v = fs._getLongValueNc(prevFi);
break; // correct double and long
default:
Misc.internalError();
}
fi = prevFi;
prevFi = null;
} else {
prevFi = fi;
}
String fn = fi.getShortName();
// correct calls done by cas copier fast loop
if (fi.getSlotKind() == SlotKind.Slot_DoubleRef) {
if (v instanceof Integer) {
return; // wait till the next part is traced
} else if (v instanceof Long) {
v = CASImpl.long2double((long) v);
}
}
if (fi.getSlotKind() == SlotKind.Slot_LongRef && (v instanceof Integer)) {
return; // output done on the next int call
}
String fv = getTraceRepOfObj(fi, v);
// if (geti2addr(fs._id).equals("79") &&
// fn.equals("sofa")) {
// new Throwable().printStackTrace(traceOut);
// }
// // debug
// if (fn.equals("lemma") &&
// fv.startsWith("Lemma:") &&
// debug1cnt < 2) {
// debug1cnt ++;
// traceOut.println("setting lemma feat:");
// new Throwable().printStackTrace(traceOut);
// }
// debug
// if (fs._getTypeImpl().getShortName().equals("Passage") &&
// "score".equals(fn) &&
// debug2cnt < 5) {
// debug2cnt++;
// traceOut.println("setting score feat in Passage");
// new Throwable().printStackTrace(traceOut);
// }
// debug
int i_v = Math.max(0, 10 - fn.length());
int i_n = Math.max(0, 10 - fv.length());
fn = Misc.elide(fn, 10 + i_n, false);
fv = Misc.elide(fv, 10 + i_v, false);
// debug
// if (!svd.traceFSisCreate && fn.equals("uninf.dWord") && fv.equals("XsgTokens")) {
// traceOut.println("debug uninf.dWord:XsgTokens: " + Misc.getCallers(3, 10));
// }
b.append(' ').append(Misc.elide(fn + ':' + fv, 21));
// value of a feature:
// - "null" or
// - if FS: type:id (converted to addr)
// - v.toString()
}
// private static int debug2cnt = 0;
/**
* @param v
* @return value of the feature: "null" or if FS: type:id (converted to addr) or v.toString()
* Note: white space in strings converted to "_' characters
*/
private String getTraceRepOfObj(FeatureImpl fi, Object v) {
if (v instanceof TOP) {
TOP fs = (TOP) v;
return Misc.elide(fs.getType().getShortName(), 5, false) + ':' + geti2addr(fs._id);
}
if (v == null) {
return "null";
}
if (v instanceof String) {
String s = Misc.elide((String) v, 50, false);
return Misc.replaceWhiteSpace(s, "_");
}
if (v instanceof Integer) {
int iv = (int) v;
switch (fi.getSlotKind()) {
case Slot_Boolean:
return (iv == 1) ? "true" : "false";
case Slot_Byte:
case Slot_Short:
case Slot_Int:
return Integer.toString(iv);
case Slot_Float:
return Float.toString(int2float(iv));
default:
// Ignore
}
}
if (v instanceof Long) {
long vl = (long) v;
return (fi.getSlotKind() == SlotKind.Slot_DoubleRef) ? Double.toString(long2double(vl))
: Long.toString(vl);
}
return Misc.replaceWhiteSpace(v.toString(), "_");
}
private String geti2addr(int id) {
if (id >= svd.id2addr.size()) {
return Integer.toString(id) + '!';
}
return Integer.toString(svd.id2addr.get(id));
}
void traceFSfeatUpdate(FeatureStructureImplC fs) {
traceFSflush();
traceFSfs(fs);
svd.traceFSisCreate = false;
}
public StringBuilder traceFSflush() {
if (!traceFSs) {
return null;
}
StringBuilder b = svd.traceFScreationSb;
if (b.length() > 0) {
traceOut.println((svd.traceFSisCreate ? "cr: " : "up: ") + b);
b.setLength(0);
svd.traceFSisCreate = false;
}
return b;
}
private static class MeasureSwitchType {
TypeImpl oldType;
TypeImpl newType;
String oldJCasClassName;
String newJCasClassName;
int count = 0;
boolean newSubsumesOld;
boolean oldSubsumesNew;
long scantime = 0;
MeasureSwitchType(TypeImpl oldType, TypeImpl newType) {
this.oldType = oldType;
this.oldJCasClassName = oldType.getJavaClass().getName();
this.newType = newType;
this.newJCasClassName = newType.getJavaClass().getName();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((newJCasClassName == null) ? 0 : newJCasClassName.hashCode());
result = prime * result + ((newType == null) ? 0 : newType.hashCode());
result = prime * result + ((oldJCasClassName == null) ? 0 : oldJCasClassName.hashCode());
result = prime * result + ((oldType == null) ? 0 : oldType.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof MeasureSwitchType)) {
return false;
}
MeasureSwitchType other = (MeasureSwitchType) obj;
if (newJCasClassName == null) {
if (other.newJCasClassName != null) {
return false;
}
} else if (!newJCasClassName.equals(other.newJCasClassName)) {
return false;
}
if (newType == null) {
if (other.newType != null) {
return false;
}
} else if (!newType.equals(other.newType)) {
return false;
}
if (oldJCasClassName == null) {
if (other.oldJCasClassName != null) {
return false;
}
} else if (!oldJCasClassName.equals(other.oldJCasClassName)) {
return false;
}
if (oldType == null) {
if (other.oldType != null) {
return false;
}
} else if (!oldType.equals(other.oldType)) {
return false;
}
return true;
}
}
private static final Map<MeasureSwitchType, MeasureSwitchType> measureSwitches = new HashMap<>();
static {
if (MEASURE_SETINT) {
Runtime.getRuntime().addShutdownHook(new Thread(null, () -> {
System.out.println("debug Switch Types dump, # entries: " + measureSwitches.size());
int s1 = 0, s2 = 0, s3 = 0;
for (MeasureSwitchType mst : measureSwitches.keySet()) {
s1 = Math.max(s1, mst.oldType.getName().length());
s2 = Math.max(s2, mst.newType.getName().length());
s3 = Math.max(s3, mst.oldJCasClassName.length());
}
for (MeasureSwitchType mst : measureSwitches.keySet()) {
System.out.format(
"count: %,6d scantime = %,7d ms, subsumes: %s %s, type: %-" + s1
+ "s newType: %-" + s2 + "s, cl: %-" + s3 + "s, newCl: %s%n",
mst.count, mst.scantime / 1000000, mst.newSubsumesOld ? "n>o" : " ",
mst.oldSubsumesNew ? "o>w" : " ", mst.oldType.getName(), mst.newType.getName(),
mst.oldJCasClassName, mst.newJCasClassName);
}
// if (traceFSs) {
// System.err.println("debug closing traceFSs output");
// traceOut.close();
// }
}, "Dump SwitchTypes"));
}
// this is definitely needed
if (traceFSs) {
Runtime.getRuntime().addShutdownHook(new Thread(null, () -> {
System.out.println("closing traceOut");
traceOut.close();
}, "close trace output"));
}
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.cas.admin.CASMgr#setCAS(org.apache.uima.cas.CAS) Internal use Never called
* Kept because it's in the interface.
*/
@Override
@Deprecated
public void setCAS(CAS cas) {
}
/**
* @return true if in Pear context, or external context outside AnalysisEngine having a UIMA
* Extension class loader e.g., if calling a call-back routine loaded outside the AE.
*/
boolean inPearContext() {
return svd.previousJCasClassLoader != null;
}
/**
* Pear context suspended while creating a base version, when we need to create a new FS (we need
* to create both the base and the trampoline version)
*/
private void suspendPearContext() {
svd.suspendPreviousJCasClassLoader = svd.previousJCasClassLoader;
svd.previousJCasClassLoader = null;
}
private void restorePearContext() {
svd.previousJCasClassLoader = svd.suspendPreviousJCasClassLoader;
}
/**
*
* @return the initial heap size specified or defaulted
*/
public int getInitialHeapSize() {
return this.svd.initialHeapSize;
}
// backwards compatibility - reinit calls
// just the public apis
/**
* Deserializer for Java-object serialized instance of CASSerializer.
*
* @param ser
* - The instance to convert back to a CAS
*/
public void reinit(CASSerializer ser) {
svd.bcsd.reinit(ser);
}
/**
* Deserializer for CASCompleteSerializer instances - includes type system and index definitions
* Never delta
*
* @param casCompSer
* -
*/
public void reinit(CASCompleteSerializer casCompSer) {
svd.bcsd.reinit(casCompSer);
}
// @formatter:off
/**
* ---------------------------------------------------------------------
* see Blob Format in CASSerializer
*
* This reads in and deserializes CAS data from a stream. Byte swapping may be needed if the blob
* is from C++ -- C++ blob serialization writes data in native byte order.
*
* Supports delta deserialization. For that, the the csds from the serialization event must be
* used.
*
* @param istream
* -
* @return - the format of the input stream detected
* @throws CASRuntimeException
* wraps IOException
*/
// @formatter:on
public SerialFormat reinit(InputStream istream) throws CASRuntimeException {
return svd.bcsd.reinit(istream);
}
void maybeHoldOntoFS(FeatureStructureImplC fs) {
if (svd.isId2Fs) {
svd.id2fs.put((TOP) fs); // does an assert - prev id should not be there
}
}
public void swapInPearVersion(Object[] a) {
if (!inPearContext()) {
return;
}
for (int i = 0; i < a.length; i++) {
Object ao = a[i];
if (ao instanceof TOP) {
a[i] = pearConvert((TOP) ao);
}
}
}
public Collection<?> collectNonPearVersions(Collection<?> c) {
if (c.size() == 0 || !inPearContext()) {
return c;
}
ArrayList<Object> items = new ArrayList<>(c.size());
for (Object o : c) {
if (o instanceof TOP) {
items.add(pearConvert((TOP) o));
}
}
return items;
}
public <T> Spliterator<T> makePearAware(Spliterator<T> baseSi) {
if (!inPearContext()) {
return baseSi;
}
return new Spliterator<T>() {
@Override
public boolean tryAdvance(Consumer<? super T> action) {
return baseSi.tryAdvance(
item -> action.accept((item instanceof TOP) ? (T) pearConvert((TOP) item) : item));
}
@Override
public Spliterator<T> trySplit() {
return baseSi.trySplit();
}
@Override
public long estimateSize() {
return baseSi.estimateSize();
}
@Override
public int characteristics() {
return baseSi.characteristics();
}
};
}
@Override
public boolean is_ll_enableV2IdRefs() {
return svd.isId2Fs;
}
@Override
public AutoCloseableNoException ll_enableV2IdRefs(boolean enable) {
final boolean restoreState = svd.isId2Fs;
if (enable && !restoreState && svd.fsIdGenerator != 0) {
throw new IllegalStateException("CAS must be empty when switching to V2 ID References mode.");
}
AutoCloseableNoException r = () -> svd.isId2Fs = restoreState;
svd.isId2Fs = enable;
return r;
}
AutoCloseableNoException ll_forceEnableV2IdRefs(boolean enable) {
final boolean restoreState = svd.isId2Fs;
AutoCloseableNoException r = () -> svd.isId2Fs = restoreState;
svd.isId2Fs = enable;
return r;
}
// int allocIntData(int sz) {
//
// if (sz > INT_DATA_FOR_ALLOC_SIZE / 4) {
// returnIntDataForAlloc = new int[sz];
// return 0;
// }
//
// if (sz + nextIntDataOffsetForAlloc > INT_DATA_FOR_ALLOC_SIZE) {
// // too large to fit, alloc a new one
// currentIntDataForAlloc = new int[INT_DATA_FOR_ALLOC_SIZE];
// nextIntDataOffsetForAlloc = 0;
// }
// int r = nextIntDataOffsetForAlloc;
// nextIntDataOffsetForAlloc += sz;
// returnIntDataForAlloc = currentIntDataForAlloc;
// return r;
// }
//
// int[] getReturnIntDataForAlloc() {
// return returnIntDataForAlloc;
// }
//
// int allocRefData(int sz) {
//
// if (sz > REF_DATA_FOR_ALLOC_SIZE / 4) {
// returnRefDataForAlloc = new Object[sz];
// return 0;
// }
//
// if (sz + nextRefDataOffsetForAlloc > REF_DATA_FOR_ALLOC_SIZE) {
// // too large to fit, alloc a new one
// currentRefDataForAlloc = new Object[REF_DATA_FOR_ALLOC_SIZE];
// nextRefDataOffsetForAlloc = 0;
// }
// int r = nextRefDataOffsetForAlloc;
// nextRefDataOffsetForAlloc += sz;
// returnRefDataForAlloc = currentRefDataForAlloc;
// return r;
// }
//
// Object[] getReturnRefDataForAlloc() {
// return returnRefDataForAlloc;
// }
// UIMA-6199 provides access to non-indexed doc annot
// to allow sofa setting to set the "length" of the local sofa data string
// @see updateDocumentAnnotation() updateDocumentAnnotation.
public void set_deserialized_doc_annot_not_indexed(Annotation doc_annot) {
deserialized_doc_annot_not_indexed = doc_annot;
}
}