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
PortletProvider
s
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 to100
, prioritizing it above allPortletProvider
s that specify the samemodel.class.name
value but have a lower rank.service = {EditPortletProvider.class, ViewPortletProvider.class}
reflects the subinterfacePortletProvider
classes this class implements.
Here’s how to create your own PortletProvider
:
-
Create a
PortletProvider
class in your module. Use the recommended class naming convention:[Entity] + [Action] + PortletProvider
Example:
LanguageEntryViewPortletProvider
-
Extend
BasePortletProvider
if you want to use itsgetPortletURL
method implementations. -
Implement one or more
PortletProvider
subinterfaces that match your action(s): -
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 replacingCLASS_NAME
with your entity’s fully qualified class name. Here’s an examplemodel.class.name
property:"model.class.name=com.liferay.wiki.model.WikiPage"
Assign the
service
element to thePortletProvider
subinterface(s) you’re implementing (e.g.,ViewPortletProvider.class
,BrowsePortletProvider
). ReplaceINTERFACE_1.class, ...
with a list of the subinterface(s) you’re implementing. -
If you’re overriding an existing
PortletProvider
, outrank it with your own customPortletProvider
by specifying aservice.ranking:Integer
property with a higher integer ranking.property= {"service.ranking:Integer=10"}
-
Implement the provider methods you want. Make sure you implement
PortletProvider
’sgetPortletName
method. If you didn’t extendBasePortletProvider
, implementPortletProvider
’sgetPortletURL
methods too.
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 PortletProvider
s to use in your apps!