PDFUtils.java
/*
* Copyright (c) 2002-2021, City of 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.forms.modules.documentproducer.utils;
import fr.paris.lutece.portal.service.plugin.Plugin;
import fr.paris.lutece.portal.service.util.AppLogService;
import fr.paris.lutece.portal.service.util.AppPathService;
import fr.paris.lutece.portal.service.util.AppPropertiesService;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Element;
import com.lowagie.text.Font;
import com.lowagie.text.Image;
import com.lowagie.text.ListItem;
import com.lowagie.text.PageSize;
import com.lowagie.text.Paragraph;
import com.lowagie.text.Phrase;
import com.lowagie.text.pdf.PdfWriter;
import fr.paris.lutece.plugins.forms.business.Form;
import fr.paris.lutece.plugins.forms.business.FormHome;
import fr.paris.lutece.plugins.forms.business.FormQuestionResponse;
import fr.paris.lutece.plugins.forms.business.FormQuestionResponseHome;
import fr.paris.lutece.plugins.forms.business.FormResponse;
import fr.paris.lutece.plugins.forms.business.FormResponseHome;
import fr.paris.lutece.plugins.forms.business.FormResponseStep;
import fr.paris.lutece.plugins.forms.business.FormResponseStepHome;
import fr.paris.lutece.plugins.forms.business.Question;
import fr.paris.lutece.plugins.forms.business.QuestionHome;
import fr.paris.lutece.plugins.forms.business.Step;
import fr.paris.lutece.plugins.forms.modules.documentproducer.business.producerconfig.IConfigProducer;
import fr.paris.lutece.plugins.genericattributes.business.Response;
import fr.paris.lutece.plugins.genericattributes.service.entrytype.EntryTypeServiceManager;
import fr.paris.lutece.util.string.StringUtil;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.collections.CollectionUtils;
/**
* class for generate PDF document from forms records
*/
public final class PDFUtils
{
// PROPERTIES
private static final String PROPERTY_POLICE_NAME = "forms.pdfgenerate.font.name";
// PORPERTIES DATE
private static final String PROPERTY_POLICE_FORMAT_DATE = "forms.pdfgenerate.format.date";
private static final String PROPERTY_POLICE_SIZE_DATE = "forms.pdfgenerate.font.size.date";
private static final String PROPERTY_POLICE_STYLE_DATE = "forms.pdfgenerate.font.style.date";
private static final String PROPERTY_POLICE_ALIGN_DATE = "forms.pdfgenerate.font.align.date";
// PROPERTIES TITLE FORM
private static final String PROPERTY_POLICE_SIZE_TITLE_FORMS = "forms.pdfgenerate.font.size.title.forms";
private static final String PROPERTY_POLICE_STYLE_TITLE_FORMS = "forms.pdfgenerate.font.style.title.forms";
private static final String PROPERTY_POLICE_SPACING_BEFORE_TITLE_FORMS = "forms.pdfgenerate.font.spacing_before.title.forms";
private static final String PROPERTY_POLICE_SPACING_AFTER_TITLE_FORMS = "forms.pdfgenerate.font.spacing_after.title.forms";
// PROPERTIES STEPS
private static final String PROPERTY_POLICE_SIZE_STEP = "forms.pdfgenerate.font.size.step";
private static final String PROPERTY_POLICE_MARGIN_LEFT_STEP = "forms.pdfgenerate.margin.left.step";
private static final String PROPERTY_POLICE_SPACING_BEFORE_STEP = "forms.pdfgenerate.font.spacing_before.step";
private static final String PROPERTY_POLICE_SPACING_AFTER_STEP = "forms.pdfgenerate.font.spacing_after.step";
// PROPERTIES QUESTION
private static final String PROPERTY_POLICE_SIZE_QUESTION = "forms.pdfgenerate.font.size.question";
private static final String PROPERTY_POLICE_STYLE_QUESTION = "forms.pdfgenerate.font.style.question";
private static final String PROPERTY_POLICE_MARGIN_LEFT_QUESTION = "forms.pdfgenerate.margin.left.question";
private static final String PROPERTY_POLICE_SPACING_BEFORE_QUESTION = "forms.pdfgenerate.font.spacing_before.question";
private static final String PROPERTY_POLICE_SPACING_AFTER_QUESTION = "forms.pdfgenerate.font.spacing_after.question";
// PROPERTIES RESPONSE
private static final String PROPERTY_POLICE_SIZE_RESPONSE = "forms.pdfgenerate.font.size.response";
private static final String PROPERTY_POLICE_STYLE_RESPONSE = "forms.pdfgenerate.font.style.response";
private static final String PROPERTY_POLICE_MARGIN_LEFT_RESPONSE = "forms.pdfgenerate.margin.left.response";
private static final String PROPERTY_POLICE_SPACING_BEFORE_RESPONSE = "forms.pdfgenerate.font.spacing_before.response";
private static final String PROPERTY_POLICE_SPACING_AFTER_RESPONSE = "forms.pdfgenerate.font.spacing_after.response";
// PROPERTIES IMAGE
private static final String PROPERTY_IMAGE_URL = "forms.pdfgenerate.image.url";
private static final String PROPERTY_IMAGE_ALIGN = "forms.pdfgenerate.image.align";
private static final String PROPERTY_IMAGE_FITWIDTH = "forms.pdfgenerate.image.fitWidth";
private static final String PROPERTY_IMAGE_FITHEIGHT = "forms.pdfgenerate.image.fitHeight";
// CONSTANTS
private static final String DEFAULT_TYPE_FILE_NAME = "default";
private static final String TEXT_TYPE_FILE_NAME = "text";
private static final String FORM_QUESTION_TYPE_FILE_NAME = "form_question";
/**
* Constructor
*/
private PDFUtils( )
{
}
/**
* method to create PDF
*
* @param out
* OutputStream
* @param nIdFormResponse
* the id of the form response
* @param listIdEntryConfig
* list of config id entry
*/
private static void doCreateDocumentPDF( OutputStream out, int nIdFormResponse, List<Integer> listIdEntryConfig )
{
Document document = new Document( PageSize.A4 );
FormResponse formResponse = FormResponseHome.findByPrimaryKey( nIdFormResponse );
Form form = FormHome.findByPrimaryKey( formResponse.getFormId( ) );
try
{
PdfWriter.getInstance( document, out );
}
catch( DocumentException e )
{
AppLogService.error( e );
}
document.open( );
if ( formResponse.getCreation( ) != null )
{
SimpleDateFormat monthDayYearformatter = new SimpleDateFormat( AppPropertiesService.getProperty( PROPERTY_POLICE_FORMAT_DATE ) );
Font fontDate = new Font( AppPropertiesService.getPropertyInt( PROPERTY_POLICE_NAME, 0 ),
AppPropertiesService.getPropertyInt( PROPERTY_POLICE_SIZE_DATE, 0 ), AppPropertiesService.getPropertyInt( PROPERTY_POLICE_STYLE_DATE, 0 ) );
Paragraph paragraphDate = new Paragraph( new Phrase( monthDayYearformatter.format( formResponse.getCreation( ) ), fontDate ) );
paragraphDate.setAlignment( AppPropertiesService.getPropertyInt( PROPERTY_POLICE_ALIGN_DATE, 0 ) );
try
{
document.add( paragraphDate );
}
catch( DocumentException e )
{
AppLogService.error( e );
}
}
float fitWidth;
float fitHeight;
try
{
fitWidth = Float.parseFloat( AppPropertiesService.getProperty( PROPERTY_IMAGE_FITWIDTH ) );
fitHeight = Float.parseFloat( AppPropertiesService.getProperty( PROPERTY_IMAGE_FITHEIGHT ) );
}
catch( NumberFormatException e )
{
fitWidth = 100f;
fitHeight = 100f;
}
try
{
Image image = Image.getInstance(
ImageIO.read( new File( AppPathService.getAbsolutePathFromRelativePath( AppPropertiesService.getProperty( PROPERTY_IMAGE_URL ) ) ) ),
null );
image.setAlignment( AppPropertiesService.getPropertyInt( PROPERTY_IMAGE_ALIGN, 0 ) );
image.scaleToFit( fitWidth, fitHeight );
document.add( image );
}
catch( IOException | DocumentException e )
{
AppLogService.error( e );
}
Font fontTitle = new Font( AppPropertiesService.getPropertyInt( PROPERTY_POLICE_NAME, 0 ),
AppPropertiesService.getPropertyInt( PROPERTY_POLICE_SIZE_TITLE_FORMS, 0 ),
AppPropertiesService.getPropertyInt( PROPERTY_POLICE_STYLE_TITLE_FORMS, 0 ) );
fontTitle.isUnderlined( );
Paragraph paragraphHeader = new Paragraph( new Phrase( form.getTitle( ), fontTitle ) );
paragraphHeader.setAlignment( Element.ALIGN_CENTER );
paragraphHeader.setSpacingBefore( AppPropertiesService.getPropertyInt( PROPERTY_POLICE_SPACING_BEFORE_TITLE_FORMS, 0 ) );
paragraphHeader.setSpacingAfter( AppPropertiesService.getPropertyInt( PROPERTY_POLICE_SPACING_AFTER_TITLE_FORMS, 0 ) );
addElementToDocument( document, paragraphHeader );
builderPDFWithFormQuestionResponse( document, formResponse, listIdEntryConfig );
document.close( );
}
/**
* method to builder PDF with forms entry
*
* @param document
* document pdf
* @param plugin
* plugin
* @param nIdRecord
* id record
* @param listEntry
* list of entry
* @param listIdEntryConfig
* list of config id entry
* @param locale
* the locale
*/
private static void builderPDFWithFormQuestionResponse( Document document, FormResponse formResponse, List<Integer> listIdEntryConfig )
{
List<FormResponseStep> listFormResponseStep = FormResponseStepHome.findStepsByFormResponse( formResponse.getId( ) );
for ( FormResponseStep formResponseStep : listFormResponseStep )
{
Step step = formResponseStep.getStep( );
List<FormQuestionResponse> listFormQuestionResponseOfStep = FormQuestionResponseHome.findQuestionsByStepAndFormResponse( formResponse.getId( ),
step.getId( ) );
if ( CollectionUtils.isEmpty( listFormQuestionResponseOfStep ) )
{
continue;
}
boolean bPrintStep = false;
for ( FormQuestionResponse formQuestionResponseOfStep : listFormQuestionResponseOfStep )
{
// Print the question
Question questionOfStep = QuestionHome.findByPrimaryKey( formQuestionResponseOfStep.getQuestion( ).getId( ) );
if ( listIdEntryConfig.isEmpty( ) || listIdEntryConfig.contains( questionOfStep.getId( ) ) )
{
bPrintStep = true;
}
}
if ( bPrintStep )
{
Font fontStepTitle = new Font( AppPropertiesService.getPropertyInt( PROPERTY_POLICE_NAME, 0 ),
AppPropertiesService.getPropertyInt( PROPERTY_POLICE_SIZE_STEP, 0 ), Font.UNDERLINE );
Paragraph paragraphTitleStep = new Paragraph( new Phrase( step.getTitle( ), fontStepTitle ) );
paragraphTitleStep.setAlignment( Element.ALIGN_LEFT );
paragraphTitleStep.setIndentationLeft( AppPropertiesService.getPropertyInt( PROPERTY_POLICE_MARGIN_LEFT_STEP, 0 ) );
paragraphTitleStep.setSpacingBefore( AppPropertiesService.getPropertyInt( PROPERTY_POLICE_SPACING_BEFORE_STEP, 0 ) );
paragraphTitleStep.setSpacingAfter( AppPropertiesService.getPropertyInt( PROPERTY_POLICE_SPACING_AFTER_STEP, 0 ) );
addElementToDocument( document, paragraphTitleStep );
}
for ( FormQuestionResponse formQuestionResponseOfStep : listFormQuestionResponseOfStep )
{
// Print the question
Question questionOfStep = QuestionHome.findByPrimaryKey( formQuestionResponseOfStep.getQuestion( ).getId( ) );
if ( listIdEntryConfig.isEmpty( ) || listIdEntryConfig.contains( questionOfStep.getId( ) ) )
{
Font fontQuestionTitle = new Font( AppPropertiesService.getPropertyInt( PROPERTY_POLICE_NAME, 0 ),
AppPropertiesService.getPropertyInt( PROPERTY_POLICE_SIZE_QUESTION, 0 ),
AppPropertiesService.getPropertyInt( PROPERTY_POLICE_STYLE_QUESTION, 0 ) );
Paragraph paragraphTitleQuestion = new Paragraph( new Phrase( questionOfStep.getTitle( ), fontQuestionTitle ) );
paragraphTitleQuestion.setAlignment( Element.ALIGN_LEFT );
paragraphTitleQuestion.setIndentationLeft( AppPropertiesService.getPropertyInt( PROPERTY_POLICE_MARGIN_LEFT_QUESTION, 0 ) );
paragraphTitleQuestion.setSpacingBefore( AppPropertiesService.getPropertyInt( PROPERTY_POLICE_SPACING_BEFORE_QUESTION, 0 ) );
paragraphTitleQuestion.setSpacingAfter( AppPropertiesService.getPropertyInt( PROPERTY_POLICE_SPACING_AFTER_QUESTION, 0 ) );
addElementToDocument( document, paragraphTitleQuestion );
// Print the responses
Font fontResponse = new Font( AppPropertiesService.getPropertyInt( PROPERTY_POLICE_NAME, 0 ),
AppPropertiesService.getPropertyInt( PROPERTY_POLICE_SIZE_RESPONSE, 0 ),
AppPropertiesService.getPropertyInt( PROPERTY_POLICE_STYLE_RESPONSE, 0 ) );
if ( formQuestionResponseOfStep.getEntryResponse( ).size( ) == 1 )
{
// One element, build a paragraph
String strValue = EntryTypeServiceManager.getEntryTypeService( questionOfStep.getEntry( ) ).getResponseValueForRecap(
questionOfStep.getEntry( ), null, formQuestionResponseOfStep.getEntryResponse( ).get( 0 ), Locale.FRENCH );
Paragraph paragraphResponse = new Paragraph( new Phrase( strValue, fontResponse ) );
paragraphResponse.setAlignment( Element.ALIGN_LEFT );
paragraphResponse.setIndentationLeft( AppPropertiesService.getPropertyInt( PROPERTY_POLICE_MARGIN_LEFT_RESPONSE, 0 ) );
paragraphResponse.setSpacingBefore( AppPropertiesService.getPropertyInt( PROPERTY_POLICE_SPACING_BEFORE_RESPONSE, 0 ) );
paragraphResponse.setSpacingAfter( AppPropertiesService.getPropertyInt( PROPERTY_POLICE_SPACING_AFTER_RESPONSE, 0 ) );
addElementToDocument( document, paragraphResponse );
}
else
{
com.lowagie.text.List listValue = new com.lowagie.text.List( true );
listValue.setPreSymbol( "- " );
listValue.setNumbered( false );
listValue.setIndentationLeft( AppPropertiesService.getPropertyInt( PROPERTY_POLICE_MARGIN_LEFT_RESPONSE, 0 ) );
// If many elements, build a list
for ( Response response : formQuestionResponseOfStep.getEntryResponse( ) )
{
String strValue = EntryTypeServiceManager.getEntryTypeService( questionOfStep.getEntry( ) )
.getResponseValueForRecap( questionOfStep.getEntry( ), null, response, Locale.FRENCH );
listValue.add( new ListItem( strValue, fontResponse ) );
}
addElementToDocument( document, listValue );
}
}
}
}
}
/**
* Method to download a PDF file generated by forms record
*
* @param request
* request
* @param response
* response
* @param plugin
* plugin
* @param configProducer
* configuration
* @param listIdQuestionConfig
* @param locale
* locale
*/
public static void doDownloadPDF( HttpServletRequest request, HttpServletResponse response, Plugin plugin, IConfigProducer configProducer,
List<Integer> listIdQuestionConfig, Locale locale, int nIdFormResponse )
{
FormResponse formResponse = FormResponseHome.findByPrimaryKey( nIdFormResponse );
Form forms = FormHome.findByPrimaryKey( formResponse.getFormId( ) );
String strName = getFileNameFromConfig( forms, configProducer, nIdFormResponse );
String strFileName = doPurgeNameFile( strName ) + ".pdf";
response.setHeader( "Content-Disposition", "attachment ;filename=\"" + strFileName + "\"" );
response.setHeader( "Pragma", "public" );
response.setHeader( "Expires", "0" );
response.setHeader( "Cache-Control", "must-revalidate,post-check=0,pre-check=0" );
response.setContentType( "application/pdf" );
try ( OutputStream os = response.getOutputStream( ) )
{
if ( listIdQuestionConfig == null )
{
listIdQuestionConfig = new ArrayList<>( );
}
doCreateDocumentPDF( os, nIdFormResponse, listIdQuestionConfig );
}
catch( IOException e )
{
AppLogService.error( e );
}
}
private static String getFileNameFromConfig( Form form, IConfigProducer configProducer, int nIdRecord )
{
String strTypeConfigFileName = configProducer.getTypeConfigFileName( );
if ( strTypeConfigFileName.equals( DEFAULT_TYPE_FILE_NAME ) )
{
return StringUtil.replaceAccent( form.getTitle( ) ).replace( " ", "_" ) + "_" + nIdRecord;
}
if ( strTypeConfigFileName.equals( TEXT_TYPE_FILE_NAME ) )
{
return StringUtil.replaceAccent( configProducer.getTextFileName( ) + "_" + nIdRecord );
}
if ( strTypeConfigFileName.equals( FORM_QUESTION_TYPE_FILE_NAME ) )
{
FormQuestionResponse formQuestionResponse = FormQuestionResponseHome
.findFormQuestionResponseByResponseQuestion( nIdRecord, configProducer.getIdQuestionFileName( ) ).get( 0 );
if ( formQuestionResponse != null )
{
return formQuestionResponse.getEntryResponse( ).get( 0 ).getResponseValue( );
}
}
return null;
}
/**
* Method to purge file name, (replace accent and punctuation)
*
* @param strNameFile
* name file
* @return purged name file
*/
public static String doPurgeNameFile( String strNameFile )
{
return StringUtil.replaceAccent( strNameFile ).replaceAll( "\\W", "_" );
}
private static void addElementToDocument( Document document, Element element )
{
try
{
document.add( element );
}
catch( DocumentException e )
{
AppLogService.error( e );
}
}
}