View Javadoc
1   /*
2    * Copyright (c) 2002-2017, 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.announce.modules.solr.search;
35  
36  import fr.paris.lutece.plugins.announce.business.Announce;
37  import fr.paris.lutece.plugins.announce.business.AnnounceHome;
38  import fr.paris.lutece.plugins.announce.business.AnnounceSort;
39  import fr.paris.lutece.plugins.announce.service.AnnouncePlugin;
40  import fr.paris.lutece.plugins.announce.service.announcesearch.AnnounceSearchItem;
41  import fr.paris.lutece.plugins.announce.utils.AnnounceUtils;
42  import fr.paris.lutece.plugins.search.solr.business.field.Field;
43  import fr.paris.lutece.plugins.search.solr.indexer.SolrIndexer;
44  import fr.paris.lutece.plugins.search.solr.indexer.SolrIndexerService;
45  import fr.paris.lutece.plugins.search.solr.indexer.SolrItem;
46  import fr.paris.lutece.plugins.search.solr.util.SolrConstants;
47  import fr.paris.lutece.portal.service.content.XPageAppService;
48  import fr.paris.lutece.portal.service.plugin.Plugin;
49  import fr.paris.lutece.portal.service.plugin.PluginService;
50  import fr.paris.lutece.portal.service.util.AppLogService;
51  import fr.paris.lutece.portal.service.util.AppPropertiesService;
52  import fr.paris.lutece.util.url.UrlItem;
53  
54  import org.apache.tika.exception.TikaException;
55  import org.apache.tika.metadata.Metadata;
56  import org.apache.tika.parser.ParseContext;
57  import org.apache.tika.parser.html.HtmlParser;
58  import org.apache.tika.sax.BodyContentHandler;
59  import org.xml.sax.ContentHandler;
60  import org.xml.sax.SAXException;
61  
62  import java.io.ByteArrayInputStream;
63  import java.io.IOException;
64  import java.io.InputStream;
65  import java.io.Reader;
66  import java.io.StringReader;
67  import java.nio.charset.StandardCharsets;
68  import java.util.ArrayList;
69  import java.util.List;
70  
71  
72  /**
73   * The Announce indexer for Solr search platform
74   */
75  public class SolrAnnounceIndexer implements SolrIndexer
76  {
77  
78      private static final String PARAMETER_ANNOUNCE_ID = "announce_id";
79  
80      private static final String PROPERTY_DESCRIPTION = "announce-solr.indexer.description";
81      private static final String PROPERTY_NAME = "announce-solr.indexer.name";
82      private static final String PROPERTY_VERSION = "announce-solr.indexer.version";
83      private static final String PROPERTY_INDEXER_ENABLE = "announce-solr.indexer.enable";
84      private static final String PROPERTY_TAGS_LABEL = "announce-solr.indexer.tags.label";
85      private static final String PROPERTY_TAGS_DESCRIPTION = "announce-solr.indexer.tags.description";
86      private static final String SHORT_NAME = "announce";
87  
88      private static final String BLANK = " ";
89      private static final List<String> LIST_RESSOURCES_NAME = new ArrayList<String>(  );
90  
91      private static final String ANNOUNCE_INDEXATION_ERROR = "[SolrAnnounceIndexer] An error occured during the indexation of the announce number ";
92      
93      /**
94       * Default constructor
95       */
96      public SolrAnnounceIndexer(  )
97      {
98          super(  );
99  
100         LIST_RESSOURCES_NAME.add( Announce.RESOURCE_TYPE );
101     }
102 
103     /**
104      * {@inheritDoc}
105      */
106     @Override
107     public String getDescription(  )
108     {
109         return AppPropertiesService.getProperty( PROPERTY_DESCRIPTION );
110     }
111 
112     /**
113      * {@inheritDoc}
114      */
115     @Override
116     public String getName(  )
117     {
118         return AppPropertiesService.getProperty( PROPERTY_NAME );
119     }
120 
121     /**
122      * {@inheritDoc}
123      */
124     @Override
125     public String getVersion(  )
126     {
127         return AppPropertiesService.getProperty( PROPERTY_VERSION );
128     }
129 
130     /**
131      * {@inheritDoc}
132      */
133     @Override
134     public List<String> indexDocuments(  )
135     {
136         Plugin plugin = PluginService.getPlugin( AnnouncePlugin.PLUGIN_NAME );
137 
138         List<String> lstErrors = new ArrayList<String>(  );
139         
140         // Announces
141         // Add SolrItem for each announce 
142         for ( Announce announce : AnnounceHome.findAllPublished( AnnounceSort.DEFAULT_SORT ) )
143         {
144         	try
145         	{
146         		if ( !announce.getSuspended(  ) && !announce.getSuspendedByUser(  ) )
147         		{
148         			UrlItem urlAnnounce = new UrlItem( SolrIndexerService.getBaseUrl(  ) );
149         			urlAnnounce.addParameter( XPageAppService.PARAM_XPAGE_APP,
150                             AppPropertiesService.getProperty( AnnounceUtils.PARAMETER_PAGE_ANNOUNCE ) );
151                     urlAnnounce.addParameter( PARAMETER_ANNOUNCE_ID, announce.getId( ) );
152 
153         			SolrItem item = getDocument( announce, urlAnnounce.getUrl(  ), plugin );
154         			SolrIndexerService.write( item );
155         		}
156         	}
157         	catch ( Exception e )
158         	{
159         		lstErrors.add( SolrIndexerService.buildErrorMessage( e ) );
160 				AppLogService.error( ANNOUNCE_INDEXATION_ERROR + announce.getId(  ), e );
161 			}
162         }
163         
164         return lstErrors;
165     }
166 
167     /**
168      * {@inheritDoc}
169      */
170     @Override
171     public boolean isEnable(  )
172     {
173         return "true".equalsIgnoreCase( AppPropertiesService.getProperty( PROPERTY_INDEXER_ENABLE ) );
174     }
175 
176     /**
177      * {@inheritDoc}
178      */
179     @Override
180     public List<Field> getAdditionalFields(  )
181     {
182         List<Field> fields = new ArrayList<Field>(  );
183         Field field = new Field(  );
184         field.setEnableFacet( false );
185         field.setName( AnnounceSearchItem.FIELD_TAGS );
186         field.setLabel( AppPropertiesService.getProperty( PROPERTY_TAGS_LABEL ) );
187         field.setDescription( AppPropertiesService.getProperty( PROPERTY_TAGS_DESCRIPTION ) );
188         fields.add( field );
189 
190         return fields;
191     }
192 
193     /**
194      * {@inheritDoc}
195      */
196     @Override
197     public List<SolrItem> getDocuments( String strDocument )
198     {
199         List<SolrItem> listDocs = new ArrayList<SolrItem>(  );
200         Plugin plugin = PluginService.getPlugin( AnnouncePlugin.PLUGIN_NAME );
201 
202         for ( Announce announce : AnnounceHome.findAllPublished( AnnounceSort.DEFAULT_SORT ) )
203         {
204             if ( !announce.getSuspended(  ) && !announce.getSuspendedByUser(  ) )
205             {
206                 UrlItem urlAnnounce = new UrlItem( SolrIndexerService.getBaseUrl(  ) );
207                 urlAnnounce.addParameter( XPageAppService.PARAM_XPAGE_APP, AnnounceUtils.PARAMETER_PAGE_ANNOUNCE ); //FIXME
208                 urlAnnounce.addParameter( PARAMETER_ANNOUNCE_ID, announce.getId( ) );
209 
210                 SolrItem docAnnounce;
211 
212                 try
213                 {
214                     docAnnounce = getDocument( announce, urlAnnounce.getUrl(  ), plugin );
215                     listDocs.add( docAnnounce );
216                 }
217                 catch ( Exception e )
218                 {
219                     throw new RuntimeException(  );
220                 }
221             }
222         }
223 
224         return listDocs;
225     }
226 
227     /**
228      * Builds a document which will be used by Lucene during the indexing of the announces list
229      * @param announce the announce
230      * @param strUrl the url
231      * @param plugin the plugin
232      * @throws java.io.IOException I/O exceiption
233      * @throws java.lang.InterruptedException interrupted exception
234      * @return the document
235      */
236     private SolrItem getDocument( Announce announce, String strUrl, Plugin plugin )
237         throws IOException, InterruptedException
238     {
239         // make a new, empty document
240         SolrItem item = new SolrItem(  );
241 
242         // Setting the Categorie field
243         List<String> categories = new ArrayList<String>(  );
244         categories.add( announce.getCategory(  ).getLabel(  ) );
245         item.setCategorie( categories );
246 
247         // Setting the tags list
248         item.addDynamicField( AnnounceSearchItem.FIELD_TAGS, announce.getTags( ) );
249 
250         // Setting the URL field
251         item.setUrl( strUrl );
252 
253         // Setting the Uid field
254         item.setUid( getResourceUid( String.valueOf( announce.getId( ) ), Announce.RESOURCE_TYPE ) );
255 
256         // Setting the Date field
257         item.setDate( announce.getDateCreation(  ) );
258 
259         // Setting the Content field
260         String strContentToIndex = getContentToIndex( announce, plugin );
261 
262         HtmlParser parser = new HtmlParser(  );
263         ContentHandler handler = new BodyContentHandler();
264         Metadata metadata = new Metadata();
265         InputStream stream = new ByteArrayInputStream(strContentToIndex.getBytes(StandardCharsets.UTF_8));
266         try {
267 			parser.parse(stream,  handler, metadata, new ParseContext());
268 		} catch (SAXException e) {
269 			e.printStackTrace();
270 		} catch (TikaException e) {
271 			e.printStackTrace();
272 		}
273 
274         
275         item.setContent( handler.toString(  ) );
276 
277         // Setting the Title field
278         item.setTitle( announce.getTitle(  ) );
279 
280         // Setting the Site field
281         item.setSite( SolrIndexerService.getWebAppName(  ) );
282 
283         // Setting the Type field
284         item.setType( AnnouncePlugin.PLUGIN_NAME );
285 
286         // return the item
287         return item;
288     }
289 
290     /**
291      * Set the Content to index (Question and Answer)
292      * @param questionAnswer The {@link QuestionAnswer} to index
293      * @param plugin The {@link Plugin}
294      * @return The content to index
295      */
296     private static String getContentToIndex( Announce announce, Plugin plugin )
297     {
298         StringBuffer sbContentToIndex = new StringBuffer(  );
299         //Do not index question here
300         sbContentToIndex.append( announce.getTitle(  ) );
301         sbContentToIndex.append( BLANK );
302         sbContentToIndex.append( announce.getDescription(  ) );
303         sbContentToIndex.append( BLANK );
304         sbContentToIndex.append( announce.getTags(  ) );
305 
306         return sbContentToIndex.toString(  );
307     }
308 
309     /**
310      * {@inheritDoc}
311      */
312     @Override
313     public String getResourceUid( String strResourceId, String strResourceType )
314     {
315     	StringBuffer sb = new StringBuffer( strResourceId );
316     	sb.append( SolrConstants.CONSTANT_UNDERSCORE ).append( SHORT_NAME );
317         
318     	return sb.toString(  );
319     }
320 
321     /**
322      * {@inheritDoc}
323      */
324     @Override
325     public List<String> getResourcesName(  )
326     {
327         return LIST_RESSOURCES_NAME;
328     }
329 }