/** * Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.engine.exec; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.lang.ObjectUtils; import org.apache.commons.lang.text.StrBuilder; import com.opengamma.engine.ComputationTargetSpecification; import com.opengamma.engine.view.AggregatedExecutionLog; import com.opengamma.engine.view.ExecutionLog; import com.opengamma.engine.view.ExecutionLogMode; import com.opengamma.engine.view.ExecutionLogWithContext; import com.opengamma.util.ArgumentChecker; import com.opengamma.util.log.LogLevel; /** * Default implementation of {@link AggregatedExecutionLog}. * <p> * In {@link ExecutionLogMode#INDICATORS} mode, the root log and dependent logs are inspected to obtain an aggregate of the log levels, but no individual logs are stored. In * {@link ExecutionLogMode#FULL} mode, individual non-empty logs are also stored. */ public final class DefaultAggregatedExecutionLog implements AggregatedExecutionLog { private static volatile Map<EnumSet<LogLevel>, DefaultAggregatedExecutionLog> s_indicatorInstances = Collections.emptyMap(); private final EnumSet<LogLevel> _logLevels; private final List<ExecutionLogWithContext> _logs; /** * Flag to indicate whether the execution log at the root level was empty and has been excluded. */ private final boolean _emptyRoot; /** * Constructs an instance for a root level with possible logs from its dependencies when the full logging mode is being used. * * @param functionName the name of the function, not null * @param target the computation target specification, not null * @param rootLog the root log, not null * @param dependentLogs the dependent logs, if any, may be null or empty * @return the log instance */ public static DefaultAggregatedExecutionLog fullLogMode(String functionName, ComputationTargetSpecification target, ExecutionLog rootLog, Collection<AggregatedExecutionLog> dependentLogs) { ArgumentChecker.notNull(functionName, "functionName"); ArgumentChecker.notNull(target, "target"); ArgumentChecker.notNull(rootLog, "rootLog"); EnumSet<LogLevel> logLevels = rootLog.getLogLevels(); boolean logLevelsCopied = false; final List<ExecutionLogWithContext> logs = new ArrayList<ExecutionLogWithContext>(); boolean emptyRoot = rootLog.isEmpty(); if (!emptyRoot) { logs.add(ExecutionLogWithContext.of(functionName, target, rootLog)); } if (dependentLogs != null) { for (AggregatedExecutionLog dependentLog : dependentLogs) { final EnumSet<LogLevel> dependentLogLevels = dependentLog.getLogLevels(); if (logLevelsCopied) { logLevels.addAll(dependentLogLevels); } else { if (!logLevels.equals(dependentLogLevels)) { logLevels = EnumSet.copyOf(logLevels); logLevels.addAll(dependentLogLevels); logLevelsCopied = true; } } if (dependentLog.getLogs() != null) { logs.addAll(dependentLog.getLogs()); } } } return new DefaultAggregatedExecutionLog(logLevels, logs, emptyRoot); } /** * Constructs an instance for a root level with possible logs from its dependencies when the indicator-only logging mode is being used. * * @param rootLogLevels the root log indicators, not null * @return the log instance */ public static DefaultAggregatedExecutionLog indicatorLogMode(EnumSet<LogLevel> rootLogLevels) { Map<EnumSet<LogLevel>, DefaultAggregatedExecutionLog> indicators = s_indicatorInstances; final DefaultAggregatedExecutionLog existing = indicators.get(rootLogLevels); if (existing != null) { return existing; } final DefaultAggregatedExecutionLog log = new DefaultAggregatedExecutionLog(rootLogLevels, null, false); indicators = new HashMap<EnumSet<LogLevel>, DefaultAggregatedExecutionLog>(indicators); indicators.put(rootLogLevels, log); s_indicatorInstances = indicators; return log; } /** * Constructs an instance from the internal fields. * <p> * Public for deserialization only. Performs no consistency checking of the inputs. * * @param logLevels an overview of the log levels, not null * @param logs the individual logs, null if not available * @param emptyRoot true if the root log was empty, false otherwise */ public DefaultAggregatedExecutionLog(EnumSet<LogLevel> logLevels, List<ExecutionLogWithContext> logs, boolean emptyRoot) { _logLevels = logLevels; _logs = logs; _emptyRoot = emptyRoot; } @Override public EnumSet<LogLevel> getLogLevels() { return _logLevels; } @Override public ExecutionLogWithContext getRootLog() { return _logs != null && !_emptyRoot ? _logs.get(0) : null; } @Override public List<ExecutionLogWithContext> getLogs() { return _logs; } //------------------------------------------------------------------------- @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + _logLevels.hashCode(); result = prime * result + (_emptyRoot ? 1231 : 1237); result = prime * result + ((_logs == null) ? 0 : _logs.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof DefaultAggregatedExecutionLog)) { return false; } // Optimise for the majority of cases where no logs have been collected. // If logs are present then don't perform detailed equality checking, just check instance equality. DefaultAggregatedExecutionLog other = (DefaultAggregatedExecutionLog) obj; return ObjectUtils.equals(_logLevels, other._logLevels) && ObjectUtils.equals(_logs, other._logs) && _emptyRoot == other._emptyRoot; } //------------------------------------------------------------------------- @Override public String toString() { StrBuilder sb = new StrBuilder() .append("AggLog["); if (!getLogLevels().isEmpty()) { sb.append("aggLevels=").append(getLogLevels()); if (getLogs() != null) { sb.append(", logs=").append(getLogs()); } } sb.append(']'); return sb.toString(); } }