Alfresco: JMX from the command line

JMX is great. Alfresco and JMX is awesome. I’ve written before about configuring Alfresco to use tunneling to connect JMX & debuggers to servers that don’t allow access to the higher numbered ports (or to only a few ports).  Let’s add another cool tool. (JMX is an Enterprise only feature of Alfresco.)

The Alfresco wiki covers a few of the clients that are available out there.  Let’s add another type to the list:  JMX from the command line.  There are a couple of options for us to choose from.   I am partial to jmxterm from CyclopsGroups.org

Jmxterm is an opensource  JMX Client (download).  It supports auto completion, history browsing and scripting.  In a word: cool.

Let’s jump in…

First thing you need to do with the client is connect

With jmxterm you can pass a connection string via the jar to connect to Alfresco

java -jar jmxterm-1.0-alpha-4-uber.jar -l \ service:jmx:rmi:///jndi/rmi://<host>:50500/alfresco/jmxrmi -p <password> -u <user>

Or, you can connect via the interactive shell

java -jar jmxterm-1.0-alpha-4-uber.jar

Next, using the open command connect to Alfresco

$>open service:jmx:rmi:///jndi/rmi://localhost:50500/alfresco/jmxrmi -p change_asap -u \ controlRole<br /> #Connection to service:jmx:rmi:///jndi/rmi://localhost:50500/alfresco/jmxrmi is opened

Or, using the jvms command (with the appropriate user permissions you can list the running java processes on the machine jmxterm is running on).

$>jvms<br /> 94822    ( ) - jmxterm-1.0-alpha-4-uber.jar<br /> 13157    (m) - org.apache.catalina.startup.Bootstrap start

And once again use the open command to connect

$>open 13157 -u controlRole -p change_asap<br /> #Connection to 13157 is opened

Now that you are connected  let’s perform a simple operation, finding out who is logged into Alfresco and then disconnect one of the users.

First you’ll list the domains that are available

$>domains<br /> #following domains are available<br /> Alfresco<br /> Catalina<br /> JMImplementation<br /> Users<br /> axis<br /> com.sun.management<br /> connector<br /> java.lang<br /> java.util.logging<br /> log4j

The bean you need is in the Alfresco domain

$>domain Alfresco<br /> #domain is set to Alfresco

You can look up the beans within the domain by using the beans command.  There are quite a few beans in the Alfresco domain, so let’s connect directly to the one that you need: RepoServerMgmt. (Don’t forget jmxterm support auto completion.)

$>bean Alfresco:Name=RepoServerMgmt<br /> #bean is set to Alfresco:Name=RepoServerMgmt

Now that you have the bean, you can now find out what it does by using the info command

$>info<br /> #mbean = Alfresco:Name=RepoServerMgmt<br /> #class name = org.alfresco.repo.admin.RepoServerMgmt<br /> # attributes<br /> %0   - LinkValidationDisabled (boolean, r)<br /> %1   - MaxUsers (int, r)<br /> %2   - ReadOnly (boolean, r)<br /> %3   - TicketCountAll (int, r)<br /> %4   - TicketCountNonExpired (int, r)<br /> %5   - UserCountAll (int, r)<br /> %6   - UserCountNonExpired (int, r)<br /> # operations<br /> %0   - int invalidateTicketsAll()<br /> %1   - int invalidateTicketsExpired()<br /> %2   - void invalidateUser(java.lang.String p1)<br /> %3   - [Ljava.lang.String; listUserNamesAll()<br /> %4   - [Ljava.lang.String; listUserNamesNonExpired()<br /> #there's no notifications

There are lots of things you can do here, you can get attributes, you can set attributes, you can run opertaions.

Looking at the returned attributes you can tell a few things: the datatype of each attribute and if you can change it.  In this case none of our attributes can be modified, they are all read only (r).  ReadWrite would be signified by rw.

Operations are just like Java functions: they can have a return type and you might be able pass parameters to them.

It can also list notifcations, but there is no mechanism (that I have found yet) in jmxterm to subscribe or unsubscribe to them.

Let’s do some more work:

First let’s see how many users are logged in.

$>get UserCountNonExpired<br /> #mbean = Alfresco:Name=RepoServerMgmt:<br /> UserCountNonExpired = 2;

And now let’s find out who these two users are

$>run listUserNamesNonExpired<br /> #calling operation listUserNamesNonExpired of mbean Alfresco:Name=RepoServerMgmt<br /> #operation returns:<br /> [ System, admin ]

So you have 2 user currently in Alfresco: System and admin

Let’s log out the admin user.  (Look back at the list from the info command.) You can either invalidate all of the authenticated users tickets or we can invalidate named user.  Since you just want to remove one user let’s invalidate the admin users session.  (The System user is a special account, so you will ignore it.)

$>run invalidateUser admin<br /> #calling operation invalidateUser of mbean Alfresco:Name=RepoServerMgmt<br /> #operation returns:<br /> null

Remember that this operation does not return anything so jmxterm returns null.

Let’s now check and see if the admin user is still logged in.

$>run listUserNamesNonExpired<br /> #calling operation listUserNamesNonExpired of mbean Alfresco:Name=RepoServerMgmt<br /> #operation returns:<br /> [ System ]

You’ve now run through some basic operations: connecting to Alfresco, listing and selecting the domain, listing and selecting the bean, discovering what the bean can do, getting an attribute, running an operation.

The last things to cover are scripting/non-interactive mode and setting properties.

From time to time you might see the need, to lock Alfresco down by setting it to Read Only mode. The following two commands will help us do this.

First let’s check the current state:

$ echo get -s -b Alfresco:Name=RepoServerMgmt ReadOnly | java -jar jmxterm-1.0-alpha-4-uber.jar -l service:jmx:rmi:///jndi/rmi://localhost:50500/alfresco/jmxrmi -p change_asap -u controlRole -v silent -n

When passing commands to jmxterm, you need to echo the command into the interpreter. So the above command passes the jmxterm get command.  we pass it a -s since we just want the value and not the full expression (ReadOnly = <value>;) returned -b names the bean and finally the attribute we are querying. On the jmxterm side we pass the connection information (connection string or PID, username and password), set the verbosity of the execution, and tell it that it should run in non-interactive mode.

In this case the command returns the value false. So the value of ReadOnly is false — Alfresco is in Read/Write mode.

Now let’s put it in ReadOnly mode

$ echo set -b Alfresco:Category=sysAdmin,Type=Configuration,id1=default server.transaction.allow-writes false | java -jar jmxterm-1.0-alpha-4-uber.jar -l service:jmx:rmi:///jndi/rmi://localhost:50500/alfresco/jmxrmi -p change_asap -u controlRole -v silent -n

This follow pretty much the same pattern.  The ReadOnly attribute is a read only property, so to change Alfresco into Read Only mode you set the value of server.transaction.allow-writes to false. The set will not return any value.  You can then check the current state of the repository by running the previous command and then when you are ready to put the repository back in Read/Write mode change the value of the set command on server.transaction.allow-writes to true.