Jekyll2017-08-02T14:04:30+00:00http://rememberjava.com/Remember JavaJava Programming Tips & Tricks. Snippets of code to learn, understand and explore.
Hello world with LibGDX2017-05-21T00:00:00+00:002017-05-21T00:00:00+00:00http://rememberjava.com/graphics/2017/05/21/libgdx_hello_world<p><a href="http://libgdx.badlogicgames.com/">libGDX</a> is a cross-platform Java game development library. It supports Windows, Gnu/Linux, Android, iOS, Mac, and web. The desktop variations use the <a href="https://www.lwjgl.org/">Lightweight Java Game Library (LWJGL)</a>, with OpenGL support. There are already <a href="http://www.gamefromscratch.com/page/LibGDX-Tutorial-series.aspx">good comprehensive tutorials</a> out there, so this article will only present the “Hello World” example with a small animation.</p>
<p>As opposed to basic OpenGL libraries, LibGDX and LWJGL offer a complete framework for creating a game, animations or interactions. To lower the bar to entry, the <em>ApplicationListener</em> interface has the common methods, most important the <em>render()</em> method, which is automatically called in a loop.</p>
<p>In the example below, a rotation matrix is defined and set, followed by drawing of the words “Hello World”. Because this method is called in a loop, the <em>angle</em> variable will update, and thus set a new rotation matrix every time. Similarly, the color is updated for each frame. The effect is a continuous never-ending animation.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"> <span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">render</span><span class="o">()</span> <span class="o">{</span>
<span class="n">Gdx</span><span class="o">.</span><span class="na">gl</span><span class="o">.</span><span class="na">glClearColor</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span> <span class="mi">1</span><span class="o">,</span> <span class="mi">1</span><span class="o">,</span> <span class="mi">1</span><span class="o">);</span>
<span class="n">Gdx</span><span class="o">.</span><span class="na">gl</span><span class="o">.</span><span class="na">glClear</span><span class="o">(</span><span class="n">GL20</span><span class="o">.</span><span class="na">GL_COLOR_BUFFER_BIT</span><span class="o">);</span>
<span class="n">Matrix4</span> <span class="n">rotate</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Matrix4</span><span class="o">();</span>
<span class="n">rotate</span><span class="o">.</span><span class="na">rotate</span><span class="o">(</span><span class="k">new</span> <span class="n">Vector3</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="mi">1</span><span class="o">),</span> <span class="n">angle</span><span class="o">--);</span>
<span class="n">rotate</span><span class="o">.</span><span class="na">trn</span><span class="o">(</span><span class="mi">200</span><span class="o">,</span> <span class="mi">200</span><span class="o">,</span> <span class="mi">0</span><span class="o">);</span>
<span class="n">batch</span><span class="o">.</span><span class="na">setTransformMatrix</span><span class="o">(</span><span class="n">rotate</span><span class="o">);</span>
<span class="n">batch</span><span class="o">.</span><span class="na">begin</span><span class="o">();</span>
<span class="n">font</span><span class="o">.</span><span class="na">setColor</span><span class="o">(</span><span class="k">new</span> <span class="n">Color</span><span class="o">(</span><span class="n">color</span><span class="o">++</span> <span class="o">%</span> <span class="mi">255</span><span class="o">));</span>
<span class="n">font</span><span class="o">.</span><span class="na">draw</span><span class="o">(</span><span class="n">batch</span><span class="o">,</span> <span class="s">"Hello World"</span><span class="o">,</span> <span class="o">-</span><span class="mi">40</span><span class="o">,</span> <span class="mi">0</span><span class="o">);</span>
<span class="n">batch</span><span class="o">.</span><span class="na">end</span><span class="o">();</span>
<span class="o">}</span></code></pre></figure>
<div class="image"><img src="/images/libgdx_hello_world.png" /></div>
<p><a href="https://mvnrepository.com/artifact/com.badlogicgames.gdx">There are multiple GDX packages</a>, for different platforms and features, and for this example the following three are needed from the Maven Central repository. Be sure to include the <strong>natives-desktop</strong> version annotation on the gdx-platform package. For other platforms, e.g. Android, other packages are needed.</p>
<figure class="highlight"><pre><code class="language-shell" data-lang="shell">repositories <span class="o">{</span>
mavenCentral<span class="o">()</span>
<span class="o">}</span>
dependencies <span class="o">{</span>
compile <span class="s1">'com.badlogicgames.gdx:gdx:1.9.6'</span>
compile <span class="s1">'com.badlogicgames.gdx:gdx-platform:1.9.6:natives-desktop'</span>
compile <span class="s1">'com.badlogicgames.gdx:gdx-backend-lwjgl:1.9.6'</span>
<span class="o">}</span></code></pre></figure>
<p>Here is the full code, as a stand-alone application.</p>
<script>
var hidden = {};
function fileshowhide(id) {
var text = document.getElementById(id);
var h = (id in hidden) ? hidden[id] : true;
h = !h;
hidden[id] = h;
if(h) {
text.style.display = "none";
} else {
text.style.display = "inline";
}
}
</script>
<div class="filename">LibGdxHelloWold.java</div>
<div class="filebuttons">
<div class="showhide"><button class="filebutton" onclick="fileshowhide('graphics20170521libgdx_hello_worldsrccomrememberjavagraphicsLibGdxHelloWoldjava')">Show file</button></div>
<a class="filebutton github" href="https://github.com/hblok/rememberjava/blob/master/_includes/src/com/rememberjava/graphics/LibGdxHelloWold.java">GitHub</a>
<a class="filebutton raw" href="https://raw.githubusercontent.com/hblok/rememberjava/master/_includes/src/com/rememberjava/graphics/LibGdxHelloWold.java">Raw</a>
</div>
<div id="graphics20170521libgdx_hello_worldsrccomrememberjavagraphicsLibGdxHelloWoldjava" class="javafile">
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">rememberjava</span><span class="o">.</span><span class="na">graphics</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.badlogic.gdx.ApplicationListener</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.badlogic.gdx.Gdx</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.badlogic.gdx.backends.lwjgl.LwjglApplication</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.badlogic.gdx.graphics.Color</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.badlogic.gdx.graphics.GL20</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.badlogic.gdx.graphics.g2d.BitmapFont</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.badlogic.gdx.graphics.g2d.SpriteBatch</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.badlogic.gdx.math.Matrix4</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.badlogic.gdx.math.Vector3</span><span class="o">;</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">LibGdxHelloWold</span> <span class="kd">implements</span> <span class="n">ApplicationListener</span> <span class="o">{</span>
<span class="kd">private</span> <span class="n">SpriteBatch</span> <span class="n">batch</span><span class="o">;</span>
<span class="kd">private</span> <span class="n">BitmapFont</span> <span class="n">font</span><span class="o">;</span>
<span class="kd">private</span> <span class="kt">float</span> <span class="n">angle</span><span class="o">;</span>
<span class="kd">private</span> <span class="kt">int</span> <span class="n">color</span><span class="o">;</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="n">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span>
<span class="n">LwjglApplicationConfiguration</span> <span class="n">cfg</span> <span class="o">=</span> <span class="k">new</span> <span class="n">LwjglApplicationConfiguration</span><span class="o">();</span>
<span class="n">cfg</span><span class="o">.</span><span class="na">title</span> <span class="o">=</span> <span class="s">"hello-world"</span><span class="o">;</span>
<span class="n">cfg</span><span class="o">.</span><span class="na">width</span> <span class="o">=</span> <span class="mi">480</span><span class="o">;</span>
<span class="n">cfg</span><span class="o">.</span><span class="na">height</span> <span class="o">=</span> <span class="mi">320</span><span class="o">;</span>
<span class="k">new</span> <span class="nf">LwjglApplication</span><span class="o">(</span><span class="k">new</span> <span class="n">LibGdxHelloWold</span><span class="o">(),</span> <span class="n">cfg</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">create</span><span class="o">()</span> <span class="o">{</span>
<span class="n">batch</span> <span class="o">=</span> <span class="k">new</span> <span class="n">SpriteBatch</span><span class="o">();</span>
<span class="n">font</span> <span class="o">=</span> <span class="k">new</span> <span class="n">BitmapFont</span><span class="o">();</span>
<span class="n">font</span><span class="o">.</span><span class="na">setColor</span><span class="o">(</span><span class="n">Color</span><span class="o">.</span><span class="na">RED</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">dispose</span><span class="o">()</span> <span class="o">{</span>
<span class="n">batch</span><span class="o">.</span><span class="na">dispose</span><span class="o">();</span>
<span class="n">font</span><span class="o">.</span><span class="na">dispose</span><span class="o">();</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">render</span><span class="o">()</span> <span class="o">{</span>
<span class="n">Gdx</span><span class="o">.</span><span class="na">gl</span><span class="o">.</span><span class="na">glClearColor</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span> <span class="mi">1</span><span class="o">,</span> <span class="mi">1</span><span class="o">,</span> <span class="mi">1</span><span class="o">);</span>
<span class="n">Gdx</span><span class="o">.</span><span class="na">gl</span><span class="o">.</span><span class="na">glClear</span><span class="o">(</span><span class="n">GL20</span><span class="o">.</span><span class="na">GL_COLOR_BUFFER_BIT</span><span class="o">);</span>
<span class="n">Matrix4</span> <span class="n">rotate</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Matrix4</span><span class="o">();</span>
<span class="n">rotate</span><span class="o">.</span><span class="na">rotate</span><span class="o">(</span><span class="k">new</span> <span class="n">Vector3</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="mi">1</span><span class="o">),</span> <span class="n">angle</span><span class="o">--);</span>
<span class="n">rotate</span><span class="o">.</span><span class="na">trn</span><span class="o">(</span><span class="mi">200</span><span class="o">,</span> <span class="mi">200</span><span class="o">,</span> <span class="mi">0</span><span class="o">);</span>
<span class="n">batch</span><span class="o">.</span><span class="na">setTransformMatrix</span><span class="o">(</span><span class="n">rotate</span><span class="o">);</span>
<span class="n">batch</span><span class="o">.</span><span class="na">begin</span><span class="o">();</span>
<span class="n">font</span><span class="o">.</span><span class="na">setColor</span><span class="o">(</span><span class="k">new</span> <span class="n">Color</span><span class="o">(</span><span class="n">color</span><span class="o">++</span> <span class="o">%</span> <span class="mi">255</span><span class="o">));</span>
<span class="n">font</span><span class="o">.</span><span class="na">draw</span><span class="o">(</span><span class="n">batch</span><span class="o">,</span> <span class="s">"Hello World"</span><span class="o">,</span> <span class="o">-</span><span class="mi">40</span><span class="o">,</span> <span class="mi">0</span><span class="o">);</span>
<span class="n">batch</span><span class="o">.</span><span class="na">end</span><span class="o">();</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">resize</span><span class="o">(</span><span class="kt">int</span> <span class="n">width</span><span class="o">,</span> <span class="kt">int</span> <span class="n">height</span><span class="o">)</span> <span class="o">{}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">pause</span><span class="o">()</span> <span class="o">{}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">resume</span><span class="o">()</span> <span class="o">{}</span>
<span class="o">}</span></code></pre></figure>
</div>libGDX is a cross-platform Java game development library. It supports Windows, Gnu/Linux, Android, iOS, Mac, and web. The desktop variations use the Lightweight Java Game Library (LWJGL), with OpenGL support. There are already good comprehensive tutorials out there, so this article will only present the “Hello World” example with a small animation.TLS 1.2 over SUN HttpsServer2017-04-29T00:00:00+00:002017-04-29T00:00:00+00:00http://rememberjava.com/http/2017/04/29/simple_https_server<p>Security can be tricky, HTTPS and TLS no less so. There are many configuration details to be aware of, and the encryption algorithms and cipher suites are moving targets, with new vulnerabilities and fixes all the time. This example does not go into all these details, but instead shows a basic example of how to bring up a HTTPS server using a self-signed TLS 1.2 key and certificate.</p>
<p>The main component of Java TLS communication is the <a href="http://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html">Java Secure Socket Extension (JSSE)</a>. A number of <a href="http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html">algorithms</a> and <a href="http://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html">cryptographic providers</a> are supported. The central class is the <a href="https://docs.oracle.com/javase/8/docs/api/javax/net/ssl/SSLContext.html"><em>SSLContext</em></a>, supported by the <a href="https://docs.oracle.com/javase/8/docs/api/java/security/KeyStore.html"><em>KeyStore</em></a>. These classes load and initialise the relevant keys, certificates, and protocols which are later used by a HTTPS server (or client). See the Oracle blog, for another brief <a href="https://blogs.oracle.com/java-platform-group/jdk-8-will-use-tls-12-as-default">introduction to TLS 1.2</a>, and <a href="https://blogs.oracle.com/java-platform-group/diagnosing-tls,-ssl,-and-https">tips on diagnosing</a> the communication. In particular, notice the unlimited strength implementations, which have to be <a href="http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html">downloaded separately</a>, and copied to <em>JAVA_HOME/lib/security</em>.</p>
<p>The example below shows how the certificate and key are loaded from a Java KeyStore (.jks) file, and used to initialise the <em>SSLContext</em> with the TLS protocol. The <em>SSLContext</em> is passed to the SUN <em>HttpsServer</em> through a <em>HttpsConfigurator</em>. The <em>HttpsServer</em> implementation takes care of the rest, and the static file handler is the same as seen in the <a href="/http/2017/01/20/simple_http_server.html">plain HTTP based example</a>.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"> <span class="kt">void</span> <span class="nf">start</span><span class="o">()</span> <span class="kd">throws</span> <span class="n">Exception</span> <span class="o">{</span>
<span class="n">HttpsServer</span> <span class="n">httpsServer</span> <span class="o">=</span> <span class="n">HttpsServer</span><span class="o">.</span><span class="na">create</span><span class="o">(</span><span class="k">new</span> <span class="n">InetSocketAddress</span><span class="o">(</span><span class="n">PORT</span><span class="o">),</span> <span class="mi">0</span><span class="o">);</span>
<span class="n">SSLContext</span> <span class="n">sslContext</span> <span class="o">=</span> <span class="n">getSslContext</span><span class="o">();</span>
<span class="n">httpsServer</span><span class="o">.</span><span class="na">setHttpsConfigurator</span><span class="o">(</span><span class="k">new</span> <span class="n">HttpsConfigurator</span><span class="o">(</span><span class="n">sslContext</span><span class="o">));</span>
<span class="n">httpsServer</span><span class="o">.</span><span class="na">createContext</span><span class="o">(</span><span class="s">"/secure"</span><span class="o">,</span> <span class="k">new</span> <span class="n">StaticFileHandler</span><span class="o">(</span><span class="n">BASEDIR</span><span class="o">));</span>
<span class="n">httpsServer</span><span class="o">.</span><span class="na">start</span><span class="o">();</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="n">SSLContext</span> <span class="nf">getSslContext</span><span class="o">()</span> <span class="kd">throws</span> <span class="n">Exception</span> <span class="o">{</span>
<span class="n">KeyStore</span> <span class="n">ks</span> <span class="o">=</span> <span class="n">KeyStore</span><span class="o">.</span><span class="na">getInstance</span><span class="o">(</span><span class="s">"JKS"</span><span class="o">);</span>
<span class="n">ks</span><span class="o">.</span><span class="na">load</span><span class="o">(</span><span class="k">new</span> <span class="n">FileInputStream</span><span class="o">(</span><span class="n">KEYSTORE_FILE</span><span class="o">),</span> <span class="n">KEYSTORE_PASSWORD</span><span class="o">.</span><span class="na">toCharArray</span><span class="o">());</span>
<span class="n">KeyManagerFactory</span> <span class="n">kmf</span> <span class="o">=</span> <span class="n">KeyManagerFactory</span><span class="o">.</span><span class="na">getInstance</span><span class="o">(</span><span class="s">"SunX509"</span><span class="o">);</span>
<span class="n">kmf</span><span class="o">.</span><span class="na">init</span><span class="o">(</span><span class="n">ks</span><span class="o">,</span> <span class="n">KEY_PASSWORD</span><span class="o">.</span><span class="na">toCharArray</span><span class="o">());</span>
<span class="n">TrustManagerFactory</span> <span class="n">tmf</span> <span class="o">=</span> <span class="n">TrustManagerFactory</span><span class="o">.</span><span class="na">getInstance</span><span class="o">(</span><span class="s">"SunX509"</span><span class="o">);</span>
<span class="n">tmf</span><span class="o">.</span><span class="na">init</span><span class="o">(</span><span class="n">ks</span><span class="o">);</span>
<span class="n">SSLContext</span> <span class="n">sslContext</span> <span class="o">=</span> <span class="n">SSLContext</span><span class="o">.</span><span class="na">getInstance</span><span class="o">(</span><span class="s">"TLS"</span><span class="o">);</span>
<span class="n">sslContext</span><span class="o">.</span><span class="na">init</span><span class="o">(</span><span class="n">kmf</span><span class="o">.</span><span class="na">getKeyManagers</span><span class="o">(),</span> <span class="n">tmf</span><span class="o">.</span><span class="na">getTrustManagers</span><span class="o">(),</span> <span class="kc">null</span><span class="o">);</span>
<span class="k">return</span> <span class="n">sslContext</span><span class="o">;</span>
<span class="o">}</span></code></pre></figure>
<p>The code also includes a hard-coded generation of the key and certificate. A normal server would of course not implement this, but it’s included here to make the example self-contained and working out of the box. The following command is executed, and a Java KeyStore file containing a RSA based 2048 bits key, valid for one year. The keytool command will either prompt for name and organisational details, or these can be passed in using the <em>dname</em> argument. Also notice that password to the keystore and key are different. Further <a href="http://docs.oracle.com/javase/7/docs/technotes/tools/solaris/keytool.html">usage details on <em>keytool</em> can be found here</a>.</p>
<figure class="highlight"><pre><code class="language-shell" data-lang="shell">keytool -genkey -keyalg RSA -alias some_alias -validity 365 -keysize 2048 <span class="se">\</span>
-dname <span class="nv">cn</span><span class="o">=</span>John_Doe,ou<span class="o">=</span>TestOrgUnit,o<span class="o">=</span>TestOrg,c<span class="o">=</span>US -keystore /tmp/test.jks -storepass pass_store -keypass pass_key</code></pre></figure>
<p>Since the certificate is self-signed, a modern browser will yield a warning, and not allow the communication to continue without an explicit exception, as seen below. For the sake of this example, that is fine. If we do allow the certificate to be used, we will see that the communication is indeed encrypted, “using a strong protocol (TLS 1.2), a strong key exchange (ECDHE_RSA with P-256), and a strong cipher (AES_128_GCM)”, aka “TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256”.</p>
<p>On the topic of keys and algorithms, Elliptic Curve Cryptography (ECC) is relevant. <a href="https://www.digicert.com/ecc.htm">Digicert</a> gives a brief introduction, with details on how to <a href="https://www.digicert.com/ecc-csr-creation-ssl-installation-apache.htm">generate keys for Apache</a>. Openssl has further <a href="https://wiki.openssl.org/index.php/Command_Line_Elliptic_Curve_Operations">information on EC using openssl</a>.</p>
<div class="image"><img src="/images/firefox_not_secure.png" /></div>
<div class="image"><img src="/images/firefox_security_info.png" /></div>
<div class="image"><img src="/images/chrome_security_overview.png" /></div>
<p>The two files below is all that is needed. A key and certificate is generate if not already present under <em>/tmp/test.jks</em>. Go to <em>https://localhost:9999/secure/test.txt</em> and enable the security exception to try it out. Also notice the logging in the console window of the server.</p>
<script>
var hidden = {};
function fileshowhide(id) {
var text = document.getElementById(id);
var h = (id in hidden) ? hidden[id] : true;
h = !h;
hidden[id] = h;
if(h) {
text.style.display = "none";
} else {
text.style.display = "inline";
}
}
</script>
<div class="filename">SimpleHttpsServer.java</div>
<div class="filebuttons">
<div class="showhide"><button class="filebutton" onclick="fileshowhide('http20170429simple_https_serversrccomrememberjavahttpSimpleHttpsServerjava')">Show file</button></div>
<a class="filebutton github" href="https://github.com/hblok/rememberjava/blob/master/_includes/src/com/rememberjava/http/SimpleHttpsServer.java">GitHub</a>
<a class="filebutton raw" href="https://raw.githubusercontent.com/hblok/rememberjava/master/_includes/src/com/rememberjava/http/SimpleHttpsServer.java">Raw</a>
</div>
<div id="http20170429simple_https_serversrccomrememberjavahttpSimpleHttpsServerjava" class="javafile">
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="cm">/* Copyright rememberjava.com. Licensed under GPL 3. See http://rememberjava.com/license */</span>
<span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">rememberjava</span><span class="o">.</span><span class="na">http</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.io.File</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.io.FileInputStream</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.lang.ProcessBuilder.Redirect</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.net.InetSocketAddress</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.security.KeyStore</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">javax.net.ssl.KeyManagerFactory</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">javax.net.ssl.SSLContext</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">javax.net.ssl.TrustManagerFactory</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.sun.net.httpserver.HttpsConfigurator</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.sun.net.httpserver.HttpsServer</span><span class="o">;</span>
<span class="cm">/**
* A HTTPS server using a self-signed TLS 1.2 key and certificate generated by
* the Java keytool command.
*
* Once running, connect to https://localhost:9999/secure/test.txt
*/</span>
<span class="nd">@SuppressWarnings</span><span class="o">(</span><span class="s">"restriction"</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">SimpleHttpsServer</span> <span class="o">{</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">File</span> <span class="n">KEYSTORE_FILE</span> <span class="o">=</span> <span class="k">new</span> <span class="n">File</span><span class="o">(</span><span class="n">System</span><span class="o">.</span><span class="na">getProperty</span><span class="o">(</span><span class="s">"java.io.tmpdir"</span><span class="o">),</span>
<span class="s">"test.jks"</span><span class="o">);</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">KEYSTORE_PASSWORD</span> <span class="o">=</span> <span class="s">"pass_store"</span><span class="o">;</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">KEY_PASSWORD</span> <span class="o">=</span> <span class="s">"pass_key"</span><span class="o">;</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">BASEDIR</span> <span class="o">=</span> <span class="s">"com/rememberjava/http"</span><span class="o">;</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="kt">int</span> <span class="n">PORT</span> <span class="o">=</span> <span class="mi">9999</span><span class="o">;</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="n">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">Exception</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">setProperty</span><span class="o">(</span><span class="s">"javax.net.debug"</span><span class="o">,</span> <span class="s">"all"</span><span class="o">);</span>
<span class="n">generateCertificate</span><span class="o">();</span>
<span class="k">new</span> <span class="nf">SimpleHttpsServer</span><span class="o">().</span><span class="na">start</span><span class="o">();</span>
<span class="o">}</span>
<span class="cm">/**
* Generates a new self-signed certificate in /tmp/test.jks, if it does not
* already exist.
*/</span>
<span class="kd">static</span> <span class="kt">void</span> <span class="nf">generateCertificate</span><span class="o">()</span> <span class="kd">throws</span> <span class="n">Exception</span> <span class="o">{</span>
<span class="n">File</span> <span class="n">keytool</span> <span class="o">=</span> <span class="k">new</span> <span class="n">File</span><span class="o">(</span><span class="n">System</span><span class="o">.</span><span class="na">getProperty</span><span class="o">(</span><span class="s">"java.home"</span><span class="o">),</span> <span class="s">"bin/keytool"</span><span class="o">);</span>
<span class="n">String</span><span class="o">[]</span> <span class="n">genkeyCmd</span> <span class="o">=</span> <span class="k">new</span> <span class="n">String</span><span class="o">[]</span> <span class="o">{</span>
<span class="n">keytool</span><span class="o">.</span><span class="na">toString</span><span class="o">(),</span>
<span class="s">"-genkey"</span><span class="o">,</span>
<span class="s">"-keyalg"</span><span class="o">,</span> <span class="s">"RSA"</span><span class="o">,</span>
<span class="s">"-alias"</span><span class="o">,</span> <span class="s">"some_alias"</span><span class="o">,</span>
<span class="s">"-validity"</span><span class="o">,</span> <span class="s">"365"</span><span class="o">,</span>
<span class="s">"-keysize"</span><span class="o">,</span> <span class="s">"2048"</span><span class="o">,</span>
<span class="s">"-dname"</span><span class="o">,</span> <span class="s">"cn=John_Doe,ou=TestOrgUnit,o=TestOrg,c=US"</span><span class="o">,</span>
<span class="s">"-keystore"</span><span class="o">,</span> <span class="n">KEYSTORE_FILE</span><span class="o">.</span><span class="na">getAbsolutePath</span><span class="o">(),</span>
<span class="s">"-storepass"</span><span class="o">,</span> <span class="n">KEYSTORE_PASSWORD</span><span class="o">,</span>
<span class="s">"-keypass"</span><span class="o">,</span> <span class="n">KEY_PASSWORD</span><span class="o">};</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">String</span><span class="o">.</span><span class="na">join</span><span class="o">(</span><span class="s">" "</span><span class="o">,</span> <span class="n">genkeyCmd</span><span class="o">));</span>
<span class="n">ProcessBuilder</span> <span class="n">processBuilder</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ProcessBuilder</span><span class="o">(</span><span class="n">genkeyCmd</span><span class="o">);</span>
<span class="n">processBuilder</span><span class="o">.</span><span class="na">redirectErrorStream</span><span class="o">(</span><span class="kc">true</span><span class="o">);</span>
<span class="n">processBuilder</span><span class="o">.</span><span class="na">redirectOutput</span><span class="o">(</span><span class="n">Redirect</span><span class="o">.</span><span class="na">INHERIT</span><span class="o">);</span>
<span class="n">processBuilder</span><span class="o">.</span><span class="na">redirectError</span><span class="o">(</span><span class="n">Redirect</span><span class="o">.</span><span class="na">INHERIT</span><span class="o">);</span>
<span class="n">Process</span> <span class="n">exec</span> <span class="o">=</span> <span class="n">processBuilder</span><span class="o">.</span><span class="na">start</span><span class="o">();</span>
<span class="n">exec</span><span class="o">.</span><span class="na">waitFor</span><span class="o">();</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Exit value: "</span> <span class="o">+</span> <span class="n">exec</span><span class="o">.</span><span class="na">exitValue</span><span class="o">());</span>
<span class="o">}</span>
<span class="kt">void</span> <span class="nf">start</span><span class="o">()</span> <span class="kd">throws</span> <span class="n">Exception</span> <span class="o">{</span>
<span class="n">HttpsServer</span> <span class="n">httpsServer</span> <span class="o">=</span> <span class="n">HttpsServer</span><span class="o">.</span><span class="na">create</span><span class="o">(</span><span class="k">new</span> <span class="n">InetSocketAddress</span><span class="o">(</span><span class="n">PORT</span><span class="o">),</span> <span class="mi">0</span><span class="o">);</span>
<span class="n">SSLContext</span> <span class="n">sslContext</span> <span class="o">=</span> <span class="n">getSslContext</span><span class="o">();</span>
<span class="n">httpsServer</span><span class="o">.</span><span class="na">setHttpsConfigurator</span><span class="o">(</span><span class="k">new</span> <span class="n">HttpsConfigurator</span><span class="o">(</span><span class="n">sslContext</span><span class="o">));</span>
<span class="n">httpsServer</span><span class="o">.</span><span class="na">createContext</span><span class="o">(</span><span class="s">"/secure"</span><span class="o">,</span> <span class="k">new</span> <span class="n">StaticFileHandler</span><span class="o">(</span><span class="n">BASEDIR</span><span class="o">));</span>
<span class="n">httpsServer</span><span class="o">.</span><span class="na">start</span><span class="o">();</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="n">SSLContext</span> <span class="nf">getSslContext</span><span class="o">()</span> <span class="kd">throws</span> <span class="n">Exception</span> <span class="o">{</span>
<span class="n">KeyStore</span> <span class="n">ks</span> <span class="o">=</span> <span class="n">KeyStore</span><span class="o">.</span><span class="na">getInstance</span><span class="o">(</span><span class="s">"JKS"</span><span class="o">);</span>
<span class="n">ks</span><span class="o">.</span><span class="na">load</span><span class="o">(</span><span class="k">new</span> <span class="n">FileInputStream</span><span class="o">(</span><span class="n">KEYSTORE_FILE</span><span class="o">),</span> <span class="n">KEYSTORE_PASSWORD</span><span class="o">.</span><span class="na">toCharArray</span><span class="o">());</span>
<span class="n">KeyManagerFactory</span> <span class="n">kmf</span> <span class="o">=</span> <span class="n">KeyManagerFactory</span><span class="o">.</span><span class="na">getInstance</span><span class="o">(</span><span class="s">"SunX509"</span><span class="o">);</span>
<span class="n">kmf</span><span class="o">.</span><span class="na">init</span><span class="o">(</span><span class="n">ks</span><span class="o">,</span> <span class="n">KEY_PASSWORD</span><span class="o">.</span><span class="na">toCharArray</span><span class="o">());</span>
<span class="n">TrustManagerFactory</span> <span class="n">tmf</span> <span class="o">=</span> <span class="n">TrustManagerFactory</span><span class="o">.</span><span class="na">getInstance</span><span class="o">(</span><span class="s">"SunX509"</span><span class="o">);</span>
<span class="n">tmf</span><span class="o">.</span><span class="na">init</span><span class="o">(</span><span class="n">ks</span><span class="o">);</span>
<span class="n">SSLContext</span> <span class="n">sslContext</span> <span class="o">=</span> <span class="n">SSLContext</span><span class="o">.</span><span class="na">getInstance</span><span class="o">(</span><span class="s">"TLS"</span><span class="o">);</span>
<span class="n">sslContext</span><span class="o">.</span><span class="na">init</span><span class="o">(</span><span class="n">kmf</span><span class="o">.</span><span class="na">getKeyManagers</span><span class="o">(),</span> <span class="n">tmf</span><span class="o">.</span><span class="na">getTrustManagers</span><span class="o">(),</span> <span class="kc">null</span><span class="o">);</span>
<span class="k">return</span> <span class="n">sslContext</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span></code></pre></figure>
</div>
<script>
var hidden = {};
function fileshowhide(id) {
var text = document.getElementById(id);
var h = (id in hidden) ? hidden[id] : true;
h = !h;
hidden[id] = h;
if(h) {
text.style.display = "none";
} else {
text.style.display = "inline";
}
}
</script>
<div class="filename">StaticFileHandler.java</div>
<div class="filebuttons">
<div class="showhide"><button class="filebutton" onclick="fileshowhide('http20170429simple_https_serversrccomrememberjavahttpStaticFileHandlerjava')">Show file</button></div>
<a class="filebutton github" href="https://github.com/hblok/rememberjava/blob/master/_includes/src/com/rememberjava/http/StaticFileHandler.java">GitHub</a>
<a class="filebutton raw" href="https://raw.githubusercontent.com/hblok/rememberjava/master/_includes/src/com/rememberjava/http/StaticFileHandler.java">Raw</a>
</div>
<div id="http20170429simple_https_serversrccomrememberjavahttpStaticFileHandlerjava" class="javafile">
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="cm">/* Copyright rememberjava.com. Licensed under GPL 3. See http://rememberjava.com/license */</span>
<span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">rememberjava</span><span class="o">.</span><span class="na">http</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.io.File</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.io.IOException</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.io.OutputStream</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.net.URI</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.nio.file.Files</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.sun.net.httpserver.Headers</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.sun.net.httpserver.HttpExchange</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.sun.net.httpserver.HttpHandler</span><span class="o">;</span>
<span class="nd">@SuppressWarnings</span><span class="o">(</span><span class="s">"restriction"</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">StaticFileHandler</span> <span class="kd">implements</span> <span class="n">HttpHandler</span> <span class="o">{</span>
<span class="kd">private</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">baseDir</span><span class="o">;</span>
<span class="kd">public</span> <span class="nf">StaticFileHandler</span><span class="o">(</span><span class="n">String</span> <span class="n">baseDir</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">baseDir</span> <span class="o">=</span> <span class="n">baseDir</span><span class="o">;</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">handle</span><span class="o">(</span><span class="n">HttpExchange</span> <span class="n">ex</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="n">URI</span> <span class="n">uri</span> <span class="o">=</span> <span class="n">ex</span><span class="o">.</span><span class="na">getRequestURI</span><span class="o">();</span>
<span class="n">String</span> <span class="n">name</span> <span class="o">=</span> <span class="k">new</span> <span class="n">File</span><span class="o">(</span><span class="n">uri</span><span class="o">.</span><span class="na">getPath</span><span class="o">()).</span><span class="na">getName</span><span class="o">();</span>
<span class="n">File</span> <span class="n">path</span> <span class="o">=</span> <span class="k">new</span> <span class="n">File</span><span class="o">(</span><span class="n">baseDir</span><span class="o">,</span> <span class="n">name</span><span class="o">);</span>
<span class="n">Headers</span> <span class="n">h</span> <span class="o">=</span> <span class="n">ex</span><span class="o">.</span><span class="na">getResponseHeaders</span><span class="o">();</span>
<span class="c1">// Could be more clever about the content type based on the filename here.</span>
<span class="n">h</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="s">"Content-Type"</span><span class="o">,</span> <span class="s">"text/html"</span><span class="o">);</span>
<span class="n">OutputStream</span> <span class="n">out</span> <span class="o">=</span> <span class="n">ex</span><span class="o">.</span><span class="na">getResponseBody</span><span class="o">();</span>
<span class="k">if</span> <span class="o">(</span><span class="n">path</span><span class="o">.</span><span class="na">exists</span><span class="o">())</span> <span class="o">{</span>
<span class="n">ex</span><span class="o">.</span><span class="na">sendResponseHeaders</span><span class="o">(</span><span class="mi">200</span><span class="o">,</span> <span class="n">path</span><span class="o">.</span><span class="na">length</span><span class="o">());</span>
<span class="n">out</span><span class="o">.</span><span class="na">write</span><span class="o">(</span><span class="n">Files</span><span class="o">.</span><span class="na">readAllBytes</span><span class="o">(</span><span class="n">path</span><span class="o">.</span><span class="na">toPath</span><span class="o">()));</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">err</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"File not found: "</span> <span class="o">+</span> <span class="n">path</span><span class="o">.</span><span class="na">getAbsolutePath</span><span class="o">());</span>
<span class="n">ex</span><span class="o">.</span><span class="na">sendResponseHeaders</span><span class="o">(</span><span class="mi">404</span><span class="o">,</span> <span class="mi">0</span><span class="o">);</span>
<span class="n">out</span><span class="o">.</span><span class="na">write</span><span class="o">(</span><span class="s">"404 File not found."</span><span class="o">.</span><span class="na">getBytes</span><span class="o">());</span>
<span class="o">}</span>
<span class="n">out</span><span class="o">.</span><span class="na">close</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span></code></pre></figure>
</div>Security can be tricky, HTTPS and TLS no less so. There are many configuration details to be aware of, and the encryption algorithms and cipher suites are moving targets, with new vulnerabilities and fixes all the time. This example does not go into all these details, but instead shows a basic example of how to bring up a HTTPS server using a self-signed TLS 1.2 key and certificate.Guava EventBus2017-03-15T00:00:00+00:002017-03-15T00:00:00+00:00http://rememberjava.com/guava/2017/03/15/guava_eventbus<p><a href="https://github.com/google/guava">Guava</a> is Google’s utilities, collections and helpers library for Java. Similar in spirit to the <a href="https://commons.apache.org/">Apache Commons</a> set of libraries, but possibly a bit more pragmatic. Google’s engineers use the Guava components in their daily work, and have fine-tuned the APIs to boost their own productivity. The current release is version 21.</p>
<p>In this article, we’ll look at the Guava <a href="https://google.github.io/guava/releases/21.0/api/docs/com/google/common/eventbus/EventBus.html">EventBus</a> class, for publishing and subscribing to application wide events of all kinds. It strikes a good balance between convenience and type-safety, and is much more lightweight than rolling your own Event, Handler and Fire classes. See also the <a href="https://github.com/google/guava/wiki/EventBusExplained">Guava documentations</a> for further details.</p>
<p>To have an example to work with, the following <em>Player</em> skeleton class is implemented. It comes with three separate Event classes, which are very minimal in this contrived example. In a real application, they might inherit from a super-Event class, and possibly carry some content, at least the source of the event or similar. Alternatively, they could have been made simpler, by being elements of an enumeration, however, then we’d have to do manual matching and routing on the receiving end.</p>
<p>Notice, that the receiving part of the EventBus events is already in place, in the form of the <em>@Subscribe</em> annotations.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"> <span class="kd">class</span> <span class="nc">Player</span> <span class="o">{</span>
<span class="kt">boolean</span> <span class="n">playing</span><span class="o">;</span>
<span class="kt">boolean</span> <span class="n">paused</span><span class="o">;</span>
<span class="nd">@Subscribe</span>
<span class="kt">void</span> <span class="nf">play</span><span class="o">(</span><span class="n">PlayEvent</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"play"</span><span class="o">);</span>
<span class="n">playing</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span>
<span class="n">paused</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
<span class="o">}</span>
<span class="nd">@Subscribe</span>
<span class="kt">void</span> <span class="nf">pause</span><span class="o">(</span><span class="n">PauseEvent</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"pause"</span><span class="o">);</span>
<span class="n">playing</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
<span class="n">paused</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span>
<span class="o">}</span>
<span class="nd">@Subscribe</span>
<span class="kt">void</span> <span class="nf">stop</span><span class="o">(</span><span class="n">StopEvent</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"stop"</span><span class="o">);</span>
<span class="n">playing</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
<span class="n">paused</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kd">class</span> <span class="nc">PlayEvent</span> <span class="o">{}</span>
<span class="kd">class</span> <span class="nc">PauseEvent</span> <span class="o">{}</span>
<span class="kd">class</span> <span class="nc">StopEvent</span> <span class="o">{}</span></code></pre></figure>
<p>In the following code, the <em>EventBus</em> is created, and the <em>Player</em> is registered as a receiver. To publish events, all that is required is to pass objects of the same types to the <em>EventBus.post()</em> method. The internals of the <em>EventBus</em> will invoke all methods which are marked with the <em>@Subscribe</em> annotation and match the exact type. Event types are not inherited, so a catch-all subscriber is not possible, which is probably a good design choice.</p>
<p>The <em>EventBus</em> also makes unit testing easier, since sender and receiver can be decoupled without extensive mocking. In fact, we now have a choice of testing the methods of the <em>Player</em> class through the <em>Eventbus</em>, or by invoking its methods directly. Either might be fine when writing unit tests. Although, for component level test, sticking with the <em>EventBus</em> is probably better, as it will be closer to the live application.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"> <span class="kd">private</span> <span class="n">Player</span> <span class="n">player</span><span class="o">;</span>
<span class="kd">private</span> <span class="n">EventBus</span> <span class="n">bus</span><span class="o">;</span>
<span class="nd">@Before</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">setup</span><span class="o">()</span> <span class="o">{</span>
<span class="n">player</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Player</span><span class="o">();</span>
<span class="n">bus</span> <span class="o">=</span> <span class="k">new</span> <span class="n">EventBus</span><span class="o">();</span>
<span class="n">bus</span><span class="o">.</span><span class="na">register</span><span class="o">(</span><span class="n">player</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@Test</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">testPlay</span><span class="o">()</span> <span class="o">{</span>
<span class="n">bus</span><span class="o">.</span><span class="na">post</span><span class="o">(</span><span class="k">new</span> <span class="n">PlayEvent</span><span class="o">());</span>
<span class="n">assertTrue</span><span class="o">(</span><span class="n">player</span><span class="o">.</span><span class="na">playing</span><span class="o">);</span>
<span class="n">assertFalse</span><span class="o">(</span><span class="n">player</span><span class="o">.</span><span class="na">paused</span><span class="o">);</span>
<span class="o">}</span></code></pre></figure>
<p>To include the Guava library from the Maven Gradle repository, this will suffice.</p>
<figure class="highlight"><pre><code class="language-shell" data-lang="shell">repositories <span class="o">{</span>
mavenCentral<span class="o">()</span>
<span class="o">}</span>
dependencies <span class="o">{</span>
compile <span class="s1">'com.google.guava:guava:21.0'</span>
<span class="o">}</span></code></pre></figure>
<p>Here is the full code listing.</p>
<script>
var hidden = {};
function fileshowhide(id) {
var text = document.getElementById(id);
var h = (id in hidden) ? hidden[id] : true;
h = !h;
hidden[id] = h;
if(h) {
text.style.display = "none";
} else {
text.style.display = "inline";
}
}
</script>
<div class="filename">EventBusTest.java</div>
<div class="filebuttons">
<div class="showhide"><button class="filebutton" onclick="fileshowhide('guava20170315guava_eventbussrccomrememberjavaguavaEventBusTestjava')">Show file</button></div>
<a class="filebutton github" href="https://github.com/hblok/rememberjava/blob/master/_includes/src/com/rememberjava/guava/EventBusTest.java">GitHub</a>
<a class="filebutton raw" href="https://raw.githubusercontent.com/hblok/rememberjava/master/_includes/src/com/rememberjava/guava/EventBusTest.java">Raw</a>
</div>
<div id="guava20170315guava_eventbussrccomrememberjavaguavaEventBusTestjava" class="javafile">
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="cm">/* Copyright rememberjava.com. Licensed under GPL 3. See http://rememberjava.com/license */</span>
<span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">rememberjava</span><span class="o">.</span><span class="na">guava</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">static</span> <span class="n">org</span><span class="o">.</span><span class="na">junit</span><span class="o">.</span><span class="na">Assert</span><span class="o">.</span><span class="na">assertFalse</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">static</span> <span class="n">org</span><span class="o">.</span><span class="na">junit</span><span class="o">.</span><span class="na">Assert</span><span class="o">.</span><span class="na">assertTrue</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.junit.Before</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.junit.Test</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.google.common.eventbus.EventBus</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.google.common.eventbus.Subscribe</span><span class="o">;</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">EventBusTest</span> <span class="o">{</span>
<span class="kd">class</span> <span class="nc">Player</span> <span class="o">{</span>
<span class="kt">boolean</span> <span class="n">playing</span><span class="o">;</span>
<span class="kt">boolean</span> <span class="n">paused</span><span class="o">;</span>
<span class="nd">@Subscribe</span>
<span class="kt">void</span> <span class="nf">play</span><span class="o">(</span><span class="n">PlayEvent</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"play"</span><span class="o">);</span>
<span class="n">playing</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span>
<span class="n">paused</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
<span class="o">}</span>
<span class="nd">@Subscribe</span>
<span class="kt">void</span> <span class="nf">pause</span><span class="o">(</span><span class="n">PauseEvent</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"pause"</span><span class="o">);</span>
<span class="n">playing</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
<span class="n">paused</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span>
<span class="o">}</span>
<span class="nd">@Subscribe</span>
<span class="kt">void</span> <span class="nf">stop</span><span class="o">(</span><span class="n">StopEvent</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"stop"</span><span class="o">);</span>
<span class="n">playing</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
<span class="n">paused</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kd">class</span> <span class="nc">PlayEvent</span> <span class="o">{}</span>
<span class="kd">class</span> <span class="nc">PauseEvent</span> <span class="o">{}</span>
<span class="kd">class</span> <span class="nc">StopEvent</span> <span class="o">{}</span>
<span class="kd">private</span> <span class="n">Player</span> <span class="n">player</span><span class="o">;</span>
<span class="kd">private</span> <span class="n">EventBus</span> <span class="n">bus</span><span class="o">;</span>
<span class="nd">@Before</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">setup</span><span class="o">()</span> <span class="o">{</span>
<span class="n">player</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Player</span><span class="o">();</span>
<span class="n">bus</span> <span class="o">=</span> <span class="k">new</span> <span class="n">EventBus</span><span class="o">();</span>
<span class="n">bus</span><span class="o">.</span><span class="na">register</span><span class="o">(</span><span class="n">player</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@Test</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">testPlay</span><span class="o">()</span> <span class="o">{</span>
<span class="n">bus</span><span class="o">.</span><span class="na">post</span><span class="o">(</span><span class="k">new</span> <span class="n">PlayEvent</span><span class="o">());</span>
<span class="n">assertTrue</span><span class="o">(</span><span class="n">player</span><span class="o">.</span><span class="na">playing</span><span class="o">);</span>
<span class="n">assertFalse</span><span class="o">(</span><span class="n">player</span><span class="o">.</span><span class="na">paused</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@Test</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">testAll</span><span class="o">()</span> <span class="o">{</span>
<span class="n">bus</span><span class="o">.</span><span class="na">post</span><span class="o">(</span><span class="k">new</span> <span class="n">Object</span><span class="o">());</span>
<span class="n">assertFalse</span><span class="o">(</span><span class="n">player</span><span class="o">.</span><span class="na">playing</span><span class="o">);</span>
<span class="n">assertFalse</span><span class="o">(</span><span class="n">player</span><span class="o">.</span><span class="na">paused</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span></code></pre></figure>
</div>Guava is Google’s utilities, collections and helpers library for Java. Similar in spirit to the Apache Commons set of libraries, but possibly a bit more pragmatic. Google’s engineers use the Guava components in their daily work, and have fine-tuned the APIs to boost their own productivity. The current release is version 21.Cantor circles and recursion2017-03-14T00:00:00+00:002017-03-14T00:00:00+00:00http://rememberjava.com/graphics/2017/03/14/cantor_circles<p>This article draws inspiration from an old post dubbed “Cantor Circles”, but which turned out to render bisecting circles rather than <a href="https://en.wikipedia.org/wiki/Cantor_set">Cantor sets</a>. Nevertheless, it gained some interest, and the exact image below, from the 2002 post, can now be easily found on <a href="https://www.google.com/search?q=cantor+circles&tbm=isch">Google Image search</a>. In this post, the old code is revived, and animation and colors are added for nice patterns and fun. Cantor’s ternary set is also implemented.</p>
<div class="image"><img src="/images/cantor/2002_47_cantor.png" /></div>
<p>I suspect the origin of the bisecting circles was a simple example for recursive code, and simply dividing by two makes the code and rendering easy to understand. In the block below, the function <em>drawCircles()</em> is recursive, calling itself twice with parameters to half the next circles. A recursive function needs a stopping condition, and in this case it is the parameter <em>times</em> which stops further recursions when it reaches 0. The helper function <em>drawMidCircle()</em> makes it more convenient to set the coordinates and size of the circle.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"> <span class="kd">private</span> <span class="kt">void</span> <span class="nf">drawCircles</span><span class="o">(</span><span class="kt">int</span> <span class="n">x</span><span class="o">,</span> <span class="kt">int</span> <span class="n">y</span><span class="o">,</span> <span class="kt">int</span> <span class="n">radius</span><span class="o">,</span> <span class="kt">int</span> <span class="n">times</span><span class="o">,</span> <span class="n">Graphics</span> <span class="n">g</span><span class="o">)</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">printf</span><span class="o">(</span><span class="s">"x=%d, y=%d, r=%d, times=%d\n"</span><span class="o">,</span> <span class="n">x</span><span class="o">,</span> <span class="n">y</span><span class="o">,</span> <span class="n">radius</span><span class="o">,</span> <span class="n">times</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">times</span> <span class="o">></span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
<span class="n">drawMidCircle</span><span class="o">(</span><span class="n">x</span><span class="o">,</span> <span class="n">y</span><span class="o">,</span> <span class="n">radius</span><span class="o">,</span> <span class="n">g</span><span class="o">);</span>
<span class="n">drawCircles</span><span class="o">(</span><span class="n">x</span> <span class="o">+</span> <span class="n">radius</span> <span class="o">/</span> <span class="mi">2</span><span class="o">,</span> <span class="n">y</span><span class="o">,</span> <span class="n">radius</span> <span class="o">/</span> <span class="mi">2</span><span class="o">,</span> <span class="n">times</span> <span class="o">-</span> <span class="mi">1</span><span class="o">,</span> <span class="n">g</span><span class="o">);</span>
<span class="n">drawCircles</span><span class="o">(</span><span class="n">x</span> <span class="o">-</span> <span class="n">radius</span> <span class="o">/</span> <span class="mi">2</span><span class="o">,</span> <span class="n">y</span><span class="o">,</span> <span class="n">radius</span> <span class="o">/</span> <span class="mi">2</span><span class="o">,</span> <span class="n">times</span> <span class="o">-</span> <span class="mi">1</span><span class="o">,</span> <span class="n">g</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">drawMidCircle</span><span class="o">(</span><span class="kt">int</span> <span class="n">x</span><span class="o">,</span> <span class="kt">int</span> <span class="n">y</span><span class="o">,</span> <span class="kt">int</span> <span class="n">radius</span><span class="o">,</span> <span class="n">Graphics</span> <span class="n">g</span><span class="o">)</span> <span class="o">{</span>
<span class="n">g</span><span class="o">.</span><span class="na">drawOval</span><span class="o">(</span><span class="n">x</span> <span class="o">-</span> <span class="n">radius</span><span class="o">,</span> <span class="n">y</span> <span class="o">-</span> <span class="n">radius</span><span class="o">,</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">radius</span><span class="o">,</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">radius</span><span class="o">);</span>
<span class="o">}</span></code></pre></figure>
<div class="image"><img src="/images/cantor/cantor_bw.gif" /></div>
<p>The next example adds animation. The recursion is the same, but adds an angle parameter to rotate the circles. Also notice that the angle <em>a</em> is negated, which leads to the alternating clockwise and counter-clockwise rotation within each small circle.</p>
<p>Also of interest here, is the <a href="https://docs.oracle.com/javase/tutorial/extra/fullscreen/doublebuf.html">Swing double buffering</a> (actually, triple buffering is used in this example) using the <a href="https://docs.oracle.com/javase/8/docs/api/java/awt/image/BufferStrategy.html"><em>BufferStrategy</em></a> class. Notice that the <em>paint()</em> method of the Frame is no longer overridden to render the graphics, but rather the <em>Graphics</em> object is provided by the <em>BufferStrategy</em> and passed to the custom <em>render()</em> function.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"> <span class="kd">private</span> <span class="kt">void</span> <span class="nf">drawCircles</span><span class="o">(</span><span class="kt">int</span> <span class="n">x</span><span class="o">,</span> <span class="kt">int</span> <span class="n">y</span><span class="o">,</span> <span class="kt">int</span> <span class="n">r</span><span class="o">,</span> <span class="kt">double</span> <span class="n">a</span><span class="o">,</span> <span class="kt">int</span> <span class="n">times</span><span class="o">,</span> <span class="n">Graphics</span> <span class="n">g</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">times</span> <span class="o"><=</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span><span class="o">;</span>
<span class="o">}</span>
<span class="n">drawMidCircle</span><span class="o">(</span><span class="n">x</span><span class="o">,</span> <span class="n">y</span><span class="o">,</span> <span class="n">r</span><span class="o">,</span> <span class="n">g</span><span class="o">);</span>
<span class="kt">int</span> <span class="n">x1</span> <span class="o">=</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span> <span class="o">(</span><span class="n">r</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">cos</span><span class="o">(</span><span class="n">a</span><span class="o">));</span>
<span class="kt">int</span> <span class="n">y1</span> <span class="o">=</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span> <span class="o">(</span><span class="n">r</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">sin</span><span class="o">(</span><span class="n">a</span><span class="o">));</span>
<span class="n">drawCircles</span><span class="o">(</span><span class="n">x</span> <span class="o">+</span> <span class="n">x1</span><span class="o">,</span> <span class="n">y</span> <span class="o">+</span> <span class="n">y1</span><span class="o">,</span> <span class="n">r</span> <span class="o">/</span> <span class="mi">2</span><span class="o">,</span> <span class="o">-</span><span class="n">a</span><span class="o">,</span> <span class="n">times</span> <span class="o">-</span> <span class="mi">1</span><span class="o">,</span> <span class="n">g</span><span class="o">);</span>
<span class="n">drawCircles</span><span class="o">(</span><span class="n">x</span> <span class="o">-</span> <span class="n">x1</span><span class="o">,</span> <span class="n">y</span> <span class="o">-</span> <span class="n">y1</span><span class="o">,</span> <span class="n">r</span> <span class="o">/</span> <span class="mi">2</span><span class="o">,</span> <span class="o">-</span><span class="n">a</span><span class="o">,</span> <span class="n">times</span> <span class="o">-</span> <span class="mi">1</span><span class="o">,</span> <span class="n">g</span><span class="o">);</span>
<span class="o">}</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-java" data-lang="java"> <span class="n">createBufferStrategy</span><span class="o">(</span><span class="mi">3</span><span class="o">);</span>
<span class="n">BufferStrategy</span> <span class="n">strategy</span> <span class="o">=</span> <span class="n">getBufferStrategy</span><span class="o">();</span>
<span class="k">new</span> <span class="nf">Thread</span><span class="o">(()</span> <span class="o">-></span> <span class="o">{</span>
<span class="k">while</span> <span class="o">(</span><span class="kc">true</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Graphics</span> <span class="n">g</span> <span class="o">=</span> <span class="n">strategy</span><span class="o">.</span><span class="na">getDrawGraphics</span><span class="o">();</span>
<span class="n">render</span><span class="o">(</span><span class="n">g</span><span class="o">);</span>
<span class="n">g</span><span class="o">.</span><span class="na">dispose</span><span class="o">();</span>
<span class="n">strategy</span><span class="o">.</span><span class="na">show</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}).</span><span class="na">start</span><span class="o">();</span></code></pre></figure>
<div class="image"><img src="/images/cantor/ui.png" /></div>
<p>The last class in this article adds colors, a few options and a spartan UI to tune them. The images and animation below give a quick impression of what is possible by adjusting the sliders. Also note, the color palette can be easily changed during runtime by pasting in hex based color string found on pages like <a href="http://www.colourlovers.com/palette/4464838/sea">colourlovers.com</a>.</p>
<p><a href="/images/cantor/yellow_light.png"><img src="/images/cantor/yellow_light_small.png" alt="" /></a>
<a href="/images/cantor/yellow_mid.png"><img src="/images/cantor/yellow_mid_small.png" alt="" /></a>
<a href="/images/cantor/yellow_dark.png"><img src="/images/cantor/yellow_dark_small.png" alt="" /></a></p>
<p><img src="/images/cantor/blue.gif" alt="" />
<img src="/images/cantor/red.gif" alt="" />
<img src="/images/cantor/cantor_set.gif" alt="" /></p>
<p>The GIF animations were created using ImageMagick, with commands like these:</p>
<figure class="highlight"><pre><code class="language-shell" data-lang="shell">convert -delay 2 -loop 0 cantor<span class="k">*</span>png cantor.gif
convert -delay 2 -loop 0 -resize 300x300 -layers Optimize -duplicate 1,-2-1 cantor0<span class="o">{</span>0000..1200<span class="o">}</span>.png cantor.gif</code></pre></figure>
<script>
var hidden = {};
function fileshowhide(id) {
var text = document.getElementById(id);
var h = (id in hidden) ? hidden[id] : true;
h = !h;
hidden[id] = h;
if(h) {
text.style.display = "none";
} else {
text.style.display = "inline";
}
}
</script>
<div class="filename">Cantor.java</div>
<div class="filebuttons">
<div class="showhide"><button class="filebutton" onclick="fileshowhide('graphics20170314cantor_circlessrccomrememberjavagraphicsCantorjava')">Show file</button></div>
<a class="filebutton github" href="https://github.com/hblok/rememberjava/blob/master/_includes/src/com/rememberjava/graphics/Cantor.java">GitHub</a>
<a class="filebutton raw" href="https://raw.githubusercontent.com/hblok/rememberjava/master/_includes/src/com/rememberjava/graphics/Cantor.java">Raw</a>
</div>
<div id="graphics20170314cantor_circlessrccomrememberjavagraphicsCantorjava" class="javafile">
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="cm">/* Copyright rememberjava.com. Licensed under GPL 3. See http://rememberjava.com/license */</span>
<span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">rememberjava</span><span class="o">.</span><span class="na">graphics</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.awt.Color</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.awt.Graphics</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">javax.swing.JFrame</span><span class="o">;</span>
<span class="cm">/**
* Draws recursive circles
*/</span>
<span class="nd">@SuppressWarnings</span><span class="o">(</span><span class="s">"serial"</span><span class="o">)</span>
<span class="kd">class</span> <span class="nc">Cantor</span> <span class="kd">extends</span> <span class="n">JFrame</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="n">String</span> <span class="n">args</span><span class="o">[])</span> <span class="o">{</span>
<span class="k">new</span> <span class="nf">Cantor</span><span class="o">();</span>
<span class="o">}</span>
<span class="n">Cantor</span><span class="o">()</span> <span class="o">{</span>
<span class="n">setDefaultCloseOperation</span><span class="o">(</span><span class="n">JFrame</span><span class="o">.</span><span class="na">EXIT_ON_CLOSE</span><span class="o">);</span>
<span class="n">setSize</span><span class="o">(</span><span class="mi">900</span><span class="o">,</span> <span class="mi">900</span><span class="o">);</span>
<span class="n">setVisible</span><span class="o">(</span><span class="kc">true</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">paint</span><span class="o">(</span><span class="n">Graphics</span> <span class="n">g</span><span class="o">)</span> <span class="o">{</span>
<span class="n">g</span><span class="o">.</span><span class="na">setColor</span><span class="o">(</span><span class="n">Color</span><span class="o">.</span><span class="na">white</span><span class="o">);</span>
<span class="n">g</span><span class="o">.</span><span class="na">fillRect</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="n">getWidth</span><span class="o">(),</span> <span class="n">getHeight</span><span class="o">());</span>
<span class="n">g</span><span class="o">.</span><span class="na">setColor</span><span class="o">(</span><span class="n">Color</span><span class="o">.</span><span class="na">black</span><span class="o">);</span>
<span class="n">drawCircles</span><span class="o">(</span><span class="mi">450</span><span class="o">,</span> <span class="mi">450</span><span class="o">,</span> <span class="mi">400</span><span class="o">,</span> <span class="mi">7</span><span class="o">,</span> <span class="n">g</span><span class="o">);</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">drawCircles</span><span class="o">(</span><span class="kt">int</span> <span class="n">x</span><span class="o">,</span> <span class="kt">int</span> <span class="n">y</span><span class="o">,</span> <span class="kt">int</span> <span class="n">radius</span><span class="o">,</span> <span class="kt">int</span> <span class="n">times</span><span class="o">,</span> <span class="n">Graphics</span> <span class="n">g</span><span class="o">)</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">printf</span><span class="o">(</span><span class="s">"x=%d, y=%d, r=%d, times=%d\n"</span><span class="o">,</span> <span class="n">x</span><span class="o">,</span> <span class="n">y</span><span class="o">,</span> <span class="n">radius</span><span class="o">,</span> <span class="n">times</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">times</span> <span class="o">></span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
<span class="n">drawMidCircle</span><span class="o">(</span><span class="n">x</span><span class="o">,</span> <span class="n">y</span><span class="o">,</span> <span class="n">radius</span><span class="o">,</span> <span class="n">g</span><span class="o">);</span>
<span class="n">drawCircles</span><span class="o">(</span><span class="n">x</span> <span class="o">+</span> <span class="n">radius</span> <span class="o">/</span> <span class="mi">2</span><span class="o">,</span> <span class="n">y</span><span class="o">,</span> <span class="n">radius</span> <span class="o">/</span> <span class="mi">2</span><span class="o">,</span> <span class="n">times</span> <span class="o">-</span> <span class="mi">1</span><span class="o">,</span> <span class="n">g</span><span class="o">);</span>
<span class="n">drawCircles</span><span class="o">(</span><span class="n">x</span> <span class="o">-</span> <span class="n">radius</span> <span class="o">/</span> <span class="mi">2</span><span class="o">,</span> <span class="n">y</span><span class="o">,</span> <span class="n">radius</span> <span class="o">/</span> <span class="mi">2</span><span class="o">,</span> <span class="n">times</span> <span class="o">-</span> <span class="mi">1</span><span class="o">,</span> <span class="n">g</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">drawMidCircle</span><span class="o">(</span><span class="kt">int</span> <span class="n">x</span><span class="o">,</span> <span class="kt">int</span> <span class="n">y</span><span class="o">,</span> <span class="kt">int</span> <span class="n">radius</span><span class="o">,</span> <span class="n">Graphics</span> <span class="n">g</span><span class="o">)</span> <span class="o">{</span>
<span class="n">g</span><span class="o">.</span><span class="na">drawOval</span><span class="o">(</span><span class="n">x</span> <span class="o">-</span> <span class="n">radius</span><span class="o">,</span> <span class="n">y</span> <span class="o">-</span> <span class="n">radius</span><span class="o">,</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">radius</span><span class="o">,</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">radius</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span></code></pre></figure>
</div>
<script>
var hidden = {};
function fileshowhide(id) {
var text = document.getElementById(id);
var h = (id in hidden) ? hidden[id] : true;
h = !h;
hidden[id] = h;
if(h) {
text.style.display = "none";
} else {
text.style.display = "inline";
}
}
</script>
<div class="filename">CantorSpin.java</div>
<div class="filebuttons">
<div class="showhide"><button class="filebutton" onclick="fileshowhide('graphics20170314cantor_circlessrccomrememberjavagraphicsCantorSpinjava')">Show file</button></div>
<a class="filebutton github" href="https://github.com/hblok/rememberjava/blob/master/_includes/src/com/rememberjava/graphics/CantorSpin.java">GitHub</a>
<a class="filebutton raw" href="https://raw.githubusercontent.com/hblok/rememberjava/master/_includes/src/com/rememberjava/graphics/CantorSpin.java">Raw</a>
</div>
<div id="graphics20170314cantor_circlessrccomrememberjavagraphicsCantorSpinjava" class="javafile">
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="cm">/* Copyright rememberjava.com. Licensed under GPL 3. See http://rememberjava.com/license */</span>
<span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">rememberjava</span><span class="o">.</span><span class="na">graphics</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">static</span> <span class="n">java</span><span class="o">.</span><span class="na">lang</span><span class="o">.</span><span class="na">Math</span><span class="o">.*;</span>
<span class="kn">import</span> <span class="nn">java.awt.Color</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.awt.Graphics</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.awt.image.BufferStrategy</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">javax.swing.JFrame</span><span class="o">;</span>
<span class="cm">/**
* Draws recursive spinning circles.
*
* Uses Double Buffering for smooth rendering. See:
* http://docs.oracle.com/javase/tutorial/extra/fullscreen/bufferstrategy.html
*/</span>
<span class="nd">@SuppressWarnings</span><span class="o">(</span><span class="s">"serial"</span><span class="o">)</span>
<span class="kd">class</span> <span class="nc">CantorSpin</span> <span class="kd">extends</span> <span class="n">JFrame</span> <span class="o">{</span>
<span class="kd">private</span> <span class="kd">final</span> <span class="kt">int</span> <span class="n">size</span><span class="o">;</span>
<span class="kd">private</span> <span class="kt">double</span> <span class="n">angle</span><span class="o">;</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="n">String</span> <span class="n">args</span><span class="o">[])</span> <span class="o">{</span>
<span class="k">new</span> <span class="nf">CantorSpin</span><span class="o">(</span><span class="mi">800</span><span class="o">);</span>
<span class="o">}</span>
<span class="n">CantorSpin</span><span class="o">(</span><span class="kt">int</span> <span class="n">size</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">size</span> <span class="o">=</span> <span class="n">size</span><span class="o">;</span>
<span class="n">setDefaultCloseOperation</span><span class="o">(</span><span class="n">JFrame</span><span class="o">.</span><span class="na">EXIT_ON_CLOSE</span><span class="o">);</span>
<span class="n">setSize</span><span class="o">(</span><span class="n">size</span><span class="o">,</span> <span class="n">size</span><span class="o">);</span>
<span class="n">setVisible</span><span class="o">(</span><span class="kc">true</span><span class="o">);</span>
<span class="n">createBufferStrategy</span><span class="o">(</span><span class="mi">3</span><span class="o">);</span>
<span class="n">BufferStrategy</span> <span class="n">strategy</span> <span class="o">=</span> <span class="n">getBufferStrategy</span><span class="o">();</span>
<span class="k">new</span> <span class="nf">Thread</span><span class="o">(()</span> <span class="o">-></span> <span class="o">{</span>
<span class="k">while</span> <span class="o">(</span><span class="kc">true</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Graphics</span> <span class="n">g</span> <span class="o">=</span> <span class="n">strategy</span><span class="o">.</span><span class="na">getDrawGraphics</span><span class="o">();</span>
<span class="n">render</span><span class="o">(</span><span class="n">g</span><span class="o">);</span>
<span class="n">g</span><span class="o">.</span><span class="na">dispose</span><span class="o">();</span>
<span class="n">strategy</span><span class="o">.</span><span class="na">show</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}).</span><span class="na">start</span><span class="o">();</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">render</span><span class="o">(</span><span class="n">Graphics</span> <span class="n">g</span><span class="o">)</span> <span class="o">{</span>
<span class="n">clear</span><span class="o">(</span><span class="n">g</span><span class="o">);</span>
<span class="n">drawCircles</span><span class="o">(</span><span class="n">size</span> <span class="o">/</span> <span class="mi">2</span><span class="o">,</span> <span class="n">size</span> <span class="o">/</span> <span class="mi">2</span><span class="o">,</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span> <span class="o">(</span><span class="n">size</span> <span class="o">*</span> <span class="mf">0.4</span><span class="o">),</span> <span class="n">angle</span><span class="o">,</span> <span class="mi">7</span><span class="o">,</span> <span class="n">g</span><span class="o">);</span>
<span class="n">angle</span> <span class="o">+=</span> <span class="mf">0.01</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">clear</span><span class="o">(</span><span class="n">Graphics</span> <span class="n">g</span><span class="o">)</span> <span class="o">{</span>
<span class="n">g</span><span class="o">.</span><span class="na">setColor</span><span class="o">(</span><span class="n">Color</span><span class="o">.</span><span class="na">white</span><span class="o">);</span>
<span class="n">g</span><span class="o">.</span><span class="na">fillRect</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="n">getWidth</span><span class="o">(),</span> <span class="n">getHeight</span><span class="o">());</span>
<span class="n">g</span><span class="o">.</span><span class="na">setColor</span><span class="o">(</span><span class="n">Color</span><span class="o">.</span><span class="na">black</span><span class="o">);</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">drawCircles</span><span class="o">(</span><span class="kt">int</span> <span class="n">x</span><span class="o">,</span> <span class="kt">int</span> <span class="n">y</span><span class="o">,</span> <span class="kt">int</span> <span class="n">r</span><span class="o">,</span> <span class="kt">double</span> <span class="n">a</span><span class="o">,</span> <span class="kt">int</span> <span class="n">times</span><span class="o">,</span> <span class="n">Graphics</span> <span class="n">g</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">times</span> <span class="o"><=</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span><span class="o">;</span>
<span class="o">}</span>
<span class="n">drawMidCircle</span><span class="o">(</span><span class="n">x</span><span class="o">,</span> <span class="n">y</span><span class="o">,</span> <span class="n">r</span><span class="o">,</span> <span class="n">g</span><span class="o">);</span>
<span class="kt">int</span> <span class="n">x1</span> <span class="o">=</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span> <span class="o">(</span><span class="n">r</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">cos</span><span class="o">(</span><span class="n">a</span><span class="o">));</span>
<span class="kt">int</span> <span class="n">y1</span> <span class="o">=</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span> <span class="o">(</span><span class="n">r</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">sin</span><span class="o">(</span><span class="n">a</span><span class="o">));</span>
<span class="n">drawCircles</span><span class="o">(</span><span class="n">x</span> <span class="o">+</span> <span class="n">x1</span><span class="o">,</span> <span class="n">y</span> <span class="o">+</span> <span class="n">y1</span><span class="o">,</span> <span class="n">r</span> <span class="o">/</span> <span class="mi">2</span><span class="o">,</span> <span class="o">-</span><span class="n">a</span><span class="o">,</span> <span class="n">times</span> <span class="o">-</span> <span class="mi">1</span><span class="o">,</span> <span class="n">g</span><span class="o">);</span>
<span class="n">drawCircles</span><span class="o">(</span><span class="n">x</span> <span class="o">-</span> <span class="n">x1</span><span class="o">,</span> <span class="n">y</span> <span class="o">-</span> <span class="n">y1</span><span class="o">,</span> <span class="n">r</span> <span class="o">/</span> <span class="mi">2</span><span class="o">,</span> <span class="o">-</span><span class="n">a</span><span class="o">,</span> <span class="n">times</span> <span class="o">-</span> <span class="mi">1</span><span class="o">,</span> <span class="n">g</span><span class="o">);</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">drawMidCircle</span><span class="o">(</span><span class="kt">int</span> <span class="n">x</span><span class="o">,</span> <span class="kt">int</span> <span class="n">y</span><span class="o">,</span> <span class="kt">int</span> <span class="n">r</span><span class="o">,</span> <span class="n">Graphics</span> <span class="n">g</span><span class="o">)</span> <span class="o">{</span>
<span class="n">g</span><span class="o">.</span><span class="na">drawOval</span><span class="o">(</span><span class="n">x</span> <span class="o">-</span> <span class="n">r</span><span class="o">,</span> <span class="n">y</span> <span class="o">-</span> <span class="n">r</span><span class="o">,</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">r</span><span class="o">,</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">r</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span></code></pre></figure>
</div>
<script>
var hidden = {};
function fileshowhide(id) {
var text = document.getElementById(id);
var h = (id in hidden) ? hidden[id] : true;
h = !h;
hidden[id] = h;
if(h) {
text.style.display = "none";
} else {
text.style.display = "inline";
}
}
</script>
<div class="filename">CantorColors.java</div>
<div class="filebuttons">
<div class="showhide"><button class="filebutton" onclick="fileshowhide('graphics20170314cantor_circlessrccomrememberjavagraphicsCantorColorsjava')">Show file</button></div>
<a class="filebutton github" href="https://github.com/hblok/rememberjava/blob/master/_includes/src/com/rememberjava/graphics/CantorColors.java">GitHub</a>
<a class="filebutton raw" href="https://raw.githubusercontent.com/hblok/rememberjava/master/_includes/src/com/rememberjava/graphics/CantorColors.java">Raw</a>
</div>
<div id="graphics20170314cantor_circlessrccomrememberjavagraphicsCantorColorsjava" class="javafile">
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="cm">/* Copyright rememberjava.com. Licensed under GPL 3. See http://rememberjava.com/license */</span>
<span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">rememberjava</span><span class="o">.</span><span class="na">graphics</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">static</span> <span class="n">java</span><span class="o">.</span><span class="na">lang</span><span class="o">.</span><span class="na">Math</span><span class="o">.*;</span>
<span class="kn">import</span> <span class="nn">java.awt.BorderLayout</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.awt.Canvas</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.awt.Color</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.awt.Dimension</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.awt.Graphics</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.awt.event.ComponentAdapter</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.awt.event.ComponentEvent</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.awt.event.KeyAdapter</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.awt.event.KeyEvent</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.awt.image.BufferedImage</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.io.File</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.io.IOException</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.util.function.Consumer</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">javax.imageio.ImageIO</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">javax.swing.BoxLayout</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">javax.swing.JButton</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">javax.swing.JFrame</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">javax.swing.JLabel</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">javax.swing.JPanel</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">javax.swing.JSlider</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">javax.swing.JTextField</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">javax.swing.JToggleButton</span><span class="o">;</span>
<span class="cm">/**
* Draws recursive spinning circles with colors.
*/</span>
<span class="nd">@SuppressWarnings</span><span class="o">(</span><span class="s">"serial"</span><span class="o">)</span>
<span class="kd">class</span> <span class="nc">CantorColors</span> <span class="kd">extends</span> <span class="n">JFrame</span> <span class="o">{</span>
<span class="kd">private</span> <span class="n">Canvas</span> <span class="n">canvas</span><span class="o">;</span>
<span class="kd">private</span> <span class="n">JPanel</span> <span class="n">colorOut</span><span class="o">;</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">colorsList</span> <span class="o">=</span>
<span class="s">"#000fff,#18A3AC,#F48024,#178CCB,#052049,#FBAF3F,#000fff"</span><span class="o">;</span>
<span class="c1">// "#18A3AC,#052049,#178CCB ,#FBAF3F,#F48024,#18A3AC,#052049,#178CCB";</span>
<span class="c1">// "#722059,#A92268,#E02477,#DB7580,#D6C689,#722059,#A92268,#E02477";</span>
<span class="c1">// "#F28E98,#FF9985,#E1CBA6,#DFCFB8,#E7E4D3,#F28E98,#FF9985,#E1CBA6";</span>
<span class="kd">private</span> <span class="n">Color</span><span class="o">[]</span> <span class="n">colors</span><span class="o">;</span>
<span class="kd">private</span> <span class="kt">double</span> <span class="n">angle</span><span class="o">;</span>
<span class="kd">private</span> <span class="kt">double</span> <span class="n">angleStepSize</span><span class="o">;</span>
<span class="kd">private</span> <span class="kt">double</span> <span class="n">alternateSign</span><span class="o">;</span>
<span class="kd">private</span> <span class="kt">int</span> <span class="n">sleepMs</span><span class="o">;</span>
<span class="kd">private</span> <span class="kt">float</span> <span class="n">transparency</span><span class="o">;</span>
<span class="kd">private</span> <span class="kt">int</span> <span class="n">recursions</span><span class="o">;</span>
<span class="kd">private</span> <span class="kt">boolean</span> <span class="n">cantor</span><span class="o">;</span>
<span class="kd">private</span> <span class="kt">boolean</span> <span class="n">clearScreen</span><span class="o">;</span>
<span class="kd">private</span> <span class="kt">boolean</span> <span class="n">save</span><span class="o">;</span>
<span class="kd">private</span> <span class="kt">int</span> <span class="n">index</span><span class="o">;</span>
<span class="kd">private</span> <span class="n">BufferedImage</span> <span class="n">bufImg</span><span class="o">;</span>
<span class="kd">private</span> <span class="n">Graphics</span> <span class="n">imgG</span><span class="o">;</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="n">String</span> <span class="n">args</span><span class="o">[])</span> <span class="o">{</span>
<span class="n">CantorColors</span> <span class="n">cc</span> <span class="o">=</span> <span class="k">new</span> <span class="n">CantorColors</span><span class="o">();</span>
<span class="n">cc</span><span class="o">.</span><span class="na">initUi</span><span class="o">();</span>
<span class="n">cc</span><span class="o">.</span><span class="na">start</span><span class="o">();</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">initUi</span><span class="o">()</span> <span class="o">{</span>
<span class="n">setLayout</span><span class="o">(</span><span class="k">new</span> <span class="n">BorderLayout</span><span class="o">());</span>
<span class="n">canvas</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Canvas</span><span class="o">();</span>
<span class="n">getContentPane</span><span class="o">().</span><span class="na">add</span><span class="o">(</span><span class="n">canvas</span><span class="o">,</span> <span class="n">BorderLayout</span><span class="o">.</span><span class="na">CENTER</span><span class="o">);</span>
<span class="n">JPanel</span> <span class="n">controls</span> <span class="o">=</span> <span class="k">new</span> <span class="n">JPanel</span><span class="o">();</span>
<span class="n">controls</span><span class="o">.</span><span class="na">setLayout</span><span class="o">(</span><span class="k">new</span> <span class="n">BoxLayout</span><span class="o">(</span><span class="n">controls</span><span class="o">,</span> <span class="n">BoxLayout</span><span class="o">.</span><span class="na">Y_AXIS</span><span class="o">));</span>
<span class="n">getContentPane</span><span class="o">().</span><span class="na">add</span><span class="o">(</span><span class="n">controls</span><span class="o">,</span> <span class="n">BorderLayout</span><span class="o">.</span><span class="na">NORTH</span><span class="o">);</span>
<span class="n">addSlider</span><span class="o">(</span><span class="n">controls</span><span class="o">,</span> <span class="s">"Rotation step size"</span><span class="o">,</span> <span class="mi">1</span><span class="o">,</span> <span class="mi">100</span><span class="o">,</span> <span class="mi">5</span><span class="o">,</span> <span class="n">slider</span> <span class="o">-></span> <span class="o">{</span>
<span class="n">angleStepSize</span> <span class="o">=</span> <span class="n">log</span><span class="o">(</span><span class="n">slider</span><span class="o">.</span><span class="na">getValue</span><span class="o">());</span>
<span class="o">});</span>
<span class="n">addSlider</span><span class="o">(</span><span class="n">controls</span><span class="o">,</span> <span class="s">"Frame delay"</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="mi">100</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="n">slider</span> <span class="o">-></span> <span class="o">{</span>
<span class="n">sleepMs</span> <span class="o">=</span> <span class="n">slider</span><span class="o">.</span><span class="na">getValue</span><span class="o">();</span>
<span class="o">});</span>
<span class="n">addSlider</span><span class="o">(</span><span class="n">controls</span><span class="o">,</span> <span class="s">"Recursions"</span><span class="o">,</span> <span class="mi">1</span><span class="o">,</span> <span class="mi">20</span><span class="o">,</span> <span class="mi">7</span><span class="o">,</span> <span class="n">slider</span> <span class="o">-></span> <span class="o">{</span>
<span class="n">recursions</span> <span class="o">=</span> <span class="n">slider</span><span class="o">.</span><span class="na">getValue</span><span class="o">();</span>
<span class="o">});</span>
<span class="n">addSlider</span><span class="o">(</span><span class="n">controls</span><span class="o">,</span> <span class="s">"Transparency"</span><span class="o">,</span> <span class="mi">1</span><span class="o">,</span> <span class="mi">1000</span><span class="o">,</span> <span class="mi">1000</span><span class="o">,</span> <span class="n">slider</span> <span class="o">-></span> <span class="o">{</span>
<span class="n">transparency</span> <span class="o">=</span> <span class="o">(</span><span class="kt">float</span><span class="o">)</span> <span class="n">slider</span><span class="o">.</span><span class="na">getValue</span><span class="o">();</span>
<span class="n">colors</span> <span class="o">=</span> <span class="n">decodeColors</span><span class="o">(</span><span class="n">colorsList</span><span class="o">);</span>
<span class="n">showColors</span><span class="o">();</span>
<span class="o">});</span>
<span class="n">JTextField</span> <span class="n">colorIn</span> <span class="o">=</span> <span class="k">new</span> <span class="n">JTextField</span><span class="o">(</span><span class="n">colorsList</span><span class="o">);</span>
<span class="n">colorIn</span><span class="o">.</span><span class="na">addKeyListener</span><span class="o">(</span><span class="k">new</span> <span class="n">KeyAdapter</span><span class="o">()</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">keyTyped</span><span class="o">(</span><span class="n">KeyEvent</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">colorsList</span> <span class="o">=</span> <span class="n">colorIn</span><span class="o">.</span><span class="na">getText</span><span class="o">();</span>
<span class="n">colors</span> <span class="o">=</span> <span class="n">decodeColors</span><span class="o">(</span><span class="n">colorsList</span><span class="o">);</span>
<span class="n">showColors</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">});</span>
<span class="n">controls</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">colorIn</span><span class="o">);</span>
<span class="n">colorOut</span> <span class="o">=</span> <span class="k">new</span> <span class="n">JPanel</span><span class="o">();</span>
<span class="n">colorOut</span><span class="o">.</span><span class="na">setLayout</span><span class="o">(</span><span class="k">new</span> <span class="n">BoxLayout</span><span class="o">(</span><span class="n">colorOut</span><span class="o">,</span> <span class="n">BoxLayout</span><span class="o">.</span><span class="na">X_AXIS</span><span class="o">));</span>
<span class="n">colors</span> <span class="o">=</span> <span class="n">decodeColors</span><span class="o">(</span><span class="n">colorsList</span><span class="o">);</span>
<span class="n">showColors</span><span class="o">();</span>
<span class="n">controls</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">colorOut</span><span class="o">);</span>
<span class="n">JPanel</span> <span class="n">buttons</span> <span class="o">=</span> <span class="k">new</span> <span class="n">JPanel</span><span class="o">();</span>
<span class="n">buttons</span><span class="o">.</span><span class="na">setLayout</span><span class="o">(</span><span class="k">new</span> <span class="n">BoxLayout</span><span class="o">(</span><span class="n">buttons</span><span class="o">,</span> <span class="n">BoxLayout</span><span class="o">.</span><span class="na">X_AXIS</span><span class="o">));</span>
<span class="n">controls</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">buttons</span><span class="o">);</span>
<span class="n">addToggleButton</span><span class="o">(</span><span class="n">buttons</span><span class="o">,</span> <span class="s">"Bisect vs. Cantor"</span><span class="o">,</span> <span class="kc">false</span><span class="o">,</span> <span class="n">button</span> <span class="o">-></span> <span class="o">{</span>
<span class="n">cantor</span> <span class="o">=</span> <span class="n">button</span><span class="o">.</span><span class="na">isSelected</span><span class="o">();</span>
<span class="o">});</span>
<span class="n">addToggleButton</span><span class="o">(</span><span class="n">buttons</span><span class="o">,</span> <span class="s">"Alternate rotation"</span><span class="o">,</span> <span class="kc">true</span><span class="o">,</span> <span class="n">button</span> <span class="o">-></span> <span class="o">{</span>
<span class="n">alternateSign</span> <span class="o">=</span> <span class="n">button</span><span class="o">.</span><span class="na">isSelected</span><span class="o">()</span> <span class="o">?</span> <span class="o">-</span><span class="mi">1</span> <span class="o">:</span> <span class="mi">1</span><span class="o">;</span>
<span class="o">});</span>
<span class="n">addToggleButton</span><span class="o">(</span><span class="n">buttons</span><span class="o">,</span> <span class="s">"Save PNGs"</span><span class="o">,</span> <span class="kc">false</span><span class="o">,</span> <span class="n">button</span> <span class="o">-></span> <span class="o">{</span>
<span class="n">save</span> <span class="o">=</span> <span class="n">button</span><span class="o">.</span><span class="na">isSelected</span><span class="o">();</span>
<span class="n">index</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
<span class="o">});</span>
<span class="n">JButton</span> <span class="n">clearButton</span> <span class="o">=</span> <span class="k">new</span> <span class="n">JButton</span><span class="o">(</span><span class="s">"Clear"</span><span class="o">);</span>
<span class="n">clearButton</span><span class="o">.</span><span class="na">addActionListener</span><span class="o">(</span><span class="n">l</span> <span class="o">-></span> <span class="o">{</span>
<span class="n">clearScreen</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span>
<span class="o">});</span>
<span class="n">buttons</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">clearButton</span><span class="o">);</span>
<span class="n">canvas</span><span class="o">.</span><span class="na">addComponentListener</span><span class="o">(</span><span class="k">new</span> <span class="n">ComponentAdapter</span><span class="o">()</span> <span class="o">{</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">componentResized</span><span class="o">(</span><span class="n">ComponentEvent</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">createRenderImage</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">});</span>
<span class="n">setDefaultCloseOperation</span><span class="o">(</span><span class="n">JFrame</span><span class="o">.</span><span class="na">EXIT_ON_CLOSE</span><span class="o">);</span>
<span class="n">setSize</span><span class="o">(</span><span class="mi">600</span><span class="o">,</span> <span class="mi">738</span><span class="o">);</span>
<span class="n">setVisible</span><span class="o">(</span><span class="kc">true</span><span class="o">);</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">addSlider</span><span class="o">(</span><span class="n">JPanel</span> <span class="n">controls</span><span class="o">,</span> <span class="n">String</span> <span class="n">text</span><span class="o">,</span> <span class="kt">int</span> <span class="n">min</span><span class="o">,</span> <span class="kt">int</span> <span class="n">max</span><span class="o">,</span> <span class="kt">int</span> <span class="n">value</span><span class="o">,</span>
<span class="n">Consumer</span><span class="o"><</span><span class="n">JSlider</span><span class="o">></span> <span class="n">changeListener</span><span class="o">)</span> <span class="o">{</span>
<span class="n">JPanel</span> <span class="n">row</span> <span class="o">=</span> <span class="k">new</span> <span class="n">JPanel</span><span class="o">();</span>
<span class="n">row</span><span class="o">.</span><span class="na">setLayout</span><span class="o">(</span><span class="k">new</span> <span class="n">BoxLayout</span><span class="o">(</span><span class="n">row</span><span class="o">,</span> <span class="n">BoxLayout</span><span class="o">.</span><span class="na">X_AXIS</span><span class="o">));</span>
<span class="n">controls</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">row</span><span class="o">);</span>
<span class="n">JLabel</span> <span class="n">label</span> <span class="o">=</span> <span class="k">new</span> <span class="n">JLabel</span><span class="o">(</span><span class="n">text</span><span class="o">);</span>
<span class="n">label</span><span class="o">.</span><span class="na">setPreferredSize</span><span class="o">(</span><span class="k">new</span> <span class="n">Dimension</span><span class="o">(</span><span class="mi">150</span><span class="o">,</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span> <span class="n">label</span><span class="o">.</span><span class="na">getPreferredSize</span><span class="o">().</span><span class="na">getHeight</span><span class="o">()));</span>
<span class="n">row</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">label</span><span class="o">);</span>
<span class="n">JSlider</span> <span class="n">slider</span> <span class="o">=</span> <span class="k">new</span> <span class="n">JSlider</span><span class="o">(</span><span class="n">min</span><span class="o">,</span> <span class="n">max</span><span class="o">,</span> <span class="n">value</span><span class="o">);</span>
<span class="n">row</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">slider</span><span class="o">);</span>
<span class="n">slider</span><span class="o">.</span><span class="na">addChangeListener</span><span class="o">(</span><span class="n">e</span> <span class="o">-></span> <span class="o">{</span>
<span class="n">changeListener</span><span class="o">.</span><span class="na">accept</span><span class="o">(</span><span class="n">slider</span><span class="o">);</span>
<span class="o">});</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">addToggleButton</span><span class="o">(</span><span class="n">JPanel</span> <span class="n">buttons</span><span class="o">,</span> <span class="n">String</span> <span class="n">text</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">selected</span><span class="o">,</span>
<span class="n">Consumer</span><span class="o"><</span><span class="n">JToggleButton</span><span class="o">></span> <span class="n">actionListener</span><span class="o">)</span> <span class="o">{</span>
<span class="n">JToggleButton</span> <span class="n">button</span> <span class="o">=</span> <span class="k">new</span> <span class="n">JToggleButton</span><span class="o">(</span><span class="n">text</span><span class="o">);</span>
<span class="n">button</span><span class="o">.</span><span class="na">setSelected</span><span class="o">(</span><span class="n">selected</span><span class="o">);</span>
<span class="n">buttons</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">button</span><span class="o">);</span>
<span class="n">button</span><span class="o">.</span><span class="na">addActionListener</span><span class="o">(</span><span class="n">e</span> <span class="o">-></span> <span class="o">{</span>
<span class="n">actionListener</span><span class="o">.</span><span class="na">accept</span><span class="o">(</span><span class="n">button</span><span class="o">);</span>
<span class="o">});</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">showColors</span><span class="o">()</span> <span class="o">{</span>
<span class="n">colorOut</span><span class="o">.</span><span class="na">removeAll</span><span class="o">();</span>
<span class="n">colorOut</span><span class="o">.</span><span class="na">setBackground</span><span class="o">(</span><span class="n">Color</span><span class="o">.</span><span class="na">WHITE</span><span class="o">);</span>
<span class="k">for</span> <span class="o">(</span><span class="n">Color</span> <span class="n">c</span> <span class="o">:</span> <span class="n">colors</span><span class="o">)</span> <span class="o">{</span>
<span class="n">JPanel</span> <span class="n">l</span> <span class="o">=</span> <span class="k">new</span> <span class="n">JPanel</span><span class="o">();</span>
<span class="n">l</span><span class="o">.</span><span class="na">setPreferredSize</span><span class="o">(</span>
<span class="k">new</span> <span class="nf">Dimension</span><span class="o">(</span><span class="n">getWidth</span><span class="o">()</span> <span class="o">/</span> <span class="n">colors</span><span class="o">.</span><span class="na">length</span><span class="o">,</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span> <span class="n">l</span><span class="o">.</span><span class="na">getPreferredSize</span><span class="o">().</span><span class="na">getHeight</span><span class="o">()));</span>
<span class="n">l</span><span class="o">.</span><span class="na">setBackground</span><span class="o">(</span><span class="n">c</span><span class="o">);</span>
<span class="n">colorOut</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">l</span><span class="o">);</span>
<span class="o">}</span>
<span class="n">colorOut</span><span class="o">.</span><span class="na">revalidate</span><span class="o">();</span>
<span class="n">colorOut</span><span class="o">.</span><span class="na">repaint</span><span class="o">();</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">start</span><span class="o">()</span> <span class="o">{</span>
<span class="n">transparency</span> <span class="o">=</span> <span class="mi">1000</span><span class="n">f</span><span class="o">;</span>
<span class="n">angleStepSize</span> <span class="o">=</span> <span class="mf">0.005</span><span class="o">;</span>
<span class="n">alternateSign</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="o">;</span>
<span class="n">recursions</span> <span class="o">=</span> <span class="mi">7</span><span class="o">;</span>
<span class="n">colors</span> <span class="o">=</span> <span class="n">decodeColors</span><span class="o">(</span><span class="n">colorsList</span><span class="o">);</span>
<span class="n">showColors</span><span class="o">();</span>
<span class="n">createRenderImage</span><span class="o">();</span>
<span class="n">Graphics</span> <span class="n">g</span> <span class="o">=</span> <span class="n">canvas</span><span class="o">.</span><span class="na">getGraphics</span><span class="o">();</span>
<span class="k">new</span> <span class="nf">Thread</span><span class="o">(()</span> <span class="o">-></span> <span class="o">{</span>
<span class="k">while</span> <span class="o">(</span><span class="kc">true</span><span class="o">)</span> <span class="o">{</span>
<span class="n">render</span><span class="o">(</span><span class="n">imgG</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">save</span> <span class="o">&&</span> <span class="n">index</span><span class="o">++</span> <span class="o">%</span> <span class="mi">3</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
<span class="n">saveImage</span><span class="o">(</span><span class="n">bufImg</span><span class="o">,</span> <span class="n">index</span><span class="o">);</span>
<span class="o">}</span>
<span class="n">g</span><span class="o">.</span><span class="na">drawImage</span><span class="o">(</span><span class="n">bufImg</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="k">this</span><span class="o">);</span>
<span class="n">sleep</span><span class="o">(</span><span class="n">sleepMs</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}).</span><span class="na">start</span><span class="o">();</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">createRenderImage</span><span class="o">()</span> <span class="o">{</span>
<span class="n">bufImg</span> <span class="o">=</span> <span class="k">new</span> <span class="n">BufferedImage</span><span class="o">(</span><span class="n">canvas</span><span class="o">.</span><span class="na">getWidth</span><span class="o">(),</span> <span class="n">canvas</span><span class="o">.</span><span class="na">getHeight</span><span class="o">(),</span> <span class="n">BufferedImage</span><span class="o">.</span><span class="na">TYPE_INT_ARGB</span><span class="o">);</span>
<span class="n">imgG</span> <span class="o">=</span> <span class="n">bufImg</span><span class="o">.</span><span class="na">createGraphics</span><span class="o">();</span>
<span class="n">clear</span><span class="o">(</span><span class="n">imgG</span><span class="o">);</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">saveImage</span><span class="o">(</span><span class="n">BufferedImage</span> <span class="n">bi</span><span class="o">,</span> <span class="kt">int</span> <span class="n">i</span><span class="o">)</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">String</span> <span class="n">name</span> <span class="o">=</span> <span class="n">String</span><span class="o">.</span><span class="na">format</span><span class="o">(</span><span class="s">"/tmp/cantor%05d.png"</span><span class="o">,</span> <span class="n">i</span><span class="o">);</span>
<span class="n">ImageIO</span><span class="o">.</span><span class="na">write</span><span class="o">(</span><span class="n">bi</span><span class="o">,</span> <span class="s">"PNG"</span><span class="o">,</span> <span class="k">new</span> <span class="n">File</span><span class="o">(</span><span class="n">name</span><span class="o">));</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">IOException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="cm">/**
* Given a string of comma separated hex encoded RGB values, creates the
* individual Color objects. All spaces are removed and ignored; the hex
* values can be prefixed by a hash (#) or not. Adds the alpha transparency
* setting from the UI.
*/</span>
<span class="kd">private</span> <span class="n">Color</span><span class="o">[]</span> <span class="nf">decodeColors</span><span class="o">(</span><span class="n">String</span> <span class="n">hexColors</span><span class="o">)</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">String</span><span class="o">[]</span> <span class="n">split</span> <span class="o">=</span> <span class="n">hexColors</span><span class="o">.</span><span class="na">replaceAll</span><span class="o">(</span><span class="s">" +"</span><span class="o">,</span> <span class="s">""</span><span class="o">).</span><span class="na">split</span><span class="o">(</span><span class="s">","</span><span class="o">);</span>
<span class="n">Color</span><span class="o">[]</span> <span class="n">result</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Color</span><span class="o">[</span><span class="n">split</span><span class="o">.</span><span class="na">length</span><span class="o">];</span>
<span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">split</span><span class="o">.</span><span class="na">length</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
<span class="n">String</span> <span class="n">str</span> <span class="o">=</span> <span class="o">(</span><span class="n">split</span><span class="o">[</span><span class="n">i</span><span class="o">].</span><span class="na">startsWith</span><span class="o">(</span><span class="s">"#"</span><span class="o">)</span> <span class="o">?</span> <span class="s">""</span> <span class="o">:</span> <span class="s">"#"</span><span class="o">)</span> <span class="o">+</span> <span class="n">split</span><span class="o">[</span><span class="n">i</span><span class="o">];</span>
<span class="kt">float</span><span class="o">[]</span> <span class="n">comp</span> <span class="o">=</span> <span class="n">Color</span><span class="o">.</span><span class="na">decode</span><span class="o">(</span><span class="n">str</span><span class="o">).</span><span class="na">getRGBComponents</span><span class="o">(</span><span class="kc">null</span><span class="o">);</span>
<span class="kt">float</span> <span class="n">a</span> <span class="o">=</span> <span class="n">max</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="n">min</span><span class="o">(</span><span class="mi">1</span><span class="n">f</span><span class="o">,</span> <span class="o">((</span><span class="kt">float</span><span class="o">)</span> <span class="n">i</span><span class="o">)</span> <span class="o">/</span> <span class="n">transparency</span><span class="o">));</span>
<span class="n">result</span><span class="o">[</span><span class="n">i</span><span class="o">]</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Color</span><span class="o">(</span><span class="n">comp</span><span class="o">[</span><span class="mi">0</span><span class="o">],</span> <span class="n">comp</span><span class="o">[</span><span class="mi">1</span><span class="o">],</span> <span class="n">comp</span><span class="o">[</span><span class="mi">2</span><span class="o">],</span> <span class="n">a</span><span class="o">);</span>
<span class="o">}</span>
<span class="k">return</span> <span class="n">result</span><span class="o">;</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">Exception</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">e</span><span class="o">);</span>
<span class="k">return</span> <span class="n">colors</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">sleep</span><span class="o">(</span><span class="kt">long</span> <span class="n">ms</span><span class="o">)</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">Thread</span><span class="o">.</span><span class="na">sleep</span><span class="o">(</span><span class="n">ms</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">InterruptedException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{}</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">render</span><span class="o">(</span><span class="n">Graphics</span> <span class="n">g</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">clearScreen</span><span class="o">)</span> <span class="o">{</span>
<span class="n">clear</span><span class="o">(</span><span class="n">g</span><span class="o">);</span>
<span class="n">clearScreen</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
<span class="o">}</span>
<span class="kt">int</span> <span class="n">size</span> <span class="o">=</span> <span class="n">min</span><span class="o">(</span><span class="n">canvas</span><span class="o">.</span><span class="na">getWidth</span><span class="o">(),</span> <span class="n">canvas</span><span class="o">.</span><span class="na">getHeight</span><span class="o">());</span>
<span class="n">drawCantor</span><span class="o">(</span><span class="n">size</span> <span class="o">/</span> <span class="mi">2</span><span class="o">,</span> <span class="n">size</span> <span class="o">/</span> <span class="mi">2</span><span class="o">,</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span> <span class="o">(</span><span class="n">size</span> <span class="o">*</span> <span class="mf">0.45</span><span class="o">),</span> <span class="n">angle</span><span class="o">,</span> <span class="n">recursions</span><span class="o">,</span> <span class="n">g</span><span class="o">);</span>
<span class="n">angle</span> <span class="o">+=</span> <span class="n">angleStepSize</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">drawCantor</span><span class="o">(</span><span class="kt">int</span> <span class="n">x</span><span class="o">,</span> <span class="kt">int</span> <span class="n">y</span><span class="o">,</span> <span class="kt">int</span> <span class="n">r</span><span class="o">,</span> <span class="kt">double</span> <span class="n">a</span><span class="o">,</span> <span class="kt">int</span> <span class="n">times</span><span class="o">,</span> <span class="n">Graphics</span> <span class="n">g</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">times</span> <span class="o"><=</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span><span class="o">;</span>
<span class="o">}</span>
<span class="n">g</span><span class="o">.</span><span class="na">setColor</span><span class="o">(</span><span class="n">colors</span><span class="o">[</span><span class="n">times</span> <span class="o">%</span> <span class="n">colors</span><span class="o">.</span><span class="na">length</span><span class="o">]);</span>
<span class="n">drawMidCircle</span><span class="o">(</span><span class="n">x</span><span class="o">,</span> <span class="n">y</span><span class="o">,</span> <span class="n">r</span><span class="o">,</span> <span class="n">g</span><span class="o">);</span>
<span class="kt">double</span> <span class="n">nextAngel</span> <span class="o">=</span> <span class="n">alternateSign</span> <span class="o">*</span> <span class="n">a</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">cantor</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// Cantor set</span>
<span class="kt">int</span> <span class="n">x1</span> <span class="o">=</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span> <span class="o">(</span><span class="n">r</span> <span class="o">/</span> <span class="mi">3</span> <span class="o">*</span> <span class="n">cos</span><span class="o">(</span><span class="n">a</span><span class="o">));</span>
<span class="kt">int</span> <span class="n">y1</span> <span class="o">=</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span> <span class="o">(</span><span class="n">r</span> <span class="o">/</span> <span class="mi">3</span> <span class="o">*</span> <span class="n">sin</span><span class="o">(</span><span class="n">a</span><span class="o">));</span>
<span class="n">drawCantor</span><span class="o">(</span><span class="n">x</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">x1</span><span class="o">,</span> <span class="n">y</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">y1</span><span class="o">,</span> <span class="n">r</span> <span class="o">/</span> <span class="mi">3</span><span class="o">,</span> <span class="n">nextAngel</span><span class="o">,</span> <span class="n">times</span> <span class="o">-</span> <span class="mi">1</span><span class="o">,</span> <span class="n">g</span><span class="o">);</span>
<span class="n">drawCantor</span><span class="o">(</span><span class="n">x</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">x1</span><span class="o">,</span> <span class="n">y</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">y1</span><span class="o">,</span> <span class="n">r</span> <span class="o">/</span> <span class="mi">3</span><span class="o">,</span> <span class="n">nextAngel</span><span class="o">,</span> <span class="n">times</span> <span class="o">-</span> <span class="mi">1</span><span class="o">,</span> <span class="n">g</span><span class="o">);</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="c1">// Bisect</span>
<span class="kt">int</span> <span class="n">x1</span> <span class="o">=</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span> <span class="o">(</span><span class="n">r</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">cos</span><span class="o">(</span><span class="n">a</span><span class="o">));</span>
<span class="kt">int</span> <span class="n">y1</span> <span class="o">=</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span> <span class="o">(</span><span class="n">r</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">sin</span><span class="o">(</span><span class="n">a</span><span class="o">));</span>
<span class="n">drawCantor</span><span class="o">(</span><span class="n">x</span> <span class="o">+</span> <span class="n">x1</span><span class="o">,</span> <span class="n">y</span> <span class="o">+</span> <span class="n">y1</span><span class="o">,</span> <span class="n">r</span> <span class="o">/</span> <span class="mi">2</span><span class="o">,</span> <span class="n">nextAngel</span><span class="o">,</span> <span class="n">times</span> <span class="o">-</span> <span class="mi">1</span><span class="o">,</span> <span class="n">g</span><span class="o">);</span>
<span class="n">drawCantor</span><span class="o">(</span><span class="n">x</span> <span class="o">-</span> <span class="n">x1</span><span class="o">,</span> <span class="n">y</span> <span class="o">-</span> <span class="n">y1</span><span class="o">,</span> <span class="n">r</span> <span class="o">/</span> <span class="mi">2</span><span class="o">,</span> <span class="n">nextAngel</span><span class="o">,</span> <span class="n">times</span> <span class="o">-</span> <span class="mi">1</span><span class="o">,</span> <span class="n">g</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">drawMidCircle</span><span class="o">(</span><span class="kt">int</span> <span class="n">x</span><span class="o">,</span> <span class="kt">int</span> <span class="n">y</span><span class="o">,</span> <span class="kt">int</span> <span class="n">r</span><span class="o">,</span> <span class="n">Graphics</span> <span class="n">g</span><span class="o">)</span> <span class="o">{</span>
<span class="n">g</span><span class="o">.</span><span class="na">drawOval</span><span class="o">(</span><span class="n">x</span> <span class="o">-</span> <span class="n">r</span><span class="o">,</span> <span class="n">y</span> <span class="o">-</span> <span class="n">r</span><span class="o">,</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">r</span><span class="o">,</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">r</span><span class="o">);</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">clear</span><span class="o">(</span><span class="n">Graphics</span> <span class="n">g</span><span class="o">)</span> <span class="o">{</span>
<span class="n">g</span><span class="o">.</span><span class="na">setColor</span><span class="o">(</span><span class="n">Color</span><span class="o">.</span><span class="na">white</span><span class="o">);</span>
<span class="n">g</span><span class="o">.</span><span class="na">fillRect</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="n">canvas</span><span class="o">.</span><span class="na">getWidth</span><span class="o">(),</span> <span class="n">canvas</span><span class="o">.</span><span class="na">getHeight</span><span class="o">());</span>
<span class="o">}</span>
<span class="o">}</span></code></pre></figure>
</div>This article draws inspiration from an old post dubbed “Cantor Circles”, but which turned out to render bisecting circles rather than Cantor sets. Nevertheless, it gained some interest, and the exact image below, from the 2002 post, can now be easily found on Google Image search. In this post, the old code is revived, and animation and colors are added for nice patterns and fun. Cantor’s ternary set is also implemented.Sun Doclet API2017-03-10T00:00:00+00:002017-03-10T00:00:00+00:00http://rememberjava.com/doclet/2017/03/10/sun_doclet_api<p>Since Java 1.2, the <em>javadoc</em> command has generated neatly formatted documentation. The tool comes with its <a href="http://docs.oracle.com/javase/8/docs/jdk/api/javadoc/doclet/index.html">own API</a> which allows <a href="http://docs.oracle.com/javase/6/docs/technotes/guides/javadoc/doclet/overview.html">customised output</a>. The relevant classes are under the <em>com.sun</em> package hierarchy, and located in <em>JRE_HOME/lib/tools.jar</em>, which typically will have to be included manually. E.g. it can be found under <em>/usr/lib/jvm/java-8-openjdk-amd64/lib/tools.jar</em>.</p>
<p>Note that the Sun Doclet API is getting long in th tooth, and is already slated for replacement in Java 9, through the “Simplified Doclet API” in <a href="http://openjdk.java.net/jeps/221">JDK Enhancement Proposal 221</a>. Java 9 is planned for Q3 2017.</p>
<p>Meanwhile, the old Doclet API still does an OK job of parsing JavaDoc in .java source files. If the goal is to parse, rather than to produce the standard formatted JavaDoc, it’s useful to <a href="http://docs.oracle.com/javase/7/docs/technotes/guides/javadoc/standard-doclet.html">start the process pragmatically</a>. Than can be achieved through its main class, <em>com.sun.tools.javadoc.Main</em>:</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"> <span class="n">Main</span><span class="o">.</span><span class="na">execute</span><span class="o">(</span><span class="s">"MyName"</span><span class="o">,</span> <span class="n">SunDocletPrinter</span><span class="o">.</span><span class="na">class</span><span class="o">.</span><span class="na">getName</span><span class="o">(),</span>
<span class="k">new</span> <span class="n">String</span><span class="o">[]</span> <span class="o">{</span> <span class="s">"com/rememberjava/doc/SunDocletPrinter.java"</span> <span class="o">});</span></code></pre></figure>
<p>The <em>execute()</em> method will invoke the public static method <em>start()</em> in the specified class. In the example below, a few of the main JavaDoc entities are enumerated. The direct output can be see the block below. The class which is parsed is the example class itself, included at the bottom of this article.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"> <span class="kd">public</span> <span class="kd">static</span> <span class="kt">boolean</span> <span class="nf">start</span><span class="o">(</span><span class="n">RootDoc</span> <span class="n">root</span><span class="o">)</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"--- start"</span><span class="o">);</span>
<span class="k">for</span> <span class="o">(</span><span class="n">ClassDoc</span> <span class="n">classDoc</span> <span class="o">:</span> <span class="n">root</span><span class="o">.</span><span class="na">classes</span><span class="o">())</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Class: "</span> <span class="o">+</span> <span class="n">classDoc</span><span class="o">);</span>
<span class="c1">// Class annotations</span>
<span class="k">for</span> <span class="o">(</span><span class="n">AnnotationDesc</span> <span class="n">annotation</span> <span class="o">:</span> <span class="n">classDoc</span><span class="o">.</span><span class="na">annotations</span><span class="o">())</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">" Annotation: "</span> <span class="o">+</span> <span class="n">annotation</span><span class="o">);</span>
<span class="o">}</span>
<span class="c1">// Class JavaDoc tags</span>
<span class="k">for</span> <span class="o">(</span><span class="n">Tag</span> <span class="n">tag</span> <span class="o">:</span> <span class="n">classDoc</span><span class="o">.</span><span class="na">tags</span><span class="o">())</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">" Class tag:"</span> <span class="o">+</span> <span class="n">tag</span><span class="o">.</span><span class="na">name</span><span class="o">()</span> <span class="o">+</span> <span class="s">"="</span> <span class="o">+</span> <span class="n">tag</span><span class="o">.</span><span class="na">text</span><span class="o">());</span>
<span class="o">}</span>
<span class="c1">// Global constants and fields</span>
<span class="k">for</span> <span class="o">(</span><span class="n">FieldDoc</span> <span class="n">fieldDoc</span> <span class="o">:</span> <span class="n">classDoc</span><span class="o">.</span><span class="na">fields</span><span class="o">())</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">" Field: "</span> <span class="o">+</span> <span class="n">fieldDoc</span><span class="o">);</span>
<span class="o">}</span>
<span class="c1">// Methods</span>
<span class="k">for</span> <span class="o">(</span><span class="n">MethodDoc</span> <span class="n">methodDoc</span> <span class="o">:</span> <span class="n">classDoc</span><span class="o">.</span><span class="na">methods</span><span class="o">())</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">" Method: "</span> <span class="o">+</span> <span class="n">methodDoc</span><span class="o">);</span>
<span class="c1">// Method annotations</span>
<span class="k">for</span> <span class="o">(</span><span class="n">AnnotationDesc</span> <span class="n">annotation</span> <span class="o">:</span> <span class="n">methodDoc</span><span class="o">.</span><span class="na">annotations</span><span class="o">())</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">" Annotation: "</span> <span class="o">+</span> <span class="n">annotation</span><span class="o">);</span>
<span class="o">}</span>
<span class="c1">// Method JavaDoc comment (without parameters)</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">" Doc: "</span> <span class="o">+</span> <span class="n">methodDoc</span><span class="o">.</span><span class="na">commentText</span><span class="o">());</span>
<span class="c1">// Method JavaDoc (only the first sentence)</span>
<span class="k">for</span> <span class="o">(</span><span class="n">Tag</span> <span class="n">tag</span> <span class="o">:</span> <span class="n">methodDoc</span><span class="o">.</span><span class="na">firstSentenceTags</span><span class="o">())</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">" Tag: "</span> <span class="o">+</span> <span class="n">tag</span><span class="o">);</span>
<span class="o">}</span>
<span class="c1">// Method parameters (without return)</span>
<span class="k">for</span> <span class="o">(</span><span class="n">ParamTag</span> <span class="n">paramTag</span> <span class="o">:</span> <span class="n">methodDoc</span><span class="o">.</span><span class="na">paramTags</span><span class="o">())</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">" Param:"</span> <span class="o">+</span> <span class="n">paramTag</span><span class="o">.</span><span class="na">parameterName</span><span class="o">()</span> <span class="o">+</span> <span class="s">"="</span> <span class="o">+</span> <span class="n">paramTag</span><span class="o">.</span><span class="na">parameterComment</span><span class="o">());</span>
<span class="o">}</span>
<span class="c1">// The full method JavaDoc text</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">" Raw doc:\n"</span> <span class="o">+</span> <span class="n">methodDoc</span><span class="o">.</span><span class="na">getRawCommentText</span><span class="o">());</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"--- the end"</span><span class="o">);</span>
<span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
<span class="o">}</span></code></pre></figure>
<pre><code>
- start main
Loading source file com/rememberjava/doc/SunDocletPrinter.java...
Constructing Javadoc information...
--- start
Class: com.rememberjava.doc.SunDocletPrinter
Annotation: @java.lang.Deprecated
Class tag:@author=Bob
Class tag:@since=123
Class tag:@custom=Custom Annotation
Class tag:@see="http://docs.oracle.com/javase/6/docs/technotes/guides/javadoc/doclet/overview.html"
Field: com.rememberjava.doc.SunDocletPrinter.SOME_FIELD
Method: com.rememberjava.doc.SunDocletPrinter.main(java.lang.String[])
Annotation: @java.lang.SuppressWarnings("Test")
Doc:
Raw doc:
@see "http://docs.oracle.com/javase/7/docs/technotes/guides/javadoc/standard-doclet.html"
Method: com.rememberjava.doc.SunDocletPrinter.start(com.sun.javadoc.RootDoc)
Doc: This method processes everything. And there's more to it.
Tag: Text:This method processes everything.
Param:root=the root element
Raw doc:
This method processes everything. And there's more to it.
@param root
the root element
@return returns true
--- the end
- done execute
</code></pre>
<p>Here is full file, which also shows the JavaDoc the example operates on.</p>
<script>
var hidden = {};
function fileshowhide(id) {
var text = document.getElementById(id);
var h = (id in hidden) ? hidden[id] : true;
h = !h;
hidden[id] = h;
if(h) {
text.style.display = "none";
} else {
text.style.display = "inline";
}
}
</script>
<div class="filename">SunDocletPrinter.java</div>
<div class="filebuttons">
<div class="showhide"><button class="filebutton" onclick="fileshowhide('doclet20170310sun_doclet_apisrccomrememberjavadocSunDocletPrinterjava')">Show file</button></div>
<a class="filebutton github" href="https://github.com/hblok/rememberjava/blob/master/_includes/src/com/rememberjava/doc/SunDocletPrinter.java">GitHub</a>
<a class="filebutton raw" href="https://raw.githubusercontent.com/hblok/rememberjava/master/_includes/src/com/rememberjava/doc/SunDocletPrinter.java">Raw</a>
</div>
<div id="doclet20170310sun_doclet_apisrccomrememberjavadocSunDocletPrinterjava" class="javafile">
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="cm">/* Copyright rememberjava.com. Licensed under GPL 3. See http://rememberjava.com/license */</span>
<span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">rememberjava</span><span class="o">.</span><span class="na">doc</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.sun.javadoc.AnnotationDesc</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.sun.javadoc.ClassDoc</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.sun.javadoc.FieldDoc</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.sun.javadoc.MethodDoc</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.sun.javadoc.ParamTag</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.sun.javadoc.RootDoc</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.sun.javadoc.Tag</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">com.sun.tools.javadoc.Main</span><span class="o">;</span>
<span class="cm">/**
* Example self-contained Doclet which prints raw text.
*
* @author Bob
* @since 123
* @custom Custom Annotation
* @see "http://docs.oracle.com/javase/6/docs/technotes/guides/javadoc/doclet/overview.html"
*/</span>
<span class="nd">@Deprecated</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">SunDocletPrinter</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="n">String</span> <span class="n">SOME_FIELD</span><span class="o">;</span>
<span class="cm">/**
* @see "http://docs.oracle.com/javase/7/docs/technotes/guides/javadoc/standard-doclet.html"
*/</span>
<span class="nd">@SuppressWarnings</span><span class="o">(</span><span class="n">value</span> <span class="o">=</span> <span class="o">{</span> <span class="s">"Test"</span> <span class="o">})</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="n">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"- start main"</span><span class="o">);</span>
<span class="n">Main</span><span class="o">.</span><span class="na">execute</span><span class="o">(</span><span class="s">"MyName"</span><span class="o">,</span> <span class="n">SunDocletPrinter</span><span class="o">.</span><span class="na">class</span><span class="o">.</span><span class="na">getName</span><span class="o">(),</span>
<span class="k">new</span> <span class="n">String</span><span class="o">[]</span> <span class="o">{</span> <span class="s">"com/rememberjava/doc/SunDocletPrinter.java"</span> <span class="o">});</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"- done execute"</span><span class="o">);</span>
<span class="o">}</span>
<span class="cm">/**
* This method processes everything. And there's more to it.
*
* @param root
* the root element
* @return returns true
*/</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">boolean</span> <span class="nf">start</span><span class="o">(</span><span class="n">RootDoc</span> <span class="n">root</span><span class="o">)</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"--- start"</span><span class="o">);</span>
<span class="k">for</span> <span class="o">(</span><span class="n">ClassDoc</span> <span class="n">classDoc</span> <span class="o">:</span> <span class="n">root</span><span class="o">.</span><span class="na">classes</span><span class="o">())</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Class: "</span> <span class="o">+</span> <span class="n">classDoc</span><span class="o">);</span>
<span class="c1">// Class annotations</span>
<span class="k">for</span> <span class="o">(</span><span class="n">AnnotationDesc</span> <span class="n">annotation</span> <span class="o">:</span> <span class="n">classDoc</span><span class="o">.</span><span class="na">annotations</span><span class="o">())</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">" Annotation: "</span> <span class="o">+</span> <span class="n">annotation</span><span class="o">);</span>
<span class="o">}</span>
<span class="c1">// Class JavaDoc tags</span>
<span class="k">for</span> <span class="o">(</span><span class="n">Tag</span> <span class="n">tag</span> <span class="o">:</span> <span class="n">classDoc</span><span class="o">.</span><span class="na">tags</span><span class="o">())</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">" Class tag:"</span> <span class="o">+</span> <span class="n">tag</span><span class="o">.</span><span class="na">name</span><span class="o">()</span> <span class="o">+</span> <span class="s">"="</span> <span class="o">+</span> <span class="n">tag</span><span class="o">.</span><span class="na">text</span><span class="o">());</span>
<span class="o">}</span>
<span class="c1">// Global constants and fields</span>
<span class="k">for</span> <span class="o">(</span><span class="n">FieldDoc</span> <span class="n">fieldDoc</span> <span class="o">:</span> <span class="n">classDoc</span><span class="o">.</span><span class="na">fields</span><span class="o">())</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">" Field: "</span> <span class="o">+</span> <span class="n">fieldDoc</span><span class="o">);</span>
<span class="o">}</span>
<span class="c1">// Methods</span>
<span class="k">for</span> <span class="o">(</span><span class="n">MethodDoc</span> <span class="n">methodDoc</span> <span class="o">:</span> <span class="n">classDoc</span><span class="o">.</span><span class="na">methods</span><span class="o">())</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">" Method: "</span> <span class="o">+</span> <span class="n">methodDoc</span><span class="o">);</span>
<span class="c1">// Method annotations</span>
<span class="k">for</span> <span class="o">(</span><span class="n">AnnotationDesc</span> <span class="n">annotation</span> <span class="o">:</span> <span class="n">methodDoc</span><span class="o">.</span><span class="na">annotations</span><span class="o">())</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">" Annotation: "</span> <span class="o">+</span> <span class="n">annotation</span><span class="o">);</span>
<span class="o">}</span>
<span class="c1">// Method JavaDoc comment (without parameters)</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">" Doc: "</span> <span class="o">+</span> <span class="n">methodDoc</span><span class="o">.</span><span class="na">commentText</span><span class="o">());</span>
<span class="c1">// Method JavaDoc (only the first sentence)</span>
<span class="k">for</span> <span class="o">(</span><span class="n">Tag</span> <span class="n">tag</span> <span class="o">:</span> <span class="n">methodDoc</span><span class="o">.</span><span class="na">firstSentenceTags</span><span class="o">())</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">" Tag: "</span> <span class="o">+</span> <span class="n">tag</span><span class="o">);</span>
<span class="o">}</span>
<span class="c1">// Method parameters (without return)</span>
<span class="k">for</span> <span class="o">(</span><span class="n">ParamTag</span> <span class="n">paramTag</span> <span class="o">:</span> <span class="n">methodDoc</span><span class="o">.</span><span class="na">paramTags</span><span class="o">())</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">" Param:"</span> <span class="o">+</span> <span class="n">paramTag</span><span class="o">.</span><span class="na">parameterName</span><span class="o">()</span> <span class="o">+</span> <span class="s">"="</span> <span class="o">+</span> <span class="n">paramTag</span><span class="o">.</span><span class="na">parameterComment</span><span class="o">());</span>
<span class="o">}</span>
<span class="c1">// The full method JavaDoc text</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">" Raw doc:\n"</span> <span class="o">+</span> <span class="n">methodDoc</span><span class="o">.</span><span class="na">getRawCommentText</span><span class="o">());</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"--- the end"</span><span class="o">);</span>
<span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span></code></pre></figure>
</div>Since Java 1.2, the javadoc command has generated neatly formatted documentation. The tool comes with its own API which allows customised output. The relevant classes are under the com.sun package hierarchy, and located in JRE_HOME/lib/tools.jar, which typically will have to be included manually. E.g. it can be found under /usr/lib/jvm/java-8-openjdk-amd64/lib/tools.jar.Connecting to Bittorrent’s Mainline DHT2017-03-01T00:00:00+00:002017-03-01T00:00:00+00:00http://rememberjava.com/bittorrent/2017/03/01/mldht_setup<p>In addition to its fast and efficient file transfer protocol, Bittorrent and other peer-to-peer file sharing networks bring another interesting technology to the masses: the <a href="https://en.wikipedia.org/wiki/Distributed_hash_table">Distributed Hash Table (DHT)</a>. In the case of Bittorrent, this is used to look up and download a torrent file based on its <a href="https://en.wikipedia.org/wiki/Magnet_URI_scheme">magnet link</a>. The DHT network for Bittorrent is called <a href="https://en.wikipedia.org/wiki/Mainline_DHT">Mainline DHT</a> based the <a href="https://en.wikipedia.org/wiki/Kademlia">Kademlia</a> DHT, although the network itself is separate from <a href="https://en.wikipedia.org/wiki/Kademlia#Implementations">other implementations</a>.</p>
<p>For Mainline DHT, there is an interesting open source client and library, called “<em>mldht</em>”. There are two instances on Github, with <a href="https://github.com/moreus/mldht">moreus/mldht</a> as the original and the fork <a href="https://github.com/the8472/mldht">the8472/mldht</a>. Although, both seems to be somewhat active. Both depend on the <a href="https://github.com/str4d/ed25519-java">EdDSA library</a> which <a href="https://github.com/the8472/ed25519-java">the8472 has also forked</a>. To get started, grab the source, and make sure the “mldht” code depend on or have access to the “ed25519” project. To confirm run the 28 unit tests from “mldht”. They should all pass.</p>
<figure class="highlight"><pre><code class="language-shell" data-lang="shell">https://github.com/the8472/ed25519-java.git
https://github.com/the8472/mldht.git</code></pre></figure>
<p>The “mldht” project includes a stand-alone DHT server node which can be started through the executable <a href="https://github.com/the8472/mldht/blob/master/src/the8472/mldht/Launcher.java">Launcher</a> class. Its main configuration is in “config.xml” which gets written to the current directory if it does not already exist. It’s based on “<a href="https://github.com/the8472/mldht/blob/master/src/the8472/mldht/config-defaults.xml">config-defaults.xml</a>”. To be able to connect to the DHT network, I had to change the option “<em>multihoming</em>” to <em>false</em> in the config file.</p>
<p>Furthermore, in order to use the CLI client utility, the CLI server has to be enabled. I ended up with the following configuration file.</p>
<p>Once started, the activity can be observed in <em>log/dht.log</em>. There will be plenty of noise.</p>
<figure class="highlight"><pre><code class="language-xml" data-lang="xml"><span class="cp"><?xml version="1.0" encoding="UTF-8"?></span>
<span class="nt"><mldht:config</span>
<span class="na">xmlns:mldht=</span><span class="s">"http://mldht/config/"</span>
<span class="na">xmlns:xsi=</span><span class="s">"http://www.w3.org/2001/XMLSchema-instance"</span>
<span class="na">xsi:schemaLocation=</span><span class="s">"http://mldht/config/config.xsd "</span><span class="nt">></span>
<span class="nt"><core></span>
<span class="nt"><logLevel></span>Info<span class="nt"></logLevel></span>
<span class="nt"><port></span>49001<span class="nt"></port></span>
<span class="nt"><useBootstrapServers></span>true<span class="nt"></useBootstrapServers></span>
<span class="nt"><multihoming></span>false<span class="nt"></multihoming></span>
<span class="nt"><persistID></span>true<span class="nt"></persistID></span>
<span class="nt"></core></span>
<span class="nt"><components></span>
<span class="nt"><component></span>
<span class="nt"><className></span>the8472.mldht.cli.Server<span class="nt"></className></span>
<span class="nt"></component></span>
<span class="nt"></components></span>
<span class="nt"></mldht:config></span></code></pre></figure>
<p>While the server is running, the CLI <a href="https://github.com/the8472/mldht/blob/master/src/the8472/mldht/cli/Client.java">Client</a> executable can be used to issue a few commands. Of interest is the “SAMPLE” command which lists random hash keys from random peers. Using that output, the “GETPEERS” can be used to look up specific hashes (make sure to remove the space formatting from the sample output). Finally, a torrent file can be downloaded with the “GETTORRENT” command.</p>
<p>Assuming the Java classpath is set correctly, example use would look like:</p>
<figure class="highlight"><pre><code class="language-shell" data-lang="shell">java the8472.mldht.cli.Client SAMPLE
java the8472.mldht.cli.Client GETPEERS f61c5a0dfaac58ba943c5d0c115343477196ad91
java the8472.mldht.cli.Client GETTORRENT f61c5a0dfaac58ba943c5d0c115343477196ad91</code></pre></figure>
<p>The hash used above is the Wikileaks “insurance” file posted last December, with the name “2016-12-09_WL-Insurance.aes256”. The “mldht” project does not contain any tools to actually read the torrent, but we can use the Transmission client:</p>
<figure class="highlight"><pre><code class="language-shell" data-lang="shell">apt-get install transmission-cli
transmission-show f61c5a0dfaac58ba943c5d0c115343477196ad91.torrent</code></pre></figure>
<p>The expected output would look like this:</p>
<figure class="highlight"><pre><code class="language-shell" data-lang="shell">Name: 2016-12-09_WL-Insurance.aes256
File: F61C5A0DFAAC58BA943C5D0C115343477196AD91.torrent
GENERAL
Name: 2016-12-09_WL-Insurance.aes256
Hash: f61c5a0dfaac58ba943c5d0c115343477196ad91
Created by:
Created on: Unknown
Piece Count: 42979
Piece Size: 2.00 MiB
Total Size: 90.13 GB
Privacy: Public torrent
TRACKERS
FILES
2016-12-09_WL-Insurance.aes256 <span class="o">(</span>90.13 GB<span class="o">)</span></code></pre></figure>
<p>Given that this worked fine, I’m thinking it should be trivial to create a custom ML DHT client which performs the steps above. I hope to come back to that in a future article.</p>In addition to its fast and efficient file transfer protocol, Bittorrent and other peer-to-peer file sharing networks bring another interesting technology to the masses: the Distributed Hash Table (DHT). In the case of Bittorrent, this is used to look up and download a torrent file based on its magnet link. The DHT network for Bittorrent is called Mainline DHT based the Kademlia DHT, although the network itself is separate from other implementations.Try Catch Exception2017-02-28T00:00:00+00:002017-02-28T00:00:00+00:00http://rememberjava.com/basics/2017/02/28/try_catch<p>This post looks at the syntax variations of the <em>try/catch/finally</em> blocks. For further details, see the excellent <a href="https://docs.oracle.com/javase/tutorial/essential/exceptions/index.html">Java tutorial on the topic</a>.</p>
<p>To start off, below is the basic syntax, with code surrounded by a <em>try</em>-block, and a <em>NullPointerException</em> caught by the <em>catch</em>-block. As can bee seen, the code will fail, since the variable “<em>str</em>” is null, leading to a <em>NullPointerException</em>. The Exception variable in the <em>catch</em>-block is by most common conventions simply “<em>e</em>”. It has a few convenience methods, including <em>printStackTrace()</em> which shows the call trace since the Exception was thrown. Although the print-out might look scary, it does provide useful information to the developer. Thus, keeping the full stack trace is helpful, typically in a detailed log-file. That is beyond the scope of this post.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"> <span class="k">try</span> <span class="o">{</span>
<span class="n">String</span> <span class="n">str</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="n">str</span><span class="o">.</span><span class="na">toString</span><span class="o">();</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">NullPointerException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
<span class="o">}</span></code></pre></figure>
<p>Exceptions are typed classes, and in the following example the <em>catch</em>-block will not be reached since the expected Exception is not the same or a sub-type of the one which is thrown: <a href="http://docs.oracle.com/javase/8/docs/api/?java/lang/NullPointerException.html"><em>NullPointerException</em></a> vs. <a href="http://docs.oracle.com/javase/8/docs/api/?java/lang/ArithmeticException.html"><em>ArithmeticException</em></a>. Instead, the <em>ArithmeticException</em> will be thrown out of the method.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"> <span class="k">try</span> <span class="o">{</span>
<span class="kt">int</span> <span class="n">a</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">/</span> <span class="mi">0</span><span class="o">;</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">NullPointerException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"This will not trigger."</span><span class="o">);</span>
<span class="o">}</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Will not reach this point."</span><span class="o">);</span></code></pre></figure>
<p>To handle multiple exception types, there are three options: Declare multiple <em>catch</em>-blocks with different types, as seen in the first part below; or declare multiple Exceptions within the same <em>catch</em> statement, as in the second part. The latter syntax has been available since Java 7. Finally, it’s possible to catch multiple Exceptions by specifying a type higher up the class hierarchy, e.g. using <em>Exception</em> or <em>Throwable</em>.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"> <span class="k">try</span> <span class="o">{</span>
<span class="n">Integer</span> <span class="n">a</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="kt">int</span> <span class="n">b</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">/</span> <span class="n">a</span><span class="o">;</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">NullPointerException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"NullPointerException"</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">ArithmeticException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"ArithmeticException"</span><span class="o">);</span>
<span class="o">}</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">Integer</span> <span class="n">a</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="kt">int</span> <span class="n">b</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">/</span> <span class="n">a</span><span class="o">;</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">NullPointerException</span> <span class="o">|</span> <span class="n">ArithmeticException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
<span class="o">}</span></code></pre></figure>
<p>In addition to the <em>try</em> and <em>catch</em> blocks, there is also a <em>finally</em>-block. It is executed at the end, regardless of whether there was an Exceptions thrown or not. This is useful for setting state or cleaning up, and a common example is closing an IO stream. However, as seen below, this can get crufty since we have to consider that the IO object might not have been opened in the first place, and that the <em>close()</em> method throws its own checked Exception.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"> <span class="n">OutputStream</span> <span class="n">out</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">out</span> <span class="o">=</span> <span class="k">new</span> <span class="n">FileOutputStream</span><span class="o">(</span><span class="s">"/dev/null"</span><span class="o">);</span>
<span class="n">out</span><span class="o">.</span><span class="na">write</span><span class="o">(</span><span class="mi">0</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">IOException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
<span class="o">}</span> <span class="k">finally</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">out</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">out</span><span class="o">.</span><span class="na">close</span><span class="o">();</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">IOException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span></code></pre></figure>
<p>To clean up the code above, the <em>try-with-resources</em> syntax was introduced in Java 7. It allows the <em>try</em> statement to take an extra block which is executed before its content. In addition, variables declared within this block will be closed at the end through the <a href="http://docs.oracle.com/javase/8/docs/api/?java/io/Closeable.html"><em>Closeable</em></a> interface. This significantly reduces the foot-print of the code above.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"> <span class="k">try</span> <span class="o">(</span><span class="n">OutputStream</span> <span class="n">out</span> <span class="o">=</span> <span class="k">new</span> <span class="n">FileOutputStream</span><span class="o">(</span><span class="s">"/dev/null"</span><span class="o">))</span> <span class="o">{</span>
<span class="n">out</span><span class="o">.</span><span class="na">write</span><span class="o">(</span><span class="mi">0</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">IOException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
<span class="o">}</span></code></pre></figure>
<p>A good example for multiple resources is the Socket example <a href="/socket/2017/02/21/socket_client_server.html">discussed previously</a>. Here the Socket and both IO streams are closable resources handled by the <em>try</em>-block.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"> <span class="k">try</span> <span class="o">(</span><span class="n">Socket</span> <span class="n">s</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Socket</span><span class="o">(</span><span class="s">"google.com"</span><span class="o">,</span> <span class="mi">80</span><span class="o">);</span>
<span class="n">OutputStream</span> <span class="n">out</span> <span class="o">=</span> <span class="n">s</span><span class="o">.</span><span class="na">getOutputStream</span><span class="o">();</span>
<span class="n">InputStream</span> <span class="n">in</span> <span class="o">=</span> <span class="n">s</span><span class="o">.</span><span class="na">getInputStream</span><span class="o">())</span> <span class="o">{</span>
<span class="n">out</span><span class="o">.</span><span class="na">write</span><span class="o">(</span><span class="mi">0</span><span class="o">);</span>
<span class="n">in</span><span class="o">.</span><span class="na">read</span><span class="o">();</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">IOException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
<span class="o">}</span></code></pre></figure>
<p>Finally, a word on messaging and wrapping of Exceptions. As <a href="https://docs.oracle.com/javase/tutorial/essential/exceptions/runtime.html">mentioned in the tutorial</a>, it’s poor practice to throw <em>RuntimeExceptions</em> or simply wrap checked Exceptions, as seen below. However, regardless of where you stand in that debate, Exceptions can always be made more helpful and useful by clear messaging and relevant context. The wrapped RuntimeException below adds a more specific message and also includes the filename the IO stream operates on, since it might not be included in all types of <em>IOExceptions</em>. Furthermore, in the case of the <em>File</em> object, is is useful to use the <em>getAbsolutePath()</em> method. It forces the full path to the resolved and included. It really helps when debugging issues where the full path can be copy/pasted and confirmed.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"> <span class="n">File</span> <span class="n">file</span> <span class="o">=</span> <span class="k">new</span> <span class="n">File</span><span class="o">(</span><span class="s">"/dev/null"</span><span class="o">);</span>
<span class="k">try</span> <span class="o">(</span><span class="n">OutputStream</span> <span class="n">out</span> <span class="o">=</span> <span class="k">new</span> <span class="n">FileOutputStream</span><span class="o">(</span><span class="n">file</span><span class="o">))</span> <span class="o">{</span>
<span class="n">out</span><span class="o">.</span><span class="na">write</span><span class="o">(</span><span class="mi">0</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">IOException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">RuntimeException</span><span class="o">(</span><span class="s">"Could not open or read file "</span> <span class="o">+</span> <span class="n">file</span><span class="o">.</span><span class="na">getAbsolutePath</span><span class="o">(),</span> <span class="n">e</span><span class="o">);</span>
<span class="o">}</span></code></pre></figure>
<p>Here is the full listing with all examples as tests.</p>
<script>
var hidden = {};
function fileshowhide(id) {
var text = document.getElementById(id);
var h = (id in hidden) ? hidden[id] : true;
h = !h;
hidden[id] = h;
if(h) {
text.style.display = "none";
} else {
text.style.display = "inline";
}
}
</script>
<div class="filename">TryCatchTest.java</div>
<div class="filebuttons">
<div class="showhide"><button class="filebutton" onclick="fileshowhide('basics20170228try_catchsrccomrememberjavabasicsTryCatchTestjava')">Show file</button></div>
<a class="filebutton github" href="https://github.com/hblok/rememberjava/blob/master/_includes/src/com/rememberjava/basics/TryCatchTest.java">GitHub</a>
<a class="filebutton raw" href="https://raw.githubusercontent.com/hblok/rememberjava/master/_includes/src/com/rememberjava/basics/TryCatchTest.java">Raw</a>
</div>
<div id="basics20170228try_catchsrccomrememberjavabasicsTryCatchTestjava" class="javafile">
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="cm">/* Copyright rememberjava.com. Licensed under GPL 3. See http://rememberjava.com/license */</span>
<span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">rememberjava</span><span class="o">.</span><span class="na">basics</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.io.File</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.io.FileOutputStream</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.io.IOException</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.io.InputStream</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.io.OutputStream</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.net.Socket</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.junit.Test</span><span class="o">;</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">TryCatchTest</span> <span class="o">{</span>
<span class="c1">// The second try-block will throw an uncaught ArithmeticException because of</span>
<span class="c1">// the divide by 0.</span>
<span class="nd">@Test</span><span class="o">(</span><span class="n">expected</span> <span class="o">=</span> <span class="n">ArithmeticException</span><span class="o">.</span><span class="na">class</span><span class="o">)</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">basic</span><span class="o">()</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">String</span> <span class="n">str</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="n">str</span><span class="o">.</span><span class="na">toString</span><span class="o">();</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">NullPointerException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
<span class="o">}</span>
<span class="k">try</span> <span class="o">{</span>
<span class="kt">int</span> <span class="n">a</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">/</span> <span class="mi">0</span><span class="o">;</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">NullPointerException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"This will not trigger."</span><span class="o">);</span>
<span class="o">}</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Will not reach this point."</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@Test</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">multi</span><span class="o">()</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">Integer</span> <span class="n">a</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="kt">int</span> <span class="n">b</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">/</span> <span class="n">a</span><span class="o">;</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">NullPointerException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"NullPointerException"</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">ArithmeticException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"ArithmeticException"</span><span class="o">);</span>
<span class="o">}</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">Integer</span> <span class="n">a</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="kt">int</span> <span class="n">b</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">/</span> <span class="n">a</span><span class="o">;</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">NullPointerException</span> <span class="o">|</span> <span class="n">ArithmeticException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="nd">@Test</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">testFinally</span><span class="o">()</span> <span class="o">{</span>
<span class="n">OutputStream</span> <span class="n">out</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">out</span> <span class="o">=</span> <span class="k">new</span> <span class="n">FileOutputStream</span><span class="o">(</span><span class="s">"/dev/null"</span><span class="o">);</span>
<span class="n">out</span><span class="o">.</span><span class="na">write</span><span class="o">(</span><span class="mi">0</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">IOException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
<span class="o">}</span> <span class="k">finally</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">out</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">out</span><span class="o">.</span><span class="na">close</span><span class="o">();</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">IOException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="nd">@Test</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">tryWith</span><span class="o">()</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">(</span><span class="n">OutputStream</span> <span class="n">out</span> <span class="o">=</span> <span class="k">new</span> <span class="n">FileOutputStream</span><span class="o">(</span><span class="s">"/dev/null"</span><span class="o">))</span> <span class="o">{</span>
<span class="n">out</span><span class="o">.</span><span class="na">write</span><span class="o">(</span><span class="mi">0</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">IOException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="nd">@Test</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">tryWithMulti</span><span class="o">()</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">(</span><span class="n">Socket</span> <span class="n">s</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Socket</span><span class="o">(</span><span class="s">"google.com"</span><span class="o">,</span> <span class="mi">80</span><span class="o">);</span>
<span class="n">OutputStream</span> <span class="n">out</span> <span class="o">=</span> <span class="n">s</span><span class="o">.</span><span class="na">getOutputStream</span><span class="o">();</span>
<span class="n">InputStream</span> <span class="n">in</span> <span class="o">=</span> <span class="n">s</span><span class="o">.</span><span class="na">getInputStream</span><span class="o">())</span> <span class="o">{</span>
<span class="n">out</span><span class="o">.</span><span class="na">write</span><span class="o">(</span><span class="mi">0</span><span class="o">);</span>
<span class="n">in</span><span class="o">.</span><span class="na">read</span><span class="o">();</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">IOException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="nd">@Test</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">message</span><span class="o">()</span> <span class="o">{</span>
<span class="n">File</span> <span class="n">file</span> <span class="o">=</span> <span class="k">new</span> <span class="n">File</span><span class="o">(</span><span class="s">"/dev/null"</span><span class="o">);</span>
<span class="k">try</span> <span class="o">(</span><span class="n">OutputStream</span> <span class="n">out</span> <span class="o">=</span> <span class="k">new</span> <span class="n">FileOutputStream</span><span class="o">(</span><span class="n">file</span><span class="o">))</span> <span class="o">{</span>
<span class="n">out</span><span class="o">.</span><span class="na">write</span><span class="o">(</span><span class="mi">0</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">IOException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">RuntimeException</span><span class="o">(</span><span class="s">"Could not open or read file "</span> <span class="o">+</span> <span class="n">file</span><span class="o">.</span><span class="na">getAbsolutePath</span><span class="o">(),</span> <span class="n">e</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span></code></pre></figure>
</div>This post looks at the syntax variations of the try/catch/finally blocks. For further details, see the excellent Java tutorial on the topic.Unit test Exceptions2017-02-24T00:00:00+00:002017-02-24T00:00:00+00:00http://rememberjava.com/junit/2017/02/24/test_exceptions<p>Testing the “happy path” of the code, when everything goes right, is fine, however error handling and Exceptions is just as much a part of the code under test. In fact, it is possibly a more delicate area, since you want an application which degrades gracefully in the event of error. This post goes through different ways of setting expectations on thrown Exceptions.</p>
<p>In the first method below, the old style pre-Junit 4 way of asserting for an Exception is shown. The idea is that the Exception must be thrown, so if the execution reaches the <em>fail()</em> statement, that did not happen. The expected path is instead that the catch-block engages, with the expected Exception type. If a different type of Exception, which is not a sub-class of the caught Exception is thrown, it propagates out of the method and the test fails. Although this style is a bit clunky and verbose, it has a few advantages over the annotation-style: You have control over exactly what point in the code you expect the Exception to be thrown; you can inspect the Exception and assert its message; you can set a custom error message.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"> <span class="kd">public</span> <span class="kt">void</span> <span class="nf">testOldStyle</span><span class="o">()</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">INVALID_INTEGER</span><span class="o">);</span>
<span class="n">fail</span><span class="o">(</span><span class="s">"Expected an Exception to be thrown"</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">NumberFormatException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">assertEquals</span><span class="o">(</span><span class="s">"For input string: \""</span> <span class="o">+</span> <span class="n">INVALID_INTEGER</span> <span class="o">+</span> <span class="s">"\""</span><span class="o">,</span> <span class="n">e</span><span class="o">.</span><span class="na">getMessage</span><span class="o">());</span>
<span class="o">}</span>
<span class="o">}</span></code></pre></figure>
<p>Since Java 6 and Junit 4, annotations become available, and the <em>@Test</em> annotation is now the way to declare a test method. It comes with an extra parameter <em>expected</em> which takes a <em>Class</em> type indicating which Exception is expected to be thrown. This approach is clean and even minimalist. If all there is to a test is a one-liner like shown below, this is a perfectly fine way to declaring the expectation. However, it loses the ability to inspect the message or cause. Furthermore, if the test method contains more lines, there is no way to control or verify from where the Exception originated.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"> <span class="nd">@Test</span><span class="o">(</span><span class="n">expected</span> <span class="o">=</span> <span class="n">NumberFormatException</span><span class="o">.</span><span class="na">class</span><span class="o">)</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">annotation</span><span class="o">()</span> <span class="o">{</span>
<span class="n">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">INVALID_INTEGER</span><span class="o">);</span>
<span class="o">}</span></code></pre></figure>
<p>Enter JUnit 4.7, and the <a href="http://junit.org/junit4/javadoc/latest/org/junit/Rule.html"><em>@Rule</em> annotation</a> and <a href="http://junit.org/junit4/javadoc/latest/org/junit/rules/ExpectedException.html">ExpectedException rule</a>. It solves the problem with the <em>Test</em> annotation above, but retains a clean way of expressing the assertion. In the example below, the <em>Rule</em> annotation makes sure the <em>thrown</em> field is initialised a-new before every test method. It can then be used right above the method which is expected to throw an Exception, and can assert on its type and message. The <em>expectMessage()</em> method asserts that the message contains rather than equals the expected string.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"> <span class="nd">@Rule</span>
<span class="kd">public</span> <span class="kd">final</span> <span class="n">ExpectedException</span> <span class="n">thrown</span> <span class="o">=</span> <span class="n">ExpectedException</span><span class="o">.</span><span class="na">none</span><span class="o">();</span>
<span class="nd">@Test</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">testThrown</span><span class="o">()</span> <span class="o">{</span>
<span class="n">thrown</span><span class="o">.</span><span class="na">expect</span><span class="o">(</span><span class="n">NumberFormatException</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>
<span class="n">thrown</span><span class="o">.</span><span class="na">expectMessage</span><span class="o">(</span><span class="n">INVALID_INTEGER</span><span class="o">);</span>
<span class="n">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">INVALID_INTEGER</span><span class="o">);</span>
<span class="o">}</span></code></pre></figure>
<p>The <em>ExpectedException</em> class comes with some extra assertion methods which takes the popular <a href="http://hamcrest.org/JavaHamcrest/">Hamcrest</a> matchers. In the code below, the <em>endsWith</em> matcher is used.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kn">import</span> <span class="nn">static</span> <span class="n">org</span><span class="o">.</span><span class="na">hamcrest</span><span class="o">.</span><span class="na">CoreMatchers</span><span class="o">.</span><span class="na">endsWith</span><span class="o">;</span>
<span class="nd">@Test</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">hamcrest</span><span class="o">()</span> <span class="o">{</span>
<span class="n">thrown</span><span class="o">.</span><span class="na">expect</span><span class="o">(</span><span class="n">NumberFormatException</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>
<span class="n">thrown</span><span class="o">.</span><span class="na">expectMessage</span><span class="o">(</span><span class="n">endsWith</span><span class="o">(</span><span class="n">INVALID_INTEGER</span> <span class="o">+</span> <span class="s">"\""</span><span class="o">));</span>
<span class="n">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">INVALID_INTEGER</span><span class="o">);</span>
<span class="o">}</span></code></pre></figure>
<p>Finally, the <em>expectCause()</em> method takes another Hamcrest matcher, where for example the type of the contained cause can be asserted. Notice that the outer exception type can be asserted as well. The <em>expectCause</em> assertion only goes one level deep, so if further unnesting is required, a custom Matcher could be implemented. In this example, the wrapping <em>RuntimeException</em> does not alter the message, so it can be asserted directly. If the outer Exception has its own message, another custom Matcher would be needed to assert on the inner message.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kn">import</span> <span class="nn">static</span> <span class="n">org</span><span class="o">.</span><span class="na">hamcrest</span><span class="o">.</span><span class="na">CoreMatchers</span><span class="o">.</span><span class="na">isA</span><span class="o">;</span>
<span class="nd">@Test</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">cause</span><span class="o">()</span> <span class="o">{</span>
<span class="n">thrown</span><span class="o">.</span><span class="na">expect</span><span class="o">(</span><span class="n">RuntimeException</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>
<span class="n">thrown</span><span class="o">.</span><span class="na">expectMessage</span><span class="o">(</span><span class="n">INVALID_INTEGER</span><span class="o">);</span>
<span class="n">thrown</span><span class="o">.</span><span class="na">expectCause</span><span class="o">(</span><span class="n">isA</span><span class="o">(</span><span class="n">NumberFormatException</span><span class="o">.</span><span class="na">class</span><span class="o">));</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">INVALID_INTEGER</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">NumberFormatException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">RuntimeException</span><span class="o">(</span><span class="n">e</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span></code></pre></figure>
<p>Here is the full test case listing.</p>
<script>
var hidden = {};
function fileshowhide(id) {
var text = document.getElementById(id);
var h = (id in hidden) ? hidden[id] : true;
h = !h;
hidden[id] = h;
if(h) {
text.style.display = "none";
} else {
text.style.display = "inline";
}
}
</script>
<div class="filename">ExceptionsTest.java</div>
<div class="filebuttons">
<div class="showhide"><button class="filebutton" onclick="fileshowhide('junit20170224test_exceptionssrccomrememberjavajunitExceptionsTestjava')">Show file</button></div>
<a class="filebutton github" href="https://github.com/hblok/rememberjava/blob/master/_includes/src/com/rememberjava/junit/ExceptionsTest.java">GitHub</a>
<a class="filebutton raw" href="https://raw.githubusercontent.com/hblok/rememberjava/master/_includes/src/com/rememberjava/junit/ExceptionsTest.java">Raw</a>
</div>
<div id="junit20170224test_exceptionssrccomrememberjavajunitExceptionsTestjava" class="javafile">
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="cm">/* Copyright rememberjava.com. Licensed under GPL 3. See http://rememberjava.com/license */</span>
<span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">rememberjava</span><span class="o">.</span><span class="na">junit</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">static</span> <span class="n">org</span><span class="o">.</span><span class="na">hamcrest</span><span class="o">.</span><span class="na">CoreMatchers</span><span class="o">.</span><span class="na">endsWith</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">static</span> <span class="n">org</span><span class="o">.</span><span class="na">hamcrest</span><span class="o">.</span><span class="na">CoreMatchers</span><span class="o">.</span><span class="na">isA</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">static</span> <span class="n">org</span><span class="o">.</span><span class="na">junit</span><span class="o">.</span><span class="na">Assert</span><span class="o">.</span><span class="na">assertEquals</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">static</span> <span class="n">org</span><span class="o">.</span><span class="na">junit</span><span class="o">.</span><span class="na">Assert</span><span class="o">.</span><span class="na">fail</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.junit.Rule</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.junit.Test</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.junit.rules.ExpectedException</span><span class="o">;</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">ExceptionsTest</span> <span class="o">{</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">INVALID_INTEGER</span> <span class="o">=</span> <span class="s">"invalid integer"</span><span class="o">;</span>
<span class="nd">@Rule</span>
<span class="kd">public</span> <span class="kd">final</span> <span class="n">ExpectedException</span> <span class="n">thrown</span> <span class="o">=</span> <span class="n">ExpectedException</span><span class="o">.</span><span class="na">none</span><span class="o">();</span>
<span class="nd">@Test</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">testOldStyle</span><span class="o">()</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">INVALID_INTEGER</span><span class="o">);</span>
<span class="n">fail</span><span class="o">(</span><span class="s">"Expected an Exception to be thrown"</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">NumberFormatException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">assertEquals</span><span class="o">(</span><span class="s">"For input string: \""</span> <span class="o">+</span> <span class="n">INVALID_INTEGER</span> <span class="o">+</span> <span class="s">"\""</span><span class="o">,</span> <span class="n">e</span><span class="o">.</span><span class="na">getMessage</span><span class="o">());</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="nd">@Test</span><span class="o">(</span><span class="n">expected</span> <span class="o">=</span> <span class="n">NumberFormatException</span><span class="o">.</span><span class="na">class</span><span class="o">)</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">annotation</span><span class="o">()</span> <span class="o">{</span>
<span class="n">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">INVALID_INTEGER</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@Test</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">testThrown</span><span class="o">()</span> <span class="o">{</span>
<span class="n">thrown</span><span class="o">.</span><span class="na">expect</span><span class="o">(</span><span class="n">NumberFormatException</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>
<span class="n">thrown</span><span class="o">.</span><span class="na">expectMessage</span><span class="o">(</span><span class="n">INVALID_INTEGER</span><span class="o">);</span>
<span class="n">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">INVALID_INTEGER</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@Test</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">hamcrest</span><span class="o">()</span> <span class="o">{</span>
<span class="n">thrown</span><span class="o">.</span><span class="na">expect</span><span class="o">(</span><span class="n">NumberFormatException</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>
<span class="n">thrown</span><span class="o">.</span><span class="na">expectMessage</span><span class="o">(</span><span class="n">endsWith</span><span class="o">(</span><span class="n">INVALID_INTEGER</span> <span class="o">+</span> <span class="s">"\""</span><span class="o">));</span>
<span class="n">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">INVALID_INTEGER</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@Test</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">cause</span><span class="o">()</span> <span class="o">{</span>
<span class="n">thrown</span><span class="o">.</span><span class="na">expect</span><span class="o">(</span><span class="n">RuntimeException</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>
<span class="n">thrown</span><span class="o">.</span><span class="na">expectMessage</span><span class="o">(</span><span class="n">INVALID_INTEGER</span><span class="o">);</span>
<span class="n">thrown</span><span class="o">.</span><span class="na">expectCause</span><span class="o">(</span><span class="n">isA</span><span class="o">(</span><span class="n">NumberFormatException</span><span class="o">.</span><span class="na">class</span><span class="o">));</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">INVALID_INTEGER</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">NumberFormatException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">RuntimeException</span><span class="o">(</span><span class="n">e</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span></code></pre></figure>
</div>Testing the “happy path” of the code, when everything goes right, is fine, however error handling and Exceptions is just as much a part of the code under test. In fact, it is possibly a more delicate area, since you want an application which degrades gracefully in the event of error. This post goes through different ways of setting expectations on thrown Exceptions.Socket client / server example2017-02-21T00:00:00+00:002017-02-21T00:00:00+00:00http://rememberjava.com/socket/2017/02/21/socket_client_server<p>After posts on several server libraries, including <a href="/http/2017/01/20/simple_http_server.html">Sun’s HTTP</a>; Simple Framework’s <a href="/http/2017/02/12/sf_http_server.html">HTTP</a>; and <a href="/websocket/2017/02/18/sf_websocket_server.html">Websocket</a>, it seems appropriate to include a plain TCP socket server / client example. Without any application protocol to adhere to, it’s straight forward to setup and test. There are two essential classes involved: On the server side there’s a <a href="https://docs.oracle.com/javase/8/docs/api/java/net/ServerSocket.html"><em>ServerSocket</em></a>, while the client has a <a href="https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html"><em>Socket</em></a>. The only difference is that the <em>ServerSocket</em> accepts one or more incoming connections, and provide a <em>Socket</em> handle for each. After that, both client and server are the same, in that the <em>Socket</em> object provides input and output streams once established.</p>
<p>In the code below, a <em>ServerSocket</em> is set to listen to a specific port, and to accept a single incoming connection. It grabs the IO streams, makes these available to the rest of the test, and finally releases a semaphore lock to allow the test to continue. Normally, the server thread would wait for further incoming requests, and would probably spawn or assign pooled threads to handle the request. Here we focus only on the basic IO parts.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="o">...</span>
<span class="n">ServerSocket</span> <span class="n">server</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ServerSocket</span><span class="o">(</span><span class="n">PORT</span><span class="o">);</span>
<span class="n">listen</span><span class="o">(</span><span class="n">server</span><span class="o">);</span>
<span class="o">...</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">listen</span><span class="o">(</span><span class="n">ServerSocket</span> <span class="n">server</span><span class="o">)</span> <span class="o">{</span>
<span class="k">new</span> <span class="nf">Thread</span><span class="o">(()</span> <span class="o">-></span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">Socket</span> <span class="n">socket</span> <span class="o">=</span> <span class="n">server</span><span class="o">.</span><span class="na">accept</span><span class="o">();</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Incoming connection: "</span> <span class="o">+</span> <span class="n">socket</span><span class="o">);</span>
<span class="n">serverOut</span> <span class="o">=</span> <span class="n">socket</span><span class="o">.</span><span class="na">getOutputStream</span><span class="o">();</span>
<span class="n">serverIn</span> <span class="o">=</span> <span class="n">socket</span><span class="o">.</span><span class="na">getInputStream</span><span class="o">();</span>
<span class="n">lock</span><span class="o">.</span><span class="na">release</span><span class="o">();</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Released lock"</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">IOException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}).</span><span class="na">start</span><span class="o">();</span>
<span class="o">}</span></code></pre></figure>
<p>On the client side, it’s just as simple: Establish a connection to the severer host and port, and get the IO streams.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"> <span class="n">Socket</span> <span class="n">client</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Socket</span><span class="o">(</span><span class="s">"localhost"</span><span class="o">,</span> <span class="n">PORT</span><span class="o">);</span>
<span class="n">OutputStream</span> <span class="n">clientOut</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="na">getOutputStream</span><span class="o">();</span>
<span class="n">InputStream</span> <span class="n">clientIn</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="na">getInputStream</span><span class="o">();</span></code></pre></figure>
<p>The rest of the test code below asserts that messages are received correctly both on the client and the server, using the raw streams and wrapped <em>PrinterWriter</em> helpers. Again, he semaphore is used to wait for the server thread to establish its connection before the rest of the test continues. Without it, using the IO streams will results in NullPointerExceptions, since they are not initialized yet.</p>
<script>
var hidden = {};
function fileshowhide(id) {
var text = document.getElementById(id);
var h = (id in hidden) ? hidden[id] : true;
h = !h;
hidden[id] = h;
if(h) {
text.style.display = "none";
} else {
text.style.display = "inline";
}
}
</script>
<div class="filename">SocketTest.java</div>
<div class="filebuttons">
<div class="showhide"><button class="filebutton" onclick="fileshowhide('socket20170221socket_client_serversrccomrememberjavanetSocketTestjava')">Show file</button></div>
<a class="filebutton github" href="https://github.com/hblok/rememberjava/blob/master/_includes/src/com/rememberjava/net/SocketTest.java">GitHub</a>
<a class="filebutton raw" href="https://raw.githubusercontent.com/hblok/rememberjava/master/_includes/src/com/rememberjava/net/SocketTest.java">Raw</a>
</div>
<div id="socket20170221socket_client_serversrccomrememberjavanetSocketTestjava" class="javafile">
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="cm">/* Copyright rememberjava.com. Licensed under GPL 3. See http://rememberjava.com/license */</span>
<span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">rememberjava</span><span class="o">.</span><span class="na">net</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">static</span> <span class="n">org</span><span class="o">.</span><span class="na">junit</span><span class="o">.</span><span class="na">Assert</span><span class="o">.</span><span class="na">assertEquals</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.io.IOException</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.io.InputStream</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.io.OutputStream</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.io.PrintWriter</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.net.ServerSocket</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.net.Socket</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.util.concurrent.Semaphore</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.junit.Test</span><span class="o">;</span>
<span class="cm">/**
* Simple client / server Socket tests, including a Buffered PrintWriter which
* has to be flushed.
*/</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">SocketTest</span> <span class="o">{</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="kt">int</span> <span class="n">PORT</span> <span class="o">=</span> <span class="mi">8887</span><span class="o">;</span>
<span class="kd">private</span> <span class="n">OutputStream</span> <span class="n">serverOut</span><span class="o">;</span>
<span class="kd">private</span> <span class="n">InputStream</span> <span class="n">serverIn</span><span class="o">;</span>
<span class="cm">/**
* Shared lock between the "client" and "server" code, to make the test case
* synchronous.
*/</span>
<span class="kd">private</span> <span class="n">Semaphore</span> <span class="n">lock</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Semaphore</span><span class="o">(</span><span class="mi">0</span><span class="o">);</span>
<span class="cm">/**
* Tests server and client side sockets in one flow. A lock object is used for
* synchronous between the two sides.
*/</span>
<span class="nd">@Test</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">testClientServer</span><span class="o">()</span> <span class="kd">throws</span> <span class="n">IOException</span><span class="o">,</span> <span class="n">InterruptedException</span> <span class="o">{</span>
<span class="n">ServerSocket</span> <span class="n">server</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ServerSocket</span><span class="o">(</span><span class="n">PORT</span><span class="o">);</span>
<span class="n">listen</span><span class="o">(</span><span class="n">server</span><span class="o">);</span>
<span class="n">Socket</span> <span class="n">client</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Socket</span><span class="o">(</span><span class="s">"localhost"</span><span class="o">,</span> <span class="n">PORT</span><span class="o">);</span>
<span class="n">OutputStream</span> <span class="n">clientOut</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="na">getOutputStream</span><span class="o">();</span>
<span class="n">InputStream</span> <span class="n">clientIn</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="na">getInputStream</span><span class="o">();</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Waiting for lock"</span><span class="o">);</span>
<span class="n">lock</span><span class="o">.</span><span class="na">acquire</span><span class="o">();</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Acquired lock"</span><span class="o">);</span>
<span class="n">write</span><span class="o">(</span><span class="n">clientOut</span><span class="o">,</span> <span class="s">"Hi"</span><span class="o">);</span>
<span class="n">assertRead</span><span class="o">(</span><span class="n">serverIn</span><span class="o">,</span> <span class="s">"Hi"</span><span class="o">);</span>
<span class="n">write</span><span class="o">(</span><span class="n">serverOut</span><span class="o">,</span> <span class="s">"Hello"</span><span class="o">);</span>
<span class="n">assertRead</span><span class="o">(</span><span class="n">clientIn</span><span class="o">,</span> <span class="s">"Hello"</span><span class="o">);</span>
<span class="n">printWrite</span><span class="o">(</span><span class="n">clientOut</span><span class="o">,</span> <span class="s">"Test printWrite"</span><span class="o">);</span>
<span class="n">assertRead</span><span class="o">(</span><span class="n">serverIn</span><span class="o">,</span> <span class="s">"Test printWrite"</span><span class="o">);</span>
<span class="n">printWrite</span><span class="o">(</span><span class="n">serverOut</span><span class="o">,</span> <span class="s">"Test printWrite again"</span><span class="o">);</span>
<span class="n">assertRead</span><span class="o">(</span><span class="n">clientIn</span><span class="o">,</span> <span class="s">"Test printWrite again"</span><span class="o">);</span>
<span class="n">client</span><span class="o">.</span><span class="na">close</span><span class="o">();</span>
<span class="n">server</span><span class="o">.</span><span class="na">close</span><span class="o">();</span>
<span class="o">}</span>
<span class="cm">/**
* Writes to an OutputStream. Used for both server and client output streams.
*/</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">write</span><span class="o">(</span><span class="n">OutputStream</span> <span class="n">out</span><span class="o">,</span> <span class="n">String</span> <span class="n">str</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="n">out</span><span class="o">.</span><span class="na">write</span><span class="o">(</span><span class="n">str</span><span class="o">.</span><span class="na">getBytes</span><span class="o">());</span>
<span class="n">out</span><span class="o">.</span><span class="na">flush</span><span class="o">();</span>
<span class="o">}</span>
<span class="cm">/**
* Writes to an OutputStream. Used for both server and client output streams.
*/</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">printWrite</span><span class="o">(</span><span class="n">OutputStream</span> <span class="n">out</span><span class="o">,</span> <span class="n">String</span> <span class="n">str</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="n">PrintWriter</span> <span class="n">pw</span> <span class="o">=</span> <span class="k">new</span> <span class="n">PrintWriter</span><span class="o">(</span><span class="n">out</span><span class="o">);</span>
<span class="n">pw</span><span class="o">.</span><span class="na">print</span><span class="o">(</span><span class="n">str</span><span class="o">);</span>
<span class="n">pw</span><span class="o">.</span><span class="na">flush</span><span class="o">();</span>
<span class="o">}</span>
<span class="cm">/**
* Reads from an InputStream. Used for both server and client input streams.
*/</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">assertRead</span><span class="o">(</span><span class="n">InputStream</span> <span class="n">in</span><span class="o">,</span> <span class="n">String</span> <span class="n">expected</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="n">assertEquals</span><span class="o">(</span><span class="s">"Too few bytes available for reading: "</span><span class="o">,</span> <span class="n">expected</span><span class="o">.</span><span class="na">length</span><span class="o">(),</span> <span class="n">in</span><span class="o">.</span><span class="na">available</span><span class="o">());</span>
<span class="kt">byte</span><span class="o">[]</span> <span class="n">buf</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">byte</span><span class="o">[</span><span class="n">expected</span><span class="o">.</span><span class="na">length</span><span class="o">()];</span>
<span class="n">in</span><span class="o">.</span><span class="na">read</span><span class="o">(</span><span class="n">buf</span><span class="o">);</span>
<span class="n">assertEquals</span><span class="o">(</span><span class="n">expected</span><span class="o">,</span> <span class="k">new</span> <span class="n">String</span><span class="o">(</span><span class="n">buf</span><span class="o">));</span>
<span class="o">}</span>
<span class="cm">/**
* Listens for and accepts one incoming request server side on a separate
* thread. When a request is received, grabs its IO streams and "signals" to
* the client side above through the shared lock object.
*/</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">listen</span><span class="o">(</span><span class="n">ServerSocket</span> <span class="n">server</span><span class="o">)</span> <span class="o">{</span>
<span class="k">new</span> <span class="nf">Thread</span><span class="o">(()</span> <span class="o">-></span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">Socket</span> <span class="n">socket</span> <span class="o">=</span> <span class="n">server</span><span class="o">.</span><span class="na">accept</span><span class="o">();</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Incoming connection: "</span> <span class="o">+</span> <span class="n">socket</span><span class="o">);</span>
<span class="n">serverOut</span> <span class="o">=</span> <span class="n">socket</span><span class="o">.</span><span class="na">getOutputStream</span><span class="o">();</span>
<span class="n">serverIn</span> <span class="o">=</span> <span class="n">socket</span><span class="o">.</span><span class="na">getInputStream</span><span class="o">();</span>
<span class="n">lock</span><span class="o">.</span><span class="na">release</span><span class="o">();</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Released lock"</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">IOException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}).</span><span class="na">start</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span></code></pre></figure>
</div>After posts on several server libraries, including Sun’s HTTP; Simple Framework’s HTTP; and Websocket, it seems appropriate to include a plain TCP socket server / client example. Without any application protocol to adhere to, it’s straight forward to setup and test. There are two essential classes involved: On the server side there’s a ServerSocket, while the client has a Socket. The only difference is that the ServerSocket accepts one or more incoming connections, and provide a Socket handle for each. After that, both client and server are the same, in that the Socket object provides input and output streams once established.Styles with JTextPane2017-02-20T00:00:00+00:002017-02-20T00:00:00+00:00http://rememberjava.com/ui/2017/02/20/JTextPane_Styles<p>The <a href="http://docs.oracle.com/javase/tutorial/uiswing/components/generaltext.html">Swing tutorial for the JTextPane</a> and <a href="http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TextComponentDemoProject/src/components/TextComponentDemo.java">demo code</a> is good and comprehensive, covering multiple ways to interact with the the <em>StyledDocument</em> and add <em>Styles</em>. So, without repeating all of that, here’s a minimal example including only simple style changes on the insert update and selection events.</p>
<p>In the first snippet below, the implementation for the <em>insertUpdate</em> event is shown. For each typed character or pasted text, the entire text of the document will be searched for the word “foo”. For each occurrence, the bold attribute is set for that word. Notice that the update of the attribute happens on a separate AWT thread.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"> <span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">insertUpdate</span><span class="o">(</span><span class="n">DocumentEvent</span> <span class="n">event</span><span class="o">)</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">String</span> <span class="n">text</span> <span class="o">=</span> <span class="n">doc</span><span class="o">.</span><span class="na">getText</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="n">doc</span><span class="o">.</span><span class="na">getLength</span><span class="o">());</span>
<span class="n">Pattern</span> <span class="n">p</span> <span class="o">=</span> <span class="n">Pattern</span><span class="o">.</span><span class="na">compile</span><span class="o">(</span><span class="n">FOO</span><span class="o">);</span>
<span class="n">Matcher</span> <span class="n">matcher</span> <span class="o">=</span> <span class="n">p</span><span class="o">.</span><span class="na">matcher</span><span class="o">(</span><span class="n">text</span><span class="o">);</span>
<span class="k">while</span> <span class="o">(</span><span class="n">matcher</span><span class="o">.</span><span class="na">find</span><span class="o">())</span> <span class="o">{</span>
<span class="n">updateAttribute</span><span class="o">(</span><span class="n">matcher</span><span class="o">.</span><span class="na">start</span><span class="o">(),</span> <span class="n">FOO</span><span class="o">.</span><span class="na">length</span><span class="o">(),</span> <span class="n">Style</span><span class="o">.</span><span class="na">BOLD</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">BadLocationException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">updateAttribute</span><span class="o">(</span><span class="kt">int</span> <span class="n">pos</span><span class="o">,</span> <span class="kt">int</span> <span class="n">len</span><span class="o">,</span> <span class="n">Style</span> <span class="n">style</span><span class="o">)</span> <span class="o">{</span>
<span class="n">SwingUtilities</span><span class="o">.</span><span class="na">invokeLater</span><span class="o">(()</span> <span class="o">-></span> <span class="o">{</span>
<span class="n">doc</span><span class="o">.</span><span class="na">setCharacterAttributes</span><span class="o">(</span><span class="n">pos</span><span class="o">,</span> <span class="n">len</span><span class="o">,</span> <span class="n">style</span><span class="o">.</span><span class="na">get</span><span class="o">(),</span> <span class="kc">true</span><span class="o">);</span>
<span class="o">});</span>
<span class="o">}</span></code></pre></figure>
<p>The other functionality of this small application is on select. If the selected word is “bar”, it is set to italic. Notice the <em>dot</em> and <em>mark</em> positions, which might be at the start or the end of the selection. Furthermore, notice that here the predefined <a href="https://docs.oracle.com/javase/8/docs/api/index.html?javax/swing/text/StyledEditorKit.ItalicAction.html"><em>ItalicAction</em></a> from the <em>StyledEditorKit</em> is used, since we’re dealing with a selection. We just have to translate the <em>CaretEvent</em> into an <em>ActionEvent</em>, or rather just make sure to forward the source component of the selection. (The alternative would have been to go with the plain update as in the example above).</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"> <span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">caretUpdate</span><span class="o">(</span><span class="n">CaretEvent</span> <span class="n">event</span><span class="o">)</span> <span class="o">{</span>
<span class="kt">int</span> <span class="n">dot</span> <span class="o">=</span> <span class="n">event</span><span class="o">.</span><span class="na">getDot</span><span class="o">();</span>
<span class="kt">int</span> <span class="n">mark</span> <span class="o">=</span> <span class="n">event</span><span class="o">.</span><span class="na">getMark</span><span class="o">();</span>
<span class="kt">int</span> <span class="n">start</span><span class="o">;</span>
<span class="kt">int</span> <span class="n">end</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">dot</span> <span class="o">==</span> <span class="n">mark</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">(</span><span class="n">dot</span> <span class="o"><</span> <span class="n">mark</span><span class="o">)</span> <span class="o">{</span>
<span class="n">start</span> <span class="o">=</span> <span class="n">dot</span><span class="o">;</span>
<span class="n">end</span> <span class="o">=</span> <span class="n">mark</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="n">start</span> <span class="o">=</span> <span class="n">mark</span><span class="o">;</span>
<span class="n">end</span> <span class="o">=</span> <span class="n">dot</span><span class="o">;</span>
<span class="o">}</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">start</span> <span class="o">+</span> <span class="s">", "</span> <span class="o">+</span> <span class="n">end</span><span class="o">);</span>
<span class="k">try</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">doc</span><span class="o">.</span><span class="na">getText</span><span class="o">(</span><span class="n">start</span><span class="o">,</span> <span class="n">BAR</span><span class="o">.</span><span class="na">length</span><span class="o">()).</span><span class="na">startsWith</span><span class="o">(</span><span class="n">BAR</span><span class="o">))</span> <span class="o">{</span>
<span class="n">ItalicAction</span> <span class="n">action</span> <span class="o">=</span> <span class="k">new</span> <span class="n">StyledEditorKit</span><span class="o">.</span><span class="na">ItalicAction</span><span class="o">();</span>
<span class="n">action</span><span class="o">.</span><span class="na">actionPerformed</span><span class="o">(</span><span class="k">new</span> <span class="n">ActionEvent</span><span class="o">(</span><span class="n">event</span><span class="o">.</span><span class="na">getSource</span><span class="o">(),</span> <span class="mi">0</span><span class="o">,</span> <span class="s">""</span><span class="o">));</span>
<span class="c1">// Alternative custom update:</span>
<span class="c1">// updateAttribute(start, BAR.length(), Style.ITALIC);</span>
<span class="o">}</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">BadLocationException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span></code></pre></figure>
<p>Here’s the full file listing, as a stand-alone application.</p>
<script>
var hidden = {};
function fileshowhide(id) {
var text = document.getElementById(id);
var h = (id in hidden) ? hidden[id] : true;
h = !h;
hidden[id] = h;
if(h) {
text.style.display = "none";
} else {
text.style.display = "inline";
}
}
</script>
<div class="filename">JTextPaneStylesExample.java</div>
<div class="filebuttons">
<div class="showhide"><button class="filebutton" onclick="fileshowhide('ui20170220JTextPane_StylessrccomrememberjavauiJTextPaneStylesExamplejava')">Show file</button></div>
<a class="filebutton github" href="https://github.com/hblok/rememberjava/blob/master/_includes/src/com/rememberjava/ui/JTextPaneStylesExample.java">GitHub</a>
<a class="filebutton raw" href="https://raw.githubusercontent.com/hblok/rememberjava/master/_includes/src/com/rememberjava/ui/JTextPaneStylesExample.java">Raw</a>
</div>
<div id="ui20170220JTextPane_StylessrccomrememberjavauiJTextPaneStylesExamplejava" class="javafile">
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="cm">/* Copyright rememberjava.com. Licensed under GPL 3. See http://rememberjava.com/license */</span>
<span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">rememberjava</span><span class="o">.</span><span class="na">ui</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.awt.event.ActionEvent</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.util.regex.Matcher</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.util.regex.Pattern</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">javax.swing.JFrame</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">javax.swing.JTextPane</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">javax.swing.SwingUtilities</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">javax.swing.event.CaretEvent</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">javax.swing.event.CaretListener</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">javax.swing.event.DocumentEvent</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">javax.swing.event.DocumentListener</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">javax.swing.text.AttributeSet</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">javax.swing.text.BadLocationException</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">javax.swing.text.MutableAttributeSet</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">javax.swing.text.SimpleAttributeSet</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">javax.swing.text.StyleConstants</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">javax.swing.text.StyledDocument</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">javax.swing.text.StyledEditorKit</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">javax.swing.text.StyledEditorKit.ItalicAction</span><span class="o">;</span>
<span class="cm">/**
* Minimal example with JTextPane and StyledDocument. When the string "foo" is
* typed or pasted it is made bold. When the string "bar" is selected it is made
* italic.
*/</span>
<span class="nd">@SuppressWarnings</span><span class="o">(</span><span class="s">"serial"</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">JTextPaneStylesExample</span> <span class="kd">extends</span> <span class="n">JFrame</span> <span class="kd">implements</span> <span class="n">DocumentListener</span><span class="o">,</span> <span class="n">CaretListener</span> <span class="o">{</span>
<span class="cm">/**
* Predefined styles.
*/</span>
<span class="kd">enum</span> <span class="n">Style</span> <span class="o">{</span>
<span class="n">BOLD</span><span class="o">(</span><span class="n">StyleConstants</span><span class="o">.</span><span class="na">Bold</span><span class="o">),</span>
<span class="n">ITALIC</span><span class="o">(</span><span class="n">StyleConstants</span><span class="o">.</span><span class="na">Italic</span><span class="o">);</span>
<span class="kd">private</span> <span class="n">MutableAttributeSet</span> <span class="n">attrib</span><span class="o">;</span>
<span class="kd">private</span> <span class="nf">Style</span><span class="o">(</span><span class="n">Object</span> <span class="n">style</span><span class="o">)</span> <span class="o">{</span>
<span class="n">attrib</span> <span class="o">=</span> <span class="k">new</span> <span class="n">SimpleAttributeSet</span><span class="o">();</span>
<span class="n">attrib</span><span class="o">.</span><span class="na">addAttribute</span><span class="o">(</span><span class="n">style</span><span class="o">,</span> <span class="kc">true</span><span class="o">);</span>
<span class="o">}</span>
<span class="n">AttributeSet</span> <span class="nf">get</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">attrib</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">FOO</span> <span class="o">=</span> <span class="s">"foo"</span><span class="o">;</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">BAR</span> <span class="o">=</span> <span class="s">"bar"</span><span class="o">;</span>
<span class="kd">private</span> <span class="kd">final</span> <span class="n">StyledDocument</span> <span class="n">doc</span><span class="o">;</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="n">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span>
<span class="k">new</span> <span class="nf">JTextPaneStylesExample</span><span class="o">();</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="nf">JTextPaneStylesExample</span><span class="o">()</span> <span class="o">{</span>
<span class="n">JTextPane</span> <span class="n">editor</span> <span class="o">=</span> <span class="k">new</span> <span class="n">JTextPane</span><span class="o">();</span>
<span class="n">doc</span> <span class="o">=</span> <span class="n">editor</span><span class="o">.</span><span class="na">getStyledDocument</span><span class="o">();</span>
<span class="n">getContentPane</span><span class="o">().</span><span class="na">add</span><span class="o">(</span><span class="n">editor</span><span class="o">);</span>
<span class="n">setSize</span><span class="o">(</span><span class="mi">500</span><span class="o">,</span> <span class="mi">500</span><span class="o">);</span>
<span class="n">setDefaultCloseOperation</span><span class="o">(</span><span class="n">JFrame</span><span class="o">.</span><span class="na">EXIT_ON_CLOSE</span><span class="o">);</span>
<span class="n">setVisible</span><span class="o">(</span><span class="kc">true</span><span class="o">);</span>
<span class="n">editor</span><span class="o">.</span><span class="na">getDocument</span><span class="o">().</span><span class="na">addDocumentListener</span><span class="o">(</span><span class="k">this</span><span class="o">);</span>
<span class="n">editor</span><span class="o">.</span><span class="na">addCaretListener</span><span class="o">(</span><span class="k">this</span><span class="o">);</span>
<span class="o">}</span>
<span class="cm">/**
* Check of a selection of the string "bar".
*/</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">caretUpdate</span><span class="o">(</span><span class="n">CaretEvent</span> <span class="n">event</span><span class="o">)</span> <span class="o">{</span>
<span class="kt">int</span> <span class="n">dot</span> <span class="o">=</span> <span class="n">event</span><span class="o">.</span><span class="na">getDot</span><span class="o">();</span>
<span class="kt">int</span> <span class="n">mark</span> <span class="o">=</span> <span class="n">event</span><span class="o">.</span><span class="na">getMark</span><span class="o">();</span>
<span class="kt">int</span> <span class="n">start</span><span class="o">;</span>
<span class="kt">int</span> <span class="n">end</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">dot</span> <span class="o">==</span> <span class="n">mark</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">(</span><span class="n">dot</span> <span class="o"><</span> <span class="n">mark</span><span class="o">)</span> <span class="o">{</span>
<span class="n">start</span> <span class="o">=</span> <span class="n">dot</span><span class="o">;</span>
<span class="n">end</span> <span class="o">=</span> <span class="n">mark</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="n">start</span> <span class="o">=</span> <span class="n">mark</span><span class="o">;</span>
<span class="n">end</span> <span class="o">=</span> <span class="n">dot</span><span class="o">;</span>
<span class="o">}</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">start</span> <span class="o">+</span> <span class="s">", "</span> <span class="o">+</span> <span class="n">end</span><span class="o">);</span>
<span class="k">try</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">doc</span><span class="o">.</span><span class="na">getText</span><span class="o">(</span><span class="n">start</span><span class="o">,</span> <span class="n">BAR</span><span class="o">.</span><span class="na">length</span><span class="o">()).</span><span class="na">startsWith</span><span class="o">(</span><span class="n">BAR</span><span class="o">))</span> <span class="o">{</span>
<span class="n">ItalicAction</span> <span class="n">action</span> <span class="o">=</span> <span class="k">new</span> <span class="n">StyledEditorKit</span><span class="o">.</span><span class="na">ItalicAction</span><span class="o">();</span>
<span class="n">action</span><span class="o">.</span><span class="na">actionPerformed</span><span class="o">(</span><span class="k">new</span> <span class="n">ActionEvent</span><span class="o">(</span><span class="n">event</span><span class="o">.</span><span class="na">getSource</span><span class="o">(),</span> <span class="mi">0</span><span class="o">,</span> <span class="s">""</span><span class="o">));</span>
<span class="c1">// Alternative custom update:</span>
<span class="c1">// updateAttribute(start, BAR.length(), Style.ITALIC);</span>
<span class="o">}</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">BadLocationException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="cm">/**
* Check for the occurrence of the string "foo".
*/</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">insertUpdate</span><span class="o">(</span><span class="n">DocumentEvent</span> <span class="n">event</span><span class="o">)</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">String</span> <span class="n">text</span> <span class="o">=</span> <span class="n">doc</span><span class="o">.</span><span class="na">getText</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="n">doc</span><span class="o">.</span><span class="na">getLength</span><span class="o">());</span>
<span class="n">Pattern</span> <span class="n">p</span> <span class="o">=</span> <span class="n">Pattern</span><span class="o">.</span><span class="na">compile</span><span class="o">(</span><span class="n">FOO</span><span class="o">);</span>
<span class="n">Matcher</span> <span class="n">matcher</span> <span class="o">=</span> <span class="n">p</span><span class="o">.</span><span class="na">matcher</span><span class="o">(</span><span class="n">text</span><span class="o">);</span>
<span class="k">while</span> <span class="o">(</span><span class="n">matcher</span><span class="o">.</span><span class="na">find</span><span class="o">())</span> <span class="o">{</span>
<span class="n">updateAttribute</span><span class="o">(</span><span class="n">matcher</span><span class="o">.</span><span class="na">start</span><span class="o">(),</span> <span class="n">FOO</span><span class="o">.</span><span class="na">length</span><span class="o">(),</span> <span class="n">Style</span><span class="o">.</span><span class="na">BOLD</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">BadLocationException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="cm">/**
* Update the string at the given position and length with the given style.
* The update happens on a separate AWT thread, to avoid mutations of the
* Document model while the event is processing.
*/</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">updateAttribute</span><span class="o">(</span><span class="kt">int</span> <span class="n">pos</span><span class="o">,</span> <span class="kt">int</span> <span class="n">len</span><span class="o">,</span> <span class="n">Style</span> <span class="n">style</span><span class="o">)</span> <span class="o">{</span>
<span class="n">SwingUtilities</span><span class="o">.</span><span class="na">invokeLater</span><span class="o">(()</span> <span class="o">-></span> <span class="o">{</span>
<span class="n">doc</span><span class="o">.</span><span class="na">setCharacterAttributes</span><span class="o">(</span><span class="n">pos</span><span class="o">,</span> <span class="n">len</span><span class="o">,</span> <span class="n">style</span><span class="o">.</span><span class="na">get</span><span class="o">(),</span> <span class="kc">true</span><span class="o">);</span>
<span class="o">});</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">removeUpdate</span><span class="o">(</span><span class="n">DocumentEvent</span> <span class="n">e</span><span class="o">)</span> <span class="o">{}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">changedUpdate</span><span class="o">(</span><span class="n">DocumentEvent</span> <span class="n">e</span><span class="o">)</span> <span class="o">{}</span>
<span class="o">}</span></code></pre></figure>
</div>The Swing tutorial for the JTextPane and demo code is good and comprehensive, covering multiple ways to interact with the the StyledDocument and add Styles. So, without repeating all of that, here’s a minimal example including only simple style changes on the insert update and selection events.