/**
* AnalyzerBeans
* Copyright (C) 2014 Neopost - Customer Information Management
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.eobjects.analyzer.job.runner;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.eobjects.analyzer.data.InputColumn;
import org.eobjects.analyzer.data.InputRow;
import org.eobjects.analyzer.job.AnalysisJob;
import org.eobjects.analyzer.job.AnyComponentRequirement;
import org.eobjects.analyzer.job.ComponentJob;
import org.eobjects.analyzer.job.ComponentRequirement;
import org.eobjects.analyzer.job.HasComponentRequirement;
import org.eobjects.analyzer.job.InputColumnSinkJob;
import org.eobjects.analyzer.util.SourceColumnFinder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Abstract implementation of {@link RowProcessingConsumer}. Contains utility
* methods to help make the 'is satisfied for execution' methods easier to
* implement.
*/
abstract class AbstractRowProcessingConsumer implements RowProcessingConsumer {
private static final Logger logger = LoggerFactory.getLogger(AbstractRowProcessingConsumer.class);
private final AnalysisJob _analysisJob;
private final AnalysisListener _analysisListener;
private final HasComponentRequirement _hasComponentRequirement;
private final Set<HasComponentRequirement> _sourceJobsOfInputColumns;
private final boolean _alwaysSatisfiedForConsume;
protected AbstractRowProcessingConsumer(RowProcessingPublishers publishers, HasComponentRequirement outcomeSinkJob,
InputColumnSinkJob inputColumnSinkJob) {
this(publishers.getAnalysisJob(), publishers.getAnalysisListener(), outcomeSinkJob, inputColumnSinkJob,
publishers.getSourceColumnFinder());
}
protected AbstractRowProcessingConsumer(AnalysisJob analysisJob, AnalysisListener analysisListener,
HasComponentRequirement outcomeSinkJob, InputColumnSinkJob inputColumnSinkJob,
SourceColumnFinder sourceColumnFinder) {
this(analysisJob, analysisListener, outcomeSinkJob, buildSourceJobsOfInputColumns(inputColumnSinkJob,
sourceColumnFinder));
}
protected AbstractRowProcessingConsumer(AnalysisJob analysisJob, AnalysisListener analysisListener,
HasComponentRequirement outcomeSinkJob, Set<HasComponentRequirement> sourceJobsOfInputColumns) {
_analysisJob = analysisJob;
_analysisListener = analysisListener;
_hasComponentRequirement = outcomeSinkJob;
_sourceJobsOfInputColumns = sourceJobsOfInputColumns;
_alwaysSatisfiedForConsume = isAlwaysSatisfiedForConsume();
}
private boolean isAlwaysSatisfiedForConsume() {
if (_sourceJobsOfInputColumns.isEmpty()) {
return true;
}
if (isAlwaysSatisfiedRequirement()) {
return true;
}
return false;
}
private boolean isAlwaysSatisfiedRequirement() {
final ComponentRequirement componentRequirement = _hasComponentRequirement.getComponentRequirement();
if (componentRequirement == null) {
return false;
}
if (componentRequirement instanceof AnyComponentRequirement) {
return true;
}
return false;
}
private static Set<HasComponentRequirement> buildSourceJobsOfInputColumns(InputColumnSinkJob inputColumnSinkJob,
SourceColumnFinder sourceColumnFinder) {
final Set<HasComponentRequirement> result = new HashSet<HasComponentRequirement>();
final Set<Object> sourceJobsOfInputColumns = sourceColumnFinder.findAllSourceJobs(inputColumnSinkJob);
for (Iterator<Object> it = sourceJobsOfInputColumns.iterator(); it.hasNext();) {
final Object sourceJob = it.next();
if (sourceJob instanceof HasComponentRequirement) {
final HasComponentRequirement sourceOutcomeSinkJob = (HasComponentRequirement) sourceJob;
final ComponentRequirement componentRequirement = sourceOutcomeSinkJob.getComponentRequirement();
if (componentRequirement != null) {
result.add(sourceOutcomeSinkJob);
}
}
}
return result;
}
/**
* Ensures that just a single outcome is satisfied
*/
@Override
public final boolean satisfiedForConsume(FilterOutcomes outcomes, InputRow row) {
boolean satisfiedOutcomesForConsume = satisfiedOutcomesForConsume(_hasComponentRequirement, row, outcomes);
if (!satisfiedOutcomesForConsume) {
return false;
}
boolean satisfiedInputsForConsume = satisfiedInputsForConsume(row, outcomes);
return satisfiedInputsForConsume;
}
@Override
public InputColumn<?>[] getOutputColumns() {
return new InputColumn[0];
}
@Override
public final void consume(InputRow row, int distinctCount, FilterOutcomes outcomes, RowProcessingChain chain) {
try {
consumeInternal(row, distinctCount, outcomes, chain);
} catch (RuntimeException e) {
final ComponentJob componentJob = getComponentJob();
if (_analysisListener == null) {
logger.error("Error occurred in component '" + componentJob + "' and no AnalysisListener is available",
e);
throw e;
} else {
_analysisListener.errorInComponent(_analysisJob, componentJob, row, e);
}
}
}
/**
* Overrideable method for subclasses
*
* @param row
* @param distinctCount
* @param outcomes
* @param chain
*/
protected abstract void consumeInternal(InputRow row, int distinctCount, FilterOutcomes outcomes, RowProcessingChain chain);
private boolean satisfiedInputsForConsume(InputRow row, FilterOutcomes outcomes) {
if (_alwaysSatisfiedForConsume) {
return _alwaysSatisfiedForConsume;
}
final ComponentRequirement componentRequirement = _hasComponentRequirement.getComponentRequirement();
if (componentRequirement == null) {
for (final Object sourceJobsOfInputColumn : _sourceJobsOfInputColumns) {
// if any of the source jobs is satisfied, then continue
if (sourceJobsOfInputColumn instanceof HasComponentRequirement) {
final HasComponentRequirement hasComponentRequirement = (HasComponentRequirement) sourceJobsOfInputColumn;
final boolean satisfiedOutcomesForConsume = satisfiedOutcomesForConsume(hasComponentRequirement, row, outcomes);
if (satisfiedOutcomesForConsume) {
return true;
}
}
}
return false;
}
return true;
}
private boolean satisfiedOutcomesForConsume(HasComponentRequirement component, InputRow row, FilterOutcomes outcomes) {
boolean isSatisfiedOutcomes = false;
final ComponentRequirement componentRequirement = component.getComponentRequirement();
if (componentRequirement == null) {
isSatisfiedOutcomes = true;
} else {
isSatisfiedOutcomes = componentRequirement.isSatisfied(row, outcomes);
}
return isSatisfiedOutcomes;
}
/**
* Ensures that ALL outcomes are available
*/
@Override
public final boolean satisfiedForFlowOrdering(FilterOutcomes outcomes) {
if (isAlwaysSatisfiedRequirement()) {
return true;
}
final ComponentRequirement componentRequirement = _hasComponentRequirement.getComponentRequirement();
if (componentRequirement == null) {
return true;
}
return componentRequirement.isSatisfied(null, outcomes);
}
}