tikhomirov@115: /* tikhomirov@115: * Copyright (c) 2011 TMate Software Ltd tikhomirov@115: * tikhomirov@115: * This program is free software; you can redistribute it and/or modify tikhomirov@115: * it under the terms of the GNU General Public License as published by tikhomirov@115: * the Free Software Foundation; version 2 of the License. tikhomirov@115: * tikhomirov@115: * This program is distributed in the hope that it will be useful, tikhomirov@115: * but WITHOUT ANY WARRANTY; without even the implied warranty of tikhomirov@115: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the tikhomirov@115: * GNU General Public License for more details. tikhomirov@115: * tikhomirov@115: * For information on how to redistribute this software under tikhomirov@115: * the terms of a license other than GNU General Public License tikhomirov@130: * contact TMate Software at support@hg4j.com tikhomirov@115: */ tikhomirov@115: package org.tmatesoft.hg.internal; tikhomirov@115: tikhomirov@148: import java.io.IOException; tikhomirov@115: import java.nio.ByteBuffer; tikhomirov@355: import java.util.ArrayList; tikhomirov@115: import java.util.Collection; tikhomirov@355: import java.util.List; tikhomirov@115: tikhomirov@157: import org.tmatesoft.hg.util.Adaptable; tikhomirov@115: import org.tmatesoft.hg.util.ByteChannel; tikhomirov@148: import org.tmatesoft.hg.util.CancelledException; tikhomirov@115: tikhomirov@115: /** tikhomirov@115: * tikhomirov@115: * @author Artem Tikhomirov tikhomirov@115: * @author TMate Software Ltd. tikhomirov@115: */ tikhomirov@157: public class FilterByteChannel implements ByteChannel, Adaptable { tikhomirov@115: private final Filter[] filters; tikhomirov@115: private final ByteChannel delegate; tikhomirov@115: tikhomirov@115: public FilterByteChannel(ByteChannel delegateChannel, Collection filtersToApply) { tikhomirov@115: if (delegateChannel == null || filtersToApply == null) { tikhomirov@115: throw new IllegalArgumentException(); tikhomirov@115: } tikhomirov@115: delegate = delegateChannel; tikhomirov@115: filters = filtersToApply.toArray(new Filter[filtersToApply.size()]); tikhomirov@115: } tikhomirov@115: tikhomirov@148: public int write(ByteBuffer buffer) throws IOException, CancelledException { tikhomirov@115: final int srcPos = buffer.position(); tikhomirov@115: ByteBuffer processed = buffer; tikhomirov@115: for (Filter f : filters) { tikhomirov@115: // each next filter consumes not more than previous tikhomirov@115: // hence total consumed equals position shift in the original buffer tikhomirov@115: processed = f.filter(processed); tikhomirov@115: } tikhomirov@115: delegate.write(processed); tikhomirov@115: return buffer.position() - srcPos; // consumed as much from original buffer tikhomirov@115: } tikhomirov@115: tikhomirov@157: // adapters or implemented interfaces of the original class shall not be obfuscated by filter tikhomirov@157: public T getAdapter(Class adapterClass) { tikhomirov@355: if (adapterClass == Preview.class) { tikhomirov@355: ArrayList previewers = new ArrayList(filters.length); tikhomirov@356: Adaptable.Factory factory = new Adaptable.Factory(Preview.class); tikhomirov@355: for (Filter f : filters) { tikhomirov@356: Preview p = factory.get(f); tikhomirov@356: if (p != null) { tikhomirov@356: previewers.add(p); tikhomirov@355: } tikhomirov@355: } tikhomirov@355: if (!previewers.isEmpty()) { tikhomirov@355: @SuppressWarnings("unchecked") tikhomirov@355: T rv = (T) new PreviewSupport(previewers); tikhomirov@355: return rv; tikhomirov@355: } tikhomirov@355: // fall through to let delegate answer tikhomirov@355: } tikhomirov@356: return Adaptable.Factory.getAdapter(delegate, adapterClass, null); tikhomirov@157: } tikhomirov@355: tikhomirov@355: private static class PreviewSupport implements Preview { tikhomirov@355: private final Preview[] participants; tikhomirov@355: tikhomirov@355: public PreviewSupport(List previewers) { tikhomirov@355: participants = new Preview[previewers.size()]; tikhomirov@355: previewers.toArray(participants); tikhomirov@355: } tikhomirov@355: tikhomirov@355: public void preview(ByteBuffer src) { tikhomirov@355: final int originalPos = src.position(); tikhomirov@355: for (Preview p : participants) { tikhomirov@355: p.preview(src); tikhomirov@355: // reset to initial state tikhomirov@355: src.position(originalPos); tikhomirov@355: } tikhomirov@355: } tikhomirov@355: } tikhomirov@115: }