ApplicationService.java

/*
 * Copyright (c) 2002-2019, Mairie de Paris
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  1. Redistributions of source code must retain the above copyright notice
 *     and the following disclaimer.
 *
 *  2. Redistributions in binary form must reproduce the above copyright notice
 *     and the following disclaimer in the documentation and/or other materials
 *     provided with the distribution.
 *
 *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
 *     contributors may be used to endorse or promote products derived from
 *     this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * License 1.0
 */
package fr.paris.lutece.plugins.appcenter.service;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Locale;
import java.util.Map;
import java.util.function.Function;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;

import org.apache.commons.collections.CollectionUtils;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

import fr.paris.lutece.plugins.appcenter.business.Application;
import fr.paris.lutece.plugins.appcenter.business.ApplicationData;
import fr.paris.lutece.plugins.appcenter.business.ApplicationDatas;
import fr.paris.lutece.plugins.appcenter.business.ApplicationHome;
import fr.paris.lutece.plugins.appcenter.business.Demand;
import fr.paris.lutece.plugins.appcenter.business.DemandHome;
import fr.paris.lutece.plugins.appcenter.util.AppCenterUtils;
import fr.paris.lutece.portal.service.workflow.WorkflowService;
import fr.paris.lutece.util.ReferenceList;
import java.util.ArrayList;
import java.util.List;

/**
 * Application Service
 */
public class ApplicationService
{
    private static ObjectMapper _mapper = new ObjectMapper( );

    /**
     * Save a data subset into the global JSON data of an application
     * 
     * @param application
     *            The application
     * @param dataSubset
     *            The data subset
     */
    public static void saveApplicationData( Application application, DataSubset dataSubset )
    {
        try
        {
            String strUpdatedJson = getApplicationData( application, dataSubset );
            ApplicationHome.updateData( application.getId( ), strUpdatedJson );
        }
        catch( IOException ex )
        {
            Logger.getLogger( ApplicationService.class.getName( ) ).log( Level.SEVERE, null, ex );
        }
    }

    /**
     * Load a datasubset from the global JSON
     * 
     * @param <T>
     *            The datasubset type
     * @param application
     *            The application
     * @param strDataSubsetName
     *            The subset name
     * @param valueType
     *            The class of the data subset
     * @return The data subset as an object
     */
    public static <R extends ApplicationData, T extends ApplicationDatas<R>> T loadApplicationDataSubset( Application application,
            Class<T> applicationDatasClass )
    {
        try
        {
            Method mGetDataSetName = applicationDatasClass.getMethod( "getName" );
            String strDataSetName = (String) mGetDataSetName.invoke( applicationDatasClass.newInstance( ), null );
            String strApplicationJson = application.getApplicationData( );
            return getDataSubset( strApplicationJson, strDataSetName, applicationDatasClass );
        }
        catch( IOException | NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
                | InstantiationException ex )
        {
            Logger.getLogger( ApplicationService.class.getName( ) ).log( Level.SEVERE, null, ex );
        }
        return null;
    }

    /**
     * Load a datasubset from the global JSON
     * 
     * @param <T>
     *            The datasubset type
     * @param application
     *            The application
     * @param strDataSubsetName
     *            The subset name
     * @param valueType
     *            The class of the data subset
     * @return The data subset as an object
     */
    public static <T> T loadApplicationDataSubset( Application application, String strDataSubsetName, Class<T> valueType )
    {
        try
        {
            String strApplicationJson = application.getApplicationData( );
            return getDataSubset( strApplicationJson, strDataSubsetName, valueType );
        }
        catch( IOException ex )
        {
            Logger.getLogger( ApplicationService.class.getName( ) ).log( Level.SEVERE, null, ex );
        }
        return null;
    }

    /**
     * Build a global JSON data of an application by adding or replacing a data subset
     * 
     * @param application
     *            The application
     * @param dataSubset
     *            The data subset
     * @return The JSON
     * @throws IOException
     *             if an error occurs
     */
    static String getApplicationData( Application application, DataSubset dataSubset ) throws IOException
    {
        String strApplicationJson = application.getApplicationData( );
        JsonNode nodeApplication = _mapper.readTree( strApplicationJson );
        JsonNode nodeData = nodeApplication.get( dataSubset.getName( ) );
        if ( nodeData != null )
        {
            ( (ObjectNode) nodeApplication ).replace( dataSubset.getName( ), _mapper.valueToTree( dataSubset ) );
        }
        else
        {
            ( (ObjectNode) nodeApplication ).set( dataSubset.getName( ), _mapper.valueToTree( dataSubset ) );
        }
        return nodeApplication.toString( );
    }

