| /* |
| * 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 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.io.UnsupportedEncodingException; |
| import java.net.URL; |
| import java.nio.ByteBuffer; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.BitSet; |
| import java.util.Collection; |
| import java.util.Collections; |
| 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.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.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.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 { |
| |
| 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 |
| 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.enable_id_to_feature_structure_map_for_all_fss"; |
| static final boolean IS_ALWAYS_HOLD_ONTO_FSS = // debug |
| 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(); |
| } |
| |
| // 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; |
| } |
| } |
| |
| // 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; |
| |
| |
| /** |
| * 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. |
| */ |
| 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<>(); |
| |
| /** |
| * 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 |
| */ |
| private FsGenerator3[] generators; |
| /** |
| * 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 |
| */ |
| 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<FSsTobeAddedback>(); |
| |
| /** |
| * 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 int casId = casIdProvider.incrementAndGet(); |
| |
| // shared singltons, created at type system commit |
| |
| private EmptyFSList emptyFSList; |
| private EmptyFloatList emptyFloatList; |
| private EmptyIntegerList emptyIntegerList; |
| private EmptyStringList emptyStringList; |
| |
| /** |
| * 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 * |
| *************************************************/ |
| /** |
| * 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 |
| */ |
| private StringSet llstringSet = null; |
| /** |
| * 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 |
| */ |
| 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; |
| |
| 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); |
| } |
| |
| void clearCasReset() { |
| // fss |
| fsIdGenerator = 0; |
| id2fs.clear(); |
| |
| // pear caches |
| id2tramp = null; |
| id2base = null; |
| for (JCasHashMap m : cl2id2tramp.values()) { |
| m.clear(); |
| } |
| |
| // 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; |
| } |
| } |
| |
| /** |
| * called by resetNoQuestions and cas complete reinit |
| */ |
| void clearSofaInfo() { |
| sofaNameSet.clear(); |
| initialSofaCreated = false; |
| } |
| |
| /** |
| * 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 |
| * |
| */ |
| void clear() { |
| clearCasReset(); |
| clearTrackingMarks(); |
| |
| // type system + index spec |
| tsi = null; |
| featureCodesInIndexKeys.clear(); |
| // featureJiInIndexKeys.clear(); |
| emptyFloatList = null; // these cleared in case new ts redefines? |
| emptyFSList = null; |
| emptyIntegerList = null; |
| emptyStringList = null; |
| |
| clearSofaInfo(); |
| |
| /** |
| * 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 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; |
| } |
| |
| void switchClassLoader(ClassLoader newClassLoader) { |
| if (null == newClassLoader) { // is null if no cl set |
| return; |
| } |
| 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; |
| 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() { |
| if (null == previousJCasClassLoader) { |
| return; |
| } |
| // System.out.println("Switching back to previous class loader"); |
| jcasClassLoader = previousJCasClassLoader; |
| previousJCasClassLoader = null; |
| generators = baseGenerators; |
| id2tramp = null; |
| } |
| |
| private int getNextFsId(TOP fs) { |
| if (reuseId != 0) { |
| // l.setStrongRef(fs, reuseId); |
| return reuseId; |
| } |
| |
| // 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 += IS_USE_V2_IDS |
| ? lastFsV2Size |
| : 1; |
| if (r < p) { |
| throw new RuntimeException("UIMA Cas Internal id value overflowed maximum int value"); |
| } |
| if (IS_USE_V2_IDS) { |
| // this computation is partial - misses length of arrays stored on heap |
| // because that info not yet available |
| lastFsV2Size = fs._getTypeImpl().getFsSpaceReq(); |
| } |
| return r; |
| } |
| } |
| |
| /***************************************************************** |
| * 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 |
| |
| |
| /** 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; |
| |
| /** |
| * 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" |
| */ |
| private Sofa mySofaRef = null; |
| |
| /** the corresponding JCas object */ |
| JCasImpl jcas = null; |
| |
| /** |
| * 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. |
| */ |
| |
| 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; |
| |
| // 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 ) { |
| super(); |
| 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<String>(); |
| 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 |
| // ---------------------------------------- |
| |
| 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 TypeSystem getTypeSystem() { |
| return getTypeSystemImpl(); |
| } |
| |
| public 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 |
| } |
| |
| 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); |
| } |
| |
| /** |
| * 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(); |
| svd.reuseId = fs._id; |
| baseFs = createFsFromGenerator(svd.baseGenerators, ti); |
| } finally { |
| restorePearContext(); |
| svd.reuseId = 0; |
| } |
| svd.id2base.put(baseFs); |
| pearBaseFs = baseFs; |
| return true; |
| } |
| |
| private TOP createFsFromGenerator(FsGenerator3[] gs, TypeImpl ti) { |
| // if (ti == null || gs == null || gs[ti.getCode()] == null) { |
| // System.out.println("debug"); |
| // } |
| return gs[ti.getCode()].createFS(ti, this); |
| } |
| |
| // public int ll_createFSAnnotCheck(int typeCode) { |
| // TOP fs = createFSAnnotCheck(getTypeFromCode(typeCode)); |
| // svd.id2fs.put(fs); // required for low level, in order to "hold onto" / prevent GC of FS |
| // return fs._id; |
| // } |
| |
| 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); |
| // case javaObjectTypeCode: return new JavaObjectArray(array_type, this, arrayLength); |
| default: Misc.internalError(); |
| } |
| // return tia.getGeneratorArray().createFS(type, this, arrayLength); |
| // return (((FsGeneratorArray)getFsGenerator(type.getCode())).createFS(type, this, arrayLength)); |
| } |
| return (TOP) createArrayFS(array_type, arrayLength); |
| } |
| |
| @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); |
| // getTypeSystemImpl().fsArrayType.getGeneratorArray() // (((FsGeneratorArray)getFsGenerator(fsArrayTypeCode)) |
| // .createFS(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); |
| } |
| |
| // public JavaObjectArray createJavaObjectArrayFS(int length) { |
| // checkArrayPreconditions(length); |
| // return new JavaObjectArray(getTypeSystemImpl().javaObjectArrayType, 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); |
| } |
| |
| /** |
| * @deprecated |
| */ |
| @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; |
| } |
| |
| 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; |
| try { |
| bis = new ByteArrayInputStream(sd.getBytes("UTF-8")); |
| } catch (UnsupportedEncodingException e) { |
| throw new RuntimeException(e); // never happen |
| } |
| 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]); |
| } |
| try { |
| return new ByteArrayInputStream(sb.toString().getBytes("UTF-8") ); |
| } catch (UnsupportedEncodingException e) { |
| throw new RuntimeException(e); // never happen |
| } |
| } |
| 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: |
| 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<T>(it, cons); |
| } |
| |
| public TypeSystemImpl commitTypeSystem() { |
| 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) { |
| if (!ts.isCommitted()) { |
| TypeSystemImpl tsc = ts.commit(getJCasClassLoader()); |
| if (tsc != ts) { |
| installTypeSystemInAllViews(tsc); |
| ts = tsc; |
| } |
| } |
| } |
| svd.baseGenerators = svd.generators = ts.getGeneratorsForClassLoader(cl, false); // false - not PEAR |
| createIndexRepository(); |
| return ts; |
| } |
| |
| 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 |
| * @param fs - |
| */ |
| @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 (!this.svd.flushEnabled) { |
| 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.casResets.incrementAndGet(); |
| svd.clearCasReset(); |
| if (trace) { |
| System.out.println("CAS Reset in thread " + Thread.currentThread().getName() + |
| " for CasId = " + getCasId() + ", new reset count = " + svd.casResets.get()); |
| } |
| |
| int numViews = this.getViewCount(); |
| // Flush indexRepository for all views |
| for (int view = 1; view <= numViews; view++) { |
| CASImpl tcas = (CASImpl) ((view == 1) ? getInitialView() : getView(view)); |
| if (tcas != null) { |
| tcas.indexRepository.flush(); |
| |
| // mySofaRef = -1 is a flag in initial view that sofa has not been set. |
| // For the initial view, it is possible to not have a sofa - it is set |
| // "lazily" upon the first need. |
| // all other views always have a sofa set. The sofaRef is set to 0, |
| // but will be set to the actual sofa addr in the cas when the view is |
| // initialized. |
| |
| tcas.mySofaRef = null; // was in v2: (1 == view) ? -1 : 0; |
| } |
| } |
| this.svd.clearTrackingMarks(); |
| |
| // safety : in case this public method is called on other than the base cas |
| this.getBaseCAS().indexRepository.flush(); // for base view, other views flushed above |
| this.svd.clearSofaInfo(); // but keep initial view, and other views |
| // because setting up the index infrastructure is expensive |
| this.svd.viewCount = 1; // initial view |
| |
| svd.traceFSid = 0; |
| if (traceFSs) svd.traceFScreationSb.setLength(0); |
| this.svd.componentInfo = null; // https://issues.apache.org/jira/browse/UIMA-5097 |
| } |
| |
| /** |
| * @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); |
| } |
| |
| /** |
| * @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 void setWithJournal(FeatureStructureImplC fs, FeatureImpl fi, Runnable setter) { |
| setter.run(); |
| maybeLogUpdate(fs, fi); |
| } |
| |
| public 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 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); |
| } |
| |
| /** |
| * 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 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 boolean isStringType(Type type) { |
| return type instanceof TypeImpl_string; |
| } |
| |
| public boolean isArrayOfFsType(Type type) { |
| return ((TypeImpl) type).isArray(); |
| } |
| |
| public boolean isPrimitiveArrayType(Type type) { |
| return (type instanceof TypeImpl_array) && ! type.getComponentType().isPrimitive(); |
| } |
| |
| public boolean isIntArrayType(Type type) { |
| return (type == getTypeSystemImpl().intArrayType); |
| } |
| |
| public boolean isFloatArrayType(Type type) { |
| return ((TypeImpl)type).getCode() == floatArrayTypeCode; |
| } |
| |
| public boolean isStringArrayType(Type type) { |
| return ((TypeImpl)type).getCode() == stringArrayTypeCode; |
| } |
| |
| public boolean isBooleanArrayType(Type type) { |
| return ((TypeImpl)type).getCode() == booleanArrayTypeCode; |
| } |
| |
| public boolean isByteArrayType(Type type) { |
| return ((TypeImpl)type).getCode() == byteArrayTypeCode; |
| } |
| |
| public boolean isShortArrayType(Type type) { |
| return ((TypeImpl)type).getCode() == byteArrayTypeCode; |
| } |
| |
| public boolean isLongArrayType(Type type) { |
| return ((TypeImpl)type).getCode() == longArrayTypeCode; |
| } |
| |
| public boolean isDoubleArrayType(Type type) { |
| return ((TypeImpl)type).getCode() == doubleArrayTypeCode; |
| } |
| |
| public boolean isFSArrayType(Type type) { |
| return ((TypeImpl)type).getCode() == fsArrayTypeCode; |
| } |
| |
| public boolean isIntType(Type type) { |
| return ((TypeImpl)type).getCode() == intTypeCode; |
| } |
| |
| public boolean isFloatType(Type type) { |
| return ((TypeImpl)type).getCode() == floatTypeCode; |
| } |
| |
| public boolean isByteType(Type type) { |
| return ((TypeImpl)type).getCode() == byteTypeCode; |
| } |
| |
| public boolean isBooleanType(Type type) { |
| return ((TypeImpl)type).getCode() == floatTypeCode; |
| } |
| |
| public boolean isShortType(Type type) { |
| return ((TypeImpl)type).getCode() == shortTypeCode; |
| } |
| |
| public boolean isLongType(Type type) { |
| return ((TypeImpl)type).getCode() == longTypeCode; |
| } |
| |
| public 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 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; |
| } |
| |
| 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; |
| */ |
| } |
| |
| /** |
| * @deprecated |
| */ |
| @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); |
| } |
| |
| private CASImpl getViewFromSofaNbr(int nbr) { |
| final ArrayList<CASImpl> sn2v = this.svd.sofaNbr2ViewMap; |
| if (nbr < sn2v.size()) { |
| return sn2v.get(nbr); |
| } |
| return null; |
| } |
| |
| void setViewForSofaNbr(int nbr, CASImpl view) { |
| Misc.setWithExpand(this.svd.sofaNbr2ViewMap, nbr, view); |
| } |
| |
| // 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(this.svd.baseCAS, (SofaFS) null); |
| setViewForSofaNbr(1, aView); |
| assert (this.svd.viewCount <= 1); |
| this.svd.viewCount = 1; |
| return aView; |
| } |
| |
| @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 > 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 = 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); |
| 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 > 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, |
| Integer.valueOf(domainType.getCode()), |
| domainType.getName(), |
| Integer.valueOf(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, |
| Integer.valueOf(fi.getCode()), |
| feat.getName(), |
| Integer.valueOf(((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, |
| Integer.valueOf(fi.getCode()), |
| fi.getName(), |
| fi.getRange().getName()); |
| } |
| } |
| |
| private final void checkFeature(int featureCode) { |
| if (!getTypeSystemImpl().isFeature(featureCode)) { |
| throw new LowLevelException(LowLevelException.INVALID_FEATURE_CODE, Integer.valueOf(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, Integer.valueOf(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, Integer.valueOf(typeCode)); |
| } |
| } |
| TOP fs = (TOP) createFS(ti); |
| if (!fs._isPearTrampoline()) { |
| if (IS_ALWAYS_HOLD_ONTO_FSS) { |
| svd.id2fs.putUnconditionally(fs); // hold on to it if nothing else is |
| } else { |
| svd.id2fs.put(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); |
| if (IS_ALWAYS_HOLD_ONTO_FSS) { |
| svd.id2fs.putUnconditionally(fs); |
| } else { |
| svd.id2fs.put(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); |
| svd.id2fs.put(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); |
| svd.id2fs.put(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); |
| svd.id2fs.put(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); |
| svd.id2fs.put(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); |
| svd.id2fs.put(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, Integer.valueOf(typeCode), ti.getName()); |
| } |
| if (arrayLength < 0) { |
| throw new LowLevelException(LowLevelException.ILLEGAL_ARRAY_LENGTH, Integer.valueOf(arrayLength)); |
| } |
| } |
| TOP fs = createArray(ti, arrayLength); |
| svd.id2fs.put(fs); |
| return fs._id; |
| } |
| |
| public void validateArraySize(int length) { |
| if (length < 0) { |
| /** Array size must be >= 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); |
| } |
| |
| /** |
| * 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 - |
| */ |
| @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[]{}); |
| } |
| } |
| |
| /** |
| * 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() > 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 |
| */ |
| 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; |
| } |
| |
| /** |
| * 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 |
| */ |
| @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, |
| Integer.valueOf(fsRef), |
| Integer.valueOf(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)); |
| } |
| } |
| |
| /** |
| * 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 |
| */ |
| 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; |
| } |
| |
| // 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) { |
| // lock out CAS functions to which annotator should not have access |
| enableReset(false); |
| svd.switchClassLoader(newClassLoader); |
| } |
| |
| // // internal use, public for cross-package ref |
| // public boolean usingBaseClassLoader() { |
| // return (this.svd.jcasClassLoader == this.svd.previousJCasClassLoader); |
| // } |
| |
| public void restoreClassLoaderUnlockCas() { |
| // unlock CAS functions |
| enableReset(true); |
| // this might be called without the switch ever being called |
| svd.restoreClassLoader(); |
| |
| } |
| |
| @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); |
| svd.id2fs.put(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<T>(); |
| 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 |
| /** |
| * 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 |
| * |
| */ |
| 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 { |
| // not in the index (yet) |
| createDocumentAnnotation(newDoc.length()); |
| } |
| } |
| return; |
| } |
| |
| /** |
| * Generic issue: The returned document annotation could be either an instance of |
| * DocumentAnnotation 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<T> it = this.<T>getAnnotationIndex(getTypeSystemImpl().docType).iterator(); |
| if (it.isValid()) { |
| return it.get(); |
| } |
| return null; |
| } |
| |
| /** |
| * |
| * @return the fs addr of the document annotation found via the index, or 0 if not there |
| */ |
| public int ll_getDocumentAnnotation() { |
| if (this == this.svd.baseCAS) { |
| // base CAS has no document |
| return 0; |
| } |
| |
| FSIterator<FeatureStructure> it = getIndexRepository().getIndex(CAS.STD_ANNOTATION_INDEX, getTypeSystemImpl().docType).iterator(); |
| if (it.isValid()) { |
| return it.get()._id(); |
| } |
| return 0; |
| } |
| |
| @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 == getViewFromSofaNbr(1)) ? CAS.NAME_DEFAULT_SOFA : |
| mySofaIsValid() ? mySofaRef.getSofaID() : |
| null; |
| } |
| |
| private boolean mySofaIsValid() { |
| return this.mySofaRef != null; |
| } |
| |
| void setDocTextFromDeserializtion(String text) { |
| if (mySofaIsValid()) { |
| SofaFS sofa = getSofaRef(); // creates sofa if doesn't already exist |
| sofa.setLocalSofaData(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 |
| */ |
| 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<CAS>(); |
| 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 corruptable 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 indies. |
| */ |
| @Override |
| public AutoCloseable protectIndexes() { |
| FSsTobeAddedback r = FSsTobeAddedback.createMultiple(this); |
| svd.fssTobeAddedback.add(r); |
| return r; |
| } |
| |
| void dropProtectIndexesLevel () { |
| svd.fssTobeAddedback.remove(svd.fssTobeAddedback.size() -1); |
| } |
| |
| /** |
| * 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 |
| * |
| * 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 |
| */ |
| void addbackModifiedFSs (FSsTobeAddedback addbacks) { |
| final List<FSsTobeAddedback> listOfAddbackInfos = svd.fssTobeAddedback; |
| if (listOfAddbackInfos.get(listOfAddbackInfos.size() - 1) == addbacks) { |
| listOfAddbackInfos.remove(listOfAddbackInfos.size()); |
| } else { |
| int pos = listOfAddbackInfos.indexOf(addbacks); |
| if (pos >= 0) { |
| for (int i = listOfAddbackInfos.size() - 1; i > pos; i--) { |
| FSsTobeAddedback toAddBack = listOfAddbackInfos.remove(i); |
| toAddBack.addback(); |
| } |
| } |
| } |
| 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 (!this.svd.flushEnabled) { |
| 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<MarkerImpl>(); |
| } 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 + "]"; |
| } |
| |
| int getCasResets() { |
| return svd.casResets.get(); |
| } |
| |
| int getCasId() { |
| return svd.casId; |
| } |
| |
| final public int getNextFsId(TOP fs) { |
| return svd.getNextFsId(fs); |
| } |
| |
| public void adjustLastFsV2size(int arrayLength) { |
| svd.lastFsV2Size += 1 + arrayLength; // 1 is for array length value |
| } |
| |
| /** |
| * Test case use |
| * @param fss the FSs to include in the id 2 fs map |
| */ |
| public void setId2FSs(FeatureStructure ... fss) { |
| for (FeatureStructure fs : fss) { |
| if (IS_ALWAYS_HOLD_ONTO_FSS) { |
| svd.id2fs.putUnconditionally((TOP)fs); |
| } else { |
| svd.id2fs.put((TOP)fs); |
| } |
| } |
| } |
| |
| // Not currently used |
| // public Int2ObjHashMap<TOP> getId2FSs() { |
| // return svd.id2fs.getId2fs(); |
| // } |
| |
| // final private int getNextFsId() { |
| // return ++ svd.fsIdGenerator; |
| // } |
| |
| final public int getLastUsedFsId() { |
| return svd.fsIdGenerator; |
| } |
| |
| /** |
| * 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).getAllFSsSorted(); |
| List<TOP> filtered = filterAboveMark(all, mark); |
| 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 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); |
| } |
| } |
| |
| public EmptyFSList getEmptyFSList() { |
| if (null == svd.emptyFSList) { |
| svd.emptyFSList = new EmptyFSList(getTypeSystemImpl().fsEListType, this); |
| } |
| return svd.emptyFSList; |
| } |
| |
| public EmptyFloatList getEmptyFloatList() { |
| if (null == svd.emptyFloatList) { |
| svd.emptyFloatList = new EmptyFloatList(getTypeSystemImpl().floatEListType, this); |
| } |
| return svd.emptyFloatList; |
| } |
| |
| public EmptyIntegerList getEmptyIntegerList() { |
| if (null == svd.emptyIntegerList) { |
| svd.emptyIntegerList = new EmptyIntegerList(getTypeSystemImpl().intEListType, this); |
| } |
| return svd.emptyIntegerList; |
| } |
| |
| public EmptyStringList getEmptyStringList() { |
| if (null == svd.emptyStringList) { |
| svd.emptyStringList = new EmptyStringList(getTypeSystemImpl().stringEListType, this); |
| } |
| return svd.emptyStringList; |
| } |
| |
| /** |
| * @param rangeCode special codes for serialization use only |
| * @return the empty list (shared) corresponding to the type |
| */ |
| public EmptyList getEmptyList(int rangeCode) { |
| return (rangeCode == CasSerializerSupport.TYPE_CLASS_INTLIST) ? getEmptyIntegerList() : |
| (rangeCode == CasSerializerSupport.TYPE_CLASS_FLOATLIST) ? getEmptyFloatList() : |
| (rangeCode == CasSerializerSupport.TYPE_CLASS_STRINGLIST) ? getEmptyStringList() : |
| getEmptyFSList(); |
| } |
| |
| /** |
| * Get an empty list from the type code of a list |
| * @param rangeCode - |
| * @return - |
| */ |
| public EmptyList getEmptyListFromTypeCode(int rangeCode) { |
| switch (rangeCode) { |
| case fsListTypeCode: |
| case fsEListTypeCode: |
| case fsNeListTypeCode: return getEmptyFSList(); |
| case floatListTypeCode: |
| case floatEListTypeCode: |
| case floatNeListTypeCode: return getEmptyFloatList(); |
| case intListTypeCode: |
| case intEListTypeCode: |
| case intNeListTypeCode: return getEmptyIntegerList(); |
| case stringListTypeCode: |
| case stringEListTypeCode: |
| case stringNeListTypeCode: return getEmptyStringList(); |
| 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; |
| } |
| |
| /****************************************** |
| * 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 |
| */ |
| 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("%-3d", 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)); |
| } |
| } |
| 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 |
| * Used by Soap |
| * @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); |
| } |
| |
| /** |
| * --------------------------------------------------------------------- |
| * 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 |
| */ |
| |
| public SerialFormat reinit(InputStream istream) throws CASRuntimeException { |
| return svd.bcsd.reinit(istream); |
| } |
| |
| void maybeHoldOntoFS(FeatureStructureImplC fs) { |
| if (IS_ALWAYS_HOLD_ONTO_FSS) { |
| svd.id2fs.putUnconditionally((TOP)fs); |
| } |
| } |
| |
| 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(); |
| } |
| |
| }; |
| } |
| |
| // 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; |
| // } |
| |
| } |