View Javadoc
1   /*
2    * Copyright (c) 2002-2022, City of Paris
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    *  1. Redistributions of source code must retain the above copyright notice
10   *     and the following disclaimer.
11   *
12   *  2. Redistributions in binary form must reproduce the above copyright notice
13   *     and the following disclaimer in the documentation and/or other materials
14   *     provided with the distribution.
15   *
16   *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17   *     contributors may be used to endorse or promote products derived from
18   *     this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   *
32   * License 1.0
33   */
34  package fr.paris.lutece.portal.service.editor;
35  
36  import fr.paris.lutece.portal.business.editor.ParserComplexElement;
37  import fr.paris.lutece.portal.business.editor.ParserElement;
38  import fr.paris.lutece.portal.service.util.AppLogService;
39  import fr.paris.lutece.portal.service.util.AppPropertiesService;
40  import fr.paris.lutece.util.parser.BbcodeUtil;
41  
42  import org.apache.commons.lang3.StringUtils;
43  import org.jsoup.Jsoup;
44  import org.jsoup.safety.Safelist;
45  
46  import java.util.ArrayList;
47  import java.util.List;
48  
49  /**
50   *
51   * This class Provides a parser BBCODE
52   *
53   */
54  public class EditorBbcodeService implements IEditorBbcodeService
55  {
56      /** Constants **/
57      private static final String CONSTANT_EDITOR_BBCODE_ELEMENT_CODE = "code";
58      private static final String CONSTANT_EDITOR_BBCODE_ELEMENT_VALUE = "value";
59      private static final String CONSTANT_EDITOR_BBCODE_COMPLEX_ELEMENT_TAG_NAME = "tagName";
60      private static final String CONSTANT_EDITOR_BBCODE_COMPLEX_ELEMENT_OPEN_SUBST_WITH_PARAM = "openSubstWithParam";
61      private static final String CONSTANT_EDITOR_BBCODE_COMPLEX_ELEMENT_CLOSE_SUBST_WITH_PARAM = "closeSubstWithParam";
62      private static final String CONSTANT_EDITOR_BBCODE_COMPLEX_ELEMENT_OPEN_SUBST_WITHOUT_PARAM = "openSubstWithoutParam";
63      private static final String CONSTANT_EDITOR_BBCODE_COMPLEX_ELEMENT_CLOSE_SUBST_WITHOUT_PARAM = "closeSubstWithoutParam";
64      private static final String CONSTANT_EDITOR_BBCODE_COMPLEX_ELEMENT_INTERNAL_SUBST = "internalSubst";
65      private static final String CONSTANT_EDITOR_BBCODE_COMPLEX_ELEMENT_PROCESS_INTERNAL_TAGS = "processInternalTags";
66      private static final String CONSTANT_EDITOR_BBCODE_COMPLEX_ELEMENT_ACCEPT_PARAM = "acceptParam";
67      private static final String CONSTANT_EDITOR_BBCODE_COMPLEX_ELEMENT_REQUIRES_QUOTED_PARAM = "requiresQuotedParam";
68  
69      /** Properties **/
70      private static final String PROPERTY_EDITOR_BBCODE_COMPLEX_ELEMENT_PATH = "editors.parser.bbcode.complexElement";
71      private static final String PROPERTY_EDITOR_BBCODE_ELEMENT_PATH = "editors.parser.bbcode.element";
72      private static final String PROPERTY_PARSER_ELEMENTS = "editors.parser.bbcode.elements";
73      private static final String PROPERTY_PARSER_COMPLEX_ELEMENTS = "editors.parser.bbcode.complexElements";
74      private static final String SEPARATOR = ",";
75      private static EditorBbcodeService _singleton;
76      private static List<ParserElement> _listParserElement;
77      private static List<ParserComplexElement> _listParserComplexElement;
78  
79      /**
80       * {@inheritDoc}
81       */
82      @Override
83      public String parse( String strValue )
84      {
85      	try {
86              // Parse BBCode and clean HTML using Jsoup with basic whitelisting of tags and attributes
87              return Jsoup.clean(BbcodeUtil.parse(strValue, _listParserElement, _listParserComplexElement),
88                      Safelist.basicWithImages());
89  
90          } catch (Exception e) {
91              // Handle any exceptions that might occur during parsing or cleaning
92              // Log the error and return an appropriate error message or fallback value
93              AppLogService.error("Error occurred while parsing and cleaning the input string", e);
94              return "Error occurred during processing. Please try again later.";
95          }
96      }
97      /**
98       * {@inheritDoc}
99       */
100     @Override
101     public String parseAndClean( String strValue, Safelist safelist )
102     {
103     	try {
104             // Parse BBCode and clean HTML using Jsoup with the provided Safelist
105             return Jsoup.clean(BbcodeUtil.parse(strValue, _listParserElement, _listParserComplexElement), safelist);
106 
107         } catch (Exception e) {
108             // Handle any exceptions that might occur during parsing or cleaning
109             // Log the error and return an appropriate error message or fallback value
110             AppLogService.error("Error occurred while parsing and cleaning the input string", e);
111             return "Error occurred during processing. Please try again later.";
112         }    
113     }
114 
115     /**
116      * Returns the unique instance of the service
117      * 
118      * @return The instance of the service
119      */
120     public static synchronized EditorBbcodeService getInstance( )
121     {
122         if ( _singleton == null )
123         {
124             _listParserElement = new ArrayList<>( );
125             _listParserComplexElement = new ArrayList<>( );
126             EditorBbcodeServicer/EditorBbcodeService.html#EditorBbcodeService">EditorBbcodeService service = new EditorBbcodeService( );
127             service.init( );
128             _singleton = service;
129         }
130 
131         return _singleton;
132     }
133 
134     /**
135      * Init service
136      */
137     public void init( )
138     {
139         // init simple elements
140         String strParserElements = AppPropertiesService.getProperty( PROPERTY_PARSER_ELEMENTS );
141 
142         if ( StringUtils.isNotBlank( strParserElements ) )
143         {
144             String [ ] tabParserElements = strParserElements.split( SEPARATOR );
145             String strCodeElement;
146             String strValueElement;
147 
148             for ( int i = 0; i < tabParserElements.length; i++ )
149             {
150                 strCodeElement = AppPropertiesService
151                         .getProperty( PROPERTY_EDITOR_BBCODE_ELEMENT_PATH + "." + tabParserElements [i] + "." + CONSTANT_EDITOR_BBCODE_ELEMENT_CODE );
152                 strValueElement = AppPropertiesService
153                         .getProperty( PROPERTY_EDITOR_BBCODE_ELEMENT_PATH + "." + tabParserElements [i] + "." + CONSTANT_EDITOR_BBCODE_ELEMENT_VALUE );
154                 _listParserElement.add( new ParserElement( strCodeElement, strValueElement ) );
155             }
156         }
157 
158         // init complex elements
159         String strParserComplexElements = AppPropertiesService.getProperty( PROPERTY_PARSER_COMPLEX_ELEMENTS );
160 
161         if ( StringUtils.isNotBlank( strParserComplexElements ) )
162         {
163             String [ ] tabParserComplexElements = strParserComplexElements.split( SEPARATOR );
164             String strTagName;
165             String strOpenSubstWithParam;
166             String strCloseSubstWithParam;
167             String strOpenSubstWithoutParam;
168             String strCloseSubstWithoutParam;
169             String strInternalSubst;
170             boolean bProcessInternalTags;
171             boolean bAcceptParam;
172             boolean bRequiresQuotedParam;
173 
174             for ( int i = 0; i < tabParserComplexElements.length; i++ )
175             {
176                 strTagName = AppPropertiesService.getProperty( PROPERTY_EDITOR_BBCODE_COMPLEX_ELEMENT_PATH + "." + tabParserComplexElements [i] + "."
177                         + CONSTANT_EDITOR_BBCODE_COMPLEX_ELEMENT_TAG_NAME );
178                 strOpenSubstWithParam = AppPropertiesService.getProperty( PROPERTY_EDITOR_BBCODE_COMPLEX_ELEMENT_PATH + "." + tabParserComplexElements [i] + "."
179                         + CONSTANT_EDITOR_BBCODE_COMPLEX_ELEMENT_OPEN_SUBST_WITH_PARAM );
180                 strCloseSubstWithParam = AppPropertiesService.getProperty( PROPERTY_EDITOR_BBCODE_COMPLEX_ELEMENT_PATH + "." + tabParserComplexElements [i]
181                         + "." + CONSTANT_EDITOR_BBCODE_COMPLEX_ELEMENT_CLOSE_SUBST_WITH_PARAM );
182                 strOpenSubstWithoutParam = AppPropertiesService.getProperty( PROPERTY_EDITOR_BBCODE_COMPLEX_ELEMENT_PATH + "." + tabParserComplexElements [i]
183                         + "." + CONSTANT_EDITOR_BBCODE_COMPLEX_ELEMENT_OPEN_SUBST_WITHOUT_PARAM );
184                 strCloseSubstWithoutParam = AppPropertiesService.getProperty( PROPERTY_EDITOR_BBCODE_COMPLEX_ELEMENT_PATH + "." + tabParserComplexElements [i]
185                         + "." + CONSTANT_EDITOR_BBCODE_COMPLEX_ELEMENT_CLOSE_SUBST_WITHOUT_PARAM );
186                 strInternalSubst = AppPropertiesService.getProperty( PROPERTY_EDITOR_BBCODE_COMPLEX_ELEMENT_PATH + "." + tabParserComplexElements [i] + "."
187                         + CONSTANT_EDITOR_BBCODE_COMPLEX_ELEMENT_INTERNAL_SUBST );
188                 bProcessInternalTags = AppPropertiesService.getPropertyBoolean( PROPERTY_EDITOR_BBCODE_COMPLEX_ELEMENT_PATH + "." + tabParserComplexElements [i]
189                         + "." + CONSTANT_EDITOR_BBCODE_COMPLEX_ELEMENT_PROCESS_INTERNAL_TAGS, false );
190                 bAcceptParam = AppPropertiesService.getPropertyBoolean( PROPERTY_EDITOR_BBCODE_COMPLEX_ELEMENT_PATH + "." + tabParserComplexElements [i] + "."
191                         + CONSTANT_EDITOR_BBCODE_COMPLEX_ELEMENT_ACCEPT_PARAM, false );
192                 bRequiresQuotedParam = AppPropertiesService.getPropertyBoolean( PROPERTY_EDITOR_BBCODE_COMPLEX_ELEMENT_PATH + "." + tabParserComplexElements [i]
193                         + "." + CONSTANT_EDITOR_BBCODE_COMPLEX_ELEMENT_REQUIRES_QUOTED_PARAM, false );
194 
195                 _listParserComplexElement.add( new ParserComplexElement( strTagName, strOpenSubstWithParam, strCloseSubstWithParam, strOpenSubstWithoutParam,
196                         strCloseSubstWithoutParam, strInternalSubst, bProcessInternalTags, bAcceptParam, bRequiresQuotedParam ) );
197             }
198         }
199     }
200 }