f-angi
8/25/2016 - 3:19 PM

Building a Liferay Rest/SOAP service decoupled from db entities

Building a Liferay Rest/SOAP service decoupled from db entities

<!DOCTYPE service-builder PUBLIC "-//Liferay//DTD Service Builder 6.2.0//EN" "http://www.liferay.com/dtd/liferay-service-builder_6_2_0.dtd">
<service-builder package-path="it.intesys.arag">
	<namespace>salesonline</namespace>
	<entity name="Rinnovo" local-service="true" remote-service="true">
	</entity>
</service-builder>
…
	<bean id="applicationContextProvider" lazy-init="false" class="it.intesys.arag.context.ApplicationContextProvider" />
	<bean id="propertiesHolder" class="it.intesys.arag.context.PropertiesHolder"/>
…
package it.intesys.arag.service.impl;

import it.intesys.arag.bean.RinnovoWsData;
import it.intesys.arag.service.RinnovoLocalServiceUtil;
import it.intesys.arag.service.base.RinnovoServiceBaseImpl;

/**
 * The implementation of the rinnovo remote service.
 *
 * <p>
 * All custom service methods should be put in this class. Whenever methods are added, rerun ServiceBuilder to copy their definitions into the {@link it.intesys.arag.service.RinnovoService} interface.
 *
 * <p>
 * This is a remote service. Methods of this service are expected to have security checks based on the propagated JAAS credentials because this service can be accessed remotely.
 * </p>
 *
 * @author Brian Wing Shun Chan
 * @see it.intesys.arag.service.base.RinnovoServiceBaseImpl
 * @see it.intesys.arag.service.RinnovoServiceUtil
 */
public class RinnovoServiceImpl extends RinnovoServiceBaseImpl {
    /*
     * NOTE FOR DEVELOPERS:
     *
     * Never reference this interface directly. Always use {@link it.intesys.arag.service.RinnovoServiceUtil} to access the rinnovo remote service.
     */
    public RinnovoWsData getRinnovoData() {
        // RinnovoLocalServiceUtil is created after installing the service and
        // deploying the portlet (after the definition of the entity Rinnovo
        // in service.xml
        return RinnovoLocalServiceUtil.getRinnovoData();
    }
}
package it.intesys.arag.service.impl;

import org.springframework.context.ApplicationContext;

import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;

import it.intesys.arag.bean.RinnovoWsData;
import it.intesys.arag.context.ApplicationContextProvider;
import it.intesys.arag.model.Anagrafica;
import it.intesys.arag.model.Emissione;
import it.intesys.arag.service.AnagraficaLocalServiceUtil;
import it.intesys.arag.service.EmissioneLocalServiceUtil;
import it.intesys.arag.service.base.RinnovoLocalServiceBaseImpl;
import it.intesys.arag.util.EmailUtil;
import it.intesys.arag.util.RinnovoUtil;

/**
 * The implementation of the rinnovo local service.
 *
 * <p>
 * All custom service methods should be put in this class. Whenever methods are added, rerun ServiceBuilder to copy their definitions into the {@link it.intesys.arag.service.RinnovoLocalService} interface.
 *
 * <p>
 * This is a local service. Methods of this service will not have security checks based on the propagated JAAS credentials because this service can only be accessed from within the same VM.
 * </p>
 *
 * @author Brian Wing Shun Chan
 * @see it.intesys.arag.service.base.RinnovoLocalServiceBaseImpl
 * @see it.intesys.arag.service.RinnovoLocalServiceUtil
 */
public class RinnovoLocalServiceImpl extends RinnovoLocalServiceBaseImpl {
    /*
     * NOTE FOR DEVELOPERS:
     *
     * Never reference this interface directly. Always use {@link it.intesys.arag.service.RinnovoLocalServiceUtil} to access the rinnovo local service.
     */

    private static Log log = LogFactoryUtil.getLog(RinnovoLocalServiceImpl.class);

    private EmailUtil emailUtil;
    private RinnovoUtil rinnovoUtil;

    public RinnovoWsData sendEmailRinnovo(String email, String numeroPolizza, int numeroEmail) {

        initContext();

        RinnovoWsData rinnovoWsData = new RinnovoWsData();
        rinnovoWsData.setUrlConferma(rinnovoUtil.getUrlConferma(numeroPolizza));
        rinnovoWsData.setUrlModifica(rinnovoUtil.getUrlModifica(numeroPolizza));

        Emissione emissione = null;
        Anagrafica anagrafica = null;
        try {
            emissione = EmissioneLocalServiceUtil.getEmissioneByNumeroPolizza(numeroPolizza);
            anagrafica = AnagraficaLocalServiceUtil.getAnagrafica(emissione.getAnagraficaId());
        }
        catch (Exception e) {
            log.error(e);
        }

        if (emissione == null || anagrafica == null) {
            // rinnovoWsData.setEr
        }
        emailUtil.sendRinnovoTemplateMandrill(email, emissione, anagrafica);
        return rinnovoWsData;
    }

    private void initContext() {

        ApplicationContext applicationContext = ApplicationContextProvider.getApplicationContext();
        PropertiesHolder propertiesHolder = (PropertiesHolder) applicationContext.getBean(PropertiesHolder.class);

        String optoutUrl = propertiesHolder.getOptoutUrl();

        emailUtil = (EmailUtil) applicationContext.getBean(EmailUtil.class);
        rinnovoUtil = (RinnovoUtil) applicationContext.getBean(RinnovoUtil.class);

    }
}
1. define an empty entity in service.xml
2. build and install the service, deploy the portlet
3. in <Entity>LocalServiceImpl define a method for each service's endpoint
4. rebuild and reinstall the service
5. in <Entity>ServiceImpl define a method for each service's endpoint (using <Entity>LocalServiceUtil)
6. build the service with liferay:build-service
7. from the top parent project run liferay:build-wsdd
8. install the service and deploy the portlet

The Rest service will be listed at http://localhost:8080/api/jsonws
The SOAP wsdl will be available at http://localhost:8080/<portlet name>/api/axis/Plugin_<namespace>_<Entity>Service?wsdl where <namespace> is the one defined in service.xml

Tips:
- the beans used by <Entity>LocalServiceImpl must be defined in the service
- in order to use the beans defined in the portlet's Spring context, implement the ApplicationContextAware interface
package it.intesys.arag.context;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class PropertiesHolder {

    @Value("${optout-url}")
    private String optoutUrl;
}
package it.intesys.arag.context;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component("applicationContextProvider")
public class ApplicationContextProvider implements ApplicationContextAware {

    private static ApplicationContext context = null;

    public static ApplicationContext getApplicationContext() {

        return context;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
        throws BeansException {

        context = applicationContext;
    }
}