Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

This page discusses ideas for supporting JCas customization, and multiple customizations possible due to PEAR classpath isolation with "customized" JCas cover classes.

The problem arises because with the Feature Structure data contained solely in a particular instance of a Java class, there must be an approach to have the differing contexts (different PEAR definitions of the customization of the JCas cover class) share and update this data.  An instance produced from a PEAR needs to be able to be used outside of the PEAR, and vice-versa. 

A catalog of customizations

Customizations are used for many things; here are some gleaned from some actual use cases:

  • Additional "setter" forms.  example: a setter for a float feature, taking a "Float" argument, and handling various NaN style including mapping "null" to one of them, then calling the underlying setter
  • Additional methods that operate on multiple fields at once (perhaps keeping them in "sync")
  • Override clone to do a deeper copy
  • modify a getter - if null is the value, substitute a custom alternative
  • Additional arbitrary methods that produce values via operations on features
  • Additional constructors, taking more arguments, setting fields
  • Additional fields (not in the type system, not serializable, etc.)

(lightbulb)Starting with customization, adding any merged type features

The merged type system (including PEARs) represents the common needed JCas cover class's fields and getters and setters.  Merge this with any customization code while loading the cover class. 

Implementation ideas here here in diagram form: JCasClassLoading.

Handling multiple customizations of a UIMA Cas Type

Multiple customizations can arise when two or more independently developed components both implement customized JCas classes.  This may happen in two ways:

...

  • Use the capabilities input/output: for the case where the particular class in the PEAR is not among the inputs or outputs, just isolate it:
    • switch and use the alternative definition, loaded under a separate class loader used for the PEAR.
    • (warning)if an outside-the-pear Feature Structure holds a reference to this - could lead to class-cast exceptions
  • Isolate it - switch and use the alternative definition
    • (warning)This is what the current UIMA does; suffers from class-cast exception problems
  • Throw an error
  • Attempt to merge 

 

 

(question)A single common system-generated implementation + an augmentation mechanism for (multiple) customizations

At the high abstraction level: UIMA is providing

...

This may be very hard to implement. There are examples of new methods being added in a customization; these methods would need to be called from a base instance (don't know how to do that).  Also, customization may add fields.

(question)Copy some Feature Structures into / out of the PEAR

A PEAR represents a packaging and a classpath isolation.  The PEAR may (for some of the shared types) have a different definition of the JCas cover class.  If the difference is simply it has fewer features than the pipeline's fully merged definition, then it can use the main pipeline's definition (it will have extra methods, but those would just go unused).  If it has a different implementation beyond that, then a lazy (when needed) copying of the main pipeline's Feature Structure into the Pear's instantiation would be done.  Likewise, on exit from the PEAR, if the type is mentioned as being an output, and it was "copied" in, then it would be copied out.

...

  • isStandardJCasClass() to test if the JCas is not customized

(question)Merge all the custom definitions into one and use that everywhere.

Do some kind of "merge" operation among all definitions of JCas cover classes including those in contained PEARs, and use that one merged definition everywhere.  

  • Advantages: is most similar to what we have now
  • Disadvantages: it's not always possible to find a merge that preserves all the original implementations.  It might be very difficult to construct an appropriate merge algorithm, given the arbitrariness of the custom code.

(thumbs down)Keep the system-generated code in one class, and use a different wrapping class for the customization

Split apart the system-generated (from the merged type system) JCas cover class and user customization, into different classes.  The user customization class would wrap the system-generated one, and create both; all value setting/getting would be via forwarding methods.  

...

  • If a JCas cover class is not customized (anywhere in the pipeline, including inside PEAR files), we have the system generated class, and its expected name as it is now.  
  • If it is customized, the custom "wrapper" would carry the official name, so users would use it, and the system-generated class would need a new name (e.g. xxxx_UIMA_JCas_Generated.), which would "hide it" from normal access.  A complete analysis of the pipeline running as an application in one JVM would be needed to find (including inside PEARs) which UIMA types had customization (anywhere, including even if in just one PEAR).  Those types would need the alternate naming protocol. 

(thumbs down)Keep the system-generated code in one class, and do the customization in a class "extension"

Another way to split apart the system-generated from the customization: have the customization "extend" rather than wrap the system-generated one.

...