Documentation

Completely Custom Configuration

A configuration UI is generated automatically when you create a configuration interface. But in some cases you want a completely custom UI for your configuration. For example, you plan to handle the configuration programmatically instead of using Liferay’s Configuration Admin. Or maybe you want the flexibility of creating a completely custom UI. Here’s how to do it.

See the Example Project

  1. Start Liferay DXP. If you don’t already have a docker container, use

    docker run -it -m 8g -p 8080:8080 liferay/dxp:7.4.13-ga1
    

    If you’re running a different Liferay Portal version or Liferay DXP, adjust the above command accordingly.

  2. Download and unzip Completely Custom Configuration.

    curl https://learn.liferay.com/dxp/latest/en/building-applications/core-frameworks/configuration-framework/liferay-u2g5.zip -O
    
    unzip liferay-u2g5.zip
    
  3. From the module root, build and deploy.

    ./gradlew deploy -Ddeploy.docker.container.id=$(docker ps -lq)
    

    Note

    This command is the same as copying the deployed jars to /opt/liferay/osgi/modules on the Docker container.

  4. Confirm the deployment in the Liferay Docker container console.

    STARTED com.acme.u2g5.web_1.0.0 [1034]
    
  5. Verify that the example module is working. Open your browser to https://localhost:8080.

  6. Navigate to Control PanelConfigurationSystem SettingsThird Party. Click U2G5 Configuration.

    Navigate to U2G5 configuration in system settings.

    Note that this view is delivered by a custom JSP file.

Create the Configuration Interface

Define the configurable attributes in the configuration interface. The sample project has three configurable attributes: fontColor, fontFamily, and fontSize.

@ExtendedObjectClassDefinition(
	category = "u2g5", generateUI = false,
	scope = ExtendedObjectClassDefinition.Scope.SYSTEM
)
@Meta.OCD(
	id = "com.acme.u2g5.web.internal.configuration.U2G5WebConfiguration",
	localization = "content/Language", name = "u2g5-configuration-name"
)
public interface U2G5WebConfiguration {

	@Meta.AD(deflt = "blue", required = false)
	public String fontColor();

	@Meta.AD(deflt = "serif", required = false)
	public String fontFamily();

	@Meta.AD(deflt = "16", required = false)
	public int fontSize();

Note that under the @ExtendedObjectClassDefinition annotation, generateUI is set to false. This excludes the configuration UI from being auto-generated.

Add the Configuration Bean Declaration

Register the configuration class with a ConfigurationBeanDeclaration. This enables the system to keep track of configuration changes as they happen.

@Component(service = ConfigurationBeanDeclaration.class)
public class U2G5WebConfigurationBeanDeclaration
	implements ConfigurationBeanDeclaration {

	@Override
	public Class<?> getConfigurationBeanClass() {
		return U2G5WebConfiguration.class;
	}

}

Implement the Configuration Screen

  1. Declare the class as an implementation of ConfigurationScreen with the @Component annotation.

    @Component(service = ConfigurationScreen.class)
    
  2. Set the category key, the configuration entry’s key, and its localized name. In the sample project, the category key is set to third-party in System Settings. The string value for the configuration’s name is set by the language key in the bundle’s Language.properties file.

    @Override
    public String getCategoryKey() {
    	return "third-party";
    }
    
    @Override
    public String getKey() {
    	return "u2g5-configuration-name";
    }
    
    @Override
    public String getName(Locale locale) {
    	return LanguageUtil.get(
    		ResourceBundleUtil.getBundle(locale, U2G5ConfigurationScreen.class),
    		"u2g5-configuration-name");
    }
    
  3. For this example, the configuration scope is set to system. To learn more, see Scoping Configurations.

    @Override
    public String getScope() {
    	return "system";
    }
    
  4. The render() method uses ConfigurationProvider to get the configuration. The servlet context provides access to the request dispatcher, which allows the custom JSP to read the configuration.

    @Override
    public void render(
    		HttpServletRequest httpServletRequest,
    		HttpServletResponse httpServletResponse)
    	throws IOException {
    
    	try {
    		RequestDispatcher requestDispatcher =
    			_servletContext.getRequestDispatcher("/u2g5.jsp");
    
    		httpServletRequest.setAttribute(
    			U2G5WebConfiguration.class.getName(),
    			_configurationProvider.getSystemConfiguration(
    				U2G5WebConfiguration.class));
    
    		requestDispatcher.include(httpServletRequest, httpServletResponse);
    	}
    	catch (Exception exception) {
    		throw new IOException("Unable to render /u2g5.jsp", exception);
    	}
    }
    
  5. Make sure to use the @Reference annotation to define the module’s symbolic name.

    @Reference(
    	target = "(osgi.web.symbolicname=com.acme.u2g5.web)"
    )
    

Add the Web-ContextPath

Specify your bundle’s Web-ContextPath in the bnd.bnd file. For example, the sample project has Web-ContextPath: /u2g5-web in the Bnd file. This is what registers the ServletContext object in the Configuration Screen file. Note that a servlet context is created automatically for portlets, but since this sample doesn’t have a portlet, you must add this line to the Bnd file.

Create a Custom JSP

  1. Import the configuration interface to the JSP.

    <%@ page import="com.acme.u2g5.web.internal.configuration.U2G5WebConfiguration" %>
    
  2. Access the configuration values from the request object.

    <%
    U2G5WebConfiguration u2g5WebConfiguration = (U2G5WebConfiguration)request.getAttribute(U2G5WebConfiguration.class.getName());
    %>
    
  3. The attributes fontColor(), fontFamily(), fontSize() can now be used in the JSP.

This sample project demonstrates a basic example of how to use ConfigurationScreen to read and display configuration values in a custom JSP. In your application, write your own code and create a completely custom configuration UI to meet your needs.