Liferay DXP (and its free counterpart Liferay 7) introduced many new features, first of all the OSGi integration. Among the many new tools provided there is a shell to interact with the OSGi container; I'm talking about Gogo shell (a subproject of Apache Felix) accessible with the command telnet localhost 11311.

Once accessed to the shell, we can see the list of all available commands simply by typing help; each command is formed by a scope (a kind of grouping) and a name.

So let's see how to create a custom command to be executed inside the Gogo shell.

First we create an empty project using Liferay IDE; for this purpose the api template is minimal and suitable. Be sure to have the following dependencies inside the build.gradle file:

dependencies {
    compileOnly group: "com.liferay.portal", name: "com.liferay.portal.kernel", version: "2.0.0"
    compileOnly group: "javax.portlet", name: "portlet-api", version: "2.0"
    compileOnly group: "org.osgi", name: "org.osgi.service.component.annotations", version: "1.3.0"
}

What we want is a command that displays the list of the companies (if invoked with no parameters) or the single company details (if invoked with the companyId parameter); so let's create a Java class with the following OSGi annotations:

package it.marconapolitano.liferay.gogo.command;

@Component(property = {
    "osgi.command.function=company", "osgi.command.scope=liferay"
}, service = Object.class)
public class CompanyCommand {
}

As you can see the only OSGi properties are the command name (company) and the scope to be used (liferay). The important thing to remember is that the command name must match the name of the Java methods that implement the command itself.

So let's define the first method, the one that will be invoked without parameters and will display the companies list:

package it.marconapolitano.liferay.gogo.command;

@Component(property = {
    "osgi.command.function=company", "osgi.command.scope=liferay"
}, service = Object.class)
public class CompanyCommand {

@Reference
private volatile CompanyLocalService _companyLocalService;

public void company() throws PortalException { List<Company> companies = _companyLocalService.getCompanies(); for (Company company : companies) { System.out.println(company.getPrimaryKey() + StringPool.COMMA_AND_SPACE + company.getName()); } } }

It's all quite simple: the method takes no parameters, retrieves the companies list and displays them on screen. Let's add now the other method, the one that will be invoked with the companyId parameter and will display the company details:

package it.marconapolitano.liferay.gogo.command;

@Component(property = {
    "osgi.command.function=company", "osgi.command.scope=liferay"
}, service = Object.class)
public class CompanyCommand {

@Reference
private volatile CompanyLocalService _companyLocalService;

public void company() throws PortalException { List<Company> companies = _companyLocalService.getCompanies(); for (Company company : companies) { System.out.println(company.getPrimaryKey() + StringPool.COMMA_AND_SPACE + company.getName()); } }

public void company(long companyId) throws PortalException {
Company company = _companyLocalService.getCompany(companyId); System.out.println("companyId = " + company.getPrimaryKey()); System.out.println("name = " + company.getName()); System.out.println("active = " + company.isActive()); System.out.println("authType = " + company.getAuthType()); System.out.println("adminName = " + company.getAdminName()); System.out.println("emailAddress = " + company.getEmailAddress()); System.out.println("homeURL = " + company.getHomeURL()); System.out.println("maxUsers = " + company.getMaxUsers()); System.out.println("mx = " + company.getMx()); System.out.println("virtualHostname = " + company.getVirtualHostname()); System.out.println("webId = " + company.getWebId()); } }

Nothing particular again: the method accepts a parameter, the company is retrieved and then the details are shown.

Now deploy the bundle and type the help command inside the Gogo shell; magically in the commands list will also appear liferay:company. For more information about the command you can type help liferay:company and the shell will show the 2 methods, with and without parameter. So let's try to launch our custom command by typing liferay:company or just company, since there are no homonyms commands in other scopes:

liferay:company
liferay:company 0
liferay:company 20116

Now you need just a little imagination to implement all the commands you need!