You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@uima.apache.org by sc...@apache.org on 2015/11/01 14:00:09 UTC
svn commit: r1711746 -
/uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java
Author: schor
Date: Sun Nov 1 13:00:08 2015
New Revision: 1711746
URL: http://svn.apache.org/viewvc?rev=1711746&view=rev
Log:
[UIMA-4665][UIMA-4679] new generator code using Java 8 Method Handles + reorganization to do built-ins just once per class loader
Modified:
uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java
Modified: uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java
URL: http://svn.apache.org/viewvc/uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java?rev=1711746&r1=1711745&r2=1711746&view=diff
==============================================================================
--- uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java (original)
+++ uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java Sun Nov 1 13:00:08 2015
@@ -19,257 +19,397 @@
package org.apache.uima.cas.impl;
-import java.util.Collections;
+import static java.lang.invoke.MethodType.methodType;
+
+import java.lang.invoke.CallSite;
+import java.lang.invoke.LambdaMetafactory;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.Map;
-import org.apache.uima.cas.Type;
+import org.apache.uima.UIMARuntimeException;
+import org.apache.uima.cas.BuiltinTypeKinds;
+import org.apache.uima.cas.CAS;
+import org.apache.uima.cas.CASRuntimeException;
+import org.apache.uima.cas.Feature;
+import org.apache.uima.cas.FeatureStructure;
+import org.apache.uima.cas.function.JCas_getter_boolean;
+import org.apache.uima.cas.function.JCas_getter_byte;
+import org.apache.uima.cas.function.JCas_getter_double;
+import org.apache.uima.cas.function.JCas_getter_float;
+import org.apache.uima.cas.function.JCas_getter_generic;
+import org.apache.uima.cas.function.JCas_getter_int;
+import org.apache.uima.cas.function.JCas_getter_long;
+import org.apache.uima.cas.function.JCas_getter_short;
+import org.apache.uima.cas.function.JCas_setter_boolean;
+import org.apache.uima.cas.function.JCas_setter_byte;
+import org.apache.uima.cas.function.JCas_setter_double;
+import org.apache.uima.cas.function.JCas_setter_float;
+import org.apache.uima.cas.function.JCas_setter_generic;
+import org.apache.uima.cas.function.JCas_setter_int;
+import org.apache.uima.cas.function.JCas_setter_long;
+import org.apache.uima.cas.function.JCas_setter_short;
+import org.apache.uima.jcas.cas.Sofa;
+import org.apache.uima.jcas.cas.TOP;
+import org.apache.uima.util.Misc;
/*
- * There is one instance of this class per type system.
- * It is shared by multiple CASes (in a CAS pool, for instance,
- * when these CASes are sharing the same type system), and
- * it is shared by all views of that CAS.
+ * There is one instance of this class per type system impl instance.
+ * - The type system impl instance points to this object
+ * - It is constructed when the type system is committed
+ * - Multiple simultaneous versions are possible with multiple type systems, but
+ * -- supporting different JCas cover classes requires using different ClassLoaders for the type system.
+ *
+ * It may be shared
+ * - by multiple CASes (in a CAS pool, for instance, when these CASes are sharing the same type system).
+ * - by all views of those CASes.
+ * - by multiple different pipelines, built using the same merged type system instance
*/
/* Design:
- * Goals: Suppport PEARs, which can switch class loaders for component
- * code. Different class loaders imply different instances of
- * JCas cover class definitions, potentially, needing different
- * generators.
+ * Goals: Support PEARs. PEARs can have different customizations for JCas classes
+ * These are located via the PEAR's classloader.
*
- * Keep the non-JCas path (relatively) uncluttered
- *
- * Concepts:
- * Base-ClassLoader: there is one class loader that is considered the base.
- * This is the one used for the "application code" (if it exists) driving
- * the UIMA framework. It is set when the CAS or CAS Pool is created,
- * according to the resource manager used. Components (annotators, flow controllers, etc.)
- * run with this same class loader, unless they are contained within a PEAR;
- * within PEAR components, the loader is switched (on a per-cas-view-collection basis)
- * when entering the component, and switched back when the component "returns".
- *
- * base-generators - these are the generators associated with the Base-ClassLoader;
- * there is one set per FSClassRegistry instance (and also, one per TypeSystem instance).
- * cas-generators - generator set kept in the CAS svd - shared-view-data -
- * that are updated as needed during the processing of the CAS, switching
- * these as needed for entering / exiting PEAR components
- *
- * Significant data structures:
- * - static map in JCasImpl - keys: typeSystem instance and classLoader instance;
- * value = a hashmap of LoadedJCasType instances for that combination, used to
- * make new instances of the _Type objects for views.
- * - map in this class: key = class loader, value = generator-set to use for this
- * class loader. This is also per unique type system, since there's one instance of
- * this class per type system instance. This is used to load the cas-generators.
+ * These must be found and merged into a common definition. This
+ * merged common definition is created in a process done outside of the
+ * normal running of the UIMA pipeline.
+ * - during running, only one classpath is used to locate JCas cover classes, and
+ * those must be the merged ones.
+ * - the merge is only needed in these situations:
+ * -- running with PEARs which have different definitions of JCas cover classes than their containing pipelines
+ * -- running with multiple, different pipelines, under a single type system class loader
*
- * Life cycle: Instances of this class are tied one-to-one with particular
- * TypeSystem instances.
+ * At typeSystemCommit time, this data structure is created and initialized with default
+ * (non-JCas) generators for all types.
+ * - The built-in JCas types are loaded; these override the standard default generator.
*
- * At typeSystemCommit time, initGenerators is called; it loads the default
- * (non-JCas) generator for all types, and then overrides the
- * built-in array types with particular generators for those.
+ * - The user-defined JCas classes are not loaded until the first call to create a JCas.
+ * -- this permits running without any customized JCas classes, which may be advantageous in some
+ * use cases, such as one where multiple different type systems are sequentially loaded
+ * (think of an application which deserializes a CAS does some "generic processing", and repeats.)
*
- * *BUT* This is done only if the type system has not already been committed,
- * so if the generators had (for some other CAS sharing this type system)
- * already been updated to JCas generators, that is never "undone".
- *
- * The cas-generators are set from the base-generators (synch'd)
- *
- * When JCas is initialized for this CAS
- * - it may have already been initialized for another CAS sharing this generator
- * - it may be initializing for a non-Base-ClassLoader
- *
- * When JCas is initialized, if it is for the Base-ClassLoader, then the
- * if this is the first time this happens for this class loader and type system,
- * the base-generators are updated (synch'd) (otherwise, the base-generators have
- * already been updated).
- *
- * The cas-generators are set from the base-generators (synch'd).
- *
- * If it is *not* for the Base-ClassLoader, the same thing happens, except that
- * the base-generators are not updated (so they can be switched-back-to when
- * leaving the PEAR component class loader environment). In this case, the
- * cas-generators are set from the static map(ts, cl) in the jcasimpl.
- *
- * When new JCas classes are loaded due to switching to a new class loader for a PEAR,
- * the static map(ts, cl) in JCasImpl is updated, and the map in this class for
- * generators for this class loader is updated, and the cas-generators are loaded
- * from that.
- *
- * When switching class loaders in component code, the cas-generators are loaded if
- * a switch is needed from this class's map(cl).
- *
- * All refs to the base-generators are synchronized, since different CASes running on
- * different threads can update these (when switching to the JCas version for the
- * Base-ClassLoader).
+ * - When the JCas is initialized, the type system set of types is used to attempt to locate
+ * and load JCas class definitions.
+ * -- User classes defined with the name of UIMA types, but which are not JCas definitions, are not used.
+ * -- These classes, once loaded, remain loaded because of Java's design, unless the ClassLoader
+ * used to load them is Garbage Collected.
+ * --- The ClassLoader used is the same ClassLoader used for the type system, because
+ * multiple sets of JCas classes per typesystem isn't supported.
+ *
+ * JCas definition merging
+ * - depends on multiple sources for JCas cover classes
+ * -- represented by multiple classloaders, each one corresponding to a different PEAR or other classpath
+ * - can be invoked for a set of classloaders
+ * - is run manually, outside of normal UIMA pipeline operation, as a stand-alone utility
*
*/
public class FSClassRegistry {
-
- private static class DefaultFSGenerator implements FSGenerator<FeatureStructureImplC> {
- private DefaultFSGenerator() {
- super();
+
+ private static final boolean GETTER = true;
+ private static final boolean SETTER = false;
+
+ private static final MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+ private static final MethodType findConstructorJCasCoverType = methodType(void.class, TypeImpl.class, CASImpl.class);
+ private static final MethodType findConstructorJCasCoverTypeArray = methodType(void.class, TypeImpl.class, CASImpl.class, int.class);
+ /**
+ * The callsite has the return type, followed by capture arguments
+ */
+ private static final MethodType callsiteFsGenerator = methodType(FsGenerator.class);
+ private static final MethodType callsiteFsGeneratorArray = methodType(FsGeneratorArray.class);
+
+ private static final MethodType fsGeneratorType = methodType(FeatureStructureImplC.class, TypeImpl.class, CASImpl.class);
+ private static final MethodType fsGeneratorArrayType = methodType(FeatureStructureImplC.class, TypeImpl.class, CASImpl.class, int.class);
+
+ public static class GetterSetter {
+ final Object getter;
+ final Object setter;
+ GetterSetter(Object getter, Object setter) {
+ this.getter = getter;
+ this.setter = setter;
}
-
- public FeatureStructureImplC createFS(int addr, CASImpl cas) {
- return new FeatureStructureImplC(cas, addr);
+ }
+
+ private static class JCasClassInfo {
+ final Object generator;
+ final Class<?> jcasClass;
+ /**
+ * map from the feature short name to the getter/setter Lambda
+ */
+ final Map<String, GetterSetter> gettersAndSetters = new HashMap<>(1);
+
+ JCasClassInfo(Class<?> jcasClass, Object generator) {
+ this.generator = generator;
+ this.jcasClass = jcasClass;
}
}
- private TypeSystemImpl ts;
-
- private FSGenerator<?>[] generators;
-
- private static final FSGenerator<FeatureStructureImplC> defaultGenerator = new DefaultFSGenerator();
-
- /*
- * Generators sometimes need to be changed while running
- *
- * An Annotator's process method is about to be called, but the class loader
- * used for loading the JCas classes differs from the one used to load the
- * Annotator class. This can happen when a PEAR with different class loader
- * is inserted into a pipeline.
- *
- * To make this switch efficient, we keep the generators stored in a map
- * keyed by the class loader.
- *
- * JCas creation will, after all the generators are created, call the
- * saveGeneratorsForClassLoader to save a copy of the generators.
- *
- * Generators can be switched by calling loadGeneratorsForClassLoader
- *
+ /**
+ * precomputed generators for built-in types
*/
- // This map can be accessed on different threads at the same time
- private final Map<ClassLoader, FSGenerator<?>[]> generatorsByClassLoader =
- Collections.synchronizedMap(new HashMap<ClassLoader, FSGenerator<?>[]>(4));
-
- // private final RedBlackTree rbt;
- // private final TreeMap map;
-// private FeatureStructure[] fsArray;
-
- FSClassRegistry(TypeSystemImpl ts) {
- this.ts = ts;
- }
-
- synchronized void initGeneratorArray() {
- this.generators = new FSGenerator[ts.getTypeArraySize()];
- for (int i = ts.getSmallestType(); i < this.generators.length; i++) {
- this.generators[i] = defaultGenerator;
+ private static final JCasClassInfo[] jcasClassesInfoForBuiltins;
+ static {
+ TypeSystemImpl tsi = TypeSystemImpl.staticTsi;
+ jcasClassesInfoForBuiltins = new JCasClassInfo[tsi.getTypeArraySize()];
+ ClassLoader cl = TypeSystemImpl.class.getClassLoader();
+
+ for (String typeName : BuiltinTypeKinds.creatableBuiltinJCas) {
+ TypeImpl ti = tsi.getType(typeName);
+ Class<?> builtinClass = maybeLoadJCas(typeName, cl);
+ assert (builtinClass != null); // builtin types must be present
+
+ // copy down to subtypes, if needed, done later
+ jcasClassesInfoForBuiltins[ti.getCode()] = createJCasClassInfo(builtinClass, ti);
}
+ /** special handling for Sofa, a non-creatable type */
+ TypeImpl ti = tsi.getType(CAS.TYPE_NAME_SOFA);
+ jcasClassesInfoForBuiltins[ti.getCode()] = createJCasClassInfo(Sofa.class, ti);
+
}
+ // the loaded JCas cover classes, generators, setters, and getters. index is typecode; value is JCas cover class which may belong to a supertype.
+ private final JCasClassInfo[] jcasClassesInfo;
+
+ //
+ //
/**
- * adds generator for type and all its subtypes. Because of this, call this on supertypes first,
- * then subtypes (otherwise subtypes will be overwritten by generators for the supertypes).
+ * install the default (non-JCas) generator for all types in the type system and the
+ * JCas style generators for the built-in types
*
- * @param type
- * the CAS type
- * @param fsFactory
- * the object having a createFS method in it for this type
+ * Also, for all loaded JCas classes, set the javaClass field (including
+ * in subtypes with no JCas class defined).
+ *
+ * @param ts - the type system
+ * @param isDoUserJCasLoading a flag to skip loading the JCas classes
*/
- synchronized void addClassForType(Type type, FSGenerator<?> fsFactory) {
- Iterator<Type> it = this.ts.getTypeIterator();
- TypeImpl sub;
- while (it.hasNext()) {
- sub = (TypeImpl) it.next();
- if (this.ts.subsumes(type, sub)) {
- this.generators[sub.getCode()] = fsFactory;
+ FSClassRegistry(TypeSystemImpl ts, boolean isDoUserJCasLoading) {
+
+ jcasClassesInfo = new JCasClassInfo[ts.getTypeArraySize()];
+
+ /**
+ * copy in built-ins
+ */
+ for (int i = 0; i < jcasClassesInfoForBuiltins.length; i++) {
+
+ JCasClassInfo jci;
+ jcasClassesInfo[i] = jci = jcasClassesInfoForBuiltins[i];
+ if (jci != null) {
+ ts.setJCasRegisteredType(Misc.getStaticIntField(getJCasClass(i), "typeIndexID"), ts.getTypeForCode(i));
}
}
+
+ /**
+ * Add all user-defined JCas Types, in subsumption order
+ * We add these now, in case JCas is turned on later - unless specifically
+ * specified to run without user-defined JCas loading
+ */
+
+ if (isDoUserJCasLoading) {
+ maybeLoadJCasAndSubtypes(ts, ts.topType, jcasClassesInfo[TypeSystemImpl.topTypeCode]);
+ }
}
+ private void maybeLoadJCasAndSubtypes(TypeSystemImpl ts, TypeImpl ti, JCasClassInfo copyDownDefault_jcasClassInfo) {
+ final int typecode = ti.getCode();
+ Class<?> clazz;
+ boolean isBuiltin = BuiltinTypeKinds.creatableBuiltinJCas.contains(ti.getName());
+
+ JCasClassInfo jcasClassInfo = copyDownDefault_jcasClassInfo; // initialize in case no JCas for this type
+
+ if (!isBuiltin) {
+ clazz = maybeLoadJCas(ti.getName(), ti.getClass().getClassLoader());
+ if (null != clazz && TOP.class.isAssignableFrom(clazz)) {
+ jcasClassInfo = createJCasClassInfo(clazz, ti);
+ ts.setJCasRegisteredType(Misc.getStaticIntField(clazz, "typeIndexID"), ti);
+ }
+ jcasClassesInfo[typecode] = jcasClassInfo; // sets new one or default one
+ }
+
+ for (TypeImpl subtype : ti.getDirectSubtypes()) {
+ maybeLoadJCasAndSubtypes(ts, subtype, jcasClassesInfo[typecode]);
+ }
+ }
+
+ private static Class<?> maybeLoadJCas(String typeName, ClassLoader cl) {
+ Class<?> clazz = null;
+ String className = typeName2ClassName(typeName);
+ try {
+ clazz = Class.forName(className, true, cl);
+ } catch (ClassNotFoundException e) {
+ // This is normal, if there is no JCas for this class
+ }
+ return clazz;
+ }
+
+ private static String typeName2ClassName(String typeName) {
+ if (typeName.startsWith(CAS.UIMA_CAS_PREFIX)) {
+ return "org.apache.uima.jcas.cas." + typeName.substring(CAS.UIMA_CAS_PREFIX.length());
+ }
+ if (typeName.startsWith(CAS.UIMA_TCAS_PREFIX)) {
+ return "org.apache.uima.jcas.tcas." + typeName.substring(CAS.UIMA_TCAS_PREFIX.length());
+ }
+ return typeName;
+ }
+
/**
- * No longer used, but left in for backward compatibility with older JCasgen'd
- * classes
- * @param type -
- * @param fsFactory -
+ * Return a Functional Interface for a generator for creating instances of a type.
+ * Function takes a casImpl arg, and returning an instance of the JCas type.
+ * @param jcasClass the class of the JCas type to construct
+ * @param typeImpl the UIMA type
+ * @return a Functional Interface whose createFS method takes a casImpl
+ * and when subsequently invoked, returns a new instance of the class
*/
- public void addGeneratorForType(TypeImpl type, FSGenerator<?> fsFactory) {
- //this.generators[type.getCode()] = fsFactory;
+ private static Object createGenerator(Class<?> jcasClass, TypeImpl typeImpl) {
+ boolean isArray = typeImpl.isArray();
+ try {
+ MethodHandle mh = lookup.findConstructor(jcasClass, isArray ? findConstructorJCasCoverTypeArray
+ : findConstructorJCasCoverType);
+ MethodType mtThisGenerator = isArray ? methodType(jcasClass, TypeImpl.class, CASImpl.class, int.class)
+ : methodType(jcasClass, TypeImpl.class, CASImpl.class);
+
+ CallSite callSite = LambdaMetafactory.metafactory(
+ lookup, // lookup context for the constructor
+ "createFS", // name of the method in the Function Interface
+ isArray ? callsiteFsGeneratorArray // signature of callsite, return type is functional interface, args are captured args if any
+ : callsiteFsGenerator,
+ isArray ? fsGeneratorArrayType
+ : fsGeneratorType, // samMethodType signature and return type of method impl by function object
+ mh, // method handle to constructor
+ mtThisGenerator);
+ return isArray ? (FsGeneratorArray) callSite.getTarget().invokeExact()
+ : (FsGenerator) callSite.getTarget().invokeExact();
+ } catch (Throwable e) {
+ if (e instanceof NoSuchMethodException) {
+ throw new CASRuntimeException(e, CASRuntimeException.JCAS_CAS_NOT_V3, jcasClass.getName());
+ }
+ throw new UIMARuntimeException(e, UIMARuntimeException.INTERNAL_ERROR);
+ }
}
+
+ /**
+ * Return a Functional Interface for a getter for getting the value of a feature,
+ * called by APIs using the non-JCas style of access via features,
+ * but accessing the values via the JCas cover class getter methods.
+ *
+ * The caller of these methods is the FeatureStructureImplC methods.
+ *
+ * There are these return values:
+ * boolean, byte, short, int, long, float, double, String, FeatureStructure
+ *
+ */
+ private static Object createGetterOrSetter(Class<?> jcasClass, FeatureImpl fi, boolean isGetter) {
+
+ TypeImpl range = fi.getRangeImpl();
+
+ try {
+ /* get an early-bound getter
+ /* find special invokes a specific method in a specific class, without looking at the
+ * runtime class */
+ MethodHandle mh = lookup.findVirtual(
+ jcasClass, // class having the method code for the getter
+ fi.getGetterSetterName(isGetter), // the name of the method for the getter
+ isGetter ? methodType(range.javaClass)
+ : methodType(void.class, range.javaClass) // return value, e.g. int.class, xyz.class, FeatureStructureImplC.class
+ );
+
+ // getter methodtype is return_type, FeatureStructure.class
+ // return_type is int, byte, etc. primitive (except string/substring), or
+ // object (to correspond with erasure)
+ // setter methodtype is void.class, FeatureStructure.class, javaclass
+ MethodType mhMt = isGetter ? methodType(range.getJavaPrimitiveClassOrObject(), FeatureStructureImplC.class)
+ : methodType(void.class, FeatureStructureImplC.class, range.getJavaPrimitiveClassOrObject());
+ MethodType iMt = isGetter ? methodType(range.javaClass, jcasClass)
+ : methodType(void.class, jcasClass, range.javaClass);
+
+// System.out.format("mh method type for %s method %s is %s%n",
+// jcasClass.getSimpleName(),
+// fi.getGetterSetterName(isGetter),
+// mhMt);
+
+ CallSite callSite = LambdaMetafactory.metafactory(
+ lookup, // lookup context for the getter
+ isGetter ? "get" : "set", // name of the method in the Function Interface
+ methodType(isGetter ? range.getter_funct_intfc_class : range.setter_funct_intfc_class), // callsite signature = just the functional interface return value
+ mhMt, // samMethodType signature and return type of method impl by function object
+ mh, // method handle to constructor
+ iMt);
+
+ if (range.getJavaClass() == boolean.class) {
+ return isGetter ? (JCas_getter_boolean) callSite.getTarget().invokeExact()
+ : (JCas_setter_boolean) callSite.getTarget().invokeExact();
+ } else if (range.getJavaClass() == byte.class) {
+ return isGetter ? (JCas_getter_byte) callSite.getTarget().invokeExact()
+ : (JCas_setter_byte) callSite.getTarget().invokeExact();
+ } else if (range.getJavaClass() == short.class) {
+ return isGetter ? (JCas_getter_short) callSite.getTarget().invokeExact()
+ : (JCas_setter_short) callSite.getTarget().invokeExact();
+ } else if (range.getJavaClass() == int.class) {
+ return isGetter ? (JCas_getter_int) callSite.getTarget().invokeExact()
+ : (JCas_setter_int) callSite.getTarget().invokeExact();
+ } else if (range.getJavaClass() == long.class) {
+ return isGetter ? (JCas_getter_long) callSite.getTarget().invokeExact()
+ : (JCas_setter_long) callSite.getTarget().invokeExact();
+ } else if (range.getJavaClass() == float.class) {
+ return isGetter ? (JCas_getter_float) callSite.getTarget().invokeExact()
+ : (JCas_setter_float) callSite.getTarget().invokeExact();
+ } else if (range.getJavaClass() == double.class) {
+ return isGetter ? (JCas_getter_double) callSite.getTarget().invokeExact()
+ : (JCas_setter_double) callSite.getTarget().invokeExact();
+ } else {
+ return isGetter ? (JCas_getter_generic) callSite.getTarget().invokeExact()
+ : (JCas_setter_generic) callSite.getTarget().invokeExact();
+ }
+ } catch (NoSuchMethodException e) {
+ return null;
+ } catch (Throwable e) {
+ throw new UIMARuntimeException(e, UIMARuntimeException.INTERNAL_ERROR);
+ }
-// // Internal use only
-// public FSGenerator getGeneratorForType(TypeImpl type) {
-// return this.generators[type.getCode()];
-// }
-
-// /**
-// * copies a generator for a type into another type. Called by JCas after basic types are created
-// * to change the generated types for things having no JCas Java model to the most specific
-// * supertype JCas Java model (if one exists). This allows writinge iterators using JCas where some
-// * of the returned items may be subtypes which have no JCas cover types.
-// *
-// */
-// public void copyGeneratorForType(TypeImpl targetType, TypeImpl sourceType) {
-// this.generators[targetType.getCode()] = this.generators[sourceType.getCode()];
-// }
-
- /* only of interest when caching (not JCas caching) FSes which has never been finished or enabled */
- void flush() {
- // commented out to reduce FindBugs noise.
-// if (this.fsArray != null) {
-// Arrays.fill(this.fsArray, null);
-// }
- }
-
- public void saveGeneratorsForClassLoader(ClassLoader cl, FSGenerator<?>[] newGenerators) {
- generatorsByClassLoader.put(cl, newGenerators);
- }
-
- public boolean swapInGeneratorsForClassLoader(ClassLoader cl, CASImpl casImpl) {
- FSGenerator<?>[] cachedGenerators = generatorsByClassLoader.get(cl);
- if (cachedGenerators != null) {
- casImpl.setLocalFsGenerators(cachedGenerators);
- return true;
- }
- return false;
}
-
-
-// // assume addr is never 0 - caller must insure this
-// FeatureStructure createFSusingGenerator(int addr, CASImpl cas) {
-// return this.generators[cas.getHeap().heap[addr]].createFS(addr, cas);
-// }
-
-// /*
-// * Generators used are created with as much info as can be looked up once, ahead of time.
-// * Things variable at run time include the cas instance, and the view.
-// *
-// * In this design, generators are shared with all views for a particular CAS, but are different for
-// * different CAS Type Systems and Class Loaders (distinct from shared-views of the same CAS)
-// *
-// * Internal use only - public only to give access to JCas routines in another package
-// */
-// public void loadJCasGeneratorForType (int type, Constructor c, TypeImpl casType, boolean isSubtypeOfAnnotationBase) {
-// FSGenerator fsGenerator = new JCasFsGenerator(type, c, isSubtypeOfAnnotationBase, ts.sofaNumFeatCode, ts.annotSofaFeatCode);
-// addGeneratorForTypeInternal(casType, fsGenerator);
-// }
-
- /*
- * Internal Use only
- * All callers must by synchronized
- * although may not be strictly necessary if you can prove that
- * no updates to the generators array could be occuring in
- * another thread
- */
+
- public synchronized FSGenerator<?> [] getBaseGenerators() {
- return this.generators;
+ Object getGenerator(int typecode) {
+ return jcasClassesInfo[typecode].generator;
}
- // internal use, public only for cross package ref
- public synchronized void setBaseGenerators(FSGenerator<?>[] generators) {
- this.generators = generators;
+ GetterSetter getGetterSetter(int typecode, String featShortName) {
+ return jcasClassesInfo[typecode].gettersAndSetters.get(featShortName);
}
- /*
- * Internal Use Only
- */
+ Class<?> getJCasClass(int typecode) {
+ return jcasClassesInfo[typecode].jcasClass;
+ }
- public synchronized FSGenerator<?>[] getNewFSGeneratorSet() {
- return this.generators.clone();
+ private static JCasClassInfo createJCasClassInfo(Class<?> jcasClass, TypeImpl ti) {
+ JCasClassInfo jcasClassInfo = new JCasClassInfo(jcasClass, ti.getName().equals(CAS.TYPE_NAME_SOFA) ? null : createGenerator(jcasClass, ti));
+
+ for (FeatureImpl fi : ti.getMergedStaticFeaturesIntroducedByThisType()) {
+ if (!isFieldInClass(fi, jcasClass)) {
+ continue;
+ }
+ Object getter = createGetterOrSetter(jcasClass, fi, GETTER);
+ Object setter = createGetterOrSetter(jcasClass, fi, SETTER);
+
+ GetterSetter prev = jcasClassInfo.gettersAndSetters.put(fi.getShortName(), new GetterSetter(getter, setter));
+ if (prev != null) {
+ throw new CASRuntimeException(CASRuntimeException.INTERNAL_ERROR);
+ }
+ }
+ return jcasClassInfo;
+ }
+
+ static boolean isFieldInClass(Feature feat, Class<?> clazz) {
+ try {
+ return null != clazz.getDeclaredField("_F_" + feat.getShortName());
+ } catch (NoSuchFieldException e) {
+ return false;
+ }
}
+
+
+
}
+
\ No newline at end of file