After building
a hook that wraps the FakeSMTP application and a portlet that gives you
file management capabilities in Liferay we now get to part 3 of the series: the CRaSH portlet. I must admit: I did actually build this portlet first, but during its development needed something to show/inspect emails and to upload, download and edit files and ended building the other apps too. It seems I have a bit of a problem staying on target and get easily distracted by something new and shiny.
But in the end I managed to get all 3 portlets finished and now it is finally time to write a blog post about the most important and powerful one: t he CRaSH portlet (the way it is written is intentional, you'll see why a bit further down).
What is CRaSH?
CRaSH, http://www.crashub.org, is a project by Julien Viet, that basically provides a shell environment for the Java platform. When embedded it allows you to connect to a running JVM via SSH, Telnet or a web interface (which is what we'll be using) and run commands. It already comes with a bunch of commands on board and you can easily add your custom commands, written in Groovy or Java, to better integrate with the application you're embedding CRaSH in. You can add your custom commands directly to the portlet's WAR file, in WEB-INF/crash/commands, or you can use LFM to add them on the fly. The portlet will create a directory named crash in your Liferay root and will continuously try to load new scripts or reload existing ones from this location.
Now you might say: that seems pretty similar to the script portlet that is already available in Liferay or even the Script Helper portlet that can be found in the Liferay Marketplace? Well there are couple of things that IMHO set CRaSH apart from the already available options:
- Unlike scripts, CRaSH commands can take parameters
- Commands can be chained/piped like in a shell
- It has man like functionality that describes the available commands
- It has tab completion for the commands, their parameters and even parameter values like file paths (and you can write your own completions)
- Other shell-like functionality like a history, clear screen, ...
- The result of a command can be updated on an interval like for example 'ps'
Out of the box you already have access to a bunch of commands (which it will list when you type 'help') like: dashboard, egrep, env, filter, jdbc, jmx, jndi, jvm, mail, ... . Below you can see the output of the dashboard command that shows a continuously updated view of thread info, your environment properties and your JVM memory usage:
Integrating CRaSH
For its
web integration CRaSH uses websockets and this is where I a hit a little snag: the version of Tomcat in my Liferay bundle, 7.0.42, doesn't have official websocket support. It does however have an unofficial, pre-standard, websocket implementation that we can use. With some small adjustments to the existing web integration code and by using the Liferay PortalDelegateServlet it wasn't too difficult to get CRaSH to work in a portlet. The visual part, the
terminal view, is handled by a very interesting JS library:
http://terminal.jcubic.pl. This library is able to give you a complete terminal view in a browser, complete with things like tab completion, history, shortcuts, etc... and the websocket integration we did is used to communicate between the browser and the CRaSH backend.
To further integrate CRaSH with Liferay I also made alternate versions of the OOTB
jdbc and
mail commands. They're called
db and
email and are basically copies of the original commands, but are changed to directly use the the Liferay database and email system/configuration by using the
InfrastructureUtil class.
You can also SSH into the CRaSH portlet, on port 9999, and the authentication has been integrated with the Liferay authentication. Any user that has the Administrator role should be able to connect using his screenname and password, e.g.: ssh test@127.0.0.1 -p 9999
Working with the portlet
While the OOTB commands are already very useful, and could give me my cache information via de jmx command, I also made some additional ones to do some more interesting stuff and serve as examples of how to create your own:
- company: shows a list of all the companies present in your Liferay installation
- cluster: displays information about all cluster nodes
- cache: a different non-JMX way to show EHCache cache names and their hits/misses (some fancy classloader magic was needed to make this work)
- tasks: shows a list of running tasks
- user: can show the list of all users and can also be used create a user
- file: can read/write CSV and JSON files
By combining the OOTB commands, the custom commands and the LFM portlet you can start to do some really interesting things, e.g.:
- Create a CSV file containing user information via the LFM portlet
- Chain the file command with the user command to read this CSV and actually create the users in Liferay (you can see the 'Your new account' emails in FakeSMTP)
- Retrieve all users, including your new one by executing: user all | file write -f JSON --fields MIXIN ../../crash/users.json
- Download this JSON file via the LFM portlet and use it as the input from another program/process/...

Being able to do these kinds of things from within Liferay or via SSH made me feel a little like this:

Creating your own commands
As the system is very extensible I urge you to
clone the project from GitHub, build the CRaSH portlet, deploy it and start experimenting! A simple example of a command to start with could be the
echo command:
- Open the LFM portlet and navigate to the crash directory
- Create a new file named echo.groovy
- Edit it and add the following content
import org.crsh.cli.Command
import org.crsh.cli.Usage
class echo {
@Usage("echo text")
@Command
Object main(
@Usage("the text to echo")
@Argument String text) {
if (text == null)
text = "";
return text;
}
}
- Save it and open the CRaSH portlet
- Type help and you should see your new command appear in the list of commands
- Type echo "Hello World" to output that text to the terminal
Starting from this base and the code you can find on GitHub should open a whole world of new possibilities within Liferay!