blob: afa1b468e643fac95896e125acf7b977a65cdde9 [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.uimacpp;
import org.apache.uima.UIMARuntimeException;
import org.apache.uima.analysis_engine.ResultSpecification;
import org.apache.uima.analysis_engine.TypeOrFeature;
import org.apache.uima.cas.CAS;
import org.apache.uima.cas.admin.CASMgr;
import org.apache.uima.cas.impl.CASImpl;
import org.apache.uima.cas.impl.CASMgrSerializer;
import org.apache.uima.cas.impl.CASSerializer;
import org.apache.uima.cas.impl.FeatureImpl;
import org.apache.uima.cas.impl.Serialization;
import org.apache.uima.cas.impl.TypeImpl;
import org.apache.uima.cas.impl.TypeSystemImpl;
import org.apache.uima.internal.util.IntVector;
public class UimacppEngine {
// Those types can not be created with CAS.createFS().
private static String[] compatibleTafJniVersions = { "2.0" };
static {
String uimacpp_lib = "uima";
String debug = System.getProperty("DEBUG_UIMACPP");
if (debug != null) {
String osname = System.getProperty("os.name");
if (osname.startsWith("Windows")) {
uimacpp_lib = "uimaD";
}
}
System.loadLibrary(uimacpp_lib);
try {
String jniVersion = getTafJNIVersion();
boolean compatible = false;
for (int i = 0; i < compatibleTafJniVersions.length; i++) {
if (jniVersion.equals(compatibleTafJniVersions[i])) {
compatible = true;
break;
}
}
if (compatible) {
createResourceManager();
} else {
throw new UIMARuntimeException(UIMARuntimeException.INCOMPATIBLE_TAF_JNI_LIBRARY,
new Object[] { jniVersion });
}
} catch (UimacppException exc) {
throw new UIMARuntimeException(exc.getEmbeddedException());
}
}
/**
* this field is the physical pointer to the C++ TafClEngine object this TafWrapper object is
* associated with. Do not use explicitly anywhere. It is set automatically by the
* <code>constructorJNI()</code> method and set to 0 by the <code>destructorJNI()</code>
* method.
*/
long cppEnginePointer = 0;
CAS cas = null;
boolean hasNext = false;
// creation of TAF resource manager
private static native void createResourceManagerJNI() throws InternalTafException;
// configuration of the TAF resource manager
private static native void configureResourceManagerJNI(String workDir, String dataDir)
throws InternalTafException;
// constructor
private native void constructorJNI() throws InternalTafException;
// destructor
private native void destructorJNI() throws InternalTafException;
// TAF functions
private native void initializeJNI(String configFile) throws InternalTafException;
private native void typeSystemInitJNI(String[] typeNames, String[] featureNames,
int[] typeInheritance, int[] featDecls, int topTypeCode, int[] featureOffsets,
int[] typeOrder, int[] stringSubTypes, String[] stringSubTypeValues,
int[] stringSubTypeValuePos, String[] indexNames, int[] nameToIndexMap,
int[] indexingStrategy, int[] comparatorIndex, int[] comparators)
throws InternalTafException;
private native void destroyJNI() throws InternalTafException;
private native void resetJNI() throws InternalTafException;
/**
* private native void fillCASJNI(int[] heapArray, int[] fsIndex, String[] stringTable);
*/
private native void fillCASJNI(int[] heapArray, int[] fsIndex, String[] stringTable,
byte[] byteArray, short[] shortArray, long[] longArray);
private native void processJNI(int isTCas, String sofaName, int[] resultSpecTypes,
int[] resultSpecFeatures) throws InternalTafException;
// set the parameter to true if you want per document data to be serialized
// false only for type system and index definitions serialization
private native void serializeCASJNI(boolean bSerializeData) throws InternalTafException;
private native Object getSerializedDataJNI(int what) throws InternalTafException;
private native void batchProcessCompleteJNI() throws InternalTafException;
private native void collectionProcessCompleteJNI() throws InternalTafException;
// JNI calls to support segmenter
private native boolean hasNextSegmentJNI() throws InternalTafException;
private native void nextSegmentJNI() throws InternalTafException;
private native void serializeSegmentJNI(boolean bSerializeData) throws InternalTafException;
private native Object getSerializedSegmentDataJNI(int what) throws InternalTafException;
private native void releaseSegmentJNI() throws InternalTafException;
/*
* serialized CAS data components - supported args to getSerializedDataJNI and
* getSegmentSerializedDataJNI. Many of these are unread and have been commented out but left here
* for documentation purposes.
*/
// private static final int TYPE_INH = 0;
//
// private static final int FEATURE_DEF = 1;
//
// private static final int FEATURE_OFFSET = 2;
//
// private static final int TYPE_SYMBOLS = 3;
//
// private static final int FEATURE_SYMBOLS = 4;
//
// private static final int TOPTYPE = 5;
//
// private static final int TYPE_PRIORITIES = 6;
private static final int FSHEAP = 10;
private static final int STRINGSYMBOL = 11;
// private static final int DOCUMENT = 20;
private static final int INDEXEDFSS = 30;
// private static final int INDEXID = 40;
//
// private static final int INDEXKIND = 41;
//
// private static final int COMPARATORDEF = 42;
//
// private static final int COMPARATORSTART = 43;
private static final int BYTEHEAP = 12;
private static final int SHORTHEAP = 13;
private static final int LONGHEAP = 14;
// helper functions
private static native String getErrorMessageJNI(long errorId) throws InternalTafException;
private static native String getVersionJNI() throws InternalTafException;
/**
* Create the TAF resource manager.
*/
private static void createResourceManager() throws UimacppException {
try {
createResourceManagerJNI();
} catch (Exception exc) {
throwJTafException(exc);
}
}
/**
* Configure the TAF Resource Manager.
*/
public static void configureResourceManager(String workDirectory, String dataDirectory)
throws UimacppException {
try {
configureResourceManagerJNI(workDirectory, dataDirectory);
} catch (Exception exc) {
throwJTafException(exc);
}
}
public UimacppEngine() throws UimacppException {
try {
constructorJNI();
} catch (Exception exc) {
throwJTafException(exc);
}
}
// ////////////////////////////////////////////////////////
// implementation of the AE interface
// getAnalysisEngineMetaData, getView, process, reset, and destroy.
/**
* create a TAF engine with a config file
*/
public static UimacppEngine createJTafTAE(String configFile) throws UimacppException {
UimacppEngine result = new UimacppEngine();
result.initialize(configFile);
return result;
}
static void printArray(String s, int[] ar) {
System.out.println("int array " + s);
for (int i = 0; i < ar.length; ++i) {
System.out.println(i + ": " + ar[i]);
}
System.out.println();
}
static void printArray(String s, String[] ar) {
System.out.println("String array " + s);
for (int i = 0; i < ar.length; ++i) {
System.out.println(i + ": " + ar[i]);
}
System.out.println();
}
// ////////////////////////////////////////////////////////
/**
* initialize Taf engine
*
* @param configFile
* the configuration as a string (not a filename)
*/
void initialize(String config) throws UimacppException {
// for (int i = 0; i < casMgrSerializer.indexNames.length; i++) {
// System.out.println(casMgrSerializer.indexNames[i]);
// }
try {
initializeJNI(config);
} catch (Exception exc) {
throwJTafException(exc);
}
}
// ////////////////////////////////////////////////////////
/**
* reinit Taf engine type system
*
* @param serialized
* CAS definition
*/
void typeSystemInit(CASMgrSerializer casMgrSerializer) throws UimacppException {
// for (int i = 0; i < casMgrSerializer.indexNames.length; i++) {
// System.out.println(casMgrSerializer.indexNames[i]);
try {
typeSystemInitJNI(casMgrSerializer.typeNames, casMgrSerializer.featureNames,
casMgrSerializer.typeInheritance, casMgrSerializer.featDecls,
casMgrSerializer.topTypeCode, casMgrSerializer.featureOffsets,
casMgrSerializer.typeOrder, casMgrSerializer.stringSubtypes,
casMgrSerializer.stringSubtypeValues, casMgrSerializer.stringSubtypeValuePos,
casMgrSerializer.indexNames, casMgrSerializer.nameToIndexMap,
casMgrSerializer.indexingStrategy, casMgrSerializer.comparatorIndex,
casMgrSerializer.comparators);
} catch (Exception exc) {
throwJTafException(exc);
}
}
/**
* de-initializes the TAF engine.
*/
public void destroy() throws UimacppException {
try {
destroyJNI();
} catch (Exception exc) {
throwJTafException(exc);
}
}
private static void serializeResultSpecification(ResultSpecification rs, CASImpl cas,
IntVector resultSpecTypes, IntVector resultSpecFeatures) {
TypeOrFeature[] tofs = rs.getResultTypesAndFeatures();
TypeSystemImpl tsImpl = cas.getTypeSystemImpl();
for (int i = 0; i < tofs.length; ++i) {
if (tofs[i].isType()) {
TypeImpl t = (TypeImpl) tsImpl.getType(tofs[i].getName());
resultSpecTypes.add(t.getCode());
} else {
FeatureImpl f = (FeatureImpl) tsImpl.getFeatureByFullName(tofs[i].getName());
resultSpecFeatures.add(f.getCode());
}
}
}
/**
* process the document.
*/
public void process(ResultSpecification rs, CAS aCas, boolean casIsEmpty) throws UimacppException {
int isTCas=0;
String sofaName=aCas.getViewName();
if (sofaName != null) {
isTCas=1;
}
cas = aCas.getCurrentView();
try {
resetJNI();
if (!casIsEmpty) {
CASSerializer casSerializerIn = Serialization.serializeCAS(cas);
/**
* fillCASJNI(casSerializerIn.heapArray, casSerializerIn.fsIndex,
* casSerializerIn.stringTable);
*/
fillCASJNI(casSerializerIn.heapArray, casSerializerIn.fsIndex, casSerializerIn.stringTable,
casSerializerIn.byteHeapArray, casSerializerIn.shortHeapArray,
casSerializerIn.longHeapArray);
}
IntVector resultSpecTypes = new IntVector();
IntVector resultSpecFeatures = new IntVector();
if (rs != null) {
serializeResultSpecification(rs, (CASImpl) cas, resultSpecTypes, resultSpecFeatures);
}
processJNI(isTCas, sofaName, resultSpecTypes.toArray(), resultSpecFeatures.toArray());
// call hasNext() to see if this returns segments
// if there are no segments this will get the
// CAS data.
if (hasNext()) {
return;
}
} catch (Exception exc) {
throwJTafException(exc);
}
}
/**
* hasNext
*/
public boolean hasNext() throws UimacppException {
try {
hasNext = hasNextSegmentJNI();
// get the CAS data of the original input CAS.
if (!hasNext) {
CASSerializer casSerializerOut = new CASSerializer();
// per document data
serializeCASJNI(true);
casSerializerOut.heapMetaData = null;
casSerializerOut.heapArray = (int[]) getSerializedDataJNI(FSHEAP);
casSerializerOut.fsIndex = (int[]) getSerializedDataJNI(INDEXEDFSS);
casSerializerOut.stringTable = (String[]) getSerializedDataJNI(STRINGSYMBOL);
casSerializerOut.byteHeapArray = (byte[]) getSerializedDataJNI(BYTEHEAP);
casSerializerOut.shortHeapArray = (short[]) getSerializedDataJNI(SHORTHEAP);
casSerializerOut.longHeapArray = (long[]) getSerializedDataJNI(LONGHEAP);
CASMgr casMgr = (CASMgr) cas;
CAS newCAS = Serialization.createCAS(casMgr, casSerializerOut);
if (newCAS != casMgr) {
throw new RuntimeException("CASMgr and CAS should be identical");
}
}
} catch (Exception exc) {
throwJTafException(exc);
}
return hasNext;
}
/**
* next
*/
public void next(CAS segment) throws UimacppException {
try {
// get the CAS data of CAS produce by segmenter component.
if (hasNext) {
nextSegmentJNI();
CASSerializer casSerializerOut = new CASSerializer();
// per document data
serializeSegmentJNI(true);
casSerializerOut.heapMetaData = null;
casSerializerOut.heapArray = (int[]) getSerializedSegmentDataJNI(FSHEAP);
casSerializerOut.fsIndex = (int[]) getSerializedSegmentDataJNI(INDEXEDFSS);
casSerializerOut.stringTable = (String[]) getSerializedSegmentDataJNI(STRINGSYMBOL);
casSerializerOut.byteHeapArray = (byte[]) getSerializedSegmentDataJNI(BYTEHEAP);
casSerializerOut.shortHeapArray = (short[]) getSerializedSegmentDataJNI(SHORTHEAP);
casSerializerOut.longHeapArray = (long[]) getSerializedSegmentDataJNI(LONGHEAP);
releaseSegmentJNI();
CASMgr casMgr = (CASMgr) segment;
CAS newCAS = Serialization.createCAS(casMgr, casSerializerOut);
if (newCAS != casMgr) {
throw new RuntimeException("CASMgr and CAS should be identical");
}
} else {
throw new RuntimeException("This analysis component has no CASs to return.");
}
} catch (Exception exc) {
throwJTafException(exc);
}
}
/**
* batchProcessComplete
*/
public void batchProcessComplete() throws UimacppException {
try {
batchProcessCompleteJNI();
} catch (Exception exc) {
throwJTafException(exc);
}
}
/**
* CasConsumer collectionProcessComplete
*/
public void collectionProcessComplete() throws UimacppException {
try {
collectionProcessCompleteJNI();
} catch (Exception exc) {
throwJTafException(exc);
}
}
/**
* helper function to get the error message for some TAF error ID.
*/
public static String getErrorMessage(long errorCode) throws UimacppException {
try {
return getErrorMessageJNI(errorCode);
} catch (Exception exc) {
throwJTafException(exc);
}
return null;
}
/**
* helper function to get the TAF JNI version.
*/
public static String getTafJNIVersion() throws UimacppException {
try {
return getVersionJNI();
} catch (Exception exc) {
throwJTafException(exc);
}
return null;
}
static void throwJTafException(Exception exc) throws UimacppException {
if (exc instanceof InternalTafException) {
InternalTafException itExc = (InternalTafException) exc;
// check special errors
long l = itExc.getTafErrorCode();
switch ((int) l) {
case 1000:
case 5000:
case 10000:
throw new OutOfMemoryError();
}
// TafException tafException = new TafException(
// itExc.getTafErrorCode(), exc.getMessage() );
throw new UimacppException(itExc);
} else {
throw new UimacppException(exc);
}
}
// //////////////////////////////////////////////////
protected void finalize() throws Throwable {
synchronized (this) {
if (cppEnginePointer != 0) {
try {
// sets cppEnginePointer to 0
destructorJNI();
} catch (Exception exc) {
throw new UIMARuntimeException(exc);
}
}
super.finalize();
}
}
}
class InternalTafException extends Exception {
private static final long serialVersionUID = -6558646639254861394L;
long errorCode = -1;
public InternalTafException(String message, long error) {
super(message + " (" + error + ")");
errorCode = error;
}
public long getTafErrorCode() {
return errorCode;
}
public String getMessage() {
return super.getMessage();
}
}