/************************************************************************************** * Copyright (C) 2008 EsperTech, Inc. All rights reserved. * * http://esper.codehaus.org * * http://www.espertech.com * * ---------------------------------------------------------------------------------- * * The software in this package is published under the terms of the GPL license * * a copy of which has been included with this distribution in the license.txt file. * **************************************************************************************/ package com.espertech.esper.core.service; import com.asper.sources.net.sf.cglib.reflect.FastClass; import com.asper.sources.net.sf.cglib.reflect.FastMethod; import com.espertech.esper.client.EPException; import com.espertech.esper.client.EventBean; import com.espertech.esper.collection.UniformPair; import com.espertech.esper.event.NaturalEventBean; import com.espertech.esper.util.JavaClassHelper; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; /** * A result delivery strategy that uses a matching "update" method and * optional start, end, and updateRStream methods, to deliver column-wise to parameters * of the update method. */ public class ResultDeliveryStrategyImpl implements ResultDeliveryStrategy { private static Log log = LogFactory.getLog(ResultDeliveryStrategyImpl.class); private final String statementName; private final Object subscriber; private final FastMethod updateFastMethod; private final FastMethod startFastMethod; private final FastMethod endFastMethod; private final FastMethod updateRStreamFastMethod; private final DeliveryConvertor deliveryConvertor; /** * Ctor. * @param subscriber is the subscriber receiving method invocations * @param deliveryConvertor for converting individual rows * @param method to deliver the insert stream to * @param startMethod to call to indicate when delivery starts, or null if no such indication is required * @param endMethod to call to indicate when delivery ends, or null if no such indication is required * @param rStreamMethod to deliver the remove stream to, or null if no such indication is required */ public ResultDeliveryStrategyImpl(String statementName, Object subscriber, DeliveryConvertor deliveryConvertor, Method method, Method startMethod, Method endMethod, Method rStreamMethod) { this.statementName = statementName; this.subscriber = subscriber; this.deliveryConvertor = deliveryConvertor; FastClass fastClass = FastClass.create(Thread.currentThread().getContextClassLoader(), subscriber.getClass()); this.updateFastMethod = fastClass.getMethod(method); if (startMethod != null) { startFastMethod = fastClass.getMethod(startMethod); } else { startFastMethod = null; } if (endMethod != null) { endFastMethod = fastClass.getMethod(endMethod); } else { endFastMethod = null; } if (rStreamMethod != null) { updateRStreamFastMethod = fastClass.getMethod(rStreamMethod); } else { updateRStreamFastMethod = null; } } public void execute(UniformPair<EventBean[]> result) { if (startFastMethod != null) { int countNew = 0; int countOld = 0; if (result != null) { countNew = count(result.getFirst()); countOld = count(result.getSecond()); } Object[] parameters = new Object[] {countNew, countOld}; try { startFastMethod.invoke(subscriber, parameters); } catch (InvocationTargetException e) { handle(statementName, log, e, parameters, subscriber, startFastMethod); } catch (Throwable t) { handleThrowable(log, t, null, subscriber, startFastMethod); } } EventBean[] newData = null; EventBean[] oldData = null; if (result != null) { newData = result.getFirst(); oldData = result.getSecond(); } if ((newData != null) && (newData.length > 0)) { for (int i = 0; i < newData.length; i++) { EventBean theEvent = newData[i]; if (theEvent instanceof NaturalEventBean) { NaturalEventBean natural = (NaturalEventBean) theEvent; Object[] parameters = deliveryConvertor.convertRow(natural.getNatural()); try { updateFastMethod.invoke(subscriber, parameters); } catch (InvocationTargetException e) { handle(statementName, log, e, parameters, subscriber, updateFastMethod); } catch (Throwable t) { handleThrowable(log, t, parameters, subscriber, updateFastMethod); } } } } if ((updateRStreamFastMethod != null) && (oldData != null) && (oldData.length > 0)) { for (int i = 0; i < oldData.length; i++) { EventBean theEvent = oldData[i]; if (theEvent instanceof NaturalEventBean) { NaturalEventBean natural = (NaturalEventBean) theEvent; Object[] parameters = deliveryConvertor.convertRow(natural.getNatural()); try { updateRStreamFastMethod.invoke(subscriber, parameters); } catch (InvocationTargetException e) { handle(statementName, log, e, parameters, subscriber, updateRStreamFastMethod); } catch (Throwable t) { handleThrowable(log, t, parameters, subscriber, updateRStreamFastMethod); } } } } if (endFastMethod != null) { try { endFastMethod.invoke(subscriber, null); } catch (InvocationTargetException e) { handle(statementName, log, e, null, subscriber, endFastMethod); } catch (Throwable t) { handleThrowable(log, t, null, subscriber, endFastMethod); } } } /** * Handle the exception, displaying a nice message and converting to {@link EPException}. * @param logger is the logger to use for error logging * @param e is the exception * @param parameters the method parameters * @param subscriber the object to deliver to * @param method the method to call * @throws EPException converted from the passed invocation exception */ protected static void handle(String statementName, Log logger, InvocationTargetException e, Object[] parameters, Object subscriber, FastMethod method) { String message = JavaClassHelper.getMessageInvocationTarget(statementName, method.getJavaMethod(), subscriber.getClass().getName(), parameters, e); logger.error(message, e.getTargetException()); } /** * Handle the exception, displaying a nice message and converting to {@link EPException}. * @param logger is the logger to use for error logging * @param t is the throwable * @param parameters the method parameters * @param subscriber the object to deliver to * @param method the method to call * @throws EPException converted from the passed invocation exception */ protected static void handleThrowable(Log logger, Throwable t, Object[] parameters, Object subscriber, FastMethod method) { String message = "Unexpected exception when invoking method '" + method.getName() + "' on subscriber class '" + subscriber.getClass().getSimpleName() + "' for parameters " + ((parameters == null) ? "null" : Arrays.toString(parameters)) + " : " + t.getClass().getSimpleName() + " : " + t.getMessage(); logger.error(message, t); } private int count(EventBean[] events) { if (events == null) { return 0; } int count = 0; for (int i = 0; i < events.length; i++) { EventBean theEvent = events[i]; if (theEvent instanceof NaturalEventBean) { count++; } } return count; } }