Binding jBPM WorkItemHandlers from a Spring Context

I’ve just spent a lump of time (too much for how simple it really is) working out how to do this with jBPM 6.3 so I’ve added this blog to help those who come after.

This has worked for me – I’m not sure that it’s the ‘right’ or most efficient way to achieve the desired result however.

I’m using Spring Boot with jBPM 6.3 (this is valid for the commercial version too – jBoss BPM Suite 6.2). I’ve successfully loaded all the appropriate jBPM services using the instructions from the jBPM 6.3 documentation (though I’ve translated it to Spring Java config rather than the XML config documented), and am happily deploying and executing services.

The problem comes when trying to load WorkItemHandlers from a Spring context and I’ve fought the good fight for a week or three now on and off trying to find a good way to solve it. It’s taken time because there really isn’t a lot of help out there in Google land other than a gamut of hints indicating that many have had this issue and have solved it eventually but haven’t reflected the solution back out there.

In the end after reading quite a lot of the source code and stepping through a few times I took the suggestion from a thread in the jBoss developer forum and extended org.kie.spring.manager.SpringRuntimeManagerFactoryImpl in order to inject my own implementation of org.kie.api.runtime.manager.RegisterableItemsFactory which has a named list of Spring managed WorkItemHandlers which need to be made available to processes executed by jBPM.

My implementation of RuntimeManagerFactory factory is as follows. I’ve overridden the adjustEnvironment method to force my version of the RegisterableItemsFactory in; this method is called when setting up the runtime environment for a process execution.

package myjbpm.jbpm.common.workitemhandlers.impl;

import org.jbpm.runtime.manager.impl.SimpleRuntimeEnvironment;
import org.kie.api.runtime.manager.RegisterableItemsFactory;
import org.kie.api.runtime.manager.RuntimeEnvironment;
import org.kie.api.runtime.process.WorkItemHandler;
import org.kie.spring.manager.SpringRuntimeManagerFactoryImpl;


/**
 * This extends the jBPM {@link SpringRuntimeManagerFactoryImpl} in order to override {@link
 * SpringRuntimeManagerFactoryImpl#adjustEnvironment(RuntimeEnvironment)} method and put in our
 * own {@link RegisterableItemsFactory} implementation which has a reference to the Spring loaded {@link
 * WorkItemHandler} beans.
 */
public class CustomRegisterableItemsSpringRuntimeManagerFactoryImpl extends SpringRuntimeManagerFactoryImpl {

    private final RegisterableItemsFactory springRegisterableItemsFactory;


    public CustomRegisterableItemsSpringRuntimeManagerFactoryImpl(
            RegisterableItemsFactory springRegisterableItemsFactory) {
        this.springRegisterableItemsFactory = springRegisterableItemsFactory;
    }


    @Override
    protected void adjustEnvironment(final RuntimeEnvironment environment) {
        super.adjustEnvironment(environment);
        ((SimpleRuntimeEnvironment) environment).setRegisterableItemsFactory(springRegisterableItemsFactory);
    }
}

The matching RegisterableItemsFactory is as follows, notice that I extend jBPM’s DefaultRegisterableItemsFactory in order to maintain default functionality for other item types; these could be overridden to be retrieved from a Spring context also I expect:

package myjbpm.jbpm.common.workitemhandlers;

import org.jbpm.runtime.manager.impl.DefaultRegisterableItemsFactory;
import org.kie.api.runtime.manager.RuntimeEngine;
import org.kie.api.runtime.process.WorkItemHandler;

import java.util.Map;


public class SpringRegisterableItemsFactory extends DefaultRegisterableItemsFactory {

    private final SpringWorkItemHandlerProducer workItemHandlerProducer;


    public SpringRegisterableItemsFactory(SpringWorkItemHandlerProducer workItemHandlerProducer) {
        this.workItemHandlerProducer = workItemHandlerProducer;
    }


