/**
* Copyright (C) 2010 Orbeon, Inc.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the Free Software Foundation; either version
* 2.1 of the License, or (at your option) any later version.
*
* 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.
*
* The full text of the license is available at http://www.gnu.org/copyleft/lesser.html
*/
package org.orbeon.oxf.processor.impl;
import org.orbeon.oxf.cache.*;
import org.orbeon.oxf.pipeline.api.PipelineContext;
import org.orbeon.oxf.processor.ProcessorImpl;
import org.orbeon.oxf.processor.ProcessorInput;
import java.util.*;
/**
* Implementation of a caching transformer output that assumes that an output simply depends on
* all the inputs plus optional local information.
*
* It is possible to implement local key and validity information as well, that represent data
* not coming from an XML input. If any input is connected to an output that is not cacheable,
* a null key is returned.
*
* Use DigestTransformerOutputImpl whenever possible.
*/
public abstract class CacheableTransformerOutputImpl extends ProcessorOutputImpl {
public CacheableTransformerOutputImpl(ProcessorImpl processor, String name) {
super(processor, name);
}
/**
* Processor outputs that use the local key/validity feature must
* override this method and return true.
*/
protected boolean supportsLocalKeyValidity() {
return false;
}
protected CacheKey getLocalKey(PipelineContext pipelineContext) {
throw new UnsupportedOperationException();
}
protected Object getLocalValidity(PipelineContext pipelineContext) {
throw new UnsupportedOperationException();
}
@Override
public OutputCacheKey getKeyImpl(PipelineContext pipelineContext) {
// NOTE: This implementation assumes that there is only one input with a given name
// Create input information
final Collection<List<ProcessorInput>> connectedInputs = getProcessor(pipelineContext).getConnectedInputs().values();
final int keyCount = connectedInputs.size() + (supportsLocalKeyValidity() ? 1 : 0);
final CacheKey[] outputKeys = new CacheKey[keyCount];
int keyIndex = 0;
for (final List<ProcessorInput> inputs : connectedInputs) {
for (final ProcessorInput input : inputs) {
final OutputCacheKey outputKey = ProcessorImpl.getInputKey(pipelineContext, input);
if (outputKey == null) {
return null;
}
outputKeys[keyIndex++] = outputKey;
}
}
// Add local key if needed
if (supportsLocalKeyValidity()) {
final CacheKey localKey = getLocalKey(pipelineContext);
if (localKey == null) return null;
outputKeys[keyIndex++] = localKey;
}
// Concatenate current processor info and input info
final Class processorClass = getProcessorClass();
final String outputName = getName();
return new CompoundOutputCacheKey(processorClass, outputName, outputKeys);
}
@Override
public Object getValidityImpl(PipelineContext pipelineContext) {
final List<Object> validityObjects = new ArrayList<Object>();
for (final List<ProcessorInput> inputs : getProcessor(pipelineContext).getConnectedInputs().values()) {
for (final ProcessorInput input : inputs) {
final Object validity = ProcessorImpl.getInputValidity(pipelineContext, input);
if (validity == null)
return null;
validityObjects.add(validity);
}
}
// Add local validity if needed
if (supportsLocalKeyValidity()) {
final Object localValidity = getLocalValidity(pipelineContext);
if (localValidity == null) return null;
validityObjects.add(localValidity);
}
return validityObjects;
}
}