Some apps perform the same operations on different entity types. For example, the Asset Publisher lets users browse, add, preview, and view various entities as assets including documents, web content, blogs, and more. The entities vary, while the operations and surrounding business logic stay the same. Apps such as the Asset Publisher rely on the Portlet Providers framework to fetch portlets to operate on the entities. In this way, the framework lets you focus on entity operations and frees you from concern about portlets that carry out those operations. This tutorial shows you how to

Creating PortletProviders

PortletProviders are Component classes associated with an entity type. They have methods that return portlet IDs and portlet URLs. Once you’ve registered a PortletProvider, you can invoke the PortletProviderUtil class to retrieve the portlet ID or portlet URL from the corresponding PortletProvider.

Examine the WikiPortletProvider class:

@Component(
    immediate = true,
    property = {
       "model.class.name=com.liferay.wiki.model.WikiPage",
       "service.ranking:Integer=100"
    },
    service = {EditPortletProvider.class, ViewPortletProvider.class}
)
public class WikiPortletProvider
    extends BasePortletProvider
    implements EditPortletProvider, ViewPortletProvider {

    @Override
    public String getPortletName() {
       return WikiPortletKeys.WIKI;
    }

}

WikiPortletProvider extends BasePortletProvider, inheriting its getPortletURL methods. It must, however, implement PortletProvider’s getPortletName method, which returns the portlet’s name WikiPortletKeys.WIKI.

WikiPortletProvider’s @Component annotation specifies these elements and properties:

  • immediate = true activates the component immediately upon installation.
  • "model.class.name=com.liferay.wiki.model.WikiPage" specifies the entity type the portlet operates on.
  • "service.ranking:Integer=100" sets the component’s rank to 100, prioritizing it above all PortletProviders that specify the same model.class.name value but have a lower rank.
  • service = {EditPortletProvider.class, ViewPortletProvider.class} reflects the subinterface PortletProvider classes this class implements.

Here’s how to create your own PortletProvider:

  1. Create an OSGi module.

  2. Create a PortletProvider class in your module. Use the recommended class naming convention:

    [Entity] + [Action] + PortletProvider

    Example:

    LanguageEntryViewPortletProvider

  3. Extend BasePortletProvider if you want to use its getPortletURL method implementations.

  4. Implement one or more PortletProvider subinterfaces that match your action(s):

  5. Make the class an OSGi Component by adding an annotation like this one:

    @Component(
        immediate = true,
        property = {"model.class.name=CLASS_NAME"},
        service = {INTERFACE_1.class, ...}
    )
    

    The immediate = true element specifies that the component should be activated immediately upon installation.

    Assign the property model.class.name class name of the entity the portlet operates on by replacing CLASS_NAME with your entity’s fully qualified class name. Here’s an example model.class.name property:

    "model.class.name=com.liferay.wiki.model.WikiPage"
    

    Assign the service element to the PortletProvider subinterface(s) you’re implementing (e.g., ViewPortletProvider.class, BrowsePortletProvider). Replace INTERFACE_1.class, ... with a list of the subinterface(s) you’re implementing.

  6. If you’re overriding an existing PortletProvider, outrank it with your own custom PortletProvider by specifying a service.ranking:Integer property with a higher integer ranking.

    property= {"service.ranking:Integer=10"}
    
  7. Implement the provider methods you want. Make sure you implement PortletProvider’s getPortletName method. If you didn’t extend BasePortletProvider, implement PortletProvider’s getPortletURL methods too.

  8. Deploy your module.

Now your PortletProvider is available to return the ID and URL of the portlet that provides the desired behaviors. Using PortletProviderUtil to fetch the portlet IDs and URLs is next.

Retrieving Portlets for Desired Behaviors

The PortletProviderUtil class facilitates fetching portlets to execute actions on entities. You can request the ID or URL of a portlet that performs the entity action you want.

The Portlet Provider framework’s PortletProvider.Action Enums define these action types:

  • ADD
  • BROWSE
  • EDIT
  • MANAGE
  • PREVIEW
  • VIEW

The action type and entity type are key parameters in fetching a portlet’s ID or URL.

Fetching a Portlet ID

The Portlet Provider framework’s PortletProviderUtil class facilitates fetching an ID of a portlet for handling an entity operation. For example, this call gets the ID of a portlet for viewing Recycle Bin entries:

String portletId = PortletProviderUtil.getPortletId(
    "com.liferay.portlet.trash.model.TrashEntry", 
    PortletProvider.Action.VIEW);

PortletProvider.Action.VIEW is the operation and com.liferay.portlet.trash.model.TrashEntry is the entity type.

Another example is how the Asset Publisher uses the Portlet Provider framework to add a previewed asset to a page—it adds the asset to a portlet and adds that portlet to the page. The Asset Publisher uses the liferay-asset:asset_display tag library tag whose asset_display/preview.jsp shows an Add button for adding the portlet. If the previewed asset is a Blogs entry, for example, the framework returns a blogs portlet ID or URL for adding the portlet to the current page. Here’s the relevant code from the asset_display/preview.jsp:

Map<String, Object> data = new HashMap<String, Object>();

<!-- populate the data map -->

String portletId = PortletProviderUtil.getPortletId(assetEntry.getClassName(), PortletProvider.Action.ADD);

data.put("portlet-id", portletId);

<!-- add more to the data map -->
%>

<c:if test="<%= PortletPermissionUtil.contains(permissionChecker, layout, portletId, ActionKeys.ADD_TO_PAGE) %>">
    <aui:button cssClass="add-button-preview" data="<%= data %>" value="add" />
</c:if>

The code above invokes PortletProviderUtil.getPortletId(assetEntry.getClassName(), PortletProvider.Action.ADD) to get the ID of a portlet that adds and displays the asset of the underlying entity class.

The JSP puts the portlet ID into the data map.

data.put("portlet-id", portletId);

Then it passes the data map to a new Add button that adds the portlet to the page.

<aui:button cssClass="add-button-preview" data="<%= data %>" value="add" />

Fetching a portlet URL is just as easy.

Fetching a Portlet URL

PortletProviderUtil’s getPortletURL methods return a javax.portlet.PortletURL based on an HttpServletRequest or PortletRequest. They also let you specify a Group.

For example, when the Asset Publisher is configured in Manual mode, the user can use an Asset Browser to select asset entries. The asset-publisher-web module’s configuration/asset_entries.jsp file uses PortletProviderUtil’s getPortletURL method (at the end of the code below) to generate a corresponding Asset Browser URL.

List<AssetRendererFactory<?>> assetRendererFactories = 
    ListUtil.sort(
        AssetRendererFactoryRegistryUtil.getAssetRendererFactories(
            company.getCompanyId()),
            new AssetRendererFactoryTypeNameComparator(locale));

for (AssetRendererFactory<?> curRendererFactory : assetRendererFactories) {
    long curGroupId = groupId;

    if (!curRendererFactory.isSelectable()) {
       continue;
    }

    PortletURL assetBrowserURL = PortletProviderUtil.getPortletURL(
        request, curRendererFactory.getClassName(),
        PortletProvider.Action.BROWSE);

Now you can unleash an arsenal of PortletProviders to use in your apps!

Related Topics

Portlets

Embedding Portlets in Themes and Layout Templates

Customizing Liferay Services

0 (0 Votes)
Back-end Frameworks Previous