View Javadoc
1   /*
2    * Copyright (c) 2002-2014, Mairie de 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.plugins.directory.modules.rest.service.formatters;
35  
36  import fr.paris.lutece.plugins.directory.business.Directory;
37  import fr.paris.lutece.plugins.directory.business.Field;
38  import fr.paris.lutece.plugins.directory.business.IEntry;
39  import fr.paris.lutece.plugins.directory.business.Record;
40  import fr.paris.lutece.plugins.directory.business.RecordField;
41  import fr.paris.lutece.plugins.directory.modules.rest.service.IDirectoryRestService;
42  import fr.paris.lutece.plugins.directory.modules.rest.util.constants.DirectoryRestConstants;
43  import fr.paris.lutece.plugins.directory.utils.DirectoryUtils;
44  import fr.paris.lutece.plugins.rest.business.resourceinfo.IResourceInfo;
45  import fr.paris.lutece.plugins.rest.service.formatters.IFormatter;
46  import fr.paris.lutece.plugins.rest.service.resourceinfo.ResourceInfoManager;
47  import fr.paris.lutece.plugins.rest.util.xml.XMLUtil;
48  import fr.paris.lutece.portal.service.i18n.I18nService;
49  import fr.paris.lutece.portal.service.util.AppLogService;
50  import fr.paris.lutece.portal.service.util.AppPropertiesService;
51  import fr.paris.lutece.util.xml.XmlUtil;
52  
53  import freemarker.template.utility.StringUtil;
54  
55  import org.apache.commons.lang.StringUtils;
56  
57  import java.util.HashMap;
58  import java.util.List;
59  import java.util.Locale;
60  import java.util.Map;
61  
62  import javax.inject.Inject;
63  
64  
65  /**
66   *
67   * Format record output to the XML format
68   * Example of the formatted record XML :
69   * <br />
70   * <code>
71   * <Response>
72   *                 <Status>SUCCESS</Status>
73   *                 <Records>
74   *                         <Record>
75   *                                 <Id>1</Id>
76   *                                 <state>
77   *                                         <id-state>1</id-state>
78   *                                         <name>state1</name>
79   *                                         <description>State 1</name>
80   *                                         <id-workflow>1</id-workflow>
81   *                                         <is-initial-state>true</is-initial-state>
82   *                                         <is-required-workgroup>false</is-required-workgroup>
83   *                                 </state>
84   *                                 <RecordFields>
85   *                                         <recordFieldTitleTypeText1>recordFieldValue1</recordFieldTitleTypeText1>
86   *                                         <recordFieldTitleTypeSelect1>
87   *                                                 <choice1>value1</choice1>
88   *                                                 <choice2>value2</choice2>
89   *                                         </recordFieldTitleTypeSelect1>
90   *                                 </RecordFields>
91   *                         <Record>
92   *                 </Records>
93   * </Response>
94   * </code>
95   */
96  public class RecordFormatterXml implements IFormatter<Record>
97  {
98      @Inject
99      private IDirectoryRestService _directoryRestService;
100     private Locale _locale = I18nService.getDefaultLocale(  );
101 
102     /**
103      * {@inheritDoc}
104      */
105     @Override
106     public String formatError( String strCode, String strMessage )
107     {
108         return XMLUtil.formatError( strMessage, DirectoryUtils.convertStringToInt( strCode ) );
109     }
110 
111     /**
112      * {@inheritDoc }
113      */
114     @Override
115     public String format( Record record )
116     {
117         StringBuffer sbXml = new StringBuffer( AppPropertiesService.getProperty( XmlUtil.PROPERTIES_XML_HEADER ) );
118         XmlUtil.beginElement( sbXml, DirectoryRestConstants.TAG_RESPONSE );
119         XmlUtil.addElement( sbXml, DirectoryRestConstants.TAG_STATUS, DirectoryRestConstants.STATUS_SUCCESS );
120 
121         formatRecord( sbXml, record );
122 
123         XmlUtil.endElement( sbXml, DirectoryRestConstants.TAG_RESPONSE );
124 
125         return sbXml.toString(  );
126     }
127 
128     /**
129      * {@inheritDoc}
130      */
131     @Override
132     public String format( List<Record> listRecords )
133     {
134         StringBuffer sbXml = new StringBuffer( AppPropertiesService.getProperty( XmlUtil.PROPERTIES_XML_HEADER ) );
135         XmlUtil.beginElement( sbXml, DirectoryRestConstants.TAG_RESPONSE );
136         XmlUtil.addElement( sbXml, DirectoryRestConstants.TAG_STATUS, DirectoryRestConstants.STATUS_SUCCESS );
137         XmlUtil.beginElement( sbXml, DirectoryRestConstants.TAG_RECORDS );
138 
139         for ( Record record : listRecords )
140         {
141             formatRecord( sbXml, record );
142         }
143 
144         XmlUtil.endElement( sbXml, DirectoryRestConstants.TAG_RECORDS );
145         XmlUtil.endElement( sbXml, DirectoryRestConstants.TAG_RESPONSE );
146 
147         return sbXml.toString(  );
148     }
149 
150     /**
151      * Format the record.
152      * Example of a formatted record XML :
153      * <br />
154      * <code>
155      * <Record>
156      *                 <Id>1</Id>
157      *                 <state>
158      *                         <id-state>1</id-state>
159      *                         <name>state1</name>
160      *                         <description>State 1</name>
161      *                         <id-workflow>1</id-workflow>
162      *                         <is-initial-state>true</is-initial-state>
163      *                         <is-required-workgroup>false</is-required-workgroup>
164      *                 </state>
165      *                 <RecordFields>
166      *                         <recordFieldTitleTypeText1>recordFieldValue1</recordFieldTitleTypeText1>
167      *                         <recordFieldTitleTypeSelect1>
168      *                                 <choice1>value1</choice1>
169      *                                 <choice2>value2</choice2>
170      *                         </recordFieldTitleTypeSelect1>
171      *                 </RecordFields>
172      * <Record>
173      * </code>
174      * @param sbXml the XML
175      * @param record the record to format
176      */
177     private void formatRecord( StringBuffer sbXml, Record record )
178     {
179         XmlUtil.beginElement( sbXml, DirectoryRestConstants.TAG_RECORD );
180         XmlUtil.addElement( sbXml, DirectoryRestConstants.TAG_ID, record.getIdRecord(  ) );
181 
182         // Put the resource info
183         formatResourceInfo( sbXml, record );
184 
185         /*
186         Plugin pluginDirectory = PluginService.getPlugin( DirectoryPlugin.PLUGIN_NAME );
187         List<IEntry> listEntries = _directoryRestService.getEntries( record.getDirectory(  ).getIdDirectory(  ) );
188         Map<String, List<RecordField>> mapIdsEntryListRecordFields = DirectoryUtils.getMapIdEntryListRecordField( listEntries,
189                 record.getIdRecord(  ), pluginDirectory );
190                 */
191         List<IEntry> listEntries = _directoryRestService.getEntries( record );
192         Map<String, List<RecordField>> mapIdsEntryListRecordFields = _directoryRestService.getMapIdEntryListRecordField( record );
193 
194         XmlUtil.beginElement( sbXml, DirectoryRestConstants.TAG_RECORD_FIELDS );
195 
196         for ( IEntry entry : listEntries )
197         {
198             if ( entry.getEntryType(  ).getGroup(  ) )
199             {
200                 if ( ( entry.getChildren(  ) != null ) && !entry.getChildren(  ).isEmpty(  ) )
201                 {
202                     String strTag = fr.paris.lutece.util.string.StringUtil.replaceAccent( entry.getTitle(  ) );
203                     XmlUtil.beginElement( sbXml, strTag );
204 
205                     for ( IEntry entryChild : entry.getChildren(  ) )
206                     {
207                         sbXml.append( getEntryXml( entryChild, mapIdsEntryListRecordFields ) );
208                     }
209 
210                     XmlUtil.endElement( sbXml, strTag );
211                 }
212             }
213             else
214             {
215                 sbXml.append( getEntryXml( entry, mapIdsEntryListRecordFields ) );
216             }
217         }
218 
219         XmlUtil.endElement( sbXml, DirectoryRestConstants.TAG_RECORD_FIELDS );
220         XmlUtil.endElement( sbXml, DirectoryRestConstants.TAG_RECORD );
221     }
222 
223     /**
224      * Get the entry XML
225      * Example of the formatted XML for entry type with mltiple choices :
226      * <br />
227      * <code>
228      * <recordFieldTitleTypeSelect1>
229      *                 <choice1>value1</choice1>
230      *                 <choice2>value2</choice2>
231      * </recordFieldTitleTypeSelect1>
232      * </code>
233      * <br />
234      * Example of the formatted XML for other entry types :
235      * <br/>
236      * <code>
237      * <recordFieldTitleTypeText1>recordFieldValue1</recordFieldTitleTypeText1>
238      * </code>
239      * @param entry the entry
240      * @param mapIdsEntryListRecordFields the map ids entry - list record fields
241      * @return the entry XML
242      */
243     private String getEntryXml( IEntry entry, Map<String, List<RecordField>> mapIdsEntryListRecordFields )
244     {
245         StringBuffer sbXml = new StringBuffer(  );
246 
247         if ( entry != null )
248         {
249             List<RecordField> listRecordFields = mapIdsEntryListRecordFields.get( Integer.toString( 
250                         entry.getIdEntry(  ) ) );
251 
252             if ( ( listRecordFields != null ) && !listRecordFields.isEmpty(  ) )
253             {
254                 String strTag = fr.paris.lutece.util.string.StringUtil.replaceAccent( entry.getTitle(  ) );
255 
256                 if ( entry instanceof fr.paris.lutece.plugins.directory.business.EntryTypeCheckBox ||
257                         entry instanceof fr.paris.lutece.plugins.directory.business.EntryTypeSelect )
258                 {
259                     // Multi choices => multi tags
260                     for ( RecordField recordField : listRecordFields )
261                     {
262                         XmlUtil.beginElement( sbXml, strTag );
263                         sbXml.append( getRecordFieldXml( entry, recordField ) );
264                         XmlUtil.endElement( sbXml, strTag );
265                     }
266                 }
267                 else
268                 {
269                     XmlUtil.beginElement( sbXml, strTag );
270 
271                     for ( RecordField recordField : listRecordFields )
272                     {
273                         sbXml.append( getRecordFieldXml( entry, recordField ) );
274                     }
275 
276                     XmlUtil.endElement( sbXml, strTag );
277                 }
278             }
279         }
280 
281         return sbXml.toString(  );
282     }
283 
284     /**
285      * Get the record field XML
286      * Example of the formatted XML for entry type Image (display the ID of the file) :
287      * <br />
288      * <code>
289      * <Id>1</Id>
290      * <Width>100</Width>
291      * <Height>100</Height>
292      * </code>
293      * <br />
294      * Example of the formatted XML for entry type File (display the ID of the file) :
295      * <br />
296      * <code>
297      * <Id>1</Id>
298      * </code>
299      * <br />
300      * Example of the formatted XML for other entry types :
301      * <br />
302      * <code>
303      * <choice1>value1</choice1>
304      * </code>
305      * @param entry the entry
306      * @param recordField the record field
307      * @return the XML of the record field
308      */
309     private String getRecordFieldXml( IEntry entry, RecordField recordField )
310     {
311         StringBuffer sbXml = new StringBuffer(  );
312 
313         if ( recordField != null )
314         {
315             if ( entry instanceof fr.paris.lutece.plugins.directory.business.EntryTypeImg )
316             {
317                 Field field = recordField.getField(  );
318 
319                 if ( field != null )
320                 {
321                     XmlUtil.beginElement( sbXml, field.getValue(  ) );
322 
323                     // For Entry type Image, we put the ID file instead of the ID of the record field
324                     if ( recordField.getFile(  ) != null )
325                     {
326                         XmlUtil.addElement( sbXml, DirectoryRestConstants.TAG_ID, recordField.getFile(  ).getIdFile(  ) );
327                     }
328 
329                     if ( ( field.getWidth(  ) != 0 ) && ( field.getHeight(  ) != 0 ) )
330                     {
331                         XmlUtil.addElement( sbXml, DirectoryRestConstants.TAG_WIDTH, field.getWidth(  ) );
332                         XmlUtil.addElement( sbXml, DirectoryRestConstants.TAG_HEIGHT, field.getHeight(  ) );
333                     }
334 
335                     XmlUtil.endElement( sbXml, field.getValue(  ) );
336                 }
337             }
338             else if ( entry instanceof fr.paris.lutece.plugins.directory.business.EntryTypeFile )
339             {
340                 // For Entry type File, we put the ID file
341                 if ( recordField.getFile(  ) != null )
342                 {
343                     XmlUtil.addElement( sbXml, DirectoryRestConstants.TAG_ID, recordField.getFile(  ).getIdFile(  ) );
344                 }
345             }
346             else if ( entry instanceof fr.paris.lutece.plugins.directory.business.EntryTypeCheckBox ||
347                     entry instanceof fr.paris.lutece.plugins.directory.business.EntryTypeSelect ||
348                     entry instanceof fr.paris.lutece.plugins.directory.business.EntryTypeRadioButton )
349             {
350                 sbXml.append( StringUtil.XMLEnc( entry.convertRecordFieldTitleToString( recordField, _locale, false ) ) );
351             }
352             else if ( entry instanceof fr.paris.lutece.plugins.directory.business.EntryTypeGeolocation )
353             {
354                 Field field = recordField.getField(  );
355 
356                 if ( ( field != null ) && StringUtils.isNotBlank( field.getTitle(  ) ) )
357                 {
358                     XmlUtil.addElement( sbXml, field.getTitle(  ),
359                         entry.convertRecordFieldValueToString( recordField, _locale, false, false ) );
360                 }
361             }
362             else
363             {
364                 sbXml.append( StringUtil.XMLEnc( entry.convertRecordFieldValueToString( recordField, _locale, false,
365                             false ) ) );
366             }
367         }
368         else
369         {
370             if ( AppLogService.isDebugEnabled(  ) )
371             {
372                 AppLogService.debug( "Record field is null for entry " + entry.getTitle(  ) + " (" +
373                     entry.getIdEntry(  ) + ")" );
374             }
375         }
376 
377         return sbXml.toString(  );
378     }
379 
380     /**
381      * Format the resource info
382      * Example of the formatted resource info XML :
383      * <br />
384      * <code>
385      * <state>
386          *                 <id-state>1</id-state>
387          *                 <name>state1</name>
388          *                 <description>State 1</name>
389          *                 <id-workflow>1</id-workflow>
390          *                 <is-initial-state>true</is-initial-state>
391          *                 <is-required-workgroup>false</is-required-workgroup>
392          * </state>
393          * <resourceInfo2>
394          *                 <data>someData</data>
395          *                 ...
396          * </resourceInfo2>
397          * ...
398      * </code>
399      * @param sbXml the XML
400      * @param record the record
401      */
402     private void formatResourceInfo( StringBuffer sbXml, Record record )
403     {
404         Directory directory = _directoryRestService.getDirectory( record.getDirectory(  ).getIdDirectory(  ) );
405         Map<String, String> mapParams = new HashMap<String, String>(  );
406         mapParams.put( DirectoryRestConstants.PARAMETER_ID_RESOURCE, Integer.toString( record.getIdRecord(  ) ) );
407         mapParams.put( DirectoryRestConstants.PARAMETER_RESOURCE_TYPE, Record.WORKFLOW_RESOURCE_TYPE );
408         mapParams.put( DirectoryRestConstants.PARAMETER_ID_WORKFLOW, Integer.toString( directory.getIdWorkflow(  ) ) );
409 
410         List<IResourceInfo> listResourceInfos = ResourceInfoManager.getResourceInfo( mapParams );
411 
412         if ( ( listResourceInfos != null ) && !listResourceInfos.isEmpty(  ) )
413         {
414             for ( IResourceInfo resourceInfo : listResourceInfos )
415             {
416                 formatResourceInfo( sbXml, resourceInfo );
417             }
418         }
419     }
420 
421     /**
422      * Format the resource info
423      * Example of the formatted resource info XML :
424      * <br />
425      * <code>
426      * <state>
427          *                 <id-state>1</id-state>
428          *                 <name>state1</name>
429          *                 <description>State 1</name>
430          *                 <id-workflow>1</id-workflow>
431          *                 <is-initial-state>true</is-initial-state>
432          *                 <is-required-workgroup>false</is-required-workgroup>
433          * </state>
434      * </code>
435      * @param sbXml the XML
436      * @param resourceInfo the resource info
437      */
438     private void formatResourceInfo( StringBuffer sbXml, IResourceInfo resourceInfo )
439     {
440         if ( resourceInfo != null )
441         {
442             if ( resourceInfo.hasChildren(  ) )
443             {
444                 XmlUtil.beginElement( sbXml, resourceInfo.getKey(  ) );
445 
446                 for ( IResourceInfo child : resourceInfo.getListChildren(  ) )
447                 {
448                     formatResourceInfo( sbXml, child );
449                 }
450 
451                 XmlUtil.endElement( sbXml, resourceInfo.getKey(  ) );
452             }
453             else
454             {
455                 XmlUtil.addElement( sbXml, resourceInfo.getKey(  ), resourceInfo.getValue(  ) );
456             }
457         }
458     }
459 }