/* QuiXProc: efficient evaluation of XProc Pipelines. Copyright (C) 2011-2015 Innovimax All rights reserved. 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package innovimax.quixproc.datamodel; import java.util.ConcurrentModificationException; import javax.xml.XMLConstants; /** * A truly Streamable CharSequence * * The definition of streamable is a real problem for much of the people Let's * say that Streamable means, we don't need to store all in memory It becomes a * bit too simplistic At least we know what is *NOT* the solution for nasty * files XML as JSON and any other document structure that doesn't limit it's * content (remember why we moved from EDI which needs to say every size) is * that when you want to process such documents, some documents may ends up * having huge content and hence you loose the power of streaming MOST IMPORTANT * CASES = TODAY, a simple document * * @author innovimax * */ public abstract class QuiXCharStream { public static final QuiXCharStream EMPTY = fromSequence(""); public static final QuiXCharStream NULL_NS_URI = fromSequence(XMLConstants.NULL_NS_URI); public static final QuiXCharStream DEFAULT_NS_PREFIX = fromSequence(XMLConstants.DEFAULT_NS_PREFIX); @Override public abstract String toString() throws ConcurrentModificationException; public abstract boolean contains(CharSequence sequence) throws ConcurrentModificationException; public abstract QuiXCharStream substringBefore(CharSequence sequence) throws ConcurrentModificationException; public abstract QuiXCharStream substringAfter(CharSequence sequence) throws ConcurrentModificationException; public abstract boolean isEmpty(); public abstract QuiXCharStream append(QuiXCharStream cs); public abstract QuiXCharStream append(CharSequence cs); public static QuiXCharStream fromSequence(CharSequence cs) { return new CharSequenceQuiXCharStream(cs); } private static final class QuiXCharStreamList extends QuiXCharStream { final QuiXCharStream a, b; QuiXCharStreamList(QuiXCharStream a, QuiXCharStream b) { this.a = a; this.b = b; } @Override public String toString() throws ConcurrentModificationException { return this.a.toString() + this.b.toString(); } @Override public boolean contains(CharSequence sequence) throws ConcurrentModificationException { return this.a.contains(sequence) || this.b.contains(sequence); } @Override public QuiXCharStream substringBefore(CharSequence sequence) throws ConcurrentModificationException { return null; } @Override public QuiXCharStream substringAfter(CharSequence sequence) throws ConcurrentModificationException { // TODO Auto-generated method stub // not easy to do... return null; } @Override public boolean isEmpty() { return this.a.isEmpty() && this.b.isEmpty(); } @Override public QuiXCharStream append(QuiXCharStream cs) { return new QuiXCharStreamList(this, cs); } @Override public QuiXCharStream append(CharSequence cs) { return new QuiXCharStreamList(this, new CharSequenceQuiXCharStream(cs)); } } private static final class CharSequenceQuiXCharStream extends QuiXCharStream { private final CharSequence cs; CharSequenceQuiXCharStream(CharSequence cs) { this.cs = cs; } @Override public String toString() { return this.cs.toString(); } @Override public boolean contains(CharSequence sequence) { return this.cs.toString().contains(sequence); } @Override public QuiXCharStream substringBefore(CharSequence sequence) { int i = this.cs.toString().indexOf(sequence.toString()); return i == -1 ? QuiXCharStream.fromSequence("") : QuiXCharStream.fromSequence(this.cs.toString().substring(0, i)); } @Override public QuiXCharStream substringAfter(CharSequence sequence) { int i = this.cs.toString().indexOf(sequence.toString()); return i == -1 ? QuiXCharStream.fromSequence("") : QuiXCharStream.fromSequence(this.cs.toString().substring(i + sequence.length())); } @Override public boolean isEmpty() { return this.cs.length() == 0; } @Override public QuiXCharStream append(QuiXCharStream c) { return new QuiXCharStreamList(this, c); } @Override public QuiXCharStream append(CharSequence c) { return QuiXCharStream.fromSequence(this.cs.toString() + c.toString()); } } }