001/* 002 * Syncany, www.syncany.org 003 * Copyright (C) 2011-2016 Philipp C. Heckel <philipp.heckel@gmail.com> 004 * 005 * This program is free software: you can redistribute it and/or modify 006 * it under the terms of the GNU General Public License as published by 007 * the Free Software Foundation, either version 3 of the License, or 008 * (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU General Public License for more details. 014 * 015 * You should have received a copy of the GNU General Public License 016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 017 */ 018package org.syncany.chunk; 019 020import java.io.IOException; 021import java.io.InputStream; 022import java.io.OutputStream; 023import java.util.Map; 024import java.util.logging.Level; 025import java.util.logging.Logger; 026 027import org.syncany.util.StringUtil; 028 029/** 030 * A transformer combines one or many stream-transforming {@link OutputStream}s and {@link InputStream}s. 031 * Implementations might provide functionality to encrypt or compress output streams, and to decrypt 032 * or uncompress a corresponding input stream. 033 * 034 * <p>Transformers can be chained in order to allow multiple consecutive output-/input stream 035 * transformers to be applied to a stream. 036 * 037 * <p>A transformer can be instantiated using its implementation-specific constructor, or by calling 038 * its default constructor and initializing it using the {@link #init(Map) init()} method. Depending 039 * on the implementation, varying settings must be passed. 040 * 041 * @author Philipp C. Heckel (philipp.heckel@gmail.com) 042 */ 043public abstract class Transformer { 044 private static final Logger logger = Logger.getLogger(Transformer.class.getSimpleName()); 045 protected Transformer nextTransformer; 046 047 /** 048 * Creates a new transformer object (no next transformer) 049 */ 050 public Transformer() { 051 this(null); 052 } 053 054 /** 055 * Create a new transformer, with a nested/chained transformer that will be 056 * be applied after this transformer. 057 * 058 * @param nextTransformer The next transformer (to be applied after this transformer) 059 */ 060 public Transformer(Transformer nextTransformer) { 061 this.nextTransformer = nextTransformer; 062 } 063 064 /** 065 * If a transformer is instantiated via the default constructor (e.g. via a config file), 066 * it must be initialized using this method. The settings passed to the method depend 067 * on the implementation of the transformer. 068 * 069 * @param settings Implementation-specific setting map 070 * @throws Exception If the given settings are invalid or insufficient for instantiation 071 */ 072 public abstract void init(Map<String, String> settings) throws Exception; 073 074 /** 075 * Create a stream-transforming {@link OutputStream}. Depending on the implementation, the 076 * bytes written to the output stream might be encrypted, compressed, etc. 077 * 078 * @param out Original output stream which is transformed by this transformer 079 * @return Returns a transformed output stream 080 * @throws IOException If an exception occurs when instantiating or writing to the stream 081 */ 082 public abstract OutputStream createOutputStream(OutputStream out) throws IOException; 083 084 /** 085 * Creates a strea-transforming {@link InputStream}. Depending on the implementation, the 086 * bytes read from the input stream are uncompressed, decrypted, etc. 087 * 088 * @param in Original input stream which is transformed by this transformer 089 * @return Returns a transformed input stream 090 * @throws IOException If an exception occurs when instantiating or reading from the stream 091 */ 092 public abstract InputStream createInputStream(InputStream in) throws IOException; 093 094 /** 095 * An implementation of a transformer must override this method to identify the 096 * type of transformer and/or its settings. 097 */ 098 @Override 099 public abstract String toString(); 100 101 /** 102 * Instantiates a transformer by its name using the default constructor. After creating 103 * a new transformer, it must be initialized using the {@link #init(Map) init()} method. 104 * 105 * <p>The given type attribute is mapped to fully qualified class name (FQCN) of the form 106 * <code>org.syncany.chunk.XTransformer</code>, where <code>X</code> is the camel-cased type 107 * attribute. 108 * 109 * @param type Type/name of the transformer (corresponds to its camel case class name) 110 * @return Returns a new transformer 111 * @throws Exception If the FQCN cannot be found or the class cannot be instantiated 112 */ 113 public static Transformer getInstance(String type) throws Exception { 114 String thisPackage = Transformer.class.getPackage().getName(); 115 String camelCaseName = StringUtil.toCamelCase(type); 116 String fqClassName = thisPackage + "." + camelCaseName + Transformer.class.getSimpleName(); 117 118 // Try to load! 119 try { 120 Class<?> clazz = Class.forName(fqClassName); 121 return (Transformer) clazz.newInstance(); 122 } 123 catch (Exception ex) { 124 logger.log(Level.INFO, "Could not find operation FQCN " + fqClassName, ex); 125 return null; 126 } 127 } 128 129 public void setNextTransformer(Transformer nextTransformer) { 130 this.nextTransformer = nextTransformer; 131 } 132}