Using File Service and File Transfer MBeans with Liberty

WebSphere Application Server V8.5.5 Liberty Profile introduces 2 new MBeans, FileServiceMXBean and FileTransferMBean, that are available under the restConnector-1.0 feature. Take a look at some of the interesting ways you can use them!

WebSphere Application Server V8.5.5 Liberty Profile introduces 2 new MBeans, FileServiceMXBean and FileTransferMBean, that are available under the restConnector-1.0 feature.

The FileServiceMXBean can be accessed by any path to the MBeanServer (ie: local connector, remote connector, JVM PlatformMBeanServer, etc), while due to its special capabilities the FileTransferMBean must be accessed through Liberty’s JMX REST Connector.

FileServiceMXBean

FileService contains methods that lets users query and package parts of the file system where the Liberty instance resides. Let’s take a closer look at its exposed interface:

Attributes:

  • ReadList
  • WriteList

Operations:

  • MetaData getMetaData(String path, String requestOptions)
  • MetaData[] getDirectoryEntries(String directory, boolean recursive, String requestOptions)
  • boolean createArchive(String sourcePath, String targetPath)
  • boolean expandArchive(String sourcePath, String targetPath)

The two attributes define the read and write “white” list, which is essential for all the operations in both FileService and FileTransfer mbeans. By default the read list contains 3 locations: ${wlp.install.dir}, ${wlp.user.dir} and ${server.output.dir}. These variables are explained in the “README” file located in the “wlp” directory in your Liberty installation. By default, the write list is empty.

So how do you override these default settings? In the server.xml, with the simple elements “readDir” and “writeDir”, both with a cardinality of 0..* under the parent “remoteFileAccess”:

<remoteFileAccess>
  <readDir>${server.output.dir}/read1</readDir>
  <readDir>${server.output.dir}/read2</readDir>
  <writeDir>${server.output.dir}/write1</writeDir>
  <writeDir>${server.output.dir}/write2</writeDir>
</remoteFileAccess>

In this case the readList has been scoped-down to only the read1 and read2 folders under the output dir, while the writeList has been scoped-up to include the write1 and write2 folders under the output dir. It is important to note that the override mechanism for each list is independent of each other, so if you only specify this…

<remoteFileAccess>
  <writeDir>${server.output.dir}/write1</writeDir>
  <writeDir>${server.output.dir}/write2</writeDir>
</remoteFileAccess>

…then your “readList” will still have the 3 default values, while your “writeList” will contain the 2 locations specified above. To get the most updated values for these lists simply query the ReadList and WriteList attributes from the FileService mbean.

The first two exposed methods, getMetaData and getDirectoryEntries, are query-like methods for the file system. The “path” and “directory” parameters can either be the absolute location or it can use one of the defined Liberty variables to reference the location. For example, let’s say we have a Liberty instance under location “/home/wlp/usr/servers/myServer”, and we want to query information about the files under its logs directory. We can accomplish this with either of the following calls:

  • getDirectoryEntries(“/home/wlp/usr/servers/myServer/logs”, true, “a”)
  • getDirectoryEntries(“${server.output.dir}/logs”, true, “a”)

As you can see, the second version is easier to remember, portable to other servers and also robust to changes in the current server’s file system. The “recursive” parameter is self explanatory (recurse every folder under that location) and the “requestOptions” parameter can be a combination of the following static variables available from the FileServiceMXBean interface:

    /**
     * Option indicating all available keys should be used for the query.
     */
    String REQUEST_OPTIONS_ALL = "a";

    /**
     * Option indicating that "isDirectory" key should be used for the query.
     */
    String REQUEST_OPTIONS_IS_DIRECTORY = "d";

    /**
     * Option indicating that "isReadOnly" key should be used for the query.
     */
    String REQUEST_OPTIONS_READ_ONLY = "r";

    /**
     * Option indicating that "size" key should be used for the query.
     */
    String REQUEST_OPTIONS_SIZE = "s";

    /**
     * Option indicating that "lastModified" key should be used for the query.
     */
    String REQUEST_OPTIONS_LAST_MODIFIED = "t";

The path/directory parameters in both methods need to be within one of the locations specified by either the read or write lists.

You might have noticed that the return values for getMetaData and getDirectoryEntries both involve a class called “MetaData”. This is a javax.management.openmbean.CompositeData instance, using the fact that FileService is a MXBean, which encapsulates java native values that describe the corresponding file location. The values can be iterated by using the CompositeData interface or (if you have the corresponding API jar in your classpath) casting to a MetaData object and using its getter methods.

Here’s a quick screenshot when viewing this result from JConsole:

jconsole Using File Service and File Transfer MBeans with Liberty

The last 2 methods on this interface, createArchive and expandArchive are self explanatory: they create and expand archives in the ZIP file format, such as zip, war, ear, eba and jar. All parameters from createArchive and expandArchive can either be an absolute path or use Liberty defined variables. To create or expand an archive the “sourcePath” must be within one of the locations specified by either the write or read list, while the “targetPath” must be within one of the locations specified by the write list.

FileTransferMBean

FileTransfer contains methods that lets users perform download, upload or delete operations on the Liberty instance. Let’s take a closer look at its exposed interface:

Operations

  • void downloadFile(String remoteSourceFile, String localTargetFile)
  • void uploadFile(String localSourceFile, String remoteTargetFile, boolean expandOnCompletion)
  • void deleteFile(String remoteSourceFile)

The remote file references from the FileTransfer methods can be absolute remote paths or remote paths containing Liberty variables. The local file references must be absolute paths only. The downloadFile operation can only work with remote files that are within one of the read or write lists, while uploadFile and deleteFile can only work with remote files that are within one of the write lists.

The uploadFile method has a special parameter called “expandOnCompletion”. This can be set to true if the user is uploading an archive and wants it to be expanded immediately after the upload has completed. For example: an invocation such as…

uploadFile(“C:\files\myArchive.zip”, “${server.output.dir}/writeFolder/myArchive.zip”, true)

…will expand the contents of myArchive.zip inside the folder:

${server.output.dir}/writeFolder/myArchive.zip/

Example scenario 1: Gathering logs from a remote Liberty instance

Retrieve a MBeanServerConnection using Liberty’s JMX REST Connector as explained in Creating remote JMX connections in Liberty.

MBeanServerConnection mbsc = jmxConnector.getMBeanServerConnection();

ObjectName FILE_SERVICE_OBJ_NAME = new ObjectName("WebSphere:feature=restConnector,type=FileService,name=FileService");
ObjectName FILE_TRANSFER_OBJ_NAME = new ObjectName("WebSphere:feature=restConnector,type=FileTransfer,name=FileTransfer");

 //Create logs archive
String[] signature = new String[]{"java.lang.String", "java.lang.String"};
Object[] params = new String[]{"${server.output.dir}/logs", "${server.output.dir}/write/logs.zip"};
mbsc.invoke(FILE_SERVICE_OBJ_NAME, "createArchive", params, signature);

//Download logs
signature = new String[]{"java.lang.String", "java.lang.String"};
params = new String[]{"${server.output.dir}/write/logs.zip", "/Users/Shared/logs.zip"};
mbsc.invoke(FILE_TRANSFER_OBJ_NAME, "downloadFile", params, signature);

//Delete logs from server (cleanup)
signature = new String[]{"java.lang.String"};
params = new String[]{"${server.output.dir}/write/logs.zip"};
mbsc.invoke(FILE_TRANSFER_OBJ_NAME, "deleteFile", params, signature);

Example scenario 2: Deploying an application remotely in expanded mode

Retrieve a MBeanServerConnection using Liberty’s JMX REST Connector as explained in Creating remote JMX connections in Liberty.

MBeanServerConnection mbsc = jmxConnector.getMBeanServerConnection();

ObjectName FILE_TRANSFER_OBJ_NAME = new ObjectName("WebSphere:feature=restConnector,type=FileTransfer,name=FileTransfer");

//Upload and expand app (will auto-deploy)
String[] signature = new String[]{"java.lang.String","java.lang.String", "java.lang.Boolean", };
Object [] params = new Object[]{"/Users/Shared/ExampleJSF.war",
"${server.config.dir}/dropins/ExampleJSF.war", true};
 mbsc.invoke(FILE_TRANSFER_OBJ_NAME, "uploadFile", params, signature);

Since the app has been expanded, individual files can later be changed by uploading new versions.