    /**
     * Get the pretty print JSON data of an application
     * 
     * @param application
     *            The application
     * @return The pretty printed JSON
     * @throws IOException
     *             if an error occurs
     */
    public static String getPrettyPrintApplicationData( Application application )
    {
        String strApplicationJson = application.getApplicationData( );
        try
        {
            Object dataApplication = _mapper.readTree( strApplicationJson );
            if ( dataApplication != null )
            {
                strApplicationJson = _mapper.writerWithDefaultPrettyPrinter( ).writeValueAsString( dataApplication );
            }
        }
        catch( IOException ex )
        {
            Logger.getLogger( ApplicationService.class.getName( ) ).log( Level.WARNING, null, ex );
        }

        return strApplicationJson;
    }

    /**
     * Load a datasubset from the global JSON
     * 
     * @param <T>
     *            The datasubset type
     * @param strApplicationJson
     *            The global JSON of the application
     * @param strDataSubsetName
     *            The subset name
     * @param valueType
     *            The class of the data subset
     * @return The data subset as an object
     */
    static <T> T getDataSubset( String strApplicationJson, String strDataSubsetName, Class<T> valueType ) throws IOException
    {
        JsonNode nodeApplication = _mapper.readTree( strApplicationJson );
        JsonNode nodeData = nodeApplication.get( strDataSubsetName );
        if ( nodeData != null )
        {
            return _mapper.treeToValue( nodeData, valueType );
        }
        return null;

    }

    /**
     * Get application data by id application data
     * 
     * @param application
     *            The application
     * @param dataSubset
     *            The data subset
     * @return The JSON
     * @throws IOException
     *             if an error occurs
     */
    public static <AD extends ApplicationData, ADS extends ApplicationDatas<AD>> ApplicationData loadApplicationDataById( Integer nIdApplicationData,
            Application application, Class<ADS> valueType ) throws IOException
    {

        ADS ads = loadApplicationDataSubset( application, valueType );
        if ( ads != null && ads.getListData( ) != null )
        {
            return ads.getListData( ).stream( ).filter( x -> x.getIdApplicationData( ) == nIdApplicationData ).findFirst( ).orElse( null );

        }
        return null;
    }

    public static <AD extends ApplicationData, ADS extends ApplicationDatas<AD>> ReferenceList getRefLisApplicationDatas( Application application,
            Class<ADS> classAds, Locale locale, boolean bWithEmptyFile, Function<AD, String> functionRefItemCode, Function<AD, String> functionRefItemName )
    {

        ADS ads = ApplicationService.loadApplicationDataSubset( application, classAds );
        ReferenceList referenceList = null;
        if ( ads != null && ads.getListData( ) != null && !CollectionUtils.isEmpty( ads.getListData( ) ) )
        {
            Map<String, String> mapReferenceItem = ads.getListData( ).stream( )
                    .collect( Collectors.toMap( functionRefItemCode, functionRefItemName, ( f, s ) -> f ) );
            referenceList = ReferenceList.convert( mapReferenceItem );
        }
        else
        {
            referenceList = new ReferenceList( );
        }

        if ( bWithEmptyFile )
        {
            AppCenterUtils.addEmptyItem( referenceList, locale );
        }

        return referenceList;

    }

    /**
     * Remove the application whose identifier is specified in parameter with its dependencies
     * 
     * @param nId
     *            The application Id
     */
    public static void remove( int nId )
    {
        List<Demand> demandList = DemandHome.getDemandsListByApplication( nId );

        for ( Demand demand : demandList )
        {
            List<Integer> idResourceList = new ArrayList<Integer>( );
            idResourceList.add( demand.getId( ) );
            int nIdWorkflow = DemandTypeService.getIdWorkflow( demand.getDemandType( ) );
            WorkflowService.getInstance( ).doRemoveWorkFlowResourceByListId( idResourceList, Demand.WORKFLOW_RESOURCE_TYPE, nIdWorkflow );
            DemandHome.remove( demand.getId( ) );
        }

        ApplicationHome.remove( nId );
    }
}