/******************************************************************************* * Copyright (c) 2006-2010 eBay Inc. All Rights Reserved. * Licensed 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 *******************************************************************************/ package org.ebayopensource.turmeric.runtime.common.impl.pipeline; import java.util.List; import java.util.Map; import java.util.logging.Level; import org.ebayopensource.turmeric.runtime.common.exceptions.ServiceException; import org.ebayopensource.turmeric.runtime.common.impl.utils.LogManager; import org.ebayopensource.turmeric.runtime.common.impl.utils.ReflectionUtils; import org.ebayopensource.turmeric.runtime.common.monitoring.MetricCategory; import org.ebayopensource.turmeric.runtime.common.monitoring.MetricDef; import org.ebayopensource.turmeric.runtime.common.monitoring.MetricsCollector; import org.ebayopensource.turmeric.runtime.common.monitoring.MetricsRegistry; import org.ebayopensource.turmeric.runtime.common.monitoring.MonitoringLevel; import org.ebayopensource.turmeric.runtime.common.monitoring.value.AverageMetricValue; import org.ebayopensource.turmeric.runtime.common.monitoring.value.LongSumMetricValue; import org.ebayopensource.turmeric.runtime.common.monitoring.value.MetricValue; import org.ebayopensource.turmeric.runtime.common.monitoring.value.MetricValueAggregator; import org.ebayopensource.turmeric.runtime.common.pipeline.Handler; import org.ebayopensource.turmeric.runtime.common.pipeline.HandlerOptions; import org.ebayopensource.turmeric.runtime.common.pipeline.MessageContext; import org.ebayopensource.turmeric.runtime.common.pipeline.Pipeline; import org.ebayopensource.turmeric.runtime.common.pipeline.PipelineMode; import org.ebayopensource.turmeric.runtime.common.service.ServiceId; import org.ebayopensource.turmeric.common.v1.types.ErrorData; import org.ebayopensource.turmeric.common.v1.types.ErrorSeverity; /** * @author ichernyshev, smalladi */ public class PipelineImpl implements Pipeline { //private ServiceId m_serviceId; private PipelineMode m_pipelineMode; private PipelineHandlerConnectorImpl[] m_handlers; /** * Create new pipeline instance according to the passed configuration */ public void init(InitContext ctx) throws ServiceException { ServiceId svcId = ctx.getServiceId(); PipelineMode pipelineMode = ctx.getPipelineMode(); List<HandlerOptions> handlerConfigs = ctx.getHandlerConfigs(); ClassLoader cl = ctx.getClassLoader(); int handlerCount = handlerConfigs.size(); PipelineHandlerConnectorImpl[] handlers = new PipelineHandlerConnectorImpl[handlerCount]; for (int i=0; i<handlerCount; i++) { HandlerOptions config = handlerConfigs.get(i); String name = config.getName(); String className = config.getClassName(); String fullName = svcId.getAdminName() + "." + name; boolean isContinueOnError = config.isContinueOnError(); boolean isErrorSafe = config.isRunOnError(); Map<String,String> options = config.getOptions(); Handler handler = ReflectionUtils.createInstance(className, Handler.class, cl); HandlerInitContextImpl initCtx = new HandlerInitContextImpl(svcId, name, options); handler.init(initCtx); initCtx.kill(); MetricValueAggregator metricTime = getMetric(svcId, name, pipelineMode, "Time", MonitoringLevel.FINE, MetricCategory.Timing, AverageMetricValue.class); MetricValueAggregator metricErrors = getMetric(svcId, name, pipelineMode, "Err", MonitoringLevel.FINE, MetricCategory.Error, LongSumMetricValue.class); handlers[i] = new PipelineHandlerConnectorImpl(handler, name, fullName, isContinueOnError, isErrorSafe, metricTime, metricErrors); } m_pipelineMode = pipelineMode; m_handlers = handlers; } private String getMetricName(String metricShortName, String handlerName, PipelineMode pipelineMode) { StringBuilder sb = new StringBuilder(); sb.append("SoaFwk."); sb.append(metricShortName); sb.append('.'); if (pipelineMode == PipelineMode.REQUEST) { sb.append("Request"); } else { sb.append("Response"); } sb.append("Pipeline."); for (int i=0; i<handlerName.length(); i++) { char c = handlerName.charAt(i); if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_') { sb.append(c); } else { sb.append('_'); } } return sb.toString(); } private MetricValueAggregator getMetric(ServiceId svcId, String handlerName, PipelineMode pipelineMode, String metricShortName, MonitoringLevel level, MetricCategory category, Class<? extends MetricValue> valueClass) throws ServiceException { boolean isClientSide = svcId.isClientSide(); MetricValueAggregator result = null; try { String metricName = getMetricName(metricShortName, handlerName, pipelineMode); MetricDef def = new MetricDef(metricName, MetricDef.SVC_APPLY_TO_ALL, MetricDef.OP_DONT_CARE, level, category, valueClass); if (isClientSide) { MetricsRegistry.getClientInstance().registerMetric(def); result = MetricsCollector.getClientInstance().getMetricValue(metricName, svcId, null); } else { MetricsRegistry.getServerInstance().registerMetric(def); result = MetricsCollector.getServerInstance().getMetricValue(metricName, svcId, null); } } catch (Exception e) { LogManager.getInstance(this.getClass()).log(Level.WARNING, "Error registering metrics for handler " + handlerName + " in " + svcId.getAdminName() + " : " + e.toString(), e); } return result; } public void invoke(MessageContext ctx) throws ServiceException { for (int i=0; i<m_handlers.length; i++) { PipelineHandlerConnectorImpl handler = m_handlers[i]; try { handler.invoke(ctx); } catch (ServiceException e) { handleError(ctx, handler, e); } catch (RuntimeException e) { handleError(ctx, handler, e); } } } private void handleError(MessageContext ctx, PipelineHandlerConnectorImpl handler, Throwable e) { LogManager.getInstance(PipelineImpl.class).log(Level.INFO, "Handler " + handler.getFullName() + " failed to execute due to: " + e.toString(), e); if (handler.isContinueOnError()) { ctx.addWarning(e); } else { ctx.addError(e); } } public PipelineMode getMode() { return m_pipelineMode; } private static class PipelineHandlerConnectorImpl { private final Handler m_handler; private final String m_name; private final String m_fullName; private final boolean m_isContinueOnError; private final boolean m_isErrorSafe; private final MetricValueAggregator m_metricTime; private final MetricValueAggregator m_metricErrors; public PipelineHandlerConnectorImpl(Handler handler, String name, String fullName, boolean isContinueOnError, boolean isErrorSafe, MetricValueAggregator metricTime, MetricValueAggregator metricErrors) { m_handler = handler; m_name = name; m_fullName = fullName; m_isContinueOnError = isContinueOnError; m_isErrorSafe = isErrorSafe; m_metricTime = metricTime; m_metricErrors = metricErrors; } public void invoke(MessageContext ctx) throws ServiceException { List<Throwable> errors = ctx.getErrorList(); int origErrCount = (errors != null ? errors.size() : 0); /** * The error count is now inclusive of RRE's */ origErrCount += ctx.hasResponseResidentErrors() ? ctx.getResponseResidentErrorList().size() : 0; if (!m_isErrorSafe && origErrCount > 0) { // skip error-unsafe handlers if we have errors return; } if (m_metricTime != null && m_metricTime.isEnabled()) { long startTime = System.nanoTime(); try { invokeHandler(ctx); } finally { long duration = System.nanoTime() - startTime; m_metricTime.update(duration); } } else { invokeHandler(ctx); } errors = ctx.getErrorList(); int newErrCount = (errors != null ? errors.size() : 0); newErrCount += getResponseResidentErrorCount( ctx ); if (newErrCount > origErrCount && m_metricErrors != null && m_metricErrors.isEnabled()) { m_metricErrors.update(1); } } /** * Fetch the number of "errors" in the RRE * @param ctx * @return */ private int getResponseResidentErrorCount( MessageContext ctx ) { int count = 0; if ( ctx.hasResponseResidentErrors() ) { for ( ErrorData errorData : ctx.getResponseResidentErrorList() ) if ( errorData.getSeverity() == ErrorSeverity.ERROR ) ++count; } return count; } public String getName() { return m_name; } public String getFullName() { return m_fullName; } public String getHandlerType() { return m_handler.getClass().getName(); } public boolean isContinueOnError() { return m_isContinueOnError; } public boolean isErrorSafe() { return m_isErrorSafe; } private void invokeHandler(MessageContext ctx) throws ServiceException { m_handler.invoke(ctx); } } }