/*
* Syncany, www.syncany.org
* Copyright (C) 2011-2016 Philipp C. Heckel <philipp.heckel@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.syncany.chunk;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.syncany.util.StringUtil;
/**
* A transformer combines one or many stream-transforming {@link OutputStream}s and {@link InputStream}s.
* Implementations might provide functionality to encrypt or compress output streams, and to decrypt
* or uncompress a corresponding input stream.
*
* <p>Transformers can be chained in order to allow multiple consecutive output-/input stream
* transformers to be applied to a stream.
*
* <p>A transformer can be instantiated using its implementation-specific constructor, or by calling
* its default constructor and initializing it using the {@link #init(Map) init()} method. Depending
* on the implementation, varying settings must be passed.
*
* @author Philipp C. Heckel <philipp.heckel@gmail.com>
*/
public abstract class Transformer {
private static final Logger logger = Logger.getLogger(Transformer.class.getSimpleName());
protected Transformer nextTransformer;
/**
* Creates a new transformer object (no next transformer)
*/
public Transformer() {
this(null);
}
/**
* Create a new transformer, with a nested/chained transformer that will be
* be applied after this transformer.
*
* @param nextTransformer The next transformer (to be applied after this transformer)
*/
public Transformer(Transformer nextTransformer) {
this.nextTransformer = nextTransformer;
}
/**
* If a transformer is instantiated via the default constructor (e.g. via a config file),
* it must be initialized using this method. The settings passed to the method depend
* on the implementation of the transformer.
*
* @param settings Implementation-specific setting map
* @throws Exception If the given settings are invalid or insufficient for instantiation
*/
public abstract void init(Map<String, String> settings) throws Exception;
/**
* Create a stream-transforming {@link OutputStream}. Depending on the implementation, the
* bytes written to the output stream might be encrypted, compressed, etc.
*
* @param out Original output stream which is transformed by this transformer
* @return Returns a transformed output stream
* @throws IOException If an exception occurs when instantiating or writing to the stream
*/
public abstract OutputStream createOutputStream(OutputStream out) throws IOException;
/**
* Creates a strea-transforming {@link InputStream}. Depending on the implementation, the
* bytes read from the input stream are uncompressed, decrypted, etc.
*
* @param in Original input stream which is transformed by this transformer
* @return Returns a transformed input stream
* @throws IOException If an exception occurs when instantiating or reading from the stream
*/
public abstract InputStream createInputStream(InputStream in) throws IOException;
/**
* An implementation of a transformer must override this method to identify the
* type of transformer and/or its settings.
*/
@Override
public abstract String toString();
/**
* Instantiates a transformer by its name using the default constructor. After creating
* a new transformer, it must be initialized using the {@link #init(Map) init()} method.
*
* <p>The given type attribute is mapped to fully qualified class name (FQCN) of the form
* <tt>org.syncany.chunk.XTransformer</tt>, where <tt>X</tt> is the camel-cased type
* attribute.
*
* @param type Type/name of the transformer (corresponds to its camel case class name)
* @return Returns a new transformer
* @throws Exception If the FQCN cannot be found or the class cannot be instantiated
*/
public static Transformer getInstance(String type) throws Exception {
String thisPackage = Transformer.class.getPackage().getName();
String camelCaseName = StringUtil.toCamelCase(type);
String fqClassName = thisPackage + "." + camelCaseName + Transformer.class.getSimpleName();
// Try to load!
try {
Class<?> clazz = Class.forName(fqClassName);
return (Transformer) clazz.newInstance();
}
catch (Exception ex) {
logger.log(Level.INFO, "Could not find operation FQCN " + fqClassName, ex);
return null;
}
}
public void setNextTransformer(Transformer nextTransformer) {
this.nextTransformer = nextTransformer;
}
}