Author: cwiklik Date: Wed Aug 9 23:44:31 2017 New Revision: 1804614 URL: http://svn.apache.org/viewvc?rev=1804614&view=rev Log: UIMA-5529 improved serialization of exceptions
Modified: uima/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/configuration/jp/HttpWorkerThread.java uima/uima-ducc/trunk/uima-ducc-user/src/main/java/org/apache/uima/ducc/user/jp/DuccAbstractProcessContainer.java uima/uima-ducc/trunk/uima-ducc-user/src/main/java/org/apache/uima/ducc/user/jp/UimaASProcessContainer.java uima/uima-ducc/trunk/uima-ducc-user/src/main/java/org/apache/uima/ducc/user/jp/UimaProcessContainer.java Modified: uima/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/configuration/jp/HttpWorkerThread.java URL: http://svn.apache.org/viewvc/uima/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/configuration/jp/HttpWorkerThread.java?rev=1804614&r1=1804613&r2=1804614&view=diff ============================================================================== --- uima/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/configuration/jp/HttpWorkerThread.java (original) +++ uima/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/configuration/jp/HttpWorkerThread.java Wed Aug 9 23:44:31 2017 @@ -308,8 +308,19 @@ public class HttpWorkerThread implements break; } IMetaCas mc = transaction.getMetaCas(); - // strip InvocationTargetException - byte[] serializedException = serializeException(ee.getCause()); + //byte[] serializedException = null; + Method getLastSerializedErrorMethod = processorInstance.getClass().getDeclaredMethod("getLastSerializedError"); + byte[] serializedException = + (byte[])getLastSerializedErrorMethod.invoke(processorInstance); + +// if ( ee.getCause() instanceof DuccUimaProcessException ) { +// // The process() exception had been serialized on the user side of the JP since +// // only there the Classloader has all the classes to serialize the exception. +// serializedException = ((DuccUimaProcessException)ee.getCause()).getSerializedException(); +// } else { +// // strip InvocationTargetException +// serializedException = serializeException(ee.getCause()); +// } /* ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); Modified: uima/uima-ducc/trunk/uima-ducc-user/src/main/java/org/apache/uima/ducc/user/jp/DuccAbstractProcessContainer.java URL: http://svn.apache.org/viewvc/uima/uima-ducc/trunk/uima-ducc-user/src/main/java/org/apache/uima/ducc/user/jp/DuccAbstractProcessContainer.java?rev=1804614&r1=1804613&r2=1804614&view=diff ============================================================================== --- uima/uima-ducc/trunk/uima-ducc-user/src/main/java/org/apache/uima/ducc/user/jp/DuccAbstractProcessContainer.java (original) +++ uima/uima-ducc/trunk/uima-ducc-user/src/main/java/org/apache/uima/ducc/user/jp/DuccAbstractProcessContainer.java Wed Aug 9 23:44:31 2017 @@ -43,6 +43,8 @@ import org.apache.uima.resource.metadata import org.apache.uima.resource.metadata.TypePriorities; import org.apache.uima.resource.metadata.TypeSystemDescription; import org.apache.uima.util.CasCreationUtils; +import org.apache.uima.util.Level; +import org.apache.uima.util.Logger; public abstract class DuccAbstractProcessContainer implements IProcessContainer{ // Container implementation must implement the following methods @@ -51,7 +53,9 @@ public abstract class DuccAbstractProces protected abstract void doStop() throws Exception; protected abstract List<Properties> doProcess(Object subject) throws Exception; protected AnalysisEngineMetaData analysisEngineMetadata; - + // Stores errors caught in doProcess() with key= current thread id. Each thread + // clears previous error in process() below before calling doProcess() + protected Map<Long, Throwable> errorMap = new HashMap<Long, Throwable>(); protected int scaleout=1; // Map to store DuccUimaSerializer instances. Each has affinity to a thread protected static Map<Long, DuccUimaSerializer> serializerMap = @@ -134,7 +138,10 @@ public abstract class DuccAbstractProces // a context cl before calling user code. ClassLoader savedCL = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader()); - try { + // Clear previous error this thread may have added in doProcess() + errorMap.remove(Thread.currentThread().getId()); + + try { return doProcess(xmi); }finally { Thread.currentThread().setContextClassLoader(savedCL); @@ -164,10 +171,14 @@ public abstract class DuccAbstractProces t.printStackTrace(new PrintWriter(sw)); serializedCause = sw.toString(); } catch (Throwable e) { - e.printStackTrace(); + try { + Logger logger = UIMAFramework.getLogger(DuccAbstractProcessContainer.class); + logger.log(Level.WARNING, "Unable to Stringfiy "+t.getClass().getName()); + + } catch( Exception ee) {} // Unable to serialize user Exception (not Serializable?) // Just send a simple msg telling user to check service log - serializedCause = "Unable to Serialize User Exception - Please Check JP Log File For More Details"; + serializedCause = "Unable to Stringifiy Exception "+t.getClass().getName()+" - Please Check JP Log File For More Details"; } return serializedCause; } @@ -178,16 +189,44 @@ public abstract class DuccAbstractProces try { oos.writeObject(t); } catch (Exception e) { - e.printStackTrace(); - // Unable to serialize user Exception (not Serializable?) - // Create a new Exception and serialize it - RuntimeException re - = new RuntimeException("Unable to Serialize User Exception - Please Check JP Log File For More Details"); - oos.writeObject(re); + try { + Logger logger = UIMAFramework.getLogger(DuccAbstractProcessContainer.class); + logger.log(Level.WARNING, "Unable to Serialize "+t.getClass().getName()+" - Will Stringify It Instead"); + + } catch( Exception ee) {} + throw e; + } finally { + oos.close(); } - oos.close(); + return baos.toByteArray(); } + protected byte[] getLastSerializedError() throws Exception { + byte[] result = null; + if (errorMap.containsKey(Thread.currentThread().getId())) { + Throwable lastError = + errorMap.get(Thread.currentThread().getId()); + + if ( System.getProperty("SendExceptionAsString")!= null ) { + // the client of this JP/Service does not have user classpath + // to be able to deserialize this exception. Instead of serializing + // the exception as a java object, stringify it first and wrap it. + // The client process might want to log this error. + result = serialize(new RuntimeException(serializeAsString(lastError))); + } else { + try { + // try to serialize as java Object + result = serialize(lastError); + } catch( Exception e) { + // Fallback is to stringify the exception and wrap it + result = serialize(new RuntimeException(serializeAsString(lastError))); + } + + } + } + return result; + } + private Socket connectWithAgent() throws Exception { InetAddress host = null; int statusUpdatePort = -1; Modified: uima/uima-ducc/trunk/uima-ducc-user/src/main/java/org/apache/uima/ducc/user/jp/UimaASProcessContainer.java URL: http://svn.apache.org/viewvc/uima/uima-ducc/trunk/uima-ducc-user/src/main/java/org/apache/uima/ducc/user/jp/UimaASProcessContainer.java?rev=1804614&r1=1804613&r2=1804614&view=diff ============================================================================== --- uima/uima-ducc/trunk/uima-ducc-user/src/main/java/org/apache/uima/ducc/user/jp/UimaASProcessContainer.java (original) +++ uima/uima-ducc/trunk/uima-ducc-user/src/main/java/org/apache/uima/ducc/user/jp/UimaASProcessContainer.java Wed Aug 9 23:44:31 2017 @@ -41,7 +41,6 @@ import org.apache.uima.aae.client.UimaAs import org.apache.uima.aae.client.UimaAsynchronousEngine; import org.apache.uima.aae.monitor.statistics.AnalysisEnginePerformanceMetrics; import org.apache.uima.adapter.jms.client.BaseUIMAAsynchronousEngine_impl; -import org.apache.uima.analysis_engine.AnalysisEngineProcessException; import org.apache.uima.cas.CAS; import org.apache.uima.collection.EntityProcessStatus; import org.apache.uima.ducc.IUser; @@ -314,7 +313,19 @@ public class UimaASProcessContainer ext if ( enablePerformanceBreakdownReporting ) { List<AnalysisEnginePerformanceMetrics> perfMetrics = new ArrayList<AnalysisEnginePerformanceMetrics>(); - uimaASClient.sendAndReceiveCAS(cas, perfMetrics); + + try { + uimaASClient.sendAndReceiveCAS(cas, perfMetrics); + } catch( Throwable t) { + // save the error + errorMap.put(Thread.currentThread().getId(), t); + // AE failed, throw an exception. The HttpWorketThread will + // subsequently call getLastSerializedException() on this class + // to fetch serialized exception saved in 'lastError' above. + // The 'lastError' is reset each time super.process() is called. + throw new RuntimeException(); + } + for( AnalysisEnginePerformanceMetrics metrics : perfMetrics ) { Properties p = new Properties(); p.setProperty("name", metrics.getName()); @@ -333,7 +344,19 @@ public class UimaASProcessContainer ext } } else { // delegate processing to the UIMA-AS service and wait for a reply - uimaASClient.sendAndReceiveCAS(cas);//, perfMetrics); + try { + uimaASClient.sendAndReceiveCAS(cas); + } catch( Throwable t) { + // save the error + errorMap.put(Thread.currentThread().getId(), t); + // AE failed, throw an exception. The HttpWorketThread will + // subsequently call getLastSerializedException() on this class + // to fetch serialized exception saved in errorMap above. + // The map entry for each thread is reset in super.process(). + + throw new RuntimeException(); + } + // convert UIMA-AS metrics into properties so that we can return this // data in a format which doesnt require UIMA-AS to digest Properties p = new Properties(); @@ -346,15 +369,16 @@ public class UimaASProcessContainer ext return metricsList; } catch( Throwable t ) { - Logger logger = UIMAFramework.getLogger(); - logger.log(Level.WARNING, "UimaProcessContainer", t); - throw new RuntimeException(super.serializeAsString(t)); + throw t; } finally { if ( cas != null) { cas.release(); } } } + public byte[] getLastSerializedError() throws Exception { + return super.getLastSerializedError(); + } private String getPID(final String fallback) { // the following code returns '<pid>@<hostname>' String name = ManagementFactory.getRuntimeMXBean().getName(); Modified: uima/uima-ducc/trunk/uima-ducc-user/src/main/java/org/apache/uima/ducc/user/jp/UimaProcessContainer.java URL: http://svn.apache.org/viewvc/uima/uima-ducc/trunk/uima-ducc-user/src/main/java/org/apache/uima/ducc/user/jp/UimaProcessContainer.java?rev=1804614&r1=1804613&r2=1804614&view=diff ============================================================================== --- uima/uima-ducc/trunk/uima-ducc-user/src/main/java/org/apache/uima/ducc/user/jp/UimaProcessContainer.java (original) +++ uima/uima-ducc/trunk/uima-ducc-user/src/main/java/org/apache/uima/ducc/user/jp/UimaProcessContainer.java Wed Aug 9 23:44:31 2017 @@ -21,7 +21,6 @@ package org.apache.uima.ducc.user.jp; import java.io.File; -import java.io.PrintWriter; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; @@ -34,7 +33,6 @@ import java.util.concurrent.atomic.Atomi import org.apache.uima.UIMAFramework; import org.apache.uima.analysis_engine.AnalysisEngine; import org.apache.uima.analysis_engine.AnalysisEngineManagement; -import org.apache.uima.analysis_engine.AnalysisEngineProcessException; import org.apache.uima.cas.CAS; import org.apache.uima.ducc.user.common.UimaUtils; import org.apache.uima.ducc.user.jp.uima.UimaAnalysisEngineInstancePoolWithThreadAffinity; @@ -107,6 +105,7 @@ public class UimaProcessContainer extend return scaleout; } + public int doInitialize(Properties props, String[] args) throws Exception { return configureAndGetScaleout(args); } @@ -186,7 +185,22 @@ public class UimaProcessContainer extend // the following checks out AE instance pinned to this thread ae = instanceMap.checkout(); List<AnalysisEnginePerformanceMetrics> beforeAnalysis = getMetrics(ae); - ae.process(cas); + + // Handle AnalysisEngineProcessException + try { + ae.process(cas); + } catch( Throwable t) { + // save the error + errorMap.put(Thread.currentThread().getId(), t); + // AE failed, throw an exception. The HttpWorketThread will + // subsequently call getLastSerializedException() on this class + // to fetch serialized exception saved in errorMap above. + // The map entry for each thread is reset in super.process(). + throw new RuntimeException(); + } + // ***************************************************** + // No exception in process() , return metrics as a List + // ***************************************************** List<AnalysisEnginePerformanceMetrics> afterAnalysis = getMetrics(ae); // get the delta @@ -210,11 +224,9 @@ public class UimaProcessContainer extend metricsList.add(p); } return metricsList; - } catch( Throwable t ) { - Logger logger = UIMAFramework.getLogger(); - logger.log(Level.WARNING, "UimaProcessContainer", t); - throw new RuntimeException(super.serializeAsString(t)); - } + } catch( Throwable tt ) { + throw tt; + } finally { if (ae != null) { instanceMap.checkin(ae); @@ -224,6 +236,9 @@ public class UimaProcessContainer extend } } } + public byte[] getLastSerializedError() throws Exception { + return super.getLastSerializedError(); + } private List<AnalysisEnginePerformanceMetrics> getMetrics(AnalysisEngine ae) throws Exception { List<AnalysisEnginePerformanceMetrics> analysisManagementObjects = new ArrayList<AnalysisEnginePerformanceMetrics>();