http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/e43574ef/commons/marmotta-commons/src/ext/java/javolution/context/internal/SecurityContextImpl.java ---------------------------------------------------------------------- diff --git a/commons/marmotta-commons/src/ext/java/javolution/context/internal/SecurityContextImpl.java b/commons/marmotta-commons/src/ext/java/javolution/context/internal/SecurityContextImpl.java new file mode 100644 index 0000000..2615119 --- /dev/null +++ b/commons/marmotta-commons/src/ext/java/javolution/context/internal/SecurityContextImpl.java @@ -0,0 +1,61 @@ +/* + * Javolution - Java(TM) Solution for Real-Time and Embedded Systems + * Copyright (C) 2012 - Javolution (http://javolution.org/) + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software is + * freely granted, provided that this notice is preserved. + */ +package javolution.context.internal; + +import javolution.context.SecurityContext; +import javolution.util.FastTable; + +/** + * Holds the default implementation of SecurityContext. + */ +public final class SecurityContextImpl extends SecurityContext { + + private FastTable<Action> actions = new FastTable<Action>(); + + @Override + public boolean isGranted(Permission<?> permission) { + boolean isGranted = true; + for (Action a : actions) { + if (a.permission.implies(permission)) + isGranted = a.grant; + } + return isGranted; + } + + @Override + public void grant(Permission<?> permission, Object certificate) + throws SecurityException { + Action a = new Action(); + a.grant = true; + a.permission = permission; + actions.add(a); + } + + @Override + public void revoke(Permission<?> permission, Object certificate) + throws SecurityException { + Action a = new Action(); + a.grant = false; + a.permission = permission; + actions.add(a); + } + + @Override + protected SecurityContext inner() { + SecurityContextImpl ctx = new SecurityContextImpl(); + ctx.actions.addAll(actions); + return ctx; + } + + // Represents the grant/revoke action performed. + private static class Action { + boolean grant; // Else revoke. + Permission<?> permission; + } +}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/e43574ef/commons/marmotta-commons/src/ext/java/javolution/context/internal/StorageContextImpl.java ---------------------------------------------------------------------- diff --git a/commons/marmotta-commons/src/ext/java/javolution/context/internal/StorageContextImpl.java b/commons/marmotta-commons/src/ext/java/javolution/context/internal/StorageContextImpl.java new file mode 100644 index 0000000..0f20936 --- /dev/null +++ b/commons/marmotta-commons/src/ext/java/javolution/context/internal/StorageContextImpl.java @@ -0,0 +1,87 @@ +/* + * Javolution - Java(TM) Solution for Real-Time and Embedded Systems + * Copyright (C) 2012 - Javolution (http://javolution.org/) + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software is + * freely granted, provided that this notice is preserved. + */ +package javolution.context.internal; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +import javolution.context.LogContext; +import javolution.context.SecurityContext; +import javolution.context.SecurityContext.Permission; +import javolution.context.StorageContext; + +/** + * Holds the default implementation of StorageContext. + */ +public final class StorageContextImpl extends StorageContext { + + @SuppressWarnings("unchecked") + @Override + public <V extends Serializable> V read(Resource<V> resource) + throws SecurityException { + SecurityContext.check(new Permission<Resource<V>>(Resource.class, + "write", resource)); + try { + File file = new File(FILE_STORAGE_LOCATION.get(), + resource.uniqueID()); + if (file.exists()) { + LogContext.debug("Read resource file ", file.getAbsolutePath()); + } else { + LogContext.debug("Resource file ", file.getAbsolutePath(), + " does not exist."); + return null; + } + + FileInputStream fileIn = new FileInputStream(file); + ObjectInputStream in = new ObjectInputStream(fileIn); + V value = (V) in.readObject(); + in.close(); + fileIn.close(); + return value; + } catch (IOException e1) { + LogContext.error(e1); + } catch (ClassNotFoundException e2) { + LogContext.error(e2); + } + return null; + + } + + @Override + public <V extends Serializable> void write(Resource<V> resource, V value) + throws SecurityException { + SecurityContext.check(new Permission<Resource<V>>(Resource.class, + "write", resource)); + try { + File storage = FILE_STORAGE_LOCATION.get(); + storage.mkdirs(); + File file = new File(storage, resource.uniqueID()); + LogContext.debug("Write resource ", file.getAbsolutePath()); + + FileOutputStream fileOut = new FileOutputStream(file); + ObjectOutputStream out = new ObjectOutputStream(fileOut); + out.writeObject(value); + out.close(); + fileOut.close(); + } catch (IOException error) { + LogContext.error(error); + } + } + + @Override + protected StorageContext inner() { + return this; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/e43574ef/commons/marmotta-commons/src/ext/java/javolution/context/package-info.java ---------------------------------------------------------------------- diff --git a/commons/marmotta-commons/src/ext/java/javolution/context/package-info.java b/commons/marmotta-commons/src/ext/java/javolution/context/package-info.java new file mode 100644 index 0000000..af177ae --- /dev/null +++ b/commons/marmotta-commons/src/ext/java/javolution/context/package-info.java @@ -0,0 +1,103 @@ +/** +<p> Run-time {@link javolution.context.AbstractContext contexts} to facilitate + separation of concerns and achieve higher level of performance and flexibility.</p> + +<h2><a name="OVERVIEW">Separation of Concerns</a></h2> + + <p> Separation of concerns is an important design principle greatly misunderstood. + Most developers think it is limited to modularity and encapsulation or it + requires special programming tools (e.g. Aspect programming).</p> + + <p> Separation of concerns is very powerful and easier than it looks. + Basically, it could be summarized as the "pass the buck principle". + If you don't know what to do with some information, just give it to someone + else who might know.</p> + + <p> A frequent example is the catching of exceptions too early (with some logging processing) + instead of throwing a checked exception. Unfortunately, they are still plenty of cases + where the separation of concerns is not as good as it could be. For example logging! + Why low-level code need to know which logging facility to use + (e.g. standard logging, Log4J library, OSGi LogService or anything else)? + Why logging should have to be based upon the class hierarchy (standard logging)? + Why can't we attach some relevant information (such as user id, session number, etc.) + to the logging content ? </p> + + <p> Separation of concerns can be addressed through "Aspect Programming", + but there is a rather simpler solution <b>"Context Programming"</b>!</p> + + <p> It does not require any particular tool, it basically says that every threads + has a {@link javolution.context.AbstractContext context} which can be customized by someone else + (the one who knows what to do, when running OSGi it is typically a separate bundle). + Then, your code looks a lot cleaner and is way more flexible as you don't have + to worry about logging, security, performance etc. in your low level methods. +[code] +void myMethod() { + ... + LogContext.info("Don't know where this is going to be logged to"); + ... +}[/code]</p> + + <p> Used properly <i><b>J</b>avolution</i>'s {@link javolution.context.AbstractContext contexts} + greatly facilitate the separation of concerns. Contexts are fully + integrated with OSGi (they are published services). Applications + may dynamically plug-in the "right context" using OSGi mechanisms. + For example, the {@link javolution.context.SecurityContext SecurityContext} + might only be known at runtime.</p> + + <h2><a name="PREDEFINED">Predefined Contexts:</a></h2> + <p> <i><b>J</b>avolution</i> provides several useful runtime contexts:<ul> + <li>{@link javolution.context.ConcurrentContext ConcurrentContext} + - To take advantage of concurrent algorithms on multi-cores systems.</li> + <li>{@link javolution.context.LogContext LogContext} + - To log events according to the runtime environment (e.g. {@link org.osgi.service.log.LogService} when running OSGi).</li> + <li>{@link javolution.context.LocalContext LocalContext} + - To define locally scoped environment settings.</li> + <li>{@link javolution.context.SecurityContext SecurityContext} + - To address application-level security concerns.</li> + <li>{@link javolution.context.StorageContext StorageContext} + - To store/retrieve your persistent data/dataset.</li> + <li>{@link javolution.context.FormatContext FormatContext} + - For plugable objects parsing/formatting. Such as {@link javolution.text.TextContext TextContext} for plain text, + or {@link javolution.xml.XMLContext XMLContext} for XML serialization/deserialization.</li> + <li>{@link javolution.context.StorageContext StorageContext} + - To store/retrieve your persistent data/dataset.</li> + <li>...add your own !</li> + </ul> + </p> + +<h2><a name="FAQ">FAQ:</a></h2> +<ol> + <a name="FAQ-1"></a> + <li><b>In my application I create new threads on-the-fly and I would like them to inherit + the current context environment. How can I do that?</b> + <p> Context is automatically inherited when performing concurrent executions using + {@link javolution.context.ConcurrentContext ConcurrentContext}. If you create + new threads yourself you can easily setup their context as shown below.</p> +[code] +//Spawns a new thread inheriting the context of the current thread. +MyThread myThread = new MyThread(); +myThread.inherited = AbstractContext.current(); +myThread.start(); + ... +class MyThread extends Thread { + AbstractContext inherited; + public void run() { + AbstractContext.inherit(inherited); // Sets current context. + ... + } +}[/code] +<p></p> + </li> + + <a name="FAQ-2"></a> + <li><b>Is it possible to configure the context of all running threads (global configuration) ?</b> + <p> Yes by publishing an OSGi implementation of the customized context + (published context services are the default contexts of all running threads). + Otherwise, you can only configure a context that you have entered (for obvious safety reasons).</p> +<p></p> + </li> + </ol> + +*/ +package javolution.context; + http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/e43574ef/commons/marmotta-commons/src/ext/java/javolution/doc-files/overview.html ---------------------------------------------------------------------- diff --git a/commons/marmotta-commons/src/ext/java/javolution/doc-files/overview.html b/commons/marmotta-commons/src/ext/java/javolution/doc-files/overview.html new file mode 100644 index 0000000..a1ac049 --- /dev/null +++ b/commons/marmotta-commons/src/ext/java/javolution/doc-files/overview.html @@ -0,0 +1,149 @@ +<BODY> +<H2><B><I><SPAN CLASS="style0">J</SPAN><SPAN CLASS="style1">avolution</I></B></SPAN> - Java<SUP>TM</SUP> Solution for Real-Time and Embedded Systems.</H2> + +<a name="license"></a> +<h3><b>License:</b></h3> +<p> Permission to use, copy, modify, and distribute this software is freely granted, + provided that copyright notices are preserved (the full license text can be found + <a href="http://javolution.org/LICENSE.txt">here</a>).</p> +<p> <b><i>Javolution</i></b>'s users are encouraged to show their support with the + <a href="http://javolution.org"><img src="http://javolution.org/src/site/css/img/javolution.png"></a> button.</p> + +<a name="overview"></a> +<h3><b>Overview:</b></h3> +Although Java<sup>TM</sup> has been very successful on the server-side; It has few shortcomings limiting +its adoption for others domains such as real-time, embedded or high-performance applications. +For these, the <b><i>Javolution</i></b> library provides important "pieces" missing +from the Java<sup>TM</sup> core library and making the Java<sup>TM</sup> platform even more attractive. + +<a name="usage"></a> +<h3><b>Usage:</b></h3> + +<p><b><i>Javolution</i></b> can be used as a standard OSGi bundle.</p> + +<div style="background: #ffffff; overflow:auto;width:auto;color:black;background:white;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;"><pre style="margin: 0; line-height: 125%"> +<span style="color: #7F0055; font-weight: bold">import</span> org.osgi.framework.*; +<span style="color: #7F0055; font-weight: bold">import</span> org.osgi.util.tracker.ServiceTracker; +<span style="color: #7F0055; font-weight: bold">public</span> <span style="color: #7F0055; font-weight: bold">class</span> MyActivator <span style="color: #7F0055; font-weight: bold">implements</span> BundleActivator { + ServiceTracker<XMLInputFactory, XMLInputFactory> tracker; + <span style="color: #7F0055; font-weight: bold">public</span> <span style="color: #7F0055; font-weight: bold">void</span> start(BundleContext bc) <span style="color: #7F0055; font-weight: bold">throws</span> Exception { + tracker = <span style="color: #7F0055; font-weight: bold">new</span> ServiceTracker<>(bc, XMLInputFactory.<span style="color: #7F0055; font-weight: bold">class</span>, null); + tracker.open(); + parse(); + } + <span style="color: #7F0055; font-weight: bold">public</span> <span style="color: #7F0055; font-weight: bold">void</span> stop(BundleContext bc) <span style="color: #7F0055; font-weight: bold">throws</span> Exception { + tracker.close(); + } + <span style="color: #7F0055; font-weight: bold">public</span> <span style="color: #7F0055; font-weight: bold">void</span> parse() <span style="color: #7F0055; font-weight: bold">throws</span> XMLStreamException { + XMLInputFactory factory = tracker.getService(); + factory.setProperty(XMLInputFactory.IS_COALESCING, true); <span style="color: #3F7F5F">// Configures.</span> + + <span style="color: #3F7F5F">// Instantiates a new reader.</span> + String xml = <span style="color: #2a00ff">"<test>This is a test</test>"</span>; + CharSequenceReader in = <span style="color: #7F0055; font-weight: bold">new</span> CharSequenceReader().setInput(xml); + XMLStreamReader reader = factory.createXMLStreamReader(in); + + <span style="color: #3F7F5F">// Parses XML.</span> + <span style="color: #7F0055; font-weight: bold">while</span> (reader.hasNext()) { + <span style="color: #7F0055; font-weight: bold">int</span> eventType = reader.next(); + <span style="color: #7F0055; font-weight: bold">if</span> (eventType == XMLStreamConstants.CHARACTERS) { + System.out.println(reader.getText()); + } + } + + <span style="color: #3F7F5F">// Closes the reader which may be recycled back to the factory.</span> + reader.close(); + } +} +</pre></div> + +<p> Or as a standard Java library (does not require OSGi runtime).</p> + +<div style="background: #ffffff; overflow:auto;width:auto;color:black;background:white;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;"><pre style="margin: 0; line-height: 125%"> +<span style="color: #7F0055; font-weight: bold">import</span> javolution.osgi.internal.OSGiServices; +<span style="color: #7F0055; font-weight: bold">public</span> <span style="color: #7F0055; font-weight: bold">class</span> Main { + <span style="color: #7F0055; font-weight: bold">public</span> <span style="color: #7F0055; font-weight: bold">static</span> <span style="color: #7F0055; font-weight: bold">void</span> main(String[] args) <span style="color: #7F0055; font-weight: bold">throws</span> XMLStreamException { + XMLInputFactory factory = OSGiServices.getXMLInputFactory(); + factory.setProperty(XMLInputFactory.IS_COALESCING, true); <span style="color: #3F7F5F">// Configures.</span> + + <span style="color: #3F7F5F">// Instantiates a reader.</span> + String xml = <span style="color: #2a00ff">"<test>This is a test</test>"</span>; + CharSequenceReader in = <span style="color: #7F0055; font-weight: bold">new</span> CharSequenceReader().setInput(xml); + XMLStreamReader reader = factory.createXMLStreamReader(in); + + <span style="color: #3F7F5F">// Parses XML.</span> + <span style="color: #7F0055; font-weight: bold">while</span> (reader.hasNext()) { + <span style="color: #7F0055; font-weight: bold">int</span> eventType = reader.next(); + <span style="color: #7F0055; font-weight: bold">if</span> (eventType == XMLStreamConstants.CHARACTERS) { + System.out.println(reader.getText()); + } + } + + <span style="color: #3F7F5F">// Closes the reader which may be recycled back to the factory.</span> + reader.close(); + } +} +</pre></div> +<a name="services"></a> +<h3><b>Services:</b></h3> +<p><b><i>Javolution</i></b> publishes the following OSGi services.</p> +<table cellpadding="2" cellspacing="2" border="1" style="text-align: left; width: 1000px;"> + <tbody> + <tr> + <td style="vertical-align: top; text-align: center;"><span style="font-weight: bold;">Published Service</span></td> + <td style="vertical-align: top; text-align: center;"><span style="font-weight: bold;">Description</span></td> + </tr> + <tr> + <td style="vertical-align: top;">{@link javolution.xml.stream.XMLInputFactory}</td> + <td style="vertical-align: top;">StAX-like version of javax.xml.stream.XMLInputFactory avoiding {@code String} allocations.</td> + </tr> + <tr> + <td style="vertical-align: top;">{@link javolution.xml.stream.XMLOutputFactory}</td> + <td style="vertical-align: top;">StAX-like version of javax.xml.stream.XMLOutputFactory using {@code CharSequence} instead of {@code String}</td> + </tr> + </tbody> +</table> +<p> These services can be accessed through the standard OSGi registry + or using {@code javolution.osgi.internal.OSGiServices} when running outside OSGi.</p> +<p><b><i>Javolution</i></b> listen to the following OSGi services.</p> +<table cellpadding="2" cellspacing="2" border="1" style="text-align: left; width: 1000px;"> + <tbody> + <tr> + <td style="vertical-align: top; text-align: center;"><span style="font-weight: bold;">Subscribed Service</span></td> + <td style="vertical-align: top; text-align: center;"><span style="font-weight: bold;">Description</span></td> + </tr> + <tr> + <td style="vertical-align: top;">{@code org.osgi.service.log.LogService}</td> + <td style="vertical-align: top;">OSGi service to log messages.</td> + </tr> + <tr> + <td style="vertical-align: top;">{@link javolution.context.LogContext}</td> + <td style="vertical-align: top;">Service to support asynchronous logging.</td> + </tr> + <tr> + <td style="vertical-align: top;">{@link javolution.context.ConcurrentContext}</td> + <td style="vertical-align: top;">Service to support concurrent executions.</td> + </tr> + <tr> + <td style="vertical-align: top;">{@link javolution.context.LocalContext}</td> + <td style="vertical-align: top;">Service to support locally scoped settings.</td> + </tr> + <tr> + <td style="vertical-align: top;">{@link javolution.context.SecurityContext}</td> + <td style="vertical-align: top;">Service granting security authorizations.</td> + </tr> + <tr> + <td style="vertical-align: top;">{@link javolution.context.StorageContext}</td> + <td style="vertical-align: top;">Service to store/retrieve persistent data/dataset.</td> + </tr> + <tr> + <td style="vertical-align: top;">{@link javolution.text.TextContext}</td> + <td style="vertical-align: top;">Service to support text parsing/formatting.</td> + </tr> + <tr> + <td style="vertical-align: top;">{@link javolution.xml.XMLContext}</td> + <td style="vertical-align: top;">Service to support XML serialization/deserialization.</td> + </tr> + </tbody> +</table> +</BODY> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/e43574ef/commons/marmotta-commons/src/ext/java/javolution/io/AppendableWriter.java ---------------------------------------------------------------------- diff --git a/commons/marmotta-commons/src/ext/java/javolution/io/AppendableWriter.java b/commons/marmotta-commons/src/ext/java/javolution/io/AppendableWriter.java new file mode 100644 index 0000000..84e6f7f --- /dev/null +++ b/commons/marmotta-commons/src/ext/java/javolution/io/AppendableWriter.java @@ -0,0 +1,163 @@ +/* + * Javolution - Java(TM) Solution for Real-Time and Embedded Systems + * Copyright (C) 2012 - Javolution (http://javolution.org/) + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software is + * freely granted, provided that this notice is preserved. + */ +package javolution.io; + +import java.io.IOException; +import java.io.Writer; +import javolution.text.Text; + +/** + * <p> This class allows any <code>Appendable</code> to be used as + * a writer.</p> + * + * @author <a href="mailto:[email protected]">Jean-Marie Dautelle</a> + * @version 3.8, May 8, 2006 + */ +public final class AppendableWriter extends Writer { + + /** + * Holds the current appendable output or <code>null</code> if closed. + */ + private Appendable _output; + + /** + * Creates a new appendable writer for which the appendable output + * is not set. + * + * @see #setOutput(Appendable) + */ + public AppendableWriter() {} + + /** + * Sets the appendable output being written to. + * For example:[code] + * Writer writer = new AppendableWriter().setOutput(new TextBuilder()); + * [/code] + * + * @param output the appendable written to. + * @return this writer. + * @throws IllegalStateException if this writer is being reused and + * it has not been {@link #close closed} or {@link #reset reset}. + */ + public AppendableWriter setOutput(Appendable output) { + if (_output != null) + throw new IllegalStateException("Writer not closed or reset"); + _output = output; + return this; + } + + /** + * Writes a single character. + * + * @param c <code>char</code> the character to be written. + * @throws IOException if an I/O error occurs. + */ + public void write(char c) throws IOException { + if (_output == null) + throw new IOException("Writer closed"); + _output.append(c); + } + + /** + * Writes the 16 low-order bits of the given integer value; + * the 16 high-order bits are ignored. + * + * @param c the value of the character to be written. + * @throws IOException if an I/O error occurs. + */ + public void write(int c) throws IOException { + if (_output == null) + throw new IOException("Writer closed"); + _output.append((char) c); + } + + /** + * Writes a portion of an array of characters. + * + * @param cbuf the array of characters. + * @param off the offset from which to start writing characters. + * @param len the number of characters to write. + * @throws IOException if an I/O error occurs. + */ + public void write(char cbuf[], int off, int len) throws IOException { + if (_output == null) + throw new IOException("Writer closed"); + _tmpBuffer = cbuf; + _output.append(_tmpBufferAsCharSequence, off, off + len); + _tmpBuffer = null; // Removes temporary references. + } + + private char[] _tmpBuffer; + + private final CharSequence _tmpBufferAsCharSequence = new CharSequence() { + public int length() { + return _tmpBuffer.length; + } + + public char charAt(int index) { + return _tmpBuffer[index]; + } + + public CharSequence subSequence(int start, int end) { + throw new UnsupportedOperationException(); + } + }; + + /** + * Writes a portion of a string. + * + * @param str a String. + * @param off the offset from which to start writing characters. + * @param len the number of characters to write. + * @throws IOException if an I/O error occurs + */ + public void write(String str, int off, int len) throws IOException { + if (_output == null) + throw new IOException("Writer closed"); + Object obj = str; + if (obj instanceof CharSequence) { + _output.append((CharSequence) obj); + } else { + _output.append(Text.valueOf(str)); + } + } + + /** + * Writes the specified character sequence. + * + * @param csq the character sequence. + * @throws IOException if an I/O error occurs + */ + public void write(CharSequence csq) throws IOException { + if (_output == null) + throw new IOException("Writer closed"); + _output.append(csq); + } + + /** + * Flushes the stream. + */ + public void flush() { + // Do nothing (no buffer). + } + + /** + * Closes and {@link #reset resets} this writer for reuse. + */ + public void close() { + if (_output != null) { + reset(); + } + } + + public void reset() { + _output = null; + _tmpBuffer = null; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/e43574ef/commons/marmotta-commons/src/ext/java/javolution/io/CharSequenceReader.java ---------------------------------------------------------------------- diff --git a/commons/marmotta-commons/src/ext/java/javolution/io/CharSequenceReader.java b/commons/marmotta-commons/src/ext/java/javolution/io/CharSequenceReader.java new file mode 100644 index 0000000..9dd0da2 --- /dev/null +++ b/commons/marmotta-commons/src/ext/java/javolution/io/CharSequenceReader.java @@ -0,0 +1,156 @@ +/* + * Javolution - Java(TM) Solution for Real-Time and Embedded Systems + * Copyright (C) 2012 - Javolution (http://javolution.org/) + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software is + * freely granted, provided that this notice is preserved. + */ +package javolution.io; + +import java.io.IOException; +import java.io.Reader; +import javolution.lang.MathLib; +import javolution.text.CharArray; +import javolution.text.Text; +import javolution.text.TextBuilder; + +/** + * <p> This class allows any <code>CharSequence</code> to be used as + * a reader.</p> + * + * @author <a href="mailto:[email protected]">Jean-Marie Dautelle</a> + * @version 3.8, May 8, 2004 + */ +public final class CharSequenceReader extends Reader { + + /** + * Holds the character sequence input. + */ + private CharSequence _input; + + /** + * Holds the current index into the character sequence. + */ + private int _index; + + /** + * Creates a new character sequence reader for which the character + * sequence input is not set. + * + * @see #setInput + */ + public CharSequenceReader() {} + + /** + * Sets the character sequence to use for reading. + * + * @param charSequence the character sequence to be read. + * @return this reader. + * @throws IllegalStateException if this reader is being reused and + * it has not been {@link #close closed} or {@link #reset reset}. + */ + public CharSequenceReader setInput(CharSequence charSequence) { + if (_input != null) + throw new IllegalStateException("Reader not closed or reset"); + _input = charSequence; + return this; + } + + /** + * Indicates if this stream is ready to be read. + * + * @return <code>true</code> if this reader has remaining characters to + * read; <code>false</code> otherwise. + * @throws IOException if an I/O error occurs. + */ + public boolean ready() throws IOException { + if (_input == null) + throw new IOException("Reader closed"); + return true; + } + + /** + * Closes and {@link #reset resets} this reader for reuse. + */ + public void close() { + if (_input != null) { + reset(); + } + } + + /** + * Reads a single character. This method does not block, <code>-1</code> + * is returned if the end of the character sequence input has been reached. + * + * @return the 31-bits Unicode of the character read, or -1 if there is + * no more remaining bytes to be read. + * @throws IOException if an I/O error occurs (e.g. incomplete + * character sequence being read). + */ + public int read() throws IOException { + if (_input == null) + throw new IOException("Reader closed"); + return (_index < _input.length()) ? _input.charAt(_index++) : -1; + } + + /** + * Reads characters into a portion of an array. This method does not + * block. + * + * @param cbuf the destination buffer. + * @param off the offset at which to start storing characters. + * @param len the maximum number of characters to read + * @return the number of characters read, or -1 if there is no more + * character to be read. + * @throws IOException if an I/O error occurs. + */ + public int read(char cbuf[], int off, int len) throws IOException { + if (_input == null) + throw new IOException("Reader closed"); + final int inputLength = _input.length(); + if (_index >= inputLength) + return -1; + final int count = MathLib.min(inputLength - _index, len); + final Object csq = _input; + if (csq instanceof String) { + String str = (String) csq; + str.getChars(_index, _index + count, cbuf, off); + } else if (csq instanceof Text) { + Text txt = (Text) csq; + txt.getChars(_index, _index + count, cbuf, off); + } else if (csq instanceof TextBuilder) { + TextBuilder tb = (TextBuilder) csq; + tb.getChars(_index, _index + count, cbuf, off); + } else if (csq instanceof CharArray) { + CharArray ca = (CharArray) csq; + System.arraycopy(ca.array(), _index + ca.offset(), cbuf, off, count); + } else { // Generic CharSequence. + for (int i = off, n = off + count, j = _index; i < n;) { + cbuf[i++] = _input.charAt(j++); + } + } + _index += count; + return count; + } + + /** + * Reads characters into the specified appendable. This method does not + * block. + * + * @param dest the destination buffer. + * @throws IOException if an I/O error occurs. + */ + public void read(Appendable dest) throws IOException { + if (_input == null) + throw new IOException("Reader closed"); + dest.append(_input); + } + + @Override + public void reset() { + _index = 0; + _input = null; + } + +} \ No newline at end of file
