tag:blogger.com,1999:blog-282284062024-03-28T23:30:02.864-04:00Java How To ...Unknownnoreply@blogger.comBlogger252125tag:blogger.com,1999:blog-28228406.post-83554937256358143662014-10-28T11:43:00.000-04:002016-03-02T14:27:48.076-05:00Javadoc closing tags in IntelliJWhen writing javadocs, IntelliJ automatically adds a closing tag for html elements. For instance, after typing <lt>, it automaticaly adds </lt>, or after typing <p>, it adds </p>. It can be annoying since simple html elements like those used in javadocs don't really need ending tags.
<br />
To disable javadoc automatic closing tags in IntelliJ, simply go to IntelliJ Preferences -> Editor -> Smart Keys, then on the right panel, uncheck Automatically insert closing tag.<br />
<br />
Intellij 14 screenshot: <br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjU08yqG63MZPM9Zgafe9U9E3ik7X2xhTSoYByDZLAD8wxHBGmfCmYpNqKBzOrrS1xQar1LxLDFQA5Gp85D88U-Hh4J4ITiaacPLpYxJFgyWvX6l9CIw3vtR6vMuf44BlNdo6NViQ/s1600/intellij-javadoc-end-tag.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjU08yqG63MZPM9Zgafe9U9E3ik7X2xhTSoYByDZLAD8wxHBGmfCmYpNqKBzOrrS1xQar1LxLDFQA5Gp85D88U-Hh4J4ITiaacPLpYxJFgyWvX6l9CIw3vtR6vMuf44BlNdo6NViQ/s320/intellij-javadoc-end-tag.png" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMmS6uyZNNCeToTXJqv9Dpph7uMnPm-XtODfiefrJmzZ12e5RFtSROKqD8O96bsFTaFMLrMBpcBzDlJQN-OZOQax74c5FHEZzyzaxIDE9GwfCpWDIsq8nossKUP3MBxGFr0uK7eg/s1600/intellij-smart-key.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="303" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMmS6uyZNNCeToTXJqv9Dpph7uMnPm-XtODfiefrJmzZ12e5RFtSROKqD8O96bsFTaFMLrMBpcBzDlJQN-OZOQax74c5FHEZzyzaxIDE9GwfCpWDIsq8nossKUP3MBxGFr0uK7eg/s320/intellij-smart-key.png" width="320" /></a></div>
<br />
Intellij 15 screenshot:<br />
<br />
A related note, JDK 8 has tightened javadoc syntax check, and as a result self-closing elements like <p/>, or <br/> are deemed invalid and will cause failures. See <a href="https://bugs.openjdk.java.net/browse/JDK-8020619">JDK-8020619</a>. However, this checking can be disabled by passing nonstandard option <code>-Xdoclint:none</code> to javadoc tool.
For official javadoc guidelines, <a href="http://www.oracle.com/technetwork/articles/java/index-137868.html">see How to Write Doc Comments for the Javadoc Tool
</a>.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-28228406.post-1109408331894269372014-09-24T13:57:00.000-04:002014-10-28T11:21:19.245-04:00Diff tools: diff, vimdiff, opendiff & twdiff4 diff tools that can be executed from command line:
<br />
<ol>
<li>
diff (/usr/bin/diff): pure CLI with text output, available in any terminals:
<br />
<pre class="brush:text">/tmp > diff Hello.java Hello2.java
1c1
< public class Hello {
---
> public class Hello2 {
3c3
< System.out.println("Hello from " + Hello.class);
---
> System.out.println("Hello2 from " + Hello2.class);
</pre>
<br />
use -wub option to view contextual diff:
<pre class="brush:text">/tmp > diff -wub Hello.java Hello2.java
--- Hello.java 2014-09-24 13:16:55.000000000 -0400
+++ Hello2.java 2014-09-24 13:18:01.000000000 -0400
@@ -1,5 +1,5 @@
-public class Hello {
+public class Hello2 {
public static void main(String[] args) {
- System.out.println("Hello from " + Hello.class);
+ System.out.println("Hello2 from " + Hello2.class);
}
}
</pre>
</li>
<br />
<li>
vimdiff (/usr/bin/vimdiff): part of vim, available in any terminals, pure CLI but blocks the current terminal:
<pre class="brush:text">
vimdiff Hello.java Hello2.java
</pre>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6SbdZOKA6jub_oH1KcoElnaqNMRnScuyaPaw71utblQ7Gql8OqerN1qPx1XOgLkdHuxQEvuw-2agDunTLHGud47yEe79Wk_hCNJqaN-iGjE2I17_nrzVsCJF11wrWEZQrxdHf7Q/s1600/vimdiff.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6SbdZOKA6jub_oH1KcoElnaqNMRnScuyaPaw71utblQ7Gql8OqerN1qPx1XOgLkdHuxQEvuw-2agDunTLHGud47yEe79Wk_hCNJqaN-iGjE2I17_nrzVsCJF11wrWEZQrxdHf7Q/s320/vimdiff.png" /></a></div>
</li>
<br />
<li>
opendiff (/usr/bin/opendiff): part of Mac OS xcode tools, launches a FileMerge window for diff and merge:
<pre class="brush:text">
opendiff Hello.java Hello2.java
</pre>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGndWz8KovvDsQU9ENxSpYmHRsUUvFaN09U8mVM0h3LiRQN2qxzt8evcTtCy2lZ5aP-eMv2Wf5w1PqWkBHiXsXP4_dgRwQerFIEBb6clr_rWw3Oi9Rcl8E2F5SuyLVjdOeTTaL1g/s1600/opendiff.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGndWz8KovvDsQU9ENxSpYmHRsUUvFaN09U8mVM0h3LiRQN2qxzt8evcTtCy2lZ5aP-eMv2Wf5w1PqWkBHiXsXP4_dgRwQerFIEBb6clr_rWw3Oi9Rcl8E2F5SuyLVjdOeTTaL1g/s320/opendiff.png" /></a></div>
</li>
<br />
<br />
<li>
twdiff (/usr/local/bin/twdiff): command line tool of TextWrangler, and launches 3 separate TextWrangler windows (left, right and bottom) for diff and merge.
<pre class="brush:text">
twdiff Hello.java Hello2.java
</pre>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0dNSepzaYhyphenhyphenTIUCFUOzOLSSed7NcdTK3RXpHhyF4LTGrz8WQWC2UkX-8OnNWaallyMHqmhrOK0b4P9DNmqeIFyP48Ms7tDP2eYh38TbMfEsVfOXLOwmsXcVsCsRky_T3UnTUdHg/s1600/twdiff.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0dNSepzaYhyphenhyphenTIUCFUOzOLSSed7NcdTK3RXpHhyF4LTGrz8WQWC2UkX-8OnNWaallyMHqmhrOK0b4P9DNmqeIFyP48Ms7tDP2eYh38TbMfEsVfOXLOwmsXcVsCsRky_T3UnTUdHg/s320/twdiff.png" /></a></div>
</li>
</ol>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-28228406.post-67963016414357695092014-07-24T08:56:00.000-04:002014-07-24T09:01:15.757-04:00java.util.Properties and character encodingjava.util.Properties class (see <a href="http://docs.oracle.com/javase/7/docs/api/java/util/Properties.html">Java SE 7 Javadoc</a>) by default assumes ISO 8859-1 character encoding in reading and writing. So when a properties file is in other character encoding, you will see strange characters and behaviors.
<br/><br/>
Properties class has no method or constructor that takes encoding or locale parameter. Fortunately, in Java SE 6, two new methods were added to allow for reading from java.io.Reader and writing to java.io.Writer:
<br/>
<pre class="brush:java">
public synchronized void load(Reader reader) throws IOException;
public void list(PrintWriter out)
</pre>
So you can create Reader or Writer instances with appropriate encoding, and pass them to Properties load or list methods. For example,
<pre class="brush:java">
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.Properties;
import org.junit.Test;
public class MyTest {
@Test
public void loadPropertiesTest() throws Exception {
final File jndiPropertiesFile = new File(System.getProperty("user.home"), "tmp/jndi.properties");
final FileInputStream fileInputStream = new FileInputStream(jndiPropertiesFile);
// FileReader does not have any constructor that takes encoding, so use InputStreamReader instead
final InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "UTF-8");
final Properties jndiProperties = new Properties();
jndiProperties.load(inputStreamReader);
//now dump the properties to verify
jndiProperties.list(System.out);
}
}
</pre>
Output from running loadPropertiesTest test:
<pre class="brush:text">
-- listing properties --
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.provider.url=jnp://localhost:1099
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
</pre>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-28228406.post-2535165649965028442013-11-26T12:03:00.003-05:002014-05-18T16:28:22.827-04:00java.util.Properties, trim, null, whitespace, and escapingThis is the simple test to show the values of properties when loading from a properties file. It tries to answer some common questions about properties value:
<br/><br/>
<b>Do I need to trim whitespaces from a property value loaded from a properties file?</b>
<br/><br/>
Yes. Leading whitespaces in a property value are automatically trimmed by Java, but trailing whitespaces are preserved. So if whitespaces are not significant, then property values need to be trimmed <code>val.trim()</code>
<br/><br/><br/>
<b>Do I need to check null when operating on a property value loaded from a properties file?</b>
<br/><br/>
Yes. If a property does not exit in the properties file, then calling props.getProperty(key) will return null.
<br/><br/><br/>
<b>Do I need to check isEmpty when operating on a property value loaded from a properties file?</b>
<br/><br/>
Yes. If only the key exits in the properties file without assigning any value, then calling props.getProperty(key) will return an empty string. If the value line contains only multiple whitespaces, they will be trimmed away and its value is still empty string.
<br/><br/><br/>
<b>Do I need to escape = or : characters in property file?</b>
<br/><br/>
No need to escape = or : in property value, but if the = or : is part of the property key, then you need to escape them. Java treats the first occurrence of = or : or whitespace as the key-value delimiter. So after the delimiter is identified, any use of them no longer needs escaping.
<br/>
<pre class="brush:java">
import java.util.*;
import java.io.*;
public class PropertiesTest {
public static void main(String args[]) throws Exception {
Properties props = new Properties();
props.load(new FileInputStream(new File("a.properties")));
for(String key : props.stringPropertyNames()) {
System.out.printf("'%s' --> '%s'%n", key, props.getProperty(key));
}
System.out.printf("property.not.defined = %s%n", props.getProperty("adsfadsfdjsakfads"));
}
}
</pre>
The properties file a.properties:<pre class="brush:text">
no.value =
no.value.with.trailing.spaces =
prop.with.leading.trailing.spaces = value
prop.with.leading.spaces = value
equal.sign.in.value = user=admin
colon.in.value = user:password
equal.sign.colon.in.value = user=admin:password=secrete
equal.sign.in.value.escaped = user\=admin
equal.sign.colon.in.value.escaped = user\=admin\:password\=secrete
\=\:in.key.escaped = value for =:in.key.escaped
=:in.key.not.escaped = value for =:in.key.not.escaped
</pre>
To compile and run this program:<pre class="brush:text">
javac PropertiesTest.java
java PropertiesTest
'equal.sign.in.value' --> 'user=admin'
'equal.sign.colon.in.value' --> 'user=admin:password=secrete'
'no.value' --> ''
'prop.with.leading.spaces' --> 'value'
'equal.sign.in.value.escaped' --> 'user=admin'
'=:in.key.escaped' --> 'value for =:in.key.escaped'
'prop.with.leading.trailing.spaces' --> 'value '
'colon.in.value' --> 'user:password'
'no.value.with.trailing.spaces' --> ''
'equal.sign.colon.in.value.escaped' --> 'user=admin:password=secrete'
'' --> ':in.key.not.escaped = value for =:in.key.not.escaped'
property.not.defined = null
</pre>
For complete description, see <a href="http://docs.oracle.com/javase/7/docs/api/java/util/Properties.html">java.util.Properties javadoc.</a>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-28228406.post-47126273627313257602013-09-13T17:17:00.000-04:002013-09-13T17:19:29.471-04:00NoSuchMethodError: javax.xml.parsers.DocumentBuilderFactory.newInstanceThis is the error from running a webapp deployed to appserver:<pre class="brush:text">
java.lang.NoSuchMethodError: javax.xml.parsers.DocumentBuilderFactory.newInstance(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljavax/xml/parsers/DocumentBuilderFactory;
</pre>
The cause: there is an xml-apis.jar under JBOSS_HOME/lib/endorsed directory, and so javax.xml.* classes in xml-apis.jar override those same class from JDK. In particular, DocumentBuilderFactory class in xml-apis.jar is of old version and only has newInstance() method, but not newInstance(String, ClassLoader) method. DocumentBuilderFactory.newInstance(String factoryClassName, ClassLoader) is introduced in Java 6.
<br/><br/>
The fix is to remove xml-apis.jar from JBOSS_HOME/lib/endorsed directory. XML parser has been in Java proper for a long time, and there is no need for xml-apis.jar in most modern applications.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-28228406.post-38482557732583124152013-05-27T23:29:00.002-04:002013-05-27T23:29:19.004-04:00java.io.IOException: No such file or directory and URIYou need to create a new file with a file URI like file:/tmp/a.txt, but had this error:<pre class="brush:text">
java.io.IOException: No such file or directory
at java.io.UnixFileSystem.createFileExclusively(Native Method)
at java.io.File.createNewFile(File.java:947)
at FileTest.main(FileTest.java:7)
</pre>
The directory /tmp (or java.io.tmpdir) should already exist and should have write permission for the application. So the error message may be complaining the file (a.txt) does not exist. But a.txt is the new file you are trying to create and of course it doesn't exist.
Take another look at the source code:<pre class="brush:java">
import java.io.File;
import java.net.URI;
public class FileTest {
public static void main(String args[]) throws Exception {
File f = new File(args[0]);
boolean b = f.createNewFile();
if(b) {
System.out.printf("Successfully created new file: %s%n", f);
} else {
System.out.printf("Failed to create new file: %s%n", f);
}
}
}</pre>
Run this class with different input, such as /tmp/a.txt, file:/tmp/a.txt:<pre class="brush:text">
$ java FileTest /tmp/a
Successfully created new file: /tmp/a
$ java FileTest /tmp/a
Failed to create new file: /tmp/a
# This failure is expected since /tmp/a already exists.
$ java FileTest file:/tmp/a
Exception in thread "main" java.io.IOException: No such file or directory
</pre>
So the cause of the IOException is input file URI is not a valid file path. If you have a file URI, then you should use another File constructor to instantiate the File:<pre class="brush:java">
//to instantiate a file with URI
//TODO: need to handle java.net.URISyntaxException
File f = new File(new URI(args[0]));
//to instantiate a filw with path string
File f = new File(args[0]);
</pre>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-28228406.post-62200152364691615182012-12-10T10:13:00.000-05:002012-12-10T22:31:02.848-05:00Java Thread Pools and their Thread DumpsWhen analysing a thead dump, if the thread is created with a custom thread name, we can easily trace it to where the thread pool is created by the unique thread name.<br />
<br />
Otherwise, we will have to guess which type of thread pool is created from the stack trace, and then search the usage of creation methods like newCachedThreadPool, newSingleThreadScheduledExecutor, newScheduledThreadPool, or newCachedThreadPool.<br />
<br />
When using Executors.newCachedThreadPool on JDK 6:<br />
<pre class="brush:text">"pool-1-thread-2" prio=5 tid=7ffb30143000 nid=0x117fde000 waiting on condition [117fdd000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <7f310c388> (a java.util.concurrent.SynchronousQueue$TransferStack)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:196)
at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:424)
at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:323)
at java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:874)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:945)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)
at java.lang.Thread.run(Thread.java:680)
</pre>
<br />
When using Executors.newCachedThreadPool on JDK 7:<br />
<pre class="brush:text">"pool-1-thread-2" prio=5 tid=0x00007f90b38c9800 nid=0x5603 waiting on condition [0x000000016cb92000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x000000014c55bbd8> (a java.util.concurrent.SynchronousQueue$TransferStack)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:226)
at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:460)
at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:359)
at java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:942)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1043)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1103)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)
</pre>
<br />
<br />
When using Executors.newScheduledThreadPool(numOfCoreThreads) on JDK 6:<br />
<pre class="brush:text">"pool-3-thread-1" prio=6 tid=0x4a5cc000 nid=0xc810 waiting on condition [0x4c96f000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x0934ccc8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:196)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2025)
at java.util.concurrent.DelayQueue.take(DelayQueue.java:164)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:609)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:602)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:947)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)
at java.lang.Thread.run(Thread.java:662)
</pre>
<br />
When using Executors.newScheduledThreadPool(numOfCoreThreads) on JDK 7:<br />
<pre class="brush:text">"pool-1-thread-1" prio=5 tid=0x00007f8075802000 nid=0x5503 waiting on condition [0x00000001610ed000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x0000000140bbc108> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1079)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:807)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1043)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1103)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)
</pre>
<br />
<br />
When using Executors.newSingleThreadScheduledExecutor on JDK 6:<br />
<pre class="brush:text">"pool-1-thread-1" prio=5 tid=7ff0fe159800 nid=0x11442e000 waiting on condition [11442d000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <7f310c8c0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:156)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1987)
at java.util.concurrent.DelayQueue.take(DelayQueue.java:160)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:609)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:602)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:947)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)
at java.lang.Thread.run(Thread.java:680)</pre>
<pre class="brush:text"> </pre>
When using Executors.newSingleThreadScheduledExecutor on JDK 7:<br />
<pre class="brush:text">"pool-1-thread-1" prio=5 tid=0x00007ff7fb0aa000 nid=0x5503 waiting on condition [0x0000000169c4d000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x000000014971c208> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1079)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:807)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1043)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1103)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)
</pre>
<br />
<br />
When using Executors.newFixedThreadPool on JDK 6:<br />
<pre class="brush:text">"pool-1-thread-2" prio=5 tid=7ff7c4854000 nid=0x118682000 waiting on condition [118681000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <7f44c0048> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:156)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1987)
at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:399)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:947)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)
at java.lang.Thread.run(Thread.java:680)
</pre>
<br />
When using Executors.newFixedThreadPool on JDK 7:<br />
<pre class="brush:text">"pool-1-thread-1" prio=5 tid=0x00007fb3b4070000 nid=0x5503 waiting on condition [0x000000016c6bf000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x000000014c18b888> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043)
at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1043)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1103)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)
</pre>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-28228406.post-59778321985361509462012-10-15T10:43:00.001-04:002012-12-04T07:54:52.134-05:00Java Applicatioin Process Hangs on Windows and Cached Thread PoolThe following java test app runs and terminates normally on Unix but hangs on Windows. <br />
<pre class="brush:java">import java.util.concurrent.*;
public class ThreadPoolTest {
private static ExecutorService es = Executors.newCachedThreadPool();
public static void main(String args[]) {
es.submit(new Task("## running task 1..."));
es.submit(new Task("## running task 2..."));
System.out.println("## after tasks, in main");
}
private static class Task implements Runnable {
private String msg;
private Task(String s) {
this.msg = s;
}
@Override public void run() {
System.out.println(msg);
}
}
}
</pre>
The direct reason for hanging is the 2 worker threads were returned to the cached thread pool after finishing the printing task, and stayed alive and idle indefinitely. Pooled threads by default are non-daemon threads. A Java program will terminate only after all non-daemon threads have terminated. Although the main thread in the above test app have finished its job, the Java process will not terminate due to the 2 live worker threads.
<br />
<br />
A couple of solutions and their pros and cons:
<br />
<br />
1, So shall we make the pooled threads daemon threads to fix it? Be careful here, since the Java process may just terminate prematurely, immediately after the main thread is done, but before daemon workers complete their work. Since they are daemon threads, their task status is totally ignored in exiting JVM.
<br />
<br />
If you really want to take the daemon approach, the application will need some logic to poll the stask status, and wait for their completion before exiting the main thread.
<br />
<br />
2, How about explicitly call <code>ExecutorService.shutdown()</code> method? After all, a task implementing app logic is not a daemon thread, and should be marked as such. Shutting down the thread pool (the actual type of ExecutorService in our example) makes more sense. But pay attention to all possible exit paths and make sure shutdown guaranteed in all paths, such as normal completion, throwable.
<br />
<br />
If the thread pool is used by various parts of a large application, how do you coordinate them such that shutdown is called only after all clients are finished? Compared to approach 1, additional coordiation (e.g., with wait/notify or CountDownLatch) is needed. To fix the hang using shutdown():<br />
<br />
<pre class="brush:java">import java.util.concurrent.*;
public class ThreadPoolTest {
private static ExecutorService es = Executors.newScheduledThreadPool(2);
public static void main(String args[]) throws InterruptedException {
es.submit(new Task("# running task 1..."));
es.submit(new Task("# running task 2..."));
es.shutdown();
//block here for all tasks to finish before proceeding in the main thead.
//if you want to enforce the execution order. optional.
es.awaitTermination(1, TimeUnit.DAYS);
System.out.println("# after tasks, in main");
}
private static class Task implements Runnable {
private String msg;
private Task(String s) {
this.msg = s;
}
@Override public void run() {
try {
Thread.sleep(1000*30);
} catch (InterruptedException e) {
}
System.out.println(msg);
}
}
}
</pre>
<br />
awaitTermination is totally optional. With it, you will see 2 task output before main thread output:<br />
<pre class="brush:text"># running task 2...
# running task 1...
# after tasks, in main
</pre>
<br />
Without it, main thread output comes before task output:<br />
<pre class="brush:text"># after tasks, in main
# running task 2...
# running task 1...
</pre>
<br />
3, Is there a default idle timeout for worker threads, so applications don't have to manage the shutdown? Yes, there is a default idle timeout 60 seconds for non-core threads. When creating a thread pool, you can specify the number of core threads, along with other parameters. By default core threads do not time out after becoming idle. But you can certainly make core threads subject to idle timeout by calling threadPool.allowCoreThreadsTimeout(true).
<br />
<br />
How does this apply to our test app? We created the thread pool by calling newCachedThreadPool() without passing any parameters. By default, the pool is created with 0 core threads and 60-second idle timeout. So any worker threads in the test app should be non-core and should automatically time out after 60 seconds. Yes, that is what happened on Mac OS or Linux. But on windows 7, the same program just hangs.
<br />
<br />
Do you still want to rely on its default idle timeout, which seems sensitive to OS?
<br />
<br />
4, Use Thread and Runnable class directly for simple use cases. When you only need threads, but don't need to maintain a pool, just directly use threads.<br />
<br />
To rewrite the above program directly using java.lang.Thread:<br />
<pre class="brush:java">public class ThreadTest {
public static void main(String args[]) throws InterruptedException {
Thread t1 = new Thread(new Task("## running task 1..."));
Thread t2 = new Thread(new Task("## running task 2..."));
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("## after tasks, in main");
}
private static class Task implements Runnable {
private String msg;
private Task(String s) {
this.msg = s;
}
@Override public void run() {
System.out.println(msg);
}
}
}
</pre>
The 2 join calls are added to wait for the 2 child threads to finish processing before proceeding to the main thread execution.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-28228406.post-13279101857497707522012-10-11T08:01:00.000-04:002012-10-12T21:59:50.859-04:00How to Configure hprof in GlassFish 3.xThese are the steps to configure hprof profiler in GlassFish 3.x:<br />
<br />
1, Identify the target JVM to profile. In most cases, it's the domain administration (DAS) JVM, but it can be other JVM such as another standalone server instance, or a cluster server instance.<br />
<br />
2, Edit $GLASSFISH_HOME/config/osgi.properties, locate org.osgi.framework.bootdelegation property, and append hprof classes to it,
using , (comma) as the package separator. Do not forget to add a comma at the end of the existing value. The resulting property should look like this:<br />
<br />
<pre class="brush:text">org.osgi.framework.bootdelegation=${eclipselink.bootdelegation}, \
com.sun.btrace, com.sun.btrace.*, \
org.netbeans.lib.profiler, org.netbeans.lib.profiler.*, \
sun.tools.hprof,com.sun.tools.hat.internal.parser,com.sun.demo.jvmti.hprof
</pre>
<br />
3, Start the domain, and go to admin console to add the hprof profiler:<br />
<br />
asadmin start-domain<br />
http://localhost:4848<br />
<br />
On the left, choose Configurations | server-config | JVM Settings, on the rigth content panel, choose Profiler tab,<br />
<br />
Name: hprof<br />
Status: enabled yes<br />
Classpath: not needed<br />
Native library path: no needed<br />
add a JVM Option:<br />
<br />
-agentlib:hprof=file=log.txt,thread=y,depth=3<br />
<br />
or using the old non-standard option:<br />
<br />
-Xrunhprof:file=log.txt,thread=y,depth=3<br />
<br />
Create this profiler and restart the domain from the command line. You will see the following elements are added to $GLASSFISH_HOME/domains/domain1/config/domain.xml, <br />
<br />
<pre class="brush:text"><profiler name="hprof" native-library-path="" classpath="">
<jvm-options>-Xrunhprof:file=log.txt,thread=y,depth=3</jvm-options>
</profiler></pre>
<br />
So you could also directly edit domain.xml (not recommended) to save you some clicks, if you know where to add this new element. For server-config, which corresponds to DAS, it is usually after the first group of jvm-options elements.<br />
<br />
There is also asadmin CLI commands to create and delete profiler configuration:<br />
<br />
<pre class="brush:text">asadmin create-profiler hprof
asadmin delete-profiler
</pre>
But create-profiler command doesn't allow you to specify hprof jvm options, so you would still need to come back to domain.xml to add jvm options. However, it takes a --target param, where you can specify where to apply the profiler configuration.<br />
<br />
4, After starting and stopping the domain, the hprof data file is created in $GLASSFISH_HOME/domains/domain1/config/ directory, which is the ${user.dir} for GlassFish server process.<br />
<br />
Another related post: <a href="http://javahowto.blogspot.com/2012/10/how-to-configure-hprof-in-jboss-as7.html">How to Configure hprof in JBoss AS7</a>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-28228406.post-72131912160566855962012-10-08T21:46:00.001-04:002014-03-25T11:37:21.308-04:00My Intellij NotesTo search by keywords for a command, setting, shortcut, etc, and execute it:<br />
Command + Shift + A<br />
<br />
To maximize or full screen (useful when reading long lines). You can also use the same shortcut to go full screen in FireFox, Safari, Chrome, Preview, iTunes, etc.<br />
Command + Ctrl + F <br />
<br />
To see javadoc for the method in focus:<br />
Ctrl + J<br />
<br />
To see which method/class the current line is in (with super long method body):<br />
Ctrl + Shift + Q<br />
<br />
To paste from clipboard history (including copied content from external apps):<br />
Command + Shift + V<br />
<br />
To copy the file path of a class:<br />
Command + Shift + C, while inside the editor of that class, not even need to highlight the class name.<br />
<br />
To copy the fully qualified name of a class (FQN):<br />
Command + Alt + Shift + C<br />
<br />
To delete a line:<br />
Command + Y (y for yank)<br />
<br />
To go to a line:<br />
Command + G<br />
<br />
To open a class:<br />
Command + N (press it again to include non-project classes like JDK classes) <br />
<br />
To organize imports:<br />
Command + Alt + O<br />
<br />
To bring up Version Control System popup (git, svn, etc):<br />
Ctrl + V<br />
<br />
To view all methods of the current class (press F12 again to include inherited methods):<br />
Command + F12 <br />
<br />
To view type hierarchy (super-types, sub-types):<br />
Ctrl + H<br />
<br />
To jump to source file of another class:<br />
Command + Click, or F4<br />
Command + Shift + I, for a quick view in pop-up without openning it in editor <br />
<br />
To go to next error/warning:<br />
F2<br />
Command + F1, to display the error details<br />
Alt + Enter, to display recommended actions<br />
<br />
To complete a statement (addthe semi-colon, going to the next line, etc):<br />
Command + Shift + Enter<br />
<br />
To auto-complete with text match (as opposed to code completion):<br />
Alt + / (upward search), Alt + Shift + / (downward search)<br />
<br />
To hide a tool window:<br />
Shift + Escape<br />
Command + window-number<br />
<br />
To format the whole file:<br />
Command + Alt + L<br />
<br />
To format a selection:<br />
Command + W to make a selection, then Command + Alt + L<br />
<br />
To view and search for recent files:<br />
Command + E, and type the first few letters to filter it in the pop-up<br />
Command + Shift + E, for recent changed files <br />
<br />
To switch between open files and tool windows:<br />
Ctrl + Tab, or Ctrl + Shift + Tab, while holding Ctrl, repeatedly press Tab to change selection<br />
<br />
To find usage of a type/class/method/variable:<br />
Alt + F7<br />
<br />
To generate constructor, getter, setter, toString, hashcode, equals, override method, inside editor window:<br />
Ctrl + N<br />
Command + O (select methods to override)<br />
Command + I (select methods to implement from interfaces)<br />
<br />
To attach to a remote debugger: F9<br />
To continue the debugger, skip all breakpoints: F9<br />
To step over (go to next line): F8<br />
To step into: F7<br />
To set/unset a breakpoint: Command + F8 <br />
To view breakpoints: Command + Shift + F8<br />
<br />
To increase indent of the current line:<br />
Command + W, then Tab. If pressing Tab without selection, it will just insert a tab at the cursor, which is not what you want unless the cursor is at the beginning of the line.<br />
<br />
To decrease indent of the current line:<br />
Shift + Tab. No need to make a selection<br />
<br />
To auto-format the current line:<br />
Command + W, then Command + Alt + L. Without a selection, it will just auto-indent the whole file<br />
<br />
To auto-indent the current line:<br />
Command + W, then Command + Alt + I. <br />
<br />
To join next line into the current line:<br />
Ctrl + Shift + J. Useful when you need to get rid of the next few blank lines. Command + Y will also delete a line, but you will need to move cursor to the blank line first.<br />
<br />
To go to the beginning and end of the file:<br />
Command + fn + Left<br />
Command + fn + right<br />
3 finger move on touch pad won't work <br />
<br />
To go to the beginning and end of the screen:<br />
Command + fn + Up<br />
Command + fn + Down<br />
<br />
To go to the beginning and end of the line:<br />
Command + Left<br />
Command + Right<br />
<br />
To move the content up and down, while keeping the cursor in the current line:<br />
Command + Up<br />
Command + Down<br />
2 fingers move on touch pad<br />
<br />
Jump to navigation bar:<br />
fn + Alt + Left<br />
<br />
To add a user dictionary to customize spelling check, create a text file, one word per line, and name it choose-a-name.dic. Inside Intellij settings, search "dictionary", and add the directory containing choose-a-name.dic. Intellij will find all dictionary files (by extension .dic) in that directory.
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-28228406.post-29685151950659968092012-10-05T14:33:00.002-04:002012-10-12T21:57:28.093-04:00How to Configure hprof in JBoss AS7These are the steps to configure hprof profiler in JBoss AS 7.x:<br />
<br />
1, Identify the target JVM to profile. In most cases, it's the standalone server JVM, but it can be other JVM such as domain process controller, host controller, or individual server.<br />
<br />
2, For standalone server, edit $JBOSS_HOME/bin/standalone.conf, locate JBOSS_MODULES_SYSTEM_PKGS property, and append hprof classes to it, using , (comma) as the package separator. This property tells JBoss Modules to make hprof classes accessible from any class loaders.<br />
<br />
<pre class="brush:text">JBOSS_MODULES_SYSTEM_PKGS="org.jboss.byteman,sun.tools.hprof,com.sun.tools.hat.internal.parser,com.sun.demo.jvmti.hprof"</pre>
<br />
3, Still in standalone.conf file, uncomment JAVA_OPTS property, and append hprof options:<br />
<br />
<pre class="brush:text">JAVA_OPTS="$JAVA_OPTS -agentlib:hprof=file=log.txt,thread=y,depth=3"</pre>
<br />
or using the old non-standard -X option:<br />
<br />
<pre class="brush:text">JAVA_OPTS="$JAVA_OPTS -Xrunhprof:file=log.txt,thread=y,depth=3"</pre>
<br />
4, Start the standalone server, and the hprof data file (log.txt) will be created in the current directory.
<br />
<br />
One common error when enabling hprof in JBoss AS 7.x is a series of NoClassDefFoundError, which indicates JBOSS_MODULES_SYSTEM_PKGS property has not been properly configured as in step 2.<br />
<br />
<pre class="brush:text">Exception in thread "main" java.lang.NoClassDefFoundError: com/sun/demo/jvmti/hprof/Tracker
at org.jboss.logmanager.LogManager$1.run(LogManager.java:65)
at org.jboss.logmanager.LogManager$1.run(LogManager.java:52)
at java.security.AccessController.doPrivileged(Native Method)
at org.jboss.logmanager.LogManager.<init>(LogManager.java:52)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at java.lang.Class.newInstance0(Class.java:355)
at java.lang.Class.newInstance(Class.java:308)
at java.util.logging.LogManager$1.run(LogManager.java:168)
at java.security.AccessController.doPrivileged(Native Method)
at java.util.logging.LogManager.<clinit>(LogManager.java:157)
at org.jboss.modules.Main.main(Main.java:278)
Caused by: java.lang.ClassNotFoundException: com.sun.demo.jvmti.hprof.Tracker from [Module "org.jboss.logmanager:main" from local module loader @1a28362]
at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:190)
at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:468)
at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:456)
at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:423)
at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:398)
at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:120)
... 14 more
Exception in thread "Thread-2" java.lang.NoClassDefFoundError: Could not initialize class java.util.logging.LogManager
at java.util.logging.LogManager$Cleaner.run(LogManager.java:211)
Dumping Java heap ... allocation sites ... done.
</pre>
<br />
Another related post: <a href="http://javahowto.blogspot.com/2012/10/how-to-configure-hprof-in-glassfish-3x.html">How to Configure hprof in GlassFish 3.x</a>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-28228406.post-12382267787653044642012-10-03T13:09:00.000-04:002012-10-03T13:10:30.447-04:00How to Create Management and Application Users in JBoss AS7JBoss AS7 is secured by default, which means you will have to create users before accessing services and components, such as admin console and remote EJB.<br />
<br />
$JBOSS_HOME/bin/add-user.sh, or add-user.bat is the tool for such purpose. By default it runs in interactive mode, and prompt for user name, password, user type, role, realm, etc. It also has a silent mode (-s, or --silent).<br />
<br />
For example, to create a management user, which can be used in admin console (http://localhost:9990):<br />
<br />
<pre class="brush:text">$JBOSS_HOME/bin/add-user.sh -s -u admin -p "abc123***"
</pre>
<br />
To create an application user, which can be used in remote EJB access:<br />
<br />
<pre class="brush:text">$JBOSS_HOME/bin/add-user.sh -s -u app -p "abc123***" -a -realm ApplicationRealm --role app,user
</pre>
<br />
To view help info:<br />
<pre class="brush:text">$JBOSS_HOME/bin/add-user.sh --help
</pre>
<br />
The user data is persisted in properties files in standalone/configuration and domain/configuration directories:<br />
<br />
<pre class="brush:text">application-roles.properties
application-users.properties
mgmt-users.properties
</pre>
<br />
Management users currently are not associated with any role, hence no mgmt-roles.properties. It would be nice to have role-based administration.
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-28228406.post-72159496616936230682012-09-26T22:34:00.003-04:002012-09-29T22:47:56.318-04:00How to Create Global Modules in JBoss AS7In other Java application servers and previous versions of JBoss AS, there is the concept of common lib, where users can put shared libraries for use by all deployed apps. How to achieve the same effect in AS7 with modules and their dependency? The easiest (not necessarily the best) way is to create a global module for a collection of shared jars.<br />
<br />
1, Create a module directory structure:<code> </code><br />
<br />
<code>mkdir -p $JBOSS_HOME/modules/com/mycompany/myproject/main </code><br />
<br />
2, Copy common jar files to the above directory:<code> </code><br />
<br />
<code>cp my-util.jar my-service.jar $JBOSS_HOME/modules/com/mycompany/myproject/main
</code><br />
<br />
3, Create a module.xml file in the new module's main directory:<br />
<br />
<pre class="brush:xml"><?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="com.mycompany.myproject">
<dependencies>
<module name="javaee.api"/>
</dependencies>
<resources>
<resource-root path="my-util.jar"/>
<resource-root path="my-services.jar"/>
</resources>
</module>
</pre>
<br />
4, Declare the module com.mycompany.myproject as a global module, by editing <code>$JBOSS_HOME/standalone/configuration/standalone.xml</code>. Add to the ee subsystem:<br />
<br />
<pre class="brush:xml"><subsystem xmlns="urn:jboss:domain:ee:1.1">
<global-modules>
<module name="com.mycompany.myproject" slot="main"/>
</global-modules>
</subsystem>
</pre>
<br />
Editing server configuration files is not a good idea, but so far this is the only way of adding global modules.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-28228406.post-33930176859269476162012-09-24T22:18:00.000-04:002012-10-08T23:03:38.460-04:00GlassFish CLI and JBoss AS7 CLI CommandsA rough comparison of GlassFish 3.x CLI and JBoss AS 7 CLI commands:
<br />
<table border="1">
<colgroup><col width="10%"></col>
<col width="45%"></col>
<col width="45%"></col>
</colgroup><tbody>
<tr>
<th>Tasks</th>
<th>GlassFish 3.x</th>
<th>JBoss AS 7</th>
</tr>
<tr>
<td>List all available commands</td>
<td>asadmin list-commands</td>
<td>jboss-cli.sh -c "help --commands"</td>
</tr>
<tr>
<td>Display help info</td>
<td>asadmin --help</td>
<td>jboss-cli.sh --help</td>
</tr>
<tr>
<td>Check version</td>
<td>asadmin version</td>
<td>jboss-cli.sh version</td>
</tr>
<tr>
<td>Start server or domain</td>
<td>asadmin start-domain</td>
<td>standalone.sh, or domain.sh</td>
</tr>
<tr>
<td>Stop server or domain</td>
<td>asadmin stop-domain</td>
<td>jboss-cli.sh -c :shutdown</td>
</tr>
<tr>
<td>Restart server or domain</td>
<td>asadmin restart-domain</td>
<td>jboss-cli.sh -c ":shutdown(restart=true)"</td>
</tr>
<tr>
<td>Start in debug mode</td>
<td>asadmin start-domain -d<br />
asadmin start-domain --debug</td>
<td>standalone.sh --debug</td>
</tr>
<tr>
<td>Deploy an app with CLI</td>
<td>asadmin deploy ~/test.war</td>
<td>jboss-cli.sh -c "deploy ~/test.war"</td>
</tr>
<tr>
<td>Undeploy the test.war app</td>
<td>asadmin undeploy test</td>
<td>jboss-cli.sh -c "undeploy test.war"</td>
</tr>
<tr>
<td>List deployed apps</td>
<td>asadmin list-applications<br />
asadmin list-components<br />
asadmin list-applications -l<br />
asadmin list-components --long
</td>
<td>jboss-cli.sh -c deploy<br />
jboss-cli.sh -c undeploy<br />
jboss-cli.sh -c "deploy -l"<br />
jboss-cli.sh -c "undeploy -l"<br />
jboss-cli.sh -c "ls deploy"
</td>
</tr>
<tr>
<td>Add a server system property</td>
<td>asadmin create-jvm-options -Dbuzz="This is buzz"</td>
<td>jboss-cli.sh <br />
-c "/system-property=buzz:add(value='This\ is\ buzz')"</td>
</tr>
<tr>
<td>List all server system properties</td>
<td>asadmin list-jvm-options</td>
<td>jboss-cli.sh -c "/system-property=*:read-resource"</td>
</tr>
<tr>
<td>Create a string or primitive JNDI resource</td>
<td>asadmin create-custom-resource <br />
--restype=java.lang.Boolean <br />
--factoryclass=<br />
org.glassfish.resources.custom.factory.PrimitivesAndStringFactory<br />
--property value=true resource/flag</td>
<td>jboss-cli.sh -c <br />
"/subsystem=naming/binding=<br />
java\:global\/env\/flag:add(<br />
binding-type=simple, type=boolean, value=true)"</td>
</tr>
<tr>
<td>List datasources</td>
<td>asadmin list-jdbc-resources</td>
<td>jboss-cli.sh -c <br />
"/subsystem=datasources:read-resource-description"</td>
</tr>
<tr>
<td>Create datasource using the default db config</td>
<td>asadmin create-jdbc-resource --connectionpoolid DerbyPool jdbc/test</td>
<td>jboss-cli.sh -c "data-source add --name=test-ds --jndi-name=java\:jboss\/datasources\/test-ds --driver-name=h2 --connection-url=jdbc\:h2\:mem\:test;DB_CLOSE_DELAY\=-1"
<br />
<br />
jboss-cli.sh -c "data-source enable --name=test-ds" </td></tr>
<tr>
<td>Delete a datasource</td>
<td>asadmin delete-jdbc-resource jdbc/test</td>
<td>jboss-cli.sh -c "data-source remove --name=test-ds"</td>
</tr>
<tr>
<td>Batch processing based on file input</td>
<td>asadmin multimode --file /tmp/glassfish-cli-commands.txt</td>
<td>jboss-cli.sh -c "batch --file=/tmp/jboss-cli-commands.txt"</td>
</tr>
</tbody></table>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-28228406.post-65321251037226654562012-09-21T23:33:00.000-04:002012-10-02T21:51:08.469-04:00How to Add System Properties to JBoss AS 7Option 1, when the server is stopped, add to $JBOSS_HOME/standalone/configuration/standalone.xml, after the <extensions> element:<br />
<pre class="brush:xml"><system-properties>
<property name="season" value="spring"/>
</system-properties>
</pre>
<br />
Option 2, when the server is running, run jboss-cli.sh or jboss-cli.bat command to add system property. The property will be persisted to standalone.xml, so it has the same effect as option 1:<br />
<pre class="brush:text">jboss-cli.sh -c "/system-property=buzz:add(value='This\ is\ buzz')"
</pre>
<br />
Option 3, add -Dkey=val to standalone.sh command line:<br />
<pre class="brush:text">standalone.sh -Dseason=spring
</pre>
<br />
Option 4, pass a properties file containing desired properties to standalone.sh. This is especially convenient if you need a list of dynamic system properties.<br />
<pre class="brush:text">standalone.sh -P /tmp/a.properties
</pre>
<br />
Now after the server is up and running, how do you verify your system properties are present with correct value?<br />
<ul>
<li>Test it with any deployed app that prints out the system properties. </li>
</ul>
<ul>
<li>View <code>$JBOSS_HOME/standalone/log/server.log</code>, search for the system property name. Only system properties specified in command line (option 3 & 4) are logged at server startup. </li>
</ul>
<ul>
<li>View all system properties in admin console at http://localhost:9990.</li>
<ul>
<li>Runtime tab | Server | Configuration | Environment Properties</li>
</ul>
</ul>
<ul>
<li>To list all system properties present in standalone.xml (not including those specified in command line):<br />
jboss-cli.sh -c "/system-property=*:read-resource"
</li>
</ul>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-28228406.post-14964250510063763982012-09-20T21:56:00.000-04:002012-09-23T23:01:55.722-04:00JBoss AS7 Ant Tasks for Deploy and UndeployI want to use ant to control deploy and undeploy apps to JBoss AS 7 in a simple test. I know I could just have ant copy the WAR, jar, or EAR files to $JBOSS_HOME/standalone/deployments directory, but then I will have to wait till the app is fully initialized before accessing it. So I decided to write some simple ant targets using JBoss AS7 CLI commands.<br />
<pre class="brush:xml"><?xml version="1.0"?>
<project name="test" default="build" basedir=".">
<property environment="env"/>
<property name="jboss.home" value="${env.JBOSS_HOME}" />
<property name="app.name" value="test.war" />
<property name="app.path" value="${app.name}" />
<presetdef name="jboss-cli">
<java jar="${jboss.home}/jboss-modules.jar" fork="true" >
<arg line="-mp ${jboss.home}/modules org.jboss.as.cli -c" />
</java>
</presetdef>
<target name="deploy">
<jboss-cli failonerror="true">
<arg line="'deploy --force ${app.path}'" />
</jboss-cli>
</target>
<target name="undeploy">
<jboss-cli failonerror="true">
<arg line="'undeploy ${app.name}'" />
</jboss-cli>
</target>
<target name="restart">
<jboss-cli failonerror="true">
<arg line="':shutdown(restart=true)'" />
</jboss-cli>
</target>
</project></pre>
The above deploy and undeploy is equivalent to the following jboss-cli commands:<br />
<pre class="brush:text">jboss-cli.sh -c "deploy --force test.war"
jboss-cli.sh -c "undeploy test.war"</pre>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-28228406.post-13860725594140986202012-08-27T22:15:00.021-04:002012-09-11T21:50:55.113-04:00How to Run JBoss Jandex<a href="https://github.com/jbossas/jandex">Jandex</a> is a tool that processes Java annotations within a directory or jar file, and saves the resulting metadata in an index file. This is similar to what a jar file index is to a classloader.<br /><br />There are 3 ways to run jandex tool:<br /><ol><li>java -jar command</li><li>ant task</li><li>jandex maven plugin</li></ol>In JBoss AS7, jandex jar is located at <code>$JBOSS_HOME/modules/org/jboss/jandex/main/jandex-1.0.3.Final.jar</code><br /><br />To display the usage message,<br /><pre class="brush:text">java -jar jandex-1.0.3.Final.jar<br /><br />Usage: jandex [-v] [-m] [-o file-name] <directory> | <jar><br /> -or-<br />jandex [-d] <index-file-name><br />Options:<br />-v verbose output<br />-m modify directory or jar instead of creating an external index file<br />-o name the external index file file-name<br />-d dump the index file index-file-name<br /><br />The default behavior, with no options specified, is to autogenerate an external index file</pre><br />To scan a WAR file, adding the result to WAR's <code>META-INF/jandex.idx</code> (not <code>WEB-INF/jandex.idx</code>):<br /><pre class="brush:text">java -jar jandex-1.0.3.Final.jar -v -m /tmp/test.war<br /><br />Indexed test.TestBean (2 annotations)<br />Indexed test.TestIF (0 annotations)<br />Indexed test.TestServlet (2 annotations)<br />Wrote META-INF/jandex.idx in 0.0710 seconds (3 classes, 4 annotations, 4 instances, 257 bytes)</pre><br />To scan a WAR file and put result in the default result file in the same directory as the WAR file:<br /><pre class="brush:text">java -jar jandex-1.0.3.Final.jar /tmp/test.war<br /><br />Wrote /tmp/test.war.idx in 0.0280 seconds (3 classes, 4 annotations, 4 instances, 257 bytes)</pre><br />To view the content of an index file:<br /><pre class="brush:text">java -jar jandex-1.0.3.Final.jar -d /tmp/test.war.idx<br /><br />Annotations:<br />javax.ejb.Stateless:<br />Class: test.TestBean<br />javax.ejb.EJB:<br />Field: test.TestIF test.TestServlet.testBean<br />javax.ejb.Local:<br />Class: test.TestBean<br /> (value = [test.TestIF])<br />javax.servlet.annotation.WebServlet:<br />Class: test.TestServlet<br /> (urlPatterns = ["/*"])<br />Subclasses:<br />javax.servlet.http.HttpServlet:<br />test.TestServlet<br />java.lang.Object:<br />test.TestBean<br />test.TestIF<br /><br />Read test.war.idx in 0.0030 seconds</pre><br />To scan a directory and save the result in a custom output file (-o option currently does not work with jar file input):<br /><pre class="brush:text">java -jar jandex-1.0.3.Final.jar -v -o /tmp/ann.dat $HOME/ws/test/<br /><br />Indexed test.TestBean (2 annotations)<br />Indexed test.TestIF (0 annotations)<br />Indexed test.TestServlet (2 annotations)<br />Wrote /tmp/ann.dat in 0.0180 seconds (3 classes, 4 annotations, 4 instances, 257 bytes)</pre><br />jandex.jar comes with an ant task, org/jboss/jandex/JandexAntTask. To run jandex with ant, first create a build.xml:<br /><pre class="brush:xml"><?xml version="1.0"?><br /><project name="test" default="jandex.modify" basedir="."><br /><property environment="env" /><br /><taskdef name="jandex" classname="org.jboss.jandex.JandexAntTask"<br />classpath="${env.JBOSS_HOME}/modules/org/jboss/jandex/main/jandex-1.0.3.Final.jar" /><br /><br /><target name="jandex.modify"><br /><jandex run="true" verbose="true" modify="true"><br /><fileset dir="${env.HOME}/ws/test" /><br /></jandex><br /></target><br /><br /><target name="jandex.newjar"><br /><jandex run="true" verbose="true" newJar="true"><br /><fileset dir="${env.HOME}/ws/test" /><br /></jandex><br /></target><br /></project></pre>To process all "*.jar" files within a directory (recursively, adding the index file to the original jar:<br /><br /><code>ant jandex.modify</code><br /><br />To process all "*.jar" files within a directory (recursively), and create a new index jar file (a jar file that only contains the generated index: <code>META-INF/jandex.idx</code>) for each source jar:<br /><br /><code>ant jandex.newjar</code><br /><br />JandexAntTask (at least this version) filters on file name "*.jar", so any other types of jar files (*.war, *.ear, *.rar, etc) will not be included.<br /><br /><a href="https://github.com/jdcasey/jandex-maven-plugin">Jandex maven plugin project page</a> has all the source and usages. With this plugin, jandex processes application annotations directly at build time, instead of post-processing the archives as in the 2 other methods. I tried the basic usage by copying the plugin element to one of the quickstart project pom.xml. After running mvn clean install, I can see the console output showing jandex being invoked as part of process-classes phase:<br /><pre class="brush:text">[INFO] --- jandex-maven-plugin:1.0.1:jandex (make-index) @ jboss-as-ejb-in-war ---<br />[INFO]<br />[INFO] --- maven-resources-plugin:2.4.3:testResources (default-testResources) @ jboss-as-ejb-in-war ---<br />[INFO] Using 'UTF-8' encoding to copy filtered resources.<br />...<br /></pre>To verify the index has been generated into target/classes and packaged into war file:<br /><pre class="brush:text">ls -l target/classes/META-INF/jandex.idx<br /><br />jar tvf target/jboss-as-ejb-in-war.war | grep jandex<br /><br />289 Tue Aug 28 10:09:40 EDT 2012 WEB-INF/classes/META-INF/jandex.idx</pre>In the above output jandex.idx seems to have been packaged into the wrong directory inside the WAR. It should be in META-INF/jandex.idx. Could be a bug in jandex plugin?<br /><br />Jandex can be used on jars or directories of any java application classes or libraries. For instance, the following command runs jandex on JDK classes.jar:<pre class="brush:text">sudo java -jar jandex-1.0.3.Final.jar $JAVA_HOME/../Classes/classes.jar<br /><br />Wrote /System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Home/../Classes/classes-jar.idx <br />in 2.4900 seconds (20723 classes, 36 annotations, 1381 instances, 678046 bytes)<br /><br />ls -l $JAVA_HOME/../Classes/*idx<br />-rw-r--r-- 1 root wheel 678046 Aug 28 10:45 /System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Home/../Classes/classes-jar.idx</pre>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-28228406.post-64723289194043332502012-08-13T11:36:00.035-04:002012-09-24T22:09:25.153-04:00My JBoss AS7 jboss-cli NotesTo start standalone server with the default server config (standalone.xml):<code><br />$JBOSS_HOME/bin/standalone.sh</code><br />
<br />
To start standalone server on custom, non-default port numbers, using offset=1, 2, 3, etc (negative offset number is invalid). When starting with offset 1, you will have http port number 8081 (the default 8080+1), CLI port number 10000 (the default 9999+1), admin console port 9991 (the default 9990+1), etc.<br />
standalone.sh -Djboss.socket.binding.port-offset=1<br />
<br />
To start standalone server with a specific server config (just the config file name in $JBOSS_HOME/standalone/configuration directory, do not specify its file path):<code><br /><br />standalone.sh -c standalone-full.xml<br />standalone.sh --server-config=standalone-ha.xml<br />standalone.sh --server-config standalone-full-ha.xml</code><br />
<br />
To avoid/disable "Press any key to continue..." when running JBoss AS7 commands on Windows:<code><br />> set NOPAUSE=true<br />> standalone<br />> jboss-cli</code><br />
<br />
To start standalone server in debug mode at default debug port 8787, or at a different port, e.g., 6000:<code><br />standalone.sh --debug<br />standalone.sh -d<br />standalone.sh -d 6000<br />standalone.sh --debug 6000</code><br />
<br />
To start domain:<code><br />domain.sh</code><br />
<br />
To save the PID from AS process, define the environment variable JBOSS_PIDFILE and LAUNCH_JBOSS_IN_BACKGROUND:<code><br />export LAUNCH_JBOSS_IN_BACKGROUND=true<br />export JBOSS_PIDFILE=$JBOSS_HOME/pid</code><br />
<br />
To stop the default standalone server or domain, with :shutdown operation request (there is no shutdown command):<code><br />jboss-cli.sh --connect --command=:shutdown<br />jboss-cli.sh -c "/:shutdown()"<br />jboss-cli.sh -c /:shutdown<br />jboss-cli.sh -c :shutdown</code><br />
<br />
To restart<code><br />jboss-cli.sh -c ":shutdown(restart=true)"</code><br />
<br />
To stop the standalone server right now no matter what. If the server is running, it has the same effect as Ctrl-C. If the server is not running, $JBOSS_PIDFILE is not present and so nothing is done.<code><br />/bin/kill -9 `cat $JBOSS_PIDFILE`</code><br />
<br />
To exit from the shell started with jboss-cli.sh, use any of the following (Ctrl-D does not work, though):<code><br />[standalone@localhost:9999 /] Ctrl-C<br />[standalone@localhost:9999 /] exit<br />[standalone@localhost:9999 /] quit<br />[standalone@localhost:9999 /] q</code><br />
<br />
To list all deployed applications, with either deploy or undeploy command (-l option gives more details about the deployed applications):<code><br />jboss-cli.sh -c deploy<br />jboss-cli.sh -c undeploy<br /><br />jboss-cli.sh -c "ls deployment"<br />jboss-cli.sh -c "deploy -l"<br />jboss-cli.sh -c "undeploy -l"</code><br />
<br />
To deploy an application:<code><br />jboss-cli.sh -c "deploy $HOME/tmp/hello.war"</code><br />
<br />
To redeploy (forcefully overwrite any existing deployed app) an app:<code><br />jboss-cli.sh -c "deploy --force $HOME/tmp/hello.war"</code><br />
<br />
To undeploy an application:<code><br />jboss-cli.sh -c "undeploy hello.war"</code><br />
<br />
To get CLI help info:<code><br />jboss-cli.sh help<br />jboss-cli.sh -c help</code><br />
<br />
To show help info for deploy command:<code><br />jboss-cli.sh -c "deploy --help"</code><br />
<br />
To display the version of the current running JBoss AS, along with $JBOSS_HOME, $JAVA_HOME, java.version, os.name, os.version, etc:<code><br />jboss-cli.sh -c version</code><br />
<br />
To create a string or primitive JNDI resource. Do not quote the value attribute, otherwise the quote will become part of the content. Also need to escape whitespace.<code><br />jboss-cli.sh -c "/subsystem=naming/binding=java\:global\/env\/flag:add(binding-type=simple, type=boolean, value=true)"<br /><br />jboss-cli.sh -c "/subsystem=naming/binding=java\:global\/env\/text:add(binding-type=simple, type=java.lang.String, value=This\ is\ a\ text\ value.)"</code><br />
<br />
To create an alias for a JNDI resource (java:global/env/condition is an alias for java:global/env/flag):<code><br />jboss-cli.sh -c "/subsystem=naming/binding=java\:global\/env\/condition:add(binding-type=lookup, lookup=java\:global\/env\/flag)"</code><br />
<br />
To list server extensions, profiles, subsystems, network interfaces, or socket-binding-groups:<code><br />jboss-cli.sh -c "ls subsystem"<br />jboss-cli.sh -c "ls extension"<br />jboss-cli.sh -c "ls profile"<br />jboss-cli.sh -c "ls interface"<br />jboss-cli.sh -c "ls socket-binding-group"</code><br />
<code> </code>
<br />
To create a datasource witht the default h2 database:<code> </code><br />
<code>data-source add --name=test-ds --jndi-name=java\:jboss\/datasources\/test-ds --driver-name=h2 --connection-url=jdbc\:h2\:mem\:test;DB_CLOSE_DELAY\=-1
<br/><br/>
data-source enable --name=test-ds
</code><br />
<br />
To verify a datasource and check if a connection can be obtained:<code> </code><br />
<code>data-source test-connection-in-pool --name=test-ds
</code><br />
<br />
To disable a datasource:<code> </code><br />
<code>data-source disable --name=test-ds </code><br />
<br />
To delete a datasource:<code> </code><br />
<code>data-source remove --name=test-ds
</code>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-28228406.post-40224916003615863272012-06-13T11:32:00.008-04:002012-07-23T08:59:45.748-04:00GlassFish multimode Command for Batch ProcessingGlassFish <code>asadmin multimode</code> command runs a series of asadmin subcommands within one single session. The <code>--file</code> option takes a file containing the list of subcommands.<br /><br />In the following example, I created 2 files named asadmin-create-resources and asadmin-delete-resources, and pass each of them to <code>asadmin multimode</code>:<pre class="brush:text"># content of file asadmin-create-resources<br />create-jms-resource --restype javax.jms.QueueConnectionFactory jms/QueueConnectionFactory1<br />create-jms-resource --restype javax.jms.Queue jms/Queue1<br />create-jms-resource --restype javax.jms.Queue jms/Queue2<br /><br /><br />$ asadmin multimode --file /tmp/asadmin-create-resources<br /><br /><br /># content of file asadmin-delete-resources<br />delete-jms-resource jms/Queue1<br />delete-jms-resource jms/Queue2<br />delete-jms-resource jms/QueueConnectionFactory1<br /><br /><br />$ asadmin multimode --file /tmp/asadmin-delete-resources</pre>More details are available in <code>asadmin help</code>:<pre>asadmin help multimode<br />asadmin multimode --help<br />asadmin multimode -\?<br /></pre>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-28228406.post-25316957364153823362012-06-04T21:55:00.006-04:002012-09-13T16:39:30.449-04:00How to Manage Type VisibilityType (class/interface) visibility can be managed at three levels:<br /><br />1, at Java language level, a type can be declared as either public, private, or package private. A public type is visible globally, a private type (usually as a private nested type) is visible only to the enclosing element, and a package private type is visible only in the current package. This is the most common mechanism for handling type visibility and information hiding.<br /><br />2, at module level, a type can be declared via module metadata to be exported externally, or kept strictly internal. Examples of such module systems are OSGi, Jigsaw, JBoss Modules, etc. In a runtime environment based on such module framework, the dependency and interaction between module components are clearly defined. Public classes in a module are not externally exposed unless declared so.<br /><br />3, at component level, an implementation class can be proxied or wrapped to mitigate any external exposure. With 1 & 2, some types may still end up being exposed. But that is not too bad with a proxy or wrapper. Even though the client application can load the proxied implementation class, but what is directly exposed is the immutable proxy/wrapper. <br /><br />For example, getServletContext() returns an implementation of javax.servlet.ServletContext, but it will not be the actual implementation class in the application server. Instead it is most likely an immutable proxy that exposes what is needed in javax.servlet.ServletContext interface. The similar pattern is also used in the implementation of ServletRequest, ServletResponse, javax.ejb.EJBContext, javax.ejb.TimerService, etc.<br /><br />Why do we want to hide certain types? A software module provides services by publishing essential interfaces and classes, which become the liability of the module. These published types are expected to be there and maintained for the life of the module. When it comes time to redesign, you will need to evaluate how to keep backward compatibility while evolving the API to adapt to the new technology. This is also the time you really wish these interfaces/classes/methods had never been exposed.<br /><br />Java EE application deployed to application server is an interesting case. User-provided application code and application server code cooperate to make the app work, but they should also be isolated from each other and keep a respectful distance. Application server internal implementation types should be completely hidden from user applications for security purpose. If the application packages the same library that the server contains, care must be taken that the server does not inadvertently load the application's version via thread context classloader.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-28228406.post-58023775979644973512012-05-18T13:30:00.016-04:002012-06-03T22:22:44.030-04:00GlassFish 3.1 to JBoss AS 7.1.1 EJB Invocation<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhE55ovQkCHbIqtOiZEIxqvPILiILXLz6b2IcTFnFT1k4KF1ThL9Oi9FHMNVEd68Ah5nFubm0UJDpxoKCj99yYk2Qa58B0oT4vfQJQHu_GJqHD8NJ8CtHaNweH-S8Lm4XR29EcBLQ/s1600/glassfish-calling-jboss.png"><img style="float: left; margin: 0pt 10px 10px 0pt; cursor: pointer; width: 289px; height: 320px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhE55ovQkCHbIqtOiZEIxqvPILiILXLz6b2IcTFnFT1k4KF1ThL9Oi9FHMNVEd68Ah5nFubm0UJDpxoKCj99yYk2Qa58B0oT4vfQJQHu_GJqHD8NJ8CtHaNweH-S8Lm4XR29EcBLQ/s320/glassfish-calling-jboss.png" alt="" id="BLOGGER_PHOTO_ID_5744030363549641330" border="0" /></a><br />This post demonstrates how to call a remote EJB deployed to JBoss AS 7.1.1 standalone server from an application deployed to GlassFish 3.1.x. It is similar to the standalone Java client connecting to JBoss AS 7.1.1, except that the remote client is running inside another application server product (GlassFish). The complete project is available in github: <a href="https://github.com/javahowto/repo/tree/master/glassfish-calling-jboss">glassfish-calling-jboss</a>.<br /><br />The following is some steps and noteworthy points.<br /><br />1, configure and start JBoss 7.1.1 standalone server (in a new terminal):<br /><pre class="brush:text">cd $JBOSS_HOME/bin<br />./standalone.sh<br /># in a new terminal/tab, or split it<br /># username: test<br /># password: 1234<br />./add-user.sh<br /></pre>2, configure and start GlassFish 3.1.x:<br /><pre class="brush:text">cd $$GLASSFISH_HOME/bin<br />./asadmin start-domain<br />./asadmin create-jvm-options -Dcom.sun.enterprise.naming.allowJndiLookupFromOSGi=false<br /><br />cp $JBOSS_HOME/bin/client/jboss-client.jar $GLASSFISH_HOME/domains/domain1/lib/ext/<br />cp project-root/client-on-glassfish/src/main/resources/jboss-ejb-client.properties $GLASSFISH_HOME/domains/domain1/lib/classes/<br />./asadmin restart-domain<br /></pre>The <code>com.sun.enterprise.naming.allowJndiLookupFromOSGi</code> system property option is needed to disable the use of <a href="http://docs.oracle.com/javase/7/docs/api/javax/naming/spi/InitialContextFactoryBuilder.html">javax.naming.spi.InitialContextFactoryBuilder</a> in GlassFish, which customizes its jndi bootstrapping. Since this configuration is jvm wide, we need to disable it to avoid any interference with JBoss jndi initialization inside GlassFish.<br /><br />jboss-client.jar is copied to GlassFish domain lib/ext to provide the JBoss client-side ejb and naming funcionality. jboss-ejb-client.properties is also copied to GlassFish domain lib/classes dir so that it share the same classloader as jboss-client.jar.<br /><br />jboss-ejb-client.properties inside the application should be sufficient. It is also copied in the above step to ensure it is always available to jboss client inside GlassFish. jboss-ejb-client.properties packaged inside the client ejb jar will be loaded by GlassFish application classloader, while jboss client-side runtime classes are loaded by GlassFish common classloader. So jboss client-side may not be able to load jboss-ejb-client.properties, especially if it uses its current classloader for resource loading.<br /><br />If you see the following error, it means jboss-ejb-client.properties is not loaded:<br /><pre class="brush:text">Tests in error:<br />invokeClientBean(com.blogspot.javahowto.ClientBeanTestIT):<br />javax.naming.NameNotFoundException:<br />ejb:/service-on-jboss/ServiceBean!com.blogspot.javahowto.ServiceIF -- service jboss.naming.context.java.jboss.exported.ejb:.service-on-jboss."ServiceBean!com.blogspot.javahowto.ServiceIF"<br /></pre>3, build and run the project:<br /><pre class="brush:text">cd project-root<br />mvn clean install<br /><br />...<br /><br />-------------------------------------------------------<br />T E S T S<br />-------------------------------------------------------<br />Running com.blogspot.javahowto.ClientBeanTestIT<br />May 18, 2012 2:00:37 PM com.sun.enterprise.v3.server.CommonClassLoaderServiceImpl findDerbyClient<br />INFO: Cannot find javadb client jar file, derby jdbc driver will not be available by default.<br />Look up ClientBean by name java:global/client-on-glassfish/ClientBean, got com.blogspot.javahowto._ClientIF_Wrapper@3735f04a<br />Result from clientBean.clientHello(): In serviceHello of com.blogspot.javahowto.ServiceBean@3e9c66de<br /><br />Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 14.354 sec<br /><br />Results :<br /><br />Tests run: 1, Failures: 0, Errors: 0, Skipped: 0</pre><br />There is no transaction context or security context propagation during the remote invocation. If you need them, another approach is to use IIOP protocol and the interoperable naming service. But that requires EJB on both sides to expose 2.x-style remote home interface even for EJB 3 beans. Topic for another day.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-28228406.post-68812633156965091982012-05-12T22:43:00.004-04:002012-05-15T22:02:05.118-04:00Standalone Java Client for JBoss AS 7.1.1: Maven and JUnit EditionIn previous post, <a href="http://javahowto.blogspot.com/2012/05/standalone-java-client-for-jboss-as-711.html">Standalone Java Client for JBoss AS 7.1.1</a>, I showed a hand-written project of standalone client in JBoss AS 7. In this post, I will rewrite it as a maven project with JUnit and jboss-as-maven-plugin. The result is project <a href="https://github.com/javahowto/repo/tree/master/jboss-as-7-client">jboss-as-7-client</a> at github.<br /><br />The steps are slightly different than the handwritten edition:<br /><br />1, start JBoss AS and add users:<code><br />cd $JBOSS_HOME<br />./standalone.sh<br />./add-user.sh (user name: test, password: 1234)</code><br /><br />2, "mvn clean install" will build the project, package and deploy the ejb jar to JBoss AS 7, and run the standalone client test.<br /><br />3, if the ejb jar is already deployed in JBoss AS, step 2 will forcefully overwrite it. If you want to undeploy the ejb jar, run<code><br />mvn jboss-as:undeploy</code>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-28228406.post-36260129045987190542012-05-11T21:41:00.009-04:002012-05-12T09:14:19.752-04:00Standalone Java Client for JBoss AS 7.1.1In <a href="http://javahowto.blogspot.com/2007/11/simple-ejb-3-on-jboss-application.html">this previous post</a>, I created a sample Java standalone client connecting to JBoss AS 5 & 6. Now let's look at how to do it in JBoss AS 7.1.1.<br /><br />This sample application consists of a stateless EJB, its remote business interface and a standalone java client that looks up the EJB and invokes its business method.<br /><div style="text-align: center;">ClientIF.java<br /></div><pre class="brush:java">package test;<br /><br />public interface ClientIF {<br />public String clientHello();<br />}</pre><div style="text-align: center;">ClientBean.java<br /></div><pre class="brush:java">package test;<br />import javax.ejb.*;<br /><br />@Stateless<br />@Remote<br />public class ClientBean implements ClientIF {<br />public String clientHello() {<br /> return "In clientHello of " + this;<br />}<br />}</pre><div style="text-align: center;">Client.java<br /></div><pre class="brush:java">package test;<br /><br />import javax.naming.*;<br /><br />public class Client {<br />public static void main(String args[]) throws Exception {<br /> ClientIF clientBean = InitialContext.doLookup(args[0]);<br /> System.out.printf("Result from clientBean.clientHello(): %s%n%n",<br /> clientBean.clientHello());<br />}<br />}</pre>In addition, you also need to prepare a jndi.properties file, and a jboss-ejb-client.properties file, both should be in the client classpath:<br /><pre class="brush:text"># jndi.properties<br />#<br />java.naming.factory.initial=org.jboss.naming.remote.client.InitialContextFactory<br />java.naming.factory.url.pkgs=org.jboss.ejb.client.naming<br />java.naming.provider.url=remote://localhost:4447<br />java.naming.security.principal=test<br />java.naming.security.credentials=1234<br /></pre><pre class="brush:text"># jboss-ejb-client.properties<br />#<br />endpoint.name=client-endpoint<br />remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false<br /><br />remote.connections=default<br /><br />remote.connection.default.host=localhost<br />remote.connection.default.port = 4447<br />remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false<br /><br />remote.connection.default.username=appuser<br />remote.connection.default.password=apppassword<br /></pre><br />With the above 5 source and config files in place, the project structure looks like this:<br /><pre>jboss-ejb/<br />.........jndi.properties<br />.........jboss-ejb-client.properties<br />.........test/<br />.............ClientIF.java<br />.............ClientBean.java<br />.............Client.java<br /></pre>While in project root directory, compile and package the ejb jar:<br /><pre class="brush:text">javac -cp $JBOSS_HOME/bin/client/jboss-client.jar test/*java<br />jar cvf client-ejb.jar test/ClientIF.class test/ClientBean.class<br /></pre>If JBoss AS is not already running, start it in a new terminal, and add the application user referenced in the above jndi.properties (add-user.sh is an interactive script). When prompted, enter user name test and password 1234.<br /><pre class="brush:text">cd $JBOSS_HOME/bin<br />./standalone.sh<br /><br />./add-user.sh<br /></pre>To deploy the ejb jar, simply copy it to JBoss AS deploy directory:<br /><pre>cp client-ejb.jar $JBOSS_HOME/standalone/deployments/<br /></pre>Finally, run our standalone Java client that looks up and invokes the remote EJB:<br /><pre class="brush:text">java -cp $JBOSS_HOME/bin/client/jboss-client.jar:. test.Client ejb:/client-ejb//ClientBean\!test.ClientIF<br /><br />May 11, 2012 10:21:16 PM org.xnio.Xnio <clinit><br />INFO: XNIO Version 3.0.3.GA<br />May 11, 2012 10:21:16 PM org.xnio.nio.NioXnio <clinit><br />INFO: XNIO NIO Implementation Version 3.0.3.GA<br />May 11, 2012 10:21:16 PM org.jboss.remoting3.EndpointImpl <clinit><br />INFO: JBoss Remoting version 3.2.3.GA<br />May 11, 2012 10:21:17 PM org.jboss.ejb.client.EJBClient <clinit><br />INFO: JBoss EJB Client version 1.0.5.Final<br />May 11, 2012 10:21:17 PM org.jboss.ejb.client.remoting.VersionReceiver handleMessage<br />INFO: Received server version 1 and marshalling strategies [river]<br />May 11, 2012 10:21:17 PM org.jboss.ejb.client.remoting.RemotingConnectionEJBReceiver associate<br />INFO: Successful version handshake completed for receiver context EJBReceiverContext{clientContext=org.jboss.ejb.client.EJBClientContext@53f64158, receiver=Remoting connection EJB receiver [connection=Remoting connection <a995a79>,channel=jboss.ejb,nodename=m-2]} on channel Channel ID bc3ed9ca (outbound) of Remoting connection 2e00e753 to localhost/127.0.0.1:4447<br />May 11, 2012 10:21:17 PM org.jboss.ejb.client.remoting.ChannelAssociation$ResponseReceiver handleMessage<br />WARN: Unsupported message received with header 0xffffffff<br />Result from clientBean.clientHello(): In clientHello of test.ClientBean@4783165b<br /></pre>The client class does a generic lookup, taking lookup jndi name from application arg. In the above java command line, ejb:/client-ejb//ClientBean!test.ClientIF is the jndi name for our remote EJB. This jndi name is constructed from the ejb module name, bean name, bean distinct name, and its remote business interface. More details are in <a href="https://docs.jboss.org/author/display/AS71/EJB+invocations+from+a+remote+client+using+JNDI">this JBoss docs page</a>.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-28228406.post-85209753590376100612012-04-22T21:44:00.008-04:002012-05-06T21:52:11.478-04:00Thoughts on ThreadLocal2 main usages of <a href="http://docs.oracle.com/javase/7/docs/api/java/lang/ThreadLocal.html">java.lang.ThreadLocal</a> variables:<br /><ol><li><span style="font-weight: bold;">Vertical sharing</span>: sharing and propagation of contextual data through the entire processing cycle. This is similar to http request attributes binding, except for the different scopes. A ThreadLocal variable (e.g., security context, transaction context) can be propagated across different tiers, e.g., from web to local EJB. After the processing is done, care must be taken to clear ThreadLocal variables to avoid context leaking.</li><br /><li><span style="font-weight: bold;">Horizontal sharing</span>: sharing of objects across repeated and concurrent processing tasks. It offers a third approach for achieving thread safety, besides object locking and unshared instances. No need to clear TheadLocal variables after the current processing is done, since they are intended to be shared throughout the life of the thread.</li></ol>However, when different class loaders are used among those tasks, the ThreadLocal object previously stored is not visible to the new class loader, and a new binding will be created. So over time, stales entries (instances of ThreadLocal data, and possibly anonymous inner subclass of ThreadLocal) will continue to consume memory. On the bright side, ThreadLocalMap keys use WeakReference and will eventually be cleared when the map approaches its capacity.<br /><br />Think of ThreadLocal as a container that holds thread-sensitive application data. Therefore, a ThreadLocal variable can be associated with multiple threads. A thread can be associated with multiple ThreadLocal variables.<br /><br />Thread class maintains a threadLocals Map (ThreadLocal.ThreadLocalMap) to hold all ThreadLocal variables for the current thread. The map key is the ThreadLocal instance, and the value is the actual object for this thread. When you call aThreadLocal.get() to retrieve the current binding, the get() method just asks the current thread to look up in its threadLocals map, using itself (aThreadLocal) as the key.<br /><br />So the per-thread data is internally stored inside Thread class. Why did they create this ThreadLocal mediator class sitting in the middle? If I were to implement it, my first thought would be to introduce new methods to Thread class, such as <code>setContextData(key, val), getContextData(key) & removeContextData(key)</code>.<br /><br />Here are some reasons I can think of why ThreadLocal was designed this way:<br /><br />1, Division of labor. Thread as a low-level construct should not be directly manipulated by applications. Application state is better managed by applcation classes.<br /><br />2, Type safety. <code>ThreadLocal<T></code> as a generic type is type-safe, and you can declare it to be <code>ThreadLocal<Integer>, ThreadLocal<String>, </code>or <code>ThreadLocal<MyType>.</code><br /><br />3, Encapsulation. The recommended practice is to declare a ThreadLocal<T> variable to be<br /><br /><code>private static final ThreadLocal<MyType> xxx = new ThreadLocal<MyType>();</code><br /><br />The applicaton class can choose to completely hide the use of ThreadLocal as an implementation detail, or selectively allow certain operations, e.g., getXXX, setXXX, or removeXXX.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-28228406.post-68058567986079135882012-03-31T09:16:00.013-04:002012-06-07T14:22:31.912-04:00Different Strategies for Acquiring Dependency inside a MethodWhen we create or refactor a method, we find some input data is needed for the method to do its job. What are the various options to acquire these dependency? I just went through a major code refactoring and module restructuring, and would like to share some thoughts:<br /><ol><li>Pass it in as method parameters. This seems to be most common approach, and some considerations are:<br /><ul><li>First forget about implementation details and needs, does it make sense to require the additional data in order to do the work? Think in terms of raw materials for completing the task, as opposed to method parameters.</li><li><br />The client code will need to acquire the new data, if not already available, or the target method declares a parameter injection.<br /></li><li><br />All subtypes (e.g., subclasses overriding this method) and callers need to be updated to the new method signature. That may not be a problem if we are changing internal interfaces or implementation classes. But for public interfaces, it presents a backward compatibility problem.</li><li><br />To what granularity do we want to add the new parameter? Is it a coarse-grained or fine-grained parameter? For example, do we pass in (String name), or (UserInfo userInfo)? Some guidelines:<ul><br /><li>Conceptually, what input is needed for the method to perform its task? Try to reduce the granularity to what's really necessary, to make it usable in more contexts. Some calling code may only have the fine-grained data (e.g., zipCode), but not the coarse-grained data (e.g., userInfo)</li><br /><li>Be consistent with other methods in the same interface or class. If many peer methods take UserInfo, it makes sense to have UserInfo in the new method even if only part of UserInfo is needed.</li><br /><li>Unless it's remote invocation, the overhead of parameter passing is the same between a fine-grained and a coarse-grained parameter.</li><br /><li>Avoid exporting information that is specific to a design tier or implementation layer. If the coarse-grained data fall into this category, then choose to export the fine-grained data that are not tied to the current tier or layer. For example,<br /><br /><ul><li>HttpServletRequest or HttpServletResponse are tied to web tier, and may be passed around during the current request processing inside web tier, but should never be exported to business tier.</li><br /><li>Security realm instances should not be passed outside security layer.</li></ul><br /></li><li>The above point is more evident and enforced by a module system like OSGi. A public class that is not exported by its host module will not be visible to other modules, and so may not be passed outwards. In this case, a fine-grained data type or even a string literal is more appropriate.</li><br /><br /></ul></li></ul></li><li>Derive from existing method parameters, when the required data is indirectly reachable from existing parameters. For example,<ul><br /><li>String zip = person.getAddress().getZip();</li><br /></ul></li><li>Is it already available as static or instance fields, or inherited from super classes?<br /><br />If some data are intrinsic attributes and relationship fields of a class, they should be initialized in constructors or injected via IoC framework and available to be shared by all methods. They consistute the class and instance state. It's possible that a method takes a type of parameter that is already available in class or instance state. They are intended to be distinct objects. For example,<br /><pre class="brush:java">/**<br />* @param userInfo a different UserInfo instance than represented by this person.<br />* @return true if userInfo is a potential friend of this person; false otherwise.<br />*/<br />public boolean maybeFriends(UserInfo userInfo) {<br />return this.userInfo.similarTo(userInfo);<br />}</pre></li><br /><li>Derive it from existing static or instance fields, for example,<ul><br /><li><code>String zipCode = this.userInfo.getZipCode();</code></li><br /></ul></li><li>Is it available from a global registry, or naming service? Typically, the global namespace is initialized and populated upon program start. If subsequent concurrent and write operations are supported, the global namespace needs to be thread-safe. For example,<ul><br /><li><code>User user = GlobalPlace.getCurrent(User.class);</code></li><br /><li><code>String m = InitialContext.doLookup("config/mode");</code></li><br /></ul></li><li>Create my own instances, using direct instantiation or some sort of factory method. Use this option if the current method has adequate information and knows how to create. For example,<ul><br /><li><code>Config config = new Config(mapping);</code></li><br /><li><code>Handler handler = HandlerFactory.createHandler();</code></li><br /><li><code>Logger logger = Logger.getLogger("abc"); //find or create the named logger</code></li></ul></li><br /></ol>Unknownnoreply@blogger.com2