package com.emc.vipr.transform;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;
/**
* Abstract base class that produces both "output" transformers that encode data and
* "output" transforms that decode data.
*
* @param <T> the class of transform that this class produces.
*/
public abstract class TransformFactory<T extends OutputTransform,
U extends InputTransform>
implements Comparable<TransformFactory<OutputTransform, InputTransform>> {
private int priority;
/**
* Gets an "output" transform for the factory in its current
* state. This will be used to transform raw data on its way "out" to the server.
* @return a transform that can encode the outbound object stream.
* @throws IOException
*/
public abstract T getOutputTransform(OutputStream streamToEncode, Map<String,String> metadataToEncode) throws IOException, TransformException;
/**
* Gets an "output" transform for the factory in its current
* state. This will be used to transform raw data on its way "out" to the server.
* This version gets an output transform in "pull" mode that uses an input stream
* to filter the data. This is useful for situations where you need to pump data
* to an output stream like when using an HTTP output stream.
* @return a transform that can encode the outbound object stream.
* @throws IOException
*/
public abstract T getOutputTransform(InputStream streamToEncode, Map<String,String> metadataToEncode) throws IOException, TransformException;
/**
* Gets the "input" transform for the given class and metadata.
* @param transformConfig the configuration of the transformClass.
* @param metadata metadata extracted from the inbound object (used to fine-tune
* the transformation and/or provide metadata to also be transformed).
* @return a transform that can decode the inbound object stream.
* @throws IOException
*/
public abstract U getInputTransform(String transformConfig,
InputStream streamToDecode, Map<String, String> metadata) throws IOException, TransformException;
/**
* Gets the high-level class of transform that this factory provides. The
* transform engine will use this to test whether the registered factory can decode
* the given object.
* @return the transformation class, e.g. "COMP" for compression or "ENC" for
* encryption.
*/
public abstract String getTransformClass();
/**
* Checks whether this class can decode the given transformation configuration.
* @param metadata the additional metadata from the object in case additional fields
* need to be checked.
* @return true if this factory can decode the given object stream.
*/
public boolean canDecode(String transformConfig, Map<String,String> metadata) {
//
return getTransformClass().equals(splitTransformConfig(transformConfig)[0]);
}
protected String[] splitTransformConfig(String transformConfig) {
String[] configTuple = transformConfig.split(":", 2);
if(configTuple.length != 2) {
throw new IllegalArgumentException("Invalid transform config string: " + transformConfig);
}
return configTuple;
}
/**
* Gets the priority of this factory. For output configurations, higher priority
* transformations will be applied first (e.g. compression should be applied before
* encryption and therefore higher priority). For input configurations, there may
* be multiple factories that can handle an object and the one with higher priority
* will take precedence.
* @return this factory's priority.
*/
public int getPriority() {
return priority;
}
/**
* Sets the priority for this factory.
*/
public void setPriority(int priority) {
this.priority = priority;
}
@Override
public int compareTo(TransformFactory<OutputTransform, InputTransform> other) {
return this.getPriority() - other.getPriority();
}
}