    @Override
    public Map<String, WorkItemHandler> getWorkItemHandlers(final RuntimeEngine runtime) {
        Map<String, WorkItemHandler> workItemHandlers = super.getWorkItemHandlers(runtime);
        workItemHandlers.putAll(workItemHandlerProducer.getWorkItemHandlers());

        return workItemHandlers;
    }
}

Where the SpringWorkItemHandlerProducer is used to translate the Spring injected java.util.List<NamedWorkItemHandler> into the java.util.Map<String, WorkItemHandler> expected by the RegisterableItemsFactory interface. It is as follows:

package myjbpm.jbpm.common.workitemhandlers.impl;

import myjbpm.jbpm.common.workitemhandlers.SpringWorkItemHandlerProducer;
import myjbpm.jbpm.domain.handler.NamedWorkItemHandler;
import org.kie.api.runtime.process.WorkItemHandler;

import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class SpringWorkItemHandlerProducerImpl implements SpringWorkItemHandlerProducer {

    private final Map&amp;amp;amp;lt;String, WorkItemHandler&amp;amp;amp;gt; workItemHandlers = new HashMap&amp;amp;amp;lt;&amp;amp;amp;gt;();


    public SpringWorkItemHandlerProducerImpl(List<NamedWorkItemHandler> workItemHandlers) {
        mapHandlers(workItemHandlers);
    }


    @Override
    public Map<String, WorkItemHandler> getWorkItemHandlers() {
        return workItemHandlers;
    }


    private void mapHandlers(final List<NamedWorkItemHandler> namedWorkItemHandlers) {
        for (NamedWorkItemHandler wih : namedWorkItemHandlers) {
            this.workItemHandlers.put(wih.getTaskName(), wih);
        }
    }
}

And NamedWorkItemHandler is:

package myjbpm.jbpm.domain.handler;

import org.kie.api.runtime.process.WorkItemHandler;


public interface NamedWorkItemHandler extends WorkItemHandler {
    String getTaskName();
}

Finally these are wired together using some simple Spring bean configuration as follows:

@Bean
public RuntimeManagerFactory runtimeManager(JtaTransactionManager transactionManager,
        UserGroupCallback userGroupCallback, RegisterableItemsFactory springRegisterableItemsFactory) {
    SpringRuntimeManagerFactoryImpl managerFactory = new CustomRegisterableItemsSpringRuntimeManagerFactoryImpl(
            springRegisterableItemsFactory);
    managerFactory.setTransactionManager(transactionManager);
    managerFactory.setUserGroupCallback(userGroupCallback);

    return managerFactory;
}


@Bean
public RegisterableItemsFactory registerableItemsFactory(
        SpringWorkItemHandlerProducer springWorkItemHandlerProducer) {
    return new SpringRegisterableItemsFactory(springWorkItemHandlerProducer);
}


@Bean
public SpringWorkItemHandlerProducer springWorkItemHandlerProducer(
        List<NamedWorkItemHandler> namedWorkItemHandlers) {
    return new SpringWorkItemHandlerProducerImpl(namedWorkItemHandlers);
}

Feedback welcome – particularly if you know a better way to do this, or can see a potential issue. I’ve only just got this working so it’s possible it’s horribly wrong once I get down the track further.

Scala – Implicit Class

Ok so this isn’t a deep dive into implicit’s in scala but rather a reminder on how helpful they can be. The camp on using implicit in scala is divided as you can use them in several different ways and like everyone you’ll go crazy and use them everywhere, then you’ll stop.

Anyway implicit classes are an ideal way to add functionality to an existing type, huh? Ok so I get fed up of seeing this

val time = LocalTime.now()
val someSpecialTime = SomeSpecialTime(time)

The code to me doesn’t read naturally anymore after using scala and I’d prefer time.toSomeSpecialTime, well there is a way if you use an implicit class:

object Converters {
  implicit class LocalTimeToSpecialTime(val localTime: LocalDateTime) extends AnyVal {
    def toSomeSpecialTime = SomeSpecialTime(time)
    def doSomthingElse = AnotherSpecialTime(time)
  }
}

Now I can import the class and use it as I want.

The implicit class however can not be top level and MUST be defined in a scope where method calls are allowed -> package, class, object. I tend to wrap them inside an object.

I like to use them as a kind of factory, where a string is passed in and the correct type is returned.

def toSurfaceExtrapMethod: SurfExtrapolationMethod = {
  value match {
    case "SE_NONE" =&gt; SurfExtrapolationMethod.NONE()
    case SE_FLATLINE" =&gt; SurfExtrapolationMethod.FLATLINE()
    case "SE_FLATLINE_TO_ZERO" =&gt; SurfExtrapolationMethod.FLATLINE_TO_ZERO()
    case "SE_WITHIN_TOLERANCE" =&gt; SurfExtrapolationMethod.WITHIN_TOLERANCE()
    case "SE_STEP_UP_WITHIN_TOLERANCE" =&gt; SurfExtrapolationMethod.STEP_UP_WITHIN_TOLERANCE()
  }
}

Also it’s possible to pass in values so you can have something like

def toRangeType(fixedRange: Option[FixedRange] = None): RangeType = {
  value match {
    case "FIT_BOTH" =&gt; RangeType.FitBoth()
    case "FIT_END" =&gt; RangeType.FitEnd()
    case "FIXED" =&gt; RangeType.Fixed(fixedRange.get)
    case "MIN_START" =&gt; RangeType.MinStart()
  }

So you can do something like

val rangeType = "FIXED".toRangeType(Some(FixedRange.FALSE))

Folding observables with Scala

I had a bunch of observables that I wanted to merge into a single observable and then subscribe to it. I knew that I could use merge but had an unknown sequence size of observables, so how could I do it? Easy I can use the merge and fold functions:-

val obs1: Observable[Int] = Observable.from(Seq(1,2,3,4,5))
val obs2: Observable[Int] = Observable.from(Seq(6,7,8,8,10))
val obs3: Observable[Int] = Observable.from(Seq(11,12,13,14))

val totalObservable = Seq(obs1, obs2, obs3)
  .fold(Observable.just[Int]())((a,b) =&gt; a.merge(b))

totalObservable.foreach(x =&gt; println(s"This is the value ${x}"))

The fold takes in an initial value, in this case “Observable.just[Int]()” followed by the aggregation function “a.merge(b)”. It took me about 30 mins to figure out the syntax, especially around the initial value but the code is clean and clear.

Hibernate and sets – use at your peril

For the past 3 weeks I’ve spent hours tuning the performance in one of the applications we use. Unfortunately rather than spend some time and come up with a proper reporting solution I was tasked to fix the existing solution which is to report off our live transactional system. We use EJB3 on JBoss so hibernate it is, which I personally think is an excellent framework for getting your application up and running quickly. Hibernate have always stated that performance isn’t it’s goal so I can’t blame hibernate for anything I’ve found. I tackled the problem in the usual way, add some sql logging and see what’s really happening and look for the usual suspects, lazy loading, code structure etc. Where I saw collections being loaded up separately I added Join fetches and rerun the reports. This worked really well then I noticed that no matter how I wrote the JPQL it always seemed to be running seperate queries for some of the realtionships. That’s when the bulb flashed they were defined as Sets!!

An example of such a thing:

@OneToMany(mappedBy="transaction")
private Set taxComponents = new HashSet(1);

I understand why sets are used but as I’m in control of what gets put in I can safely use:

@OneToMany(mappedBy="transaction")
 private Collection taxComponents = new ArrayList(1);
 

So using set’s is great but it comes at a cost and beware it’s not just fetches but deletes and inserts have a similar issue in that they get deleted one by one and then reinserted to ensure uniqueness, so if you do update the set it also has a performance hit.

The performance of the major report moved from 30 mins to 6 mins, still not lightning fast but a good improvement. I could of course move to native SQL but I didn’t want to have to rewrite a load of code to do that.

Weld JUnit 4 Runner

I’ve been having a look at Weld recently and wanted to be able to try some stuff out without a container in JUnit, but couldn’t find a JUnit Runner class to do it for me.

I was really suprised how simple it was:

package org.objectopia.test;

import org.jboss.weld.environment.se.Weld;
import org.jboss.weld.environment.se.WeldContainer;

import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.InitializationError;

public class WeldJUnit4Runner extends BlockJUnit4ClassRunner {

    private final Class klass;
    private final Weld weld;
    private final WeldContainer container;

    public WeldJUnit4Runner(final Class klass) throws InitializationError {
        super(klass);
        this.klass = klass;
        this.weld = new Weld();
        this.container = weld.initialize();
    }

    @Override
    protected Object createTest() throws Exception {
        final Object test = container.instance().select(klass).get();

        return test;
    }
}

Now you can do this :

@RunWith(WeldJUnit4Runner.class)
public class PersistenceTest {

    @Inject UserRepository repository;

    ...
}

Because your test class is just another CDI bean, you can inject any bean reference you require.

This is where the power of CDI comes in to play, you can do something like this:

    @Inject @Mock UserRepository userRepository;

And create a producer method to mock it out:

    @Produces @Mock UserRepository createUserRepository() { ... }

The arrogance of Gantt charts

Gantt charts, popularized by Microsoft Project, are a mechanism for managing projects. The idea is that you list all the tasks required to complete a project. You then estimate how long each task will take. Once you figure out the dependencies between the tasks you the layout a plan from left to right connecting up all the dependent tasks. This allows for some parallelism between non dependent tasks. Given the project start date and all the durations you get the project end date.

As long as everyone sticks to the plan, then the project will be completed on time.

Simple, eh? Err – not so fast! The major flaw is that Gantt charts are task focused so when a new task is discovered the project is guaranteed to be late. The reason behind this is that developers are focused on delivery of the tasks they are assigned – not value to the client. Coupled with the truism that tasks will take as much time as they are given and you will be late.

The task-centric approach only hints at the real problem with Gantt charts: that better planning and task discovery up front would have resolved these issues. This is the most deplorable aspect: God-like wisdom can be achieved and would have fixed the problem.

Historically, software development has used the notion of “defined process control” where all aspects of the plan can be controlled, to a low-level and to a high-degree of accuracy. This does not work for most software projects because software development is not a simple undertaking- it is usually a complex process where small changes in the inputs can greatly affect the outcome.

Big, upfront planning that depends on infinite wisdom does not work and the only mechanism we have for complex problems is Empirical Process Control. This is the notion of frequent inspection and adaptation to a process.

Emperical control is _the_ key to Agile software. You’re not are Agile if you don’t have a regular process for improvement – you’re just hacking away.

Gantt charts have no place in an agile process; they are the tool of bluff used by the project manager that really doesn’t understand software development.

Securing your JBoss JMX Invoker Layer

If you use JBoss and have a nicely secured JMX Console and/or Web Console it’s a fairly safe bet that, like me, you haven’t secured the invoker layer; meaning any old monkey can most likely shutdown your container whenever they feel like it.

Recently I implemented an MBean in JBoss to use as a batch trigger from a ControlM implementation and was surprised (probably shouldn’t have been though) that all my carefully crafted security for the JMXConsole and Web Console was ignored with complete impunity by the tool (twiddle.sh) that I used to invoke my MBean. Since then I’ve been through a pile of pain trying to get an RMI call to a JBoss XMBean to require authentication and I thought I’d put some instructions in plain language on how to do it.

I do this for two reasons:

  1. because I bet a lot of developers miss this one; and
  2. because the documentation and other information I find online is limited and confusing.

For demonstration I’m going to use a standard JBoss MBean for setting system properties in a running application container.

A Simple Example of Setting a System Property in JBoss using Twiddle

Using the default JBoss version of twiddle.sh (in the bin directory beneath JBoss home) against the default JNP location of JBoss (localhost:1099) you can execute the following to set a system property in a running container.

# this assumes you're in the bin directory of JBoss Home.
./twiddle.sh -s localhost:1099 invoke "jboss:type=Service,name=SystemProperties" set myprop mypropvalue
'null'

To verify that you have been succesful (assuming you didn’t get an exception in the last operation) you can do the following:

# this assumes you're in the bin directory of JBoss Home.
./twiddle.sh -s localhost:1099 invoke "jboss:type=Service,name=SystemProperties" get myprop
mypropvalue

This example will work from anywhere on your network where you’re not prevented from reaching the JNP URL of the container (prevented by a firewall or IP filter for example) regardless of the JMX Console and Web Console security you’ve put in place (there is plenty of documentation around for securing the JMX Console and Web Console). This is because the JMX Console and Web Console are HTTP based and as such are secured in the normal way you would secure a website on JBoss (i.e. in web-inf.xml and jboss-web.xml) whereas the invoker layer is not HTTP based and as such must use an alternate method of security; the key file in this operation is the jmx-invoker-service.xml file in the JBoss deploy directory.

Securing the Invoker Layer

The invoker layer is the one you are calling through when you query or invoke on an MBean via RMI (i.e. with twiddle.sh – as above). This layer is not subject to the security constraints you will have placed on your HTTP based JMX Console or Web Consoles.

To make this layer secure the key file you’re interested in is the jmx-invoker-service.xml in the JBoss deploy directory; and the key operation configuration you will need to change is for ‘invoke’.

The default configuration of the invoke operation in this file is:

<server>

	<!-- excluded for brevity -->

	<mbean code="org.jboss.jmx.connector.invoker.InvokerAdaptorService" name="jboss.jmx:type=adaptor,name=Invoker" xmbean-dd="">
		<xmbean>
			<description>The JMX Detached Invoker Service</description>
			<class>org.jboss.jmx.connector.invoker.InvokerAdaptorService</class>

			<!-- excluded for brevity -->

			<operation>
				<description>The detached invoker entry point</description>
				<name>invoke</name>
				<parameter>
					<description>The method invocation context</description>
					<name>invocation</name>
					<type>org.jboss.invocation.Invocation</type>
				</parameter>
				<return-type>java.lang.Object</return-type>
				<descriptors>
					<interceptors>

						<!-- Uncomment to require authenticated users -->
						<!-- <interceptor code="org.jboss.jmx.connector.invoker.AuthenticationInterceptor" securityDomain="java:/jaas/jmx-console"/> -->

						<!-- Interceptor that deals with non-serializable results -->
						<interceptor code="org.jboss.jmx.connector.invoker.SerializableInterceptor" policyClass="StripModelMBeanInfoPolicy"/>

					</interceptors>
				</descriptors>
			</operation>
		</xmbean>
	</mbean>
</server>

So to switch on authentication we do what it says and ‘Uncomment to require authenticated users’:

<server>

	<!-- excluded for brevity -->

	<mbean code="org.jboss.jmx.connector.invoker.InvokerAdaptorService" name="jboss.jmx:type=adaptor,name=Invoker" xmbean-dd="">
		<xmbean>
			<description>The JMX Detached Invoker Service</description>
			<class>org.jboss.jmx.connector.invoker.InvokerAdaptorService</class>

			<!-- excluded for brevity -->

			<operation>
				<description>The detached invoker entry point</description>
				<name>invoke</name>
				<parameter>
					<description>The method invocation context</description>
					<name>invocation</name>
					<type>org.jboss.invocation.Invocation</type>
				</parameter>
				<return-type>java.lang.Object</return-type>
				<descriptors>
					<interceptors>

						<!-- Uncomment to require authenticated users -->
						<interceptor code="org.jboss.jmx.connector.invoker.AuthenticationInterceptor" securityDomain="java:/jaas/jmx-console"/>

						<!-- Interceptor that deals with non-serializable results -->
						<interceptor code="org.jboss.jmx.connector.invoker.SerializableInterceptor" policyClass="StripModelMBeanInfoPolicy"/>

					</interceptors>
				</descriptors>
			</operation>
		</xmbean>
	</mbean>
</server>

If you haven’t changed the default security realm for your JMX Console (i.e. java:/jaas/jmx-console) you will now have an invoker layer secured with the same credentials as for your JMX Console. To change this add a new security realm to your global login-config.xml in the conf directory of your container and match the name you give it in the securityDomain attribute of the Authentication Interceptor.

I’ve not yet delved too deeply into setting a specific set of roles, at this point I set my invoker user to JBossAdmin which means that user can do pretty much anything exposed to JMX. That’s ok for my purposes tho (feel free to write a response with the details of setting roles for particular JMX functions :-)).

Invoking on a Secure Invoker Layer

Ok so now that it’s secure how do you invoke an operation on it?

With the default JBoss twiddle.sh utility there are arguments -u (or –user=) for user and -p (–password=) for password.

# this assumes you're in the bin directory of JBoss Home.
./twiddle.sh -s localhost:1099 --user=myuser --password=mypassword invoke "jboss:type=Service,name=SystemProperties" get myprop
mypropvalue

These arguments work fine except your password is now in clear text and even worse is visible in the process list while it’s executing – in clear text with ‘password=’ conveniently placed for extraction by a simple script!! This seems a bit of an oversight in the tool to me.

To get around this issue in my environment I took the source and modified the main class of twiddle.jar to accept a password from Standard In (patch is below – no promises or guarantees though) which prevents the password showing in your password list and allows you to use standard encryption utilities to decrypt and pipe it into the process without ever making it visible clear text.

You would now invoke as follows:

# this assumes you're in the bin directory of JBoss Home.
mypassword | ./twiddle.sh -s localhost:1099 --user=myuser invoke "jboss:type=Service,name=SystemProperties" get myprop
mypropvalue

or better; from an encrypted password file (or better yet a repository) such as follows:

# this assumes you're in the bin directory of JBoss Home and have previously encrypted your password and encryption key into ~/.<username>.key and ~/.<username>.psw.
KEY=`cat ~/.<execution username>.key`
PWD=`cat ~/.<execution username>.psw | crypt $KEY`

PWD | ./twiddle.sh -s localhost:1099 --user=myuser invoke "jboss:type=Service,name=SystemProperties" get myprop
mypropvalue

to encrypt your password to be used as above you might do:

echo "<password>" | crypt > ~/.<execution username>.psw

which will request an encryption key which you would save as follows (for this example anyway):

cat "<encryption key>" > ~/.<execution username>.key

These files would, of course, be accessable only from your execution user.

Securing the JMX Console

For reference the key files you’re interested in here are:

  • conf/login-config.xml
  • deploy/jmx-console.war/META-INF/web.xml
  • deploy/jmx-console.war/META-INF/jboss-web.xml

Securing the JMX Web Console

For reference the key files you’re interested in here are:

  • conf/login-config.xml
  • deploy/management/web-console.war/META-INF/web.xml
  • deploy/management/web-console.war/META-INF/jboss-web.xml

Stack

These instructions will apply broadly but for reference purposes the stack I have is:

  • JBoss 4.2.3.GA
  • Java jdk1.6.0_13
  • Windows XP or Solaris 10

References

http://www.jboss.org/community/wiki/Twiddle

http://www.jboss.org/community/wiki/jbossserver-aquicktour

https://jira.jboss.org/jira/secure/attachment/12313982/jboss-securejmx.pdf (PDF Document)

Regards,
Jon

:)

Patch For Twiddle to Take Password from StdIn (no promises or guarantees)


Index: src/main/org/jboss/console/twiddle/Twiddle.java
===================================================================
--- src/main/org/jboss/console/twiddle/Twiddle.java    (revision 94201)
+++ src/main/org/jboss/console/twiddle/Twiddle.java    (working copy)
@@ -24,8 +24,10 @@
 import gnu.getopt.Getopt;
 import gnu.getopt.LongOpt;

+import java.io.BufferedReader;
 import java.io.File;
 import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.io.PrintWriter;
 import java.net.MalformedURLException;
 import java.net.URL;
@@ -41,7 +43,6 @@
 import javax.naming.Context;
 import javax.naming.InitialContext;
 import javax.naming.NamingException;
-
 import org.jboss.console.twiddle.command.Command;
 import org.jboss.console.twiddle.command.CommandContext;
 import org.jboss.console.twiddle.command.CommandException;
@@ -148,7 +149,7 @@
 }
 };
 }
-
+
 public Command createCommand(final String name)
 throws NoSuchCommandException, Exception
 {
@@ -383,7 +384,7 @@

 out.println("A JMX client to 'twiddle' with a remote JBoss server.");
 out.println();
-      out.println("usage: " + PROGRAM_NAME + " [options] <command> [command_arguments]");
+      out.println("usage: [echo <password> | ] " + PROGRAM_NAME + " [options] <command> [command_arguments]");
 out.println();
 out.println("options:");
 out.println("    -h, --help                Show this help message");
@@ -397,6 +398,10 @@
 out.println("    -u, --user=<name>         Specify the username for authentication");
 out.println("    -p, --password=<name>     Specify the password for authentication");
 out.println("    -q, --quiet               Be somewhat more quiet");
+      out.println();
+      out.println("A password should be passed in by echoing it and piping it to the command. If you");
+      out.println("use the -p (--password) option your password may be visible in clear text in a ");
+      out.println("process listing such as `ps -ef`.");
 out.flush();
 }

@@ -421,6 +426,28 @@
 Getopt getopt = new Getopt(PROGRAM_NAME, args, sopts, lopts);
 int code;

+        /* Get standard in if it's there - assume it's a password. This is to allow a password to be passed and
+         * prevent it showing in a process listing (e.g. ps -ef in Unix). The -p argument will be ignored if
+         * the password is passed through Standard In.
+         */
+        boolean passwordRetrievedFromStdIn = false;
+        if (System.in.available() > 0) {
+            InputStreamReader inp = new InputStreamReader(System.in);
+            BufferedReader br = new BufferedReader(inp);
+            String stdin = br.readLine();
+
+            if (stdin != null &amp;&amp; stdin.trim().length() > 0) {
+                String password = stdin.trim();
+                SecurityAssociation.setCredential(password);
+
+                passwordRetrievedFromStdIn = true;
+
+                if (log.isDebugEnabled()) {
+                    log.debug("Password retrieved from standard in. Ignoring -p argument.");
+                }
+            }
+        }
+
 PROCESS_ARGUMENTS:

 while ((code = getopt.getopt()) != -1)
@@ -531,8 +558,13 @@
 SecurityAssociation.setPrincipal(new SimplePrincipal(username));
 break;
 case 'p':
-                 String password = getopt.getOptarg();
-                 SecurityAssociation.setCredential(password);
+                  if (!passwordRetrievedFromStdIn) {
+                     String password = getopt.getOptarg();
+                     SecurityAssociation.setCredential(password);
+
+                     log.warn("Password retrieved from -p argument. Your password may be visible in cleartext in a process listing during execution. " +
+                             "Consider using Standard In to enter the password instead (i.e. echo \"password\" | twiddle ...)");
+                  }
 break;

 // Enable quiet operations

 light="true"