blob: 499bcce937f68c0cec5a8288b90c6c62772e19b4 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.uima.jcas.impl;
// * todo:
// *
// * Compatibility removes at some point: TypeSystemInit and it's caller
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.WeakHashMap;
import org.apache.uima.UIMAFramework;
import org.apache.uima.cas.AbstractCas;
import org.apache.uima.cas.AbstractCas_ImplBase;
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.ConstraintFactory;
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.SofaFS;
import org.apache.uima.cas.SofaID;
import org.apache.uima.cas.Type;
import org.apache.uima.cas.TypeSystem;
import org.apache.uima.cas.impl.CASImpl;
import org.apache.uima.cas.impl.FSClassRegistry;
import org.apache.uima.cas.impl.FSGenerator;
import org.apache.uima.cas.impl.FeatureStructureImpl;
import org.apache.uima.cas.impl.LowLevelCAS;
import org.apache.uima.cas.impl.LowLevelException;
import org.apache.uima.cas.impl.LowLevelIndexRepository;
import org.apache.uima.cas.impl.TypeImpl;
import org.apache.uima.cas.impl.TypeSystemImpl;
import org.apache.uima.cas.text.AnnotationIndex;
import org.apache.uima.internal.util.UIMAClassLoader;
import org.apache.uima.jcas.JCas;
import org.apache.uima.jcas.JCasRegistry;
import org.apache.uima.jcas.JFSIndexRepository;
import org.apache.uima.jcas.cas.AnnotationBase;
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.Sofa;
import org.apache.uima.jcas.cas.StringArray;
import org.apache.uima.jcas.cas.TOP;
import org.apache.uima.jcas.cas.TOP_Type;
import org.apache.uima.jcas.tcas.Annotation;
import org.apache.uima.util.Level;
import org.apache.uima.util.Logger;
// *********************************
// * Implementation of JCas *
// *********************************
/*
*
* Overview --------
*
* This design uses classes for types, not Interfaces. JCas CAS types are represented in a running
* server by a collection of classes A set of 2 classes for each loaded equivalent-to-CAS type Foo
* (Class) Foo_Type (Class)
*
* JCas and Foo_Type style classes have one instantiation per CAS View
*
* Integrated with Framework Design -------------------------------- Assume: Framework collects for
* each CAS creation all the types that will be defined for this CAS. Note: can create multiple
* instances of CASs (and JCases) each TAE/App.
*
* Assume: Each JCas instance (associated with a CAS) is single-threaded. if not - must synchronize
* refs to tables/arrays associated with this
*
* Assume: Each CAS instance only has one associated set of types, specified by a String[] of
* fully-qual-type-names Implication: if CAS type system changes, create new JCas instance. This
* allows many things to be "final".
*
* Integrate with UIMA Framework Resource Manager for use of class loaders.
*
* Framework will call getJCas once after the CAS types are completely specified, or when a
* deserialization has re-initialized a CAS.
*
* Initialize: To get to the type object from Foo, use jcas.getType(Foo.type) To get to the JCas
* type object from instance of Foo, use this.jcasType.
*
* If the CAS has its contents reset, call jcas.clearData() to reset the corresponding JCas content.
*
* Implementation Notes: At loadtime, Foo and Foo_Type classes are assigned static integer indexes,
* using the JCasRegistry. These indexes are used in arrays in the jcas instance to go from Foo
* class (not instances) to Foo_Type instances (one per CAS). Things which require "types" at
* runtime reference the Foo_Type instances.
*
* Maps: Note: per CAS means per shared JCas instance assoc w/ CAS
*
* (universal) (static field in class) go from Foo class to index unique ID used with next map to
* locate Foo_Type instance associated with this class If universal - becomes an index for all
* FooStyle classes loaded (per CAS)
*
* (ArrayList) map index from Foo (static) to Foo_Type instance used in creating new instances.
* Needs to be one per CAS because a particular "xyz" feature in CAS1 != "xyz" feature in CAS2 If
* above universal, then can become large array with mostly unused slots. Possibility: reuse
* no-longer-used slots. Identify no-longer-used slots at CAS Type unload event?
*/
/**
* implements the supporting infrastructure for JCas model linked with a Cas. There is one logical
* instance of this instantiated per Cas or CasView. If you hold a reference to a CAS, to get a
* reference to the corresponding JCas, use the method getJCas(). Likewise, if you hold a reference
* to this object, you can get a reference to the corresponding CAS object using the method
* getCas().
* <p>
* There are variables here that hold references to constant, frequently needed Cas values, such as
* 0-length FSArrays, 0-length Strings, etc. These can be used to improve efficiency, since the same
* object can be shared and used for all instances because it is unchangeable. These objects are
* reset when the CAS is reset, and are initialized lazily, on first use.
*/
public class JCasImpl extends AbstractCas_ImplBase implements AbstractCas, JCas {
// * FSIndexRepository - the get method returns the java type *
// * so FSIndexRepository can't be in the implements clause *
// constant used in the following function
/** internal use - constant used in getting constructors */
final static private Class<?>[] jcasBaseAndType = new Class[] { JCas.class, Type.class };
final static private Class<?>[] intAnd_Type = new Class[] { int.class, TOP_Type.class };
private static class LoadedJCasType<T extends TOP> {
final String typeName;
final int index;
final boolean isSubtypeOfAnnotationBase;
final Constructor<? extends TOP_Type> constructorFor_Type;
final Constructor<T> constructorForType;
LoadedJCasType(String typeName, Class<? extends TOP_Type> a_TypeClass, ClassLoader cl) {
Class<? extends TOP_Type> _TypeClass = a_TypeClass;
this.typeName = typeName;
int tempindex = 0;
boolean tempisSubtypeOfAnnotationBase = false;
Constructor<? extends TOP_Type> tempconstructorFor_Type = null;
Constructor<T> tempconstructorForType = null;
String name = _TypeClass.getName();
try {
@SuppressWarnings("unchecked")
Class<T> typeClass = (Class<T>) Class.forName(name.substring(0, name.length() - 5), true, cl); // drop
// _Type
Field typeIndexField = null;
try {
typeIndexField = _TypeClass.getDeclaredField("typeIndexID");
} catch (NoSuchFieldException e) {
try {
// old version has the index in the base type
typeIndexField = typeClass.getDeclaredField("typeIndexID");
} catch (NoSuchFieldException e2) {
logAndThrow(e2);
}
}
tempindex = typeIndexField.getInt(null); // null - static instance var
tempconstructorFor_Type = _TypeClass.getDeclaredConstructor(jcasBaseAndType);
tempconstructorForType = typeClass.getDeclaredConstructor(intAnd_Type);
tempisSubtypeOfAnnotationBase = AnnotationBase.class.isAssignableFrom(typeClass);
} catch (SecurityException e) {
logAndThrow(e);
} catch (NoSuchMethodException e) {
logAndThrow(e);
} catch (ClassNotFoundException e) {
logAndThrow(e);
} catch (IllegalArgumentException e) {
logAndThrow(e);
} catch (IllegalAccessException e) {
logAndThrow(e);
} finally {
index = tempindex;
constructorFor_Type = tempconstructorFor_Type;
constructorForType = tempconstructorForType;
isSubtypeOfAnnotationBase = tempisSubtypeOfAnnotationBase;
}
}
private void logAndThrow(Exception e) {
CASRuntimeException casEx = new CASRuntimeException(CASRuntimeException.JCAS_CAS_MISMATCH);
casEx.initCause(e);
throw casEx;
}
}
static public class ErrorReport {
final Exception e;
final boolean doThrow;
ErrorReport(Exception e, boolean doThrow) {
this.e = e;
this.doThrow = doThrow;
}
}
// *************************************************
// * Static Data shared with all instances of JCas *
// *************************************************
private final static int INITIAL_HASHMAP_SIZE = 256;
// key = typeSystemImpl instance, value = Maps:
// key = class loader instance, value = Maps:
// key = string = fully qualified java type names of _Type classes,
// value = instances of LoadedJCasType:
// fully-qualified-name-of-CAS-type
// the _Type class for this (specific to class loader)
// the class loader instance
// Note: cannot use treemap here because keys (class loaders) are not comparable (have no sort
// order)
// To use: first look up with key = typeSystemImpl instance (uses object identity ("==") test)
// Then use value and look up using class loader (uses object identity ("==") test)
// The first two maps (with keys typeSystemImpl and classLoader) are
// Weak maps so that they don't hold onto their keys (class loader or type system) if
// these are no longer in use
//
// This is a static map - effectively indexed by all loaded type systems and all classloaders
// Access to this must be synch'd
private static Map<TypeSystemImpl, Map<ClassLoader, Map<String, LoadedJCasType<?>>>> typeSystemToLoadedJCasTypesByClassLoader =
new WeakHashMap<TypeSystemImpl, Map<ClassLoader, Map<String, LoadedJCasType<?>>>>(4);
// **********************************************
// * Data shared among views of a single CAS *
// * We keep one copy per view set *
// **********************************************/
private static class JCasSharedView {
// ********************************************************
// * Data shared among all views in a (J)CAS View group *
// * Access to this data is assumed to be single threaded *
// ********************************************************
/**
* key = CAS addr, value = corresponding Java instance.
*
* The Java instance may be a JCas cover object, or a non-JCas Java cover object of type FeatureStructureImplC
*
*This impl was changed in May 2007 to a
* design of one cover object per CAS object, when dealing with multiple views. This implements
* better semantics for co-located components sharing these objects - they all get to share the
* same object, independent of which view(s) the object may be indexed in. For cases where the
* user has augmented the definition of the JCas object to have native Java fields, this design
* is closer to the user's expectation.
*
* The only use for multiple objects, previously, was to implement the 0-argument version of
* addToIndexes and removeFromIndexes. The new implementation will come close (but not be
* perfectly the same) as the old implementation, by doing the following:
*
* Changing the "new" and get/next from iterator methods to set the _Type field of the retrieved
* cover class object (or new object) to the correct view.
*
* Deref objects follow many paths. They all have a default view they create the object with
* respect to. A simple deref uses the same cas ref the original object had.
*
*/
private JCasHashMap cAddr2Jfs;
private final Map<ClassLoader, JCasHashMap> cAddr2JfsByClassLoader = new IdentityHashMap<ClassLoader, JCasHashMap>();
/* convenience holders of CAS constants that may be useful */
/* initialization done lazily - on first call to getter */
public StringArray stringArray0L = null;
public IntegerArray integerArray0L = null;
public FloatArray floatArray0L = null;
public FSArray fsArray0L = null;
// * collection of errors that occur during initialization
public Collection<ErrorReport> errorSet = new ArrayList<ErrorReport>();
public ClassLoader currentClassLoader = null;
private ClassLoader cacheClassLoaderInitialized;
final private Map<ClassLoader, Boolean> isInitializedForClassLoader = Collections.synchronizedMap(new IdentityHashMap<ClassLoader, Boolean>());
private JCasSharedView(CASImpl aCAS, boolean useJcasCache) {
setupJCasHashMap(aCAS.getJCasClassLoader(), useJcasCache, aCAS.getHeap().getInitialSize() / 16);
}
private void setupJCasHashMap(ClassLoader cl, boolean isUsedCache, int initialSize) {
int size = Math.max(INITIAL_HASHMAP_SIZE, initialSize);
cAddr2Jfs = new JCasHashMap(size, isUsedCache);
cAddr2JfsByClassLoader.put(cl, cAddr2Jfs);
currentClassLoader = cl;
}
}
// *******************
// * Data per (J)CAS *
// * There may be multiples of these for one base CAS - one per "view"
// * Access to this data is assumed to be single threaded
// *******************
private final JCasSharedView sharedView;
// not public to protect it from accidents
private final CASImpl casImpl;
private final LowLevelIndexRepository ll_IndexRepository;
private final JFSIndexRepository jfsIndexRepository;
private final boolean isUsedCache;
/*
* typeArray is one per CAS because it holds pointers to instances of _Type objects, per CAS.
* It is not in the shared view, because the typeArray points to instances that go with the view.
* This is used when making instances - it allows each instance to be associated with a view,
* for purposes of making addtoIndexes() and removeFromIndexes() work.
* It is not final, because it may need to be "extended" if
* alternate versions of types are loaded from different class loaders, at some point in the
* execution. The alternate versions are given their own slots in this array.
*/
private TOP_Type[] typeArray = new TOP_Type[0]; // contents are subtypes of TOP_Type
// *********************************
// * Getters for read-only objects *
// *********************************
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getFSIndexRepository()
*/
public FSIndexRepository getFSIndexRepository() {
return casImpl.getIndexRepository();
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getLowLevelIndexRepository()
*/
public LowLevelIndexRepository getLowLevelIndexRepository() {
return ll_IndexRepository;
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getCas()
*/
public CAS getCas() {
return casImpl;
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getCasImpl()
*/
public CASImpl getCasImpl() {
return casImpl;
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getLowLevelCas()
*/
public LowLevelCAS getLowLevelCas() {
return casImpl;
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getTypeSystem()
*/
public TypeSystem getTypeSystem() {
return casImpl.getTypeSystem();
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getType(int)
*/
public TOP_Type getType(final int i) {
if (i >= typeArray.length || null == typeArray[i]) {
getTypeInit(i);
}
return typeArray[i];
}
/**
* Map from type codes to _Type instances kept per view in the field typeArray
* @param i
*/
private void getTypeInit(final int i) {
// unknown ID. This may be due to a need to update the typeArray
// due to switching class loaders. This updating is done
// partially lazily - when needed, beyond the particular CAS instance and
// view that was being passed to a process method when the
// class loader switch was done.
// In order for this to work, all access to the typeArray must be
// via this getter.
// Try instantiating the entries in typeArray for this class loader
instantiateJCas_Types(this.sharedView.currentClassLoader);
if (i >= typeArray.length || null == typeArray[i]) {
// unknown ID. Attempt to get offending class.
Class<? extends TOP> cls = JCasRegistry.getClassForIndex(i);
if (cls != null) {
String typeName = cls.getName();
// is type in type system
if (this.casImpl.getTypeSystem().getType(typeName) == null) {
// no - report error that JCAS type was not defined in XML
// descriptor
CASRuntimeException casEx = new CASRuntimeException(
CASRuntimeException.JCAS_TYPE_NOT_IN_CAS, new String[] { typeName });
throw casEx;
} else {
// yes - there was some problem loading the _Type object
CASRuntimeException casEx = new CASRuntimeException(
CASRuntimeException.JCAS_MISSING_COVERCLASS, new String[] { typeName + "_Type" });
throw casEx;
}
} else {
throw new CASRuntimeException(CASRuntimeException.JCAS_UNKNOWN_TYPE_NOT_IN_CAS);
}
}
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getCasType(int)
*/
public Type getCasType(int i) {
return getType(i).casType;
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getType(org.apache.uima.jcas.cas.TOP)
*/
public TOP_Type getType(TOP instance) {
return getType(instance.getTypeIndexID());
}
/** throws (an unchecked) CASRuntimeException */
private void logAndThrow(Exception e) {
CASRuntimeException casEx = new CASRuntimeException(CASRuntimeException.JCAS_CAS_MISMATCH);
casEx.initCause(e);
throw casEx;
}
// never called, but have to set values to null because they're final
private JCasImpl() {
sharedView = null;
casImpl = null;
ll_IndexRepository = null;
isUsedCache = false;
throw new RuntimeException("JCas constructor with no args called, should never be called.");
}
/*
* Private constructor, called when new instance (either for new cas, or for old cas but new
* Annotator/Application class, needed
*
* Called by JCas.getJCas(cas)
*
* The CAS must be initialized when this is called.
*
*/
private JCasImpl(CASImpl cas) throws CASException {
// * A new instance of JCas exists for each CAS
// * At this point, some but not necessarily all of the Types have been
// loaded
// * the typeArray needs to be big enough to hold all the types
// * that will be loaded.
this.casImpl = cas;
this.isUsedCache = cas.doUseJcasCache();
if (casImpl != casImpl.getBaseCAS()) {
sharedView = ((JCasImpl) casImpl.getBaseCAS().getJCas()).sharedView;
sharedView.errorSet.clear();
} else {
sharedView = new JCasSharedView(cas, this.isUsedCache);
}
this.ll_IndexRepository = casImpl.ll_getIndexRepository();
this.jfsIndexRepository = new JFSIndexRepositoryImpl(this, cas.getIndexRepository());
// * acquire the lock for this thread that is the same lock
// * used in the getNextIndexIncr operation. This will block
// * any other (meaning on another thread)
// * loading of the JCas Type classes until this thread's loading
// * completes.
synchronized (JCasImpl.class) {
ClassLoader cl = cas.getJCasClassLoader();
instantiateJCas_Types(cl);
} // end of synchronized block
}
/**
* This is only called when the JCas is already set up
*
* @param cl
* class loader to switch to
*/
public void switchClassLoader(ClassLoader cl) {
// first try a fast switch - works if we've switched before to this class loader
if (!casImpl.getFSClassRegistry().swapInGeneratorsForClassLoader(cl, casImpl)) {
instantiateJCas_Types(cl);
}
final JCasSharedView sv = this.sharedView;
sv.cAddr2Jfs = sv.cAddr2JfsByClassLoader.get(cl);
if (null == sv.cAddr2Jfs) {
// initial size low because this is the use case where a Pear isolation is happening,
// it is more likely that the PEAR is only doing a subset of the JCas things
sv.setupJCasHashMap(cl, isUsedCache, casImpl.getHeap().getInitialSize() / 1024);
} else {
sv.currentClassLoader = cl;
}
}
/**
* There may be several type systems with different defined types loaded and operating at the same
* time (in different CASes) There is an instance of the loaded JCas Classes for each Type System
* for each class loader.
*
* @param cl
* @return a Map from the string of the fully qualified type name to LoadedJCasType instances
*/
@SuppressWarnings("unchecked")
private synchronized Map<String, LoadedJCasType<?>> loadJCasClasses(ClassLoader cl) {
final TypeSystem ts = casImpl.getTypeSystem();
Iterator<Type> typeIt = ts.getTypeIterator();
TypeImpl t;
String casName;
Map<String, LoadedJCasType<?>> jcasTypes = new HashMap<>();
// * note that many of these may have already been loaded
// * load all the others. Actually, we ask to load all the types
// * and the ones already loaded - we just get their loaded versions
// returned.
// * Loading will run the static init functions.
while (typeIt.hasNext()) {
t = (TypeImpl) typeIt.next();
casName = t.getName();
String name_Type;
if (builtInsWithNoJCas.contains(casName))
continue;
if (builtInsWithAltNames.contains(casName))
// * convert uima.cas.Xxx -> org.apache.uima.jcas.cas.Xxx
// * convert uima.tcas.Annotator -> org.apache.uima.jcas.tcas.Annotator
try {
String nameBase = "org.apache.uima.jcas." + casName.substring(5);
name_Type = nameBase + "_Type";
jcasTypes.put(nameBase, new LoadedJCasType<>(t.getName(), (Class<? extends TOP_Type>) Class
.forName(name_Type, true, cl), cl));
} catch (ClassNotFoundException e1) {
// OK for DocumentAnnotation, which may not have a cover class.
// Otherwise, not OK.
if (!CAS.TYPE_NAME_DOCUMENT_ANNOTATION.equals(casName)) {
assert false : "never get here because built-ins have java cover types";
e1.printStackTrace();
}
}
// this is done unconditionally to pick up old style cover functions if
// any
// as well as other JCas model types
try {
name_Type = casName + "_Type";
jcasTypes.put(casName, new LoadedJCasType<>(t.getName(), (Class<? extends TOP_Type>) Class.forName(name_Type, true, cl),
cl));
// also force the load the plain name without _Type for
// old-style - that's where
// the index is incremented
Class.forName(casName, true, cl);
} catch (ClassNotFoundException e1) {
// many classes may not have JCas models, so this is not an
// error
}
}
// note: this entire method is synchronized
Map<ClassLoader, Map<String, LoadedJCasType<?>>> classLoaderToLoadedJCasTypes = typeSystemToLoadedJCasTypesByClassLoader.get(casImpl
.getTypeSystemImpl());
if (null == classLoaderToLoadedJCasTypes) {
classLoaderToLoadedJCasTypes = new WeakHashMap<ClassLoader, Map<String, LoadedJCasType<?>>>(4);
typeSystemToLoadedJCasTypesByClassLoader.put(casImpl.getTypeSystemImpl(),
classLoaderToLoadedJCasTypes);
}
classLoaderToLoadedJCasTypes.put(cl, jcasTypes);
expandTypeArrayIfNeeded();
return jcasTypes;
}
// note: callers are not synchronized because the typeArray has a
// separate instance per CAS (actually per CAS view)
private void expandTypeArrayIfNeeded() {
if (typeArray.length < JCasRegistry.getNumberOfRegisteredClasses()) {
TOP_Type[] newTypeArray = new TOP_Type[JCasRegistry.getNumberOfRegisteredClasses()];
System.arraycopy(typeArray, 0, newTypeArray, 0, typeArray.length);
typeArray = newTypeArray;
}
}
/**
* called when switching to JCas and the JCas already exists to check if
* the JCas needs to have classes loaded for this class loader. This can happen when the JCas is first
* instantiated while under the scope of a nested UIMA class loader. This could be a Pear class loader, or
* even just an ordinary UIMA Class loader for a pipeline, where the Framework is running an "exit routine" supplied
* by the user, but loaded in a (for example) initial application loader context.
* @param cl the class loader in use
*/
public void maybeInitializeForClassLoader(ClassLoader cl) {
if (sharedView.cacheClassLoaderInitialized == cl) {
return;
}
if (this.sharedView.isInitializedForClassLoader.get(cl) == null) {
instantiateJCas_Types(cl);
}
sharedView.cacheClassLoaderInitialized = cl;
}
/**
*
* @param cl the class loader to use as the initiating loader for loading JCas classes
*/
public void instantiateJCas_Types(ClassLoader cl) {
Map<String, LoadedJCasType<?>> loadedJCasTypes = null;
FSClassRegistry fscr = casImpl.getFSClassRegistry();
boolean alreadyLoaded; // means the "classes" have been loaded, but doesn't mean
// the _Type instances of those classes have been created.
boolean anyNewInstances = false; // true if any new instances of _Type are generated
FSGenerator<?>[] newFSGeneratorSet;
synchronized (JCasImpl.class) {
Map<ClassLoader, Map<String, LoadedJCasType<?>>> classLoaderToLoadedJCasTypes = typeSystemToLoadedJCasTypesByClassLoader.get(casImpl
.getTypeSystemImpl());
if (null != classLoaderToLoadedJCasTypes) {
loadedJCasTypes = classLoaderToLoadedJCasTypes.get(cl);
}
alreadyLoaded = (null != loadedJCasTypes);
if (!alreadyLoaded) {
loadedJCasTypes = loadJCasClasses(cl);
}
expandTypeArrayIfNeeded();
// if already loaded, can skip making new generators -
// in this case newFSGeneratorSet is never referenced
// Set it to null for "safety"
// If not already loaded, initialize the generators to a clone of the FSClassRegistry generators.
newFSGeneratorSet = (alreadyLoaded ? null : fscr.getNewFSGeneratorSet());
for (Iterator<Map.Entry<String, LoadedJCasType<?>>> it = loadedJCasTypes.entrySet().iterator(); it.hasNext();) {
// Explanation for this logic:
// Instances of _Types are kept per class loader, per Cas (e.g., in the cas pool)
// and per view (to support having the ref to the casImpl be to the right view
// so add-to-indexes works better).
// The "typeArray" field is per view.
// When switching class loaders (e.g. a pear in the pipeline), some of the
// _Type instances (e.g. the built-ins) might be already instantiated, but others are not
//
boolean madeNewInstance = makeInstanceOf_Type(it.next().getValue(), alreadyLoaded,
newFSGeneratorSet);
anyNewInstances = madeNewInstance || anyNewInstances;
}
// speed up - skip rest if nothing to do
if (!anyNewInstances &&
sharedView.isInitializedForClassLoader.get(cl) != null) { // don't skip if need to install the new generators for this class loader UIMA-5055
return;
}
if (!alreadyLoaded) {
copyDownSuperGenerators(loadedJCasTypes, newFSGeneratorSet);
if (casImpl.usingBaseClassLoader()) {
fscr.setBaseGenerators(newFSGeneratorSet); // should be under sync lock
}
fscr.saveGeneratorsForClassLoader(cl, newFSGeneratorSet);
}
}
if (alreadyLoaded) {
fscr.swapInGeneratorsForClassLoader(cl, casImpl);
} else {
casImpl.setLocalFsGenerators(newFSGeneratorSet);
}
sharedView.isInitializedForClassLoader.put(cl, Boolean.TRUE);
}
// note all callers are synchronized
private void copyDownSuperGenerators(Map<String, LoadedJCasType<?>> jcasTypes, FSGenerator<?>[] fsGenerators) {
final TypeSystem ts = casImpl.getTypeSystem();
Iterator<Type> typeIt = ts.getTypeIterator(); // reset iterator to start
Type topType = ts.getTopType();
Type superType = null;
while (typeIt.hasNext()) {
Type t = typeIt.next();
if (builtInsWithNoJCas.contains(t.getName()))
continue;
// comment here
if (CAS.TYPE_NAME_DOCUMENT_ANNOTATION.equals(t.getName())) {
if (jcasTypes.get("org.apache.uima.jcas.tcas.DocumentAnnotation") != null)
continue;
} else if (builtInsWithAltNames.contains(t.getName()))
continue; // because jcasTypes has no entry for these
if (null != jcasTypes.get(t.getName()))
continue;
// we believe that at this point, t is not "top", because top is
// always loaded
// find closest supertype that has a loaded cover class
superType = t;
String superTypeName;
do {
superType = ts.getParent(superType);
superTypeName = superType.getName();
if (builtInsWithAltNames.contains(superTypeName)) {
superTypeName = "org.apache.uima.jcas." + superTypeName.substring(5);
}
} while ((null == jcasTypes.get(superTypeName) && !superType.equals(topType)));
// copy down its generator
fsGenerators[((TypeImpl) t).getCode()] = fsGenerators[((TypeImpl) superType).getCode()];
}
}
/**
* creates a new JCas instance that corresponds to a CAS instance. Will be called once by the UIMA
* framework when it creates the CAS.
*
* @param cas
* a CAS instance
* @return newly created and initialized JCas
* @throws CASException -
*/
public static JCas getJCas(CASImpl cas) throws CASException {
JCasImpl jcas = new JCasImpl(cas);
reportInitErrors(jcas);
return jcas;
}
private static void reportInitErrors(JCasImpl jcas) throws CASException {
JCasSharedView sv = jcas.sharedView;
if (sv.errorSet.size() > 0) {
boolean doThrow = false;
StringBuffer msg = new StringBuffer(100);
msg.append('\n');
for (ErrorReport f : sv.errorSet) {
msg.append(f.e.getMessage());
msg.append('\n');
doThrow = doThrow || f.doThrow;
}
if (doThrow) {
CASException e = new CASException(CASException.JCAS_INIT_ERROR,
new String[] { msg.toString() });
throw e;
} else {
Logger logger = UIMAFramework.getLogger();
if (null == logger) {
throw new CASRuntimeException(CASException.JCAS_INIT_ERROR, new String[] {msg.toString()});
} else {
logger.log(Level.WARNING, msg.toString());
}
}
}
}
/**
* built-in types which have alternate names It really isn't necessary to skip these - they're
* never instantiated. But it is a very slight performance boost, and it may be safer given
* possible future changes to these types' implementations.
*/
private static final Collection<String> builtInsWithNoJCas = new ArrayList<String>();
static {
builtInsWithNoJCas.add(CAS.TYPE_NAME_BOOLEAN);
builtInsWithNoJCas.add(CAS.TYPE_NAME_BYTE);
builtInsWithNoJCas.add(CAS.TYPE_NAME_SHORT);
builtInsWithNoJCas.add(CAS.TYPE_NAME_INTEGER);
builtInsWithNoJCas.add(CAS.TYPE_NAME_LONG);
builtInsWithNoJCas.add(CAS.TYPE_NAME_FLOAT);
builtInsWithNoJCas.add(CAS.TYPE_NAME_DOUBLE);
builtInsWithNoJCas.add(CAS.TYPE_NAME_STRING);
builtInsWithNoJCas.add(CAS.TYPE_NAME_ARRAY_BASE);
builtInsWithNoJCas.add(CAS.TYPE_NAME_LIST_BASE);
}
private static final Collection<String> builtInsWithAltNames = new ArrayList<String>();
static { // initialization code
builtInsWithAltNames.add(CAS.TYPE_NAME_TOP);
builtInsWithAltNames.add(CAS.TYPE_NAME_STRING_ARRAY);
builtInsWithAltNames.add(CAS.TYPE_NAME_BOOLEAN_ARRAY);
builtInsWithAltNames.add(CAS.TYPE_NAME_BYTE_ARRAY);
builtInsWithAltNames.add(CAS.TYPE_NAME_SHORT_ARRAY);
builtInsWithAltNames.add(CAS.TYPE_NAME_INTEGER_ARRAY);
builtInsWithAltNames.add(CAS.TYPE_NAME_LONG_ARRAY);
builtInsWithAltNames.add(CAS.TYPE_NAME_FS_ARRAY);
builtInsWithAltNames.add(CAS.TYPE_NAME_FLOAT_ARRAY);
builtInsWithAltNames.add(CAS.TYPE_NAME_DOUBLE_ARRAY);
builtInsWithAltNames.add(CAS.TYPE_NAME_EMPTY_FLOAT_LIST);
builtInsWithAltNames.add(CAS.TYPE_NAME_EMPTY_FS_LIST);
builtInsWithAltNames.add(CAS.TYPE_NAME_EMPTY_INTEGER_LIST);
builtInsWithAltNames.add(CAS.TYPE_NAME_EMPTY_STRING_LIST);
builtInsWithAltNames.add(CAS.TYPE_NAME_FLOAT_LIST);
builtInsWithAltNames.add(CAS.TYPE_NAME_FS_LIST);
builtInsWithAltNames.add(CAS.TYPE_NAME_INTEGER_LIST);
builtInsWithAltNames.add(CAS.TYPE_NAME_STRING_LIST);
builtInsWithAltNames.add(CAS.TYPE_NAME_NON_EMPTY_FLOAT_LIST);
builtInsWithAltNames.add(CAS.TYPE_NAME_NON_EMPTY_FS_LIST);
builtInsWithAltNames.add(CAS.TYPE_NAME_NON_EMPTY_INTEGER_LIST);
builtInsWithAltNames.add(CAS.TYPE_NAME_NON_EMPTY_STRING_LIST);
builtInsWithAltNames.add(CAS.TYPE_NAME_SOFA);
builtInsWithAltNames.add(CAS.TYPE_NAME_ANNOTATION_BASE);
builtInsWithAltNames.add(CAS.TYPE_NAME_ANNOTATION);
builtInsWithAltNames.add(CAS.TYPE_NAME_DOCUMENT_ANNOTATION);
}
// This generator class is used in place of the generator that is in each of the
// older JCasGen'd classes
// It makes use of the passed-in CAS view so one generator works for all Cas Views.
// It references the xxx_Type instance using the getType call, which will
// (lazily) instantiate the xxx_Type object if needed (due to switching class loaders:
// see comment under getType(int))
static private class JCasFsGenerator<T extends TOP> implements FSGenerator<T> {
// multiple reader threads in same CAS
static final ThreadLocal<Object[]> initArgsThreadLocal = new ThreadLocal<Object[]>() {
protected Object[] initialValue() { return new Object[2]; } };
private final int type;
private final Constructor<T> c;
private final boolean isSubtypeOfAnnotationBase;
private final int sofaNbrFeatCode;
private final int annotSofaFeatCode;
JCasFsGenerator(int type, Constructor<T> c, boolean isSubtypeOfAnnotationBase,
int sofaNbrFeatCode, int annotSofaFeatCode) {
this.type = type;
this.c = c;
this.isSubtypeOfAnnotationBase = isSubtypeOfAnnotationBase;
this.sofaNbrFeatCode = sofaNbrFeatCode;
this.annotSofaFeatCode = annotSofaFeatCode;
}
/*
* Called from the CAS's this.svd.localFsGenerators
*
* Those are set up with either JCas style generators, or the
* the shared common instances of FeatureStructureImplC for non-JCas classes.
*
*/
// Called in 3 cases
// 1) a non-JCas call to create a new JCas style FS
// 2) a dereference of an existing FS
// 3) an iterator
public T createFS(int addr, CASImpl casView) {
try {
JCasImpl jcasView = (JCasImpl) casView.getJCas();
T fs = jcasView.<T>getJfsFromCaddr(addr);
if (null != fs) {
fs.jcasType = jcasView.getType(type);
return fs;
}
return doCreateFS(addr, casView);
} catch (CASException e1) {
logAndThrow(e1, null);
return null; // to avoid compile warning
}
}
private T doCreateFS(int addr, CASImpl casView) {
// this funny logic is because although the annotationView should always be set if
// a type is a subtype of annotation, it isn't always set if an application uses low-level
// api's. Rather than blow up, we limp along.
CASImpl maybeAnnotationView = null;
if (isSubtypeOfAnnotationBase) {
final int sofaNbr = getSofaNbr(addr, casView);
if (sofaNbr > 0) {
maybeAnnotationView = (CASImpl) casView.getView(sofaNbr);
}
}
final CASImpl view = (null != maybeAnnotationView) ? maybeAnnotationView : casView;
try {
JCasImpl jcasView = (JCasImpl) view.getJCas();
final Object[] initargs = initArgsThreadLocal.get();
initargs[0] = Integer.valueOf(addr);
initargs[1] = jcasView.getType(type);
T fs = null;
try {
fs = (T) c.newInstance(initargs);
} catch (IllegalArgumentException e) {
logAndThrow(e, jcasView);
} catch (InstantiationException e) {
logAndThrow(e, jcasView);
} catch (IllegalAccessException e) {
logAndThrow(e, jcasView);
} catch (InvocationTargetException e) {
logAndThrow(e, jcasView);
}
jcasView.putJfsFromCaddr(addr, fs);
return fs;
} catch (CASException e1) {
logAndThrow(e1, null);
return null;
}
}
private void logAndThrow(Exception e, JCasImpl jcasView) {
CASRuntimeException casEx = new CASRuntimeException(
CASRuntimeException.JCAS_CAS_MISMATCH,
new String[] { (null == jcasView) ? "-- ignore outer msg, error is can''t get value of jcas from cas"
: (jcasView.getType(type).casType.getName() + "; exception= "
+ e.getClass().getName() + "; msg= " + e.getLocalizedMessage()) });
casEx.initCause(e);
throw casEx;
}
private int getSofaNbr(final int addr, final CASImpl casView) {
final int sofa = casView.ll_getIntValue(addr, annotSofaFeatCode, false);
return (sofa == 0) ? 0 : casView.ll_getIntValue(sofa, sofaNbrFeatCode);
}
}
// per JCas instance - so don't need to synch.
private final Object[] constructorArgsFor_Type = new Object[2];
/**
* Make the instance of the JCas xxx_Type class for this CAS. Note: not all types will have
* xxx_Type. Instance creation does the typeSystemInit kind of function, as well.
*
* @param jcasTypeInfo -
* @param alreadyLoaded -
* @param fsGenerators updated by side effect with new instances of the _Type class
* @return true if a new instance of a _Type class was created
*/
private <T extends TOP> boolean makeInstanceOf_Type(LoadedJCasType<T> jcasTypeInfo, boolean alreadyLoaded,
FSGenerator<?>[] fsGenerators) {
// return without doing anything if the _Type instance is already existing
// this happens when a JCas has some _Type instances made (e.g, the
// built-in ones) but the class loader was switched. Some of the
// _Type instances for the new class loader can share previously
// instantiated _Type instances, but others may be different
// (due to different impls of the _Type class loaded by the different
// class loader).
// This can also happen in the case where JCasImpl.getType is called for a non-existing class.
// What happens in this case is that the getType code has to assume that
// perhaps none of the _Type instances were made for this JCas (yet), because
// these are created lazily - so it calls instantiateJCas_Types to make them.
// If they were already made, this next test short circuits this.
int typeIndex = jcasTypeInfo.index;
if (typeArray[typeIndex] != null) {
return false;
}
Constructor<?> c_Type = jcasTypeInfo.constructorFor_Type;
Constructor<T> cType = jcasTypeInfo.constructorForType;
TypeImpl casType = (TypeImpl) casImpl.getTypeSystem().getType(jcasTypeInfo.typeName);
try {
constructorArgsFor_Type[0] = this;
constructorArgsFor_Type[1] = casType;
TOP_Type x_Type_instance = (TOP_Type) c_Type.newInstance(constructorArgsFor_Type);
typeArray[typeIndex] = x_Type_instance;
// install the standard generator
// this is sharable by all views, since the CAS is passed to the generator
// Also sharable by all in a CasPool, except for "swapping" due to PEARs/Classloaders.
if (!alreadyLoaded) {
final TypeSystemImpl ts = casImpl.getTypeSystemImpl();
fsGenerators[casType.getCode()] = new JCasFsGenerator<T>(typeIndex, cType,
jcasTypeInfo.isSubtypeOfAnnotationBase, TypeSystemImpl.sofaNumFeatCode, TypeSystemImpl.annotSofaFeatCode);
// this.casImpl.getFSClassRegistry().loadJCasGeneratorForType(typeIndex, cType, casType,
// jcasTypeInfo.isSubtypeOfAnnotationBase);
}
} catch (SecurityException e) {
logAndThrow(e);
} catch (InstantiationException e) {
logAndThrow(e);
} catch (IllegalAccessException e) {
logAndThrow(e);
} catch (InvocationTargetException e) {
logAndThrow(e);
} catch (ArrayIndexOutOfBoundsException e) {
logAndThrow(e);
}
return true;
}
/**
* Make the instance of the JCas xxx_Type class for this CAS. Note: not all types will have
* xxx_Type. Instance creation does the typeSystemInit kind of function, as well.
*/
/*
* private void makeInstanceOf_Type(Type casType, Class clas, CASImpl cas) { Constructor c; Field
* typeIndexField = null; int typeIndex; try { c = clas.getDeclaredConstructor(jcasBaseAndType);
* try {
*
* typeIndexField = clas.getDeclaredField("typeIndexID"); } catch (NoSuchFieldException e) { try { //
* old version has the index in the base type String name = clas.getName(); Class clas2 =
* Class.forName(name.substring(0, name.length() - 5), true, cas .getJCasClassLoader()); // drop
* _Type typeIndexField = clas2.getDeclaredField("typeIndexID"); } catch (NoSuchFieldException e2) {
* logAndThrow(e2); } catch (ClassNotFoundException e3) { logAndThrow(e3); } } typeIndex =
* typeIndexField.getInt(null); // null - static instance var TOP_Type x_Type_instance =
* (TOP_Type) c.newInstance(new Object[] { this, casType }); typeArray[typeIndex] =
* x_Type_instance; } catch (SecurityException e) { logAndThrow(e); } catch (NoSuchMethodException
* e) { logAndThrow(e); } catch (InstantiationException e) { logAndThrow(e); } catch
* (IllegalAccessException e) { logAndThrow(e); } catch (InvocationTargetException e) {
* logAndThrow(e); } catch (ArrayIndexOutOfBoundsException e) { logAndThrow(e); } }
*/
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getRequiredType(java.lang.String)
*/
public Type getRequiredType(String s) throws CASException {
Type t = getTypeSystem().getType(s);
if (null == t) {
CASException casEx = new CASException(CASException.JCAS_TYPENOTFOUND_ERROR,
new String[] { s });
throw casEx;
}
return t;
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getRequiredFeature(org.apache.uima.cas.Type, java.lang.String)
*/
public Feature getRequiredFeature(Type t, String s) throws CASException {
Feature f = t.getFeatureByBaseName(s);
if (null == f) {
CASException casEx = new CASException(CASException.JCAS_FEATURENOTFOUND_ERROR, new String[] {
t.getName(), s });
throw casEx;
}
return f;
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getRequiredFeatureDE(org.apache.uima.cas.Type, java.lang.String,
* java.lang.String, boolean)
*/
public Feature getRequiredFeatureDE(Type t, String s, String rangeName, boolean featOkTst) {
Feature f = t.getFeatureByBaseName(s);
Type rangeType = this.getTypeSystem().getType(rangeName);
if (null == f && featOkTst) {
CASException casEx = new CASException(CASException.JCAS_FEATURENOTFOUND_ERROR, new String[] {
t.getName(), s });
sharedView.errorSet.add(new ErrorReport(casEx, false)); // false - no throw
}
if (null != f)
try {
casImpl.checkTypingConditions(t, rangeType, f);
} catch (LowLevelException e) {
CASException casEx = new CASException(CASException.JCAS_FEATURE_WRONG_TYPE, new String[] {
t.getName(), s, rangeName, f.getRange().toString() });
sharedView.errorSet.add(new ErrorReport(casEx, true));
}
return f;
}
/**
* Internal - throw missing feature exception at runtime
*
* @param feat -
* @param type -
*/
public void throwFeatMissing(String feat, String type) {
CASRuntimeException e = new CASRuntimeException(CASRuntimeException.INAPPROP_FEAT,
new String[] { feat, type });
throw e;
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#putJfsFromCaddr(int, org.apache.uima.cas.FeatureStructure)
*/
public void putJfsFromCaddr(int casAddr, FeatureStructure fs) {
sharedView.cAddr2Jfs.put((FeatureStructureImpl) fs);
}
/*
* (non-Javadoc)
*
* Generics: extends FeatureStructure, not TOP, because
* when the JCas is being used, but a particular type instance doesn't have a JCas cover class,
* this holds instances of FeatureStructureC - the shared Class for non-JCas Java cover objects.
*
* @see org.apache.uima.jcas.JCas#getJfsFromCaddr(int)
*/
@SuppressWarnings("unchecked")
public <T extends TOP> T getJfsFromCaddr(int casAddr) {
return (T) sharedView.cAddr2Jfs.getReserve(casAddr);
}
public void showJfsFromCaddrHistogram() {
sharedView.cAddr2Jfs.showHistogram();
}
// * Implementation of part of the Cas interface as part of JCas*
/*
* (Internal Use only) called by the CAS reset function - clears the hashtable holding the
* associations.
*/
public static void clearData(CAS cas) {
JCasImpl jcas = (JCasImpl) ((CASImpl) cas).getExistingJCas();
final JCasSharedView sv = jcas.sharedView;
sv.stringArray0L = null;
sv.floatArray0L = null;
sv.fsArray0L = null;
sv.integerArray0L = null;
// JCasHashMap currentMap = sv.cAddr2JfsByClassLoader.get( ((CASImpl) cas).getJCasClassLoader() );
for (Iterator<Map.Entry<ClassLoader, JCasHashMap>> it = sv.cAddr2JfsByClassLoader.entrySet().iterator(); it.hasNext();) {
Map.Entry<ClassLoader, JCasHashMap> e = it.next();
e.getValue().clear(); // implements resize as well
ClassLoader cl = e.getKey();
JCasHashMap jcas_hashmap = e.getValue();
jcas_hashmap.clear();
if (cl instanceof UIMAClassLoader) {
if (((UIMAClassLoader) cl).isClosed()) {
it.remove();
if (sv.cAddr2Jfs == jcas_hashmap) {
sv.cAddr2Jfs = null;
}
}
}
// sv.cAddr2Jfs = e.getValue();
// sv.cAddr2Jfs.clear(); // implements resize as well
// if (! e.getValue().equals(currentMap)) {
// it.remove();
// }
}
// sv.cAddr2Jfs = sv.cAddr2JfsByClassLoader
// .get(((CASImpl) cas).getJCasClassLoader());
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#reset()
*/
public void reset() {
casImpl.reset();
}
private final static int NULL = 0;
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#checkArrayBounds(int, int)
*/
public final void checkArrayBounds(int fsRef, int pos) {
if (NULL == fsRef) {
LowLevelException e = new LowLevelException(LowLevelException.NULL_ARRAY_ACCESS);
// note - need to add this to ll_runtimeException
e.addArgument(Integer.toString(pos));
throw e;
}
final int arrayLength = casImpl.ll_getArraySize(fsRef);
if (pos < 0 || pos >= arrayLength) {
LowLevelException e = new LowLevelException(LowLevelException.ARRAY_INDEX_OUT_OF_RANGE);
e.addArgument(Integer.toString(pos));
throw e;
}
}
// *****************
// * Sofa support *
// *****************
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getSofa(org.apache.uima.cas.SofaID)
*/
public Sofa getSofa(SofaID sofaID) {
return (Sofa) casImpl.getSofa(sofaID);
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getSofa()
*/
public Sofa getSofa() {
return (Sofa) casImpl.getSofa();
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#createView(java.lang.String)
*/
public JCas createView(String sofaID) throws CASException {
return casImpl.createView(sofaID).getJCas();
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getJCas(org.apache.uima.jcas.cas.Sofa)
*/
public JCas getJCas(Sofa sofa) throws CASException {
return casImpl.getView(sofa).getJCas();
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getSofaIterator()
*/
public FSIterator<SofaFS> getSofaIterator() {
return casImpl.getSofaIterator();
}
// *****************
// * Index support *
// *****************
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getJFSIndexRepository()
*/
public JFSIndexRepository getJFSIndexRepository() {
return jfsIndexRepository;
}
// ****************
// * TCas support *
// ****************
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getDocumentAnnotationFs()
*/
public TOP getDocumentAnnotationFs() {
return (TOP) casImpl.getDocumentAnnotation();
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getDocumentText()
*/
public String getDocumentText() {
return casImpl.getDocumentText();
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getSofaDataString()
*/
public String getSofaDataString() {
return casImpl.getSofaDataString();
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getSofaDataArray()
*/
public FeatureStructure getSofaDataArray() {
return casImpl.getSofaDataArray();
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getSofaDataURI()
*/
public String getSofaDataURI() {
return casImpl.getSofaDataURI();
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getSofaMimeType()
*/
public String getSofaMimeType() {
return casImpl.getSofaMimeType();
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#setDocumentText(java.lang.String)
*/
public void setDocumentText(String text) throws CASRuntimeException {
casImpl.setDocumentText(text);
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#setSofaDataString(java.lang.String, java.lang.String)
*/
public void setSofaDataString(String text, String mime) throws CASRuntimeException {
casImpl.setSofaDataString(text, mime);
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#setSofaDataArray(org.apache.uima.jcas.cas.TOP, java.lang.String)
*/
public void setSofaDataArray(FeatureStructure array, String mime) throws CASRuntimeException {
casImpl.setSofaDataArray(array, mime);
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#setSofaDataURI(java.lang.String, java.lang.String)
*/
public void setSofaDataURI(String uri, String mime) throws CASRuntimeException {
casImpl.setSofaDataURI(uri, mime);
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getDocumentLanguage()
*/
public String getDocumentLanguage() {
return casImpl.getDocumentLanguage();
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#setDocumentLanguage(java.lang.String)
*/
public void setDocumentLanguage(String language) throws CASRuntimeException {
casImpl.setDocumentLanguage(language);
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getSofaDataStream()
*/
public InputStream getSofaDataStream() {
return casImpl.getSofaDataStream();
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getConstraintFactory()
*/
public ConstraintFactory getConstraintFactory() {
return casImpl.getConstraintFactory();
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#createFeaturePath()
*/
public FeaturePath createFeaturePath() {
return casImpl.createFeaturePath();
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#createFilteredIterator(org.apache.uima.cas.FSIterator,
* org.apache.uima.cas.FSMatchConstraint)
*/
public <T extends FeatureStructure> FSIterator<T> createFilteredIterator(FSIterator<T> it, FSMatchConstraint constraint) {
return casImpl.createFilteredIterator(it, constraint);
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getStringArray0L()
*/
public StringArray getStringArray0L() {
if (null == sharedView.stringArray0L)
sharedView.stringArray0L = new StringArray(this, 0);
return sharedView.stringArray0L;
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getIntegerArray0L()
*/
public IntegerArray getIntegerArray0L() {
if (null == sharedView.integerArray0L)
sharedView.integerArray0L = new IntegerArray(this, 0);
return sharedView.integerArray0L;
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getFloatArray0L()
*/
public FloatArray getFloatArray0L() {
if (null == sharedView.floatArray0L)
sharedView.floatArray0L = new FloatArray(this, 0);
return sharedView.floatArray0L;
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getFSArray0L()
*/
public FSArray getFSArray0L() {
if (null == sharedView.fsArray0L)
sharedView.fsArray0L = new FSArray(this, 0);
return sharedView.fsArray0L;
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#processInit()
*/
public void processInit() {
// unused
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.cas.AbstractCas_ImplBase#setOwn
*/
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#setOwner(org.apache.uima.cas.CasOwner)
*/
public void setOwner(CasOwner aCasOwner) {
casImpl.setOwner(aCasOwner);
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#release()
*/
public void release() {
casImpl.release();
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getView(java.lang.String)
*/
public JCas getView(String localViewName) throws CASException {
// try { // defer because can break some use cases see UIMA-5869
return casImpl.getView(localViewName).getJCas();
// } catch (CASRuntimeException e) {
// throw new CASException(e); // https://issues.apache.org/jira/browse/UIMA-5869
// }
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getView(org.apache.uima.cas.SofaFS)
*/
public JCas getView(SofaFS aSofa) throws CASException {
return casImpl.getView(aSofa).getJCas();
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#addFsToIndexes(org.apache.uima.cas.FeatureStructure)
*/
public void addFsToIndexes(FeatureStructure instance) {
casImpl.addFsToIndexes(instance);
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#removeFsFromIndexes(org.apache.uima.cas.FeatureStructure)
*/
public void removeFsFromIndexes(FeatureStructure instance) {
casImpl.removeFsFromIndexes(instance);
}
/* (non-Javadoc)
* @see org.apache.uima.jcas.JCas#removeAllIncludingSubtypes(int)
*/
public void removeAllIncludingSubtypes(int i) {
getFSIndexRepository().removeAllIncludingSubtypes(getCasType(i));
}
/* (non-Javadoc)
* @see org.apache.uima.jcas.JCas#removeAllExcludingSubtypes(int)
*/
public void removeAllExcludingSubtypes(int i) {
getFSIndexRepository().removeAllExcludingSubtypes(getCasType(i));
}
/**
* @see org.apache.uima.cas.CAS#fs2listIterator(FSIterator)
*/
public <T extends FeatureStructure> ListIterator<T> fs2listIterator(FSIterator<T> it) {
return casImpl.fs2listIterator(it);
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.cas.BaseCas#createFeatureValuePath(java.lang.String)
*/
public FeatureValuePath createFeatureValuePath(String featureValuePath)
throws CASRuntimeException {
return casImpl.createFeatureValuePath(featureValuePath);
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.cas.BaseCas#createSofa(org.apache.uima.cas.SofaID, java.lang.String)
* @deprecated
*/
public SofaFS createSofa(SofaID sofaID, String mimeType) {
// extract absolute SofaName string from the ID
return casImpl.createSofa(sofaID, mimeType);
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.cas.BaseCas#getIndexRepository()
*/
public FSIndexRepository getIndexRepository() {
return casImpl.getIndexRepository();
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.cas.BaseCas#getViewName()
*/
public String getViewName() {
return casImpl.getViewName();
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.cas.BaseCas#size()
*/
public int size() {
// TODO improve this to account for JCas
// structure sizes
return casImpl.size();
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getAnnotationIndex()
*/
public AnnotationIndex<Annotation> getAnnotationIndex() {
return casImpl.<Annotation>getAnnotationIndex();
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getAnnotationIndex(org.apache.uima.cas.Type)
*/
@Override
public <T extends Annotation> AnnotationIndex<T> getAnnotationIndex(Type type) throws CASRuntimeException {
return (AnnotationIndex<T>) casImpl.<T>getAnnotationIndex(type);
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getAnnotationIndex(int)
*/
public <T extends Annotation> AnnotationIndex<T> getAnnotationIndex(int type) throws CASRuntimeException {
return (AnnotationIndex<T>) casImpl.<T>getAnnotationIndex(this.getCasType(type));
}
public <T extends Annotation> AnnotationIndex<T> getAnnotationIndex(Class<T> clazz) {
return getAnnotationIndex(getCasType(clazz));
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getViewIterator()
*/
public Iterator<JCas> getViewIterator() throws CASException {
List<JCas> viewList = new ArrayList<JCas>();
Iterator<CAS> casViewIter = casImpl.getViewIterator();
while (casViewIter.hasNext()) {
viewList.add((casViewIter.next()).getJCas());
}
return viewList.iterator();
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.jcas.JCas#getViewIterator(java.lang.String)
*/
public Iterator<JCas> getViewIterator(String localViewNamePrefix) throws CASException {
List<JCas> viewList = new ArrayList<JCas>();
Iterator<CAS> casViewIter = casImpl.getViewIterator(localViewNamePrefix);
while (casViewIter.hasNext()) {
viewList.add((casViewIter.next()).getJCas());
}
return viewList.iterator();
}
/* (non-Javadoc)
* @see org.apache.uima.jcas.JCas#protectIndexes()
*/
@Override
public AutoCloseable protectIndexes() {
return casImpl.protectIndexes();
}
/* (non-Javadoc)
* @see org.apache.uima.jcas.JCas#protectIndexes(java.lang.Runnable)
*/
@Override
public void protectIndexes(Runnable runnable) {
casImpl.protectIndexes(runnable);
}
/**
* Static method to get the corresponding Type for a JCas class object
*/
private int getTypeRegistryIndex(Class<? extends TOP> clazz) {
try {
return clazz.getField("type").getInt(clazz);
} catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
throw new RuntimeException(e); // should never happen
}
}
/**
* Return the UIMA Type object corresponding to this JCas's JCas cover class
* (Note: different JCas's, with different type systems, may share the same cover class impl)
* @param clazz a JCas cover class
* @return the corresponding UIMA Type object
*/
public Type getCasType(Class<? extends TOP> clazz) {
return getCasType(getTypeRegistryIndex(clazz));
}
@Override
public <T extends TOP> FSIterator<T> getAllIndexedFS(Class<T> clazz) {
return getFSIndexRepository().getAllIndexedFS(getCasType(clazz));
}
@Override
public <T extends TOP> FSIndex<T> getIndex(String label, Class<T> clazz) {
return getFSIndexRepository().getIndex(label, getCasType(clazz));
}
}