Liferay: Converting 6.2 Portlets to 7.1 Part 3. The Remote Service
Created: 5 August 2019 Modified:
We have Java code that accesses remote services. Primarily it is accessed through Liferay’s JSON Web Services. Using AJAX we then make calls to those services. Security is important since these calls occur on the client side. Converting Liferay 6.2 remote services can be broken down into the following steps. These steps will all occur in the modules/MyApplication-Service/MyApplication-Service-service module.
Make Resource Actions file.
Make constants class.
Make permissions classes.
Make service registrar.
A resource actions file is needed to define permissions on the service. An example is below and needed permissions may
vary based on project. Strangely it seems to require a portlet name. You will also need to create a portlet.properties
file to point to the default.xml. Consult the legacy version which may be located src/main/resources/resource-actions/default.xml. Not all legacy projects have one.
modules/MyApplication-Service/MyApplication-Service-service/src/main/resources/META-INF/resource-actions/default.xml
<?xml version="1.0"?>
<!DOCTYPE resource-action-mapping PUBLIC "-//Liferay//DTD Resource Action Mapping 7.0.0//EN" "http://www.liferay.com/dtd/liferay-resource-action-mapping_7_0_0.dtd">
<resource-action-mapping>
<model-resource>
<model-name> com.codeexcursion.application.myapplication.service.model</model-name>
<portlet-ref>
<portlet-name> myapplication</portlet-name>
</portlet-ref>
<root> true</root>
<permissions>
<supports>
<action-key> UPDATE</action-key>
<action-key> DELETE</action-key>
<action-key> VIEW</action-key>
</supports>
<site-member-defaults />
<guest-defaults />
<guest-unsupported>
<action-key> UPDATE</action-key>
<action-key> DELETE</action-key>
<action-key> VIEW</action-key>
</guest-unsupported>
</permissions>
</model-resource>
<model-resource>
<model-name> com.codeexcursion.application.myapplication.service.model.Newsfeed</model-name>
<portlet-ref>
<portlet-name> myapplication</portlet-name>
</portlet-ref>
<permissions>
<supports>
<action-key> UPDATE</action-key>
<action-key> DELETE</action-key>
<action-key> VIEW</action-key>
</supports>
<site-member-defaults />
<guest-defaults />
<guest-unsupported>
<action-key> UPDATE</action-key>
<action-key> DELETE</action-key>
<action-key> VIEW</action-key>
</guest-unsupported>
</permissions>
</model-resource>
<model-resource>
<model-name> com.codeexcursion.application.myapplication.service.model.Location</model-name>
<portlet-ref>
<portlet-name> myapplication</portlet-name>
</portlet-ref>
<permissions>
<supports>
<action-key> UPDATE</action-key>
<action-key> DELETE</action-key>
<action-key> VIEW</action-key>
</supports>
<site-member-defaults />
<guest-defaults />
<guest-unsupported>
<action-key> UPDATE</action-key>
<action-key> DELETE</action-key>
<action-key> VIEW</action-key>
</guest-unsupported>
</permissions>
</model-resource>
</resource-action-mapping>
MyApplication-Service/MyApplication-Service-service/src/main/resources/portlet.properties
resource .actions .configs =META -INF /resource -actions /default .xml
Now we will create a class which will contain String constants. You will need one constant for each model in the project. For this project that would be: Newsfeed and Location. The String literals should match entries in the default.xml. These constants will be used in our permissions classes. It would also be used in indexing and search classes.
com.codeexcursion.application.myapplication.constants.MyApplicationConstants
package com.codeexcursion.application.myapplication.constants ;
public class MyApplicationConstants {
public static final String NEWSFEED_RESOURCE_NAME = "com.codeexcursion.application.myapplication.service.model.Newsfeed" ;
public static final String LOCATION_RESOURCE_NAME = "com.codeexcursion.application.myapplication.service.model.Location" ;
}
Our next step will be to create a permissions class for our model. Since our legacy code that doesn’t meet the requirements as discussed in Liferay From 6.2 to 7.1: The Model is the key to Services, Security and Search . This is a double issue for the Newsfeed model since it doesn’t have a primary key of the Long data type. The permissions interface ModelResourcePermissionOtherwise requires the primary key be long. This means we wil have to put a hack in place. We are going to all this trouble because we need the permission class in order to register the remotes services.
com.codeexcursion.application.myapplication.internal.security.permission.resource.NewsfeedModelResourcePermission
package com.codeexcursion.application.myapplication.internal.security.permission.resource ;
import com.liferay.portal.kernel.exception.PortalException ;
import com.liferay.portal.kernel.security.auth.PrincipalException ;
import com.liferay.portal.kernel.security.permission.PermissionChecker ;
import com.liferay.portal.kernel.security.permission.resource.ModelResourcePermission ;
import com.liferay.portal.kernel.security.permission.resource.PortletResourcePermission ;
import org.osgi.service.component.annotations.Component ;
import com.codeexcursion.application.myapplication.constants.MyApplicationConstants ;
import com.codeexcursion.application.myapplication.model.Newsfeed ;
@Component (
immediate = true ,
property = "model.class.name=" + MyApplicationConstants . NEWSFEED_RESOURCE_NAME ,
service = ModelResourcePermission . class
)
public class NewsfeedModelResourcePermission
implements ModelResourcePermission < Newsfeed > {
@Override
public void check (
PermissionChecker permissionChecker ,
Newsfeed newsFeed , String actionId )
throws PortalException {
check ( permissionChecker , 0 , actionId );
}
@Override
public void check (
PermissionChecker permissionChecker , long newsfeedId ,
String actionId )
throws PortalException {
if (! contains ( permissionChecker , newsfeedId , actionId )) {
throw new PrincipalException . MustHavePermission (
permissionChecker , Newsfeed . class . getName (),
newsfeedId , actionId );
}
}
@Override
public boolean contains (
PermissionChecker permissionChecker ,
Newsfeed newsfeed , String actionId )
throws PortalException {
return permissionChecker . isOmniadmin ();
}
@Override
public boolean contains (
PermissionChecker permissionChecker , long newsfeedId ,
String actionId )
throws PortalException {
return permissionChecker . isOmniadmin ();
}
@Override
public String getModelName () {
return Newsfeed . class . getName ();
}
@Override
public PortletResourcePermission getPortletResourcePermission () {
return null ;
}
}
We now add the service class and load the permissions.
com.codeexcursion.application.myapplication.service.impl.NewsfeedServiceImpl
package com.codeexcursion.application.myapplication.service.impl ;
import com.liferay.portal.kernel.dao.orm.QueryUtil ;
import com.liferay.portal.kernel.exception.PortalException ;
import com.liferay.portal.kernel.security.auth.PrincipalException ;
import com.liferay.portal.kernel.security.permission.ActionKeys ;
import com.liferay.portal.kernel.security.permission.resource.ModelResourcePermission ;
import com.liferay.portal.kernel.security.permission.resource.ModelResourcePermissionFactory ;
import java.util.List ;
import org.json.JSONObject ;
import com.codeexcursion.application.myapplication.model.Newsfeed ;
import com.codeexcursion.application.myapplication.service.base.NewsfeedServiceBaseImpl ;
public class NewsfeedServiceImpl extends NewsfeedServiceBaseImpl {
/*
* NOTE FOR DEVELOPERS:
*
* Never reference this class directly. Always use {@link com.codeexcursion.application.myapplication.service.NewsfeedServiceUtil} to access the newsfeed remote service.
*/
private static volatile ModelResourcePermission < Newsfeed >
newsfeedModelResourcePermission =
ModelResourcePermissionFactory . getInstance (
NewsfeedServiceImpl . class ,
"newsfeedModelResourcePermission" ,
Newsfeed . class );
public Newsfeed addNewsfeed ( String key , String displayName , String url ) throws PortalException {
newsfeedModelResourcePermission . check ( getPermissionChecker (), 0 , ActionKeys . UPDATE );
return this . newsfeedLocalService . addNewsfeed ( key , displayName , url );
}
public Newsfeed updateNewsfeed ( String key , String displayName , String url ) throws PortalException {
newsfeedModelResourcePermission . check ( getPermissionChecker (), 0 , ActionKeys . UPDATE );
Newsfeed newsfeed = this . newsfeedLocalService . getNewsfeed ( key );
return this . newsfeedLocalService . updateNewsfeed ( newsfeed );
}
public Newsfeed deleteNewsfeed ( String key ) throws PortalException {
newsfeedModelResourcePermission . check ( getPermissionChecker (), 0 , ActionKeys . DELETE );
return this . newsfeedLocalService . deleteNewsfeed ( key );
}
public List < Newsfeed > getAll () {
return this . newsfeedLocalService . getNewsfeeds ( QueryUtil . ALL_POS , QueryUtil . ALL_POS );
}
}
Finally we make our registrar class.
com.codeexcursion.application.myapplication.internal.security.permission.resource.NewsfeedModelResourcePermission
package com.codeexcursion.application.myapplication.internal.security.permission.resource ;
import com.liferay.portal.kernel.exception.PortalException ;
import com.liferay.portal.kernel.security.permission.resource.ModelResourcePermission ;
import com.liferay.portal.kernel.security.permission.resource.ModelResourcePermissionFactory ;
import com.liferay.portal.kernel.service.ResourceLocalService ;
import com.liferay.portal.kernel.util.HashMapDictionary ;
import java.util.Dictionary ;
import org.osgi.framework.BundleContext ;
import org.osgi.framework.ServiceRegistration ;
import org.osgi.service.component.annotations.Activate ;
import org.osgi.service.component.annotations.Component ;
import org.osgi.service.component.annotations.Deactivate ;
import org.osgi.service.component.annotations.Reference ;
import com.codeexcursion.application.myapplication.model.Newsfeed ;
import com.codeexcursion.application.myapplication.service.impl.NewsfeedServiceImpl ;
@Component ( immediate = true )
public class MyApplicationModelResourcePermissionRegistrar {
@Reference
ResourceLocalService _resourceLocalService ;
private static volatile ModelResourcePermission < Newsfeed > newsfeedModelResourcePermission =
ModelResourcePermissionFactory . getInstance (
NewsfeedServiceImpl . class ,
"newsfeedModelResourcePermission" ,
Newsfeed . class );
private ServiceRegistration < ModelResourcePermission > newsfeedRegistration ;
@Activate
public void activate ( BundleContext bundleContext ) throws PortalException {
Dictionary < String , Object > properties = new HashMapDictionary <>();
properties . put ( "model.class.name" , Newsfeed . class . getName ());
newsfeedRegistration = bundleContext . registerService (
ModelResourcePermission . class ,
newsfeedModelResourcePermission ,
properties );
}
@Deactivate
public void deactivate () throws PortalException {
newsfeedRegistration . unregister ();
}
}
tags: java - liferay - portlet - service builder