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.dila.service.impl;
35  
36  import fr.paris.lutece.plugins.dila.business.fichelocale.dao.IXmlDAO;
37  import fr.paris.lutece.plugins.dila.business.fichelocale.dto.XmlDTO;
38  import fr.paris.lutece.plugins.dila.service.IDilaXmlService;
39  import fr.paris.lutece.portal.service.i18n.I18nService;
40  import fr.paris.lutece.portal.service.util.AppLogService;
41  import fr.paris.lutece.portal.service.util.AppPropertiesService;
42  
43  import org.apache.commons.io.IOUtils;
44  import org.apache.commons.lang.StringUtils;
45  
46  import org.apache.http.HttpHost;
47  import org.apache.http.auth.AuthScope;
48  import org.apache.http.auth.UsernamePasswordCredentials;
49  import org.apache.http.client.ClientProtocolException;
50  import org.apache.http.client.CredentialsProvider;
51  import org.apache.http.client.config.RequestConfig;
52  import org.apache.http.client.methods.CloseableHttpResponse;
53  import org.apache.http.client.methods.HttpGet;
54  import org.apache.http.impl.client.BasicCredentialsProvider;
55  import org.apache.http.impl.client.CloseableHttpClient;
56  import org.apache.http.impl.client.HttpClientBuilder;
57  import org.apache.http.impl.client.HttpClients;
58  
59  import org.w3c.dom.Document;
60  import org.w3c.dom.Element;
61  import org.w3c.dom.Node;
62  import org.w3c.dom.NodeList;
63  
64  import org.xml.sax.SAXException;
65  
66  import java.io.ByteArrayInputStream;
67  import java.io.IOException;
68  import java.io.InputStream;
69  import java.io.Serializable;
70  import java.io.StringWriter;
71  
72  import java.net.HttpURLConnection;
73  
74  import java.util.List;
75  import java.util.Locale;
76  
77  import javax.inject.Inject;
78  import javax.inject.Named;
79  
80  import javax.xml.parsers.DocumentBuilder;
81  
82  
83  /**
84   * Implementation of {@link IDilaXmlService}
85   */
86  public class DilaXmlService implements IDilaXmlService, Serializable
87  {
88      private static final String ID_ATTRIBUTE = "ID";
89      private static final String HOW_TO_TAG = "CommentFaire";
90      private static final String ERROR_RSS_FEED = "dila.error.rssFeed";
91      private static final String ITEM_TAG = "item";
92      private static final String HTTP_ACCESS_PROXY_PASSWORD = "httpAccess.proxyPassword";
93      private static final String HTTP_ACCESS_PROXY_USERNAME = "httpAccess.proxyUserName";
94      private static final String HTTP_ACCESS_PROXY_PORT = "httpAccess.proxyPort";
95      private static final String URL_ATTR = "URL";
96      private static final String TYPE_ATTR_FIL = "Fil";
97      private static final String TYPE_ATTR = "type";
98      private static final String ACTUALITE_TAG = "Actualite";
99      private static final String ERROR_TAG = "Error";
100     private static final String HTTP_ACCESS_PROXY_HOST = "httpAccess.proxyHost";
101 
102     /** Serial ID */
103     private static final long serialVersionUID = 3901887734209752792L;
104     @Inject
105     @Named( "dilaXmlDAO" )
106     private IXmlDAO _dilaXmlDAO;
107 
108     /**
109      * {@inheritDoc}
110      */
111     @Override
112     public String findTitleById( String strId )
113     {
114         return _dilaXmlDAO.findTitleById( strId );
115     }
116 
117     /**
118      * {@inheritDoc}
119      */
120     @Override
121     public XmlDTO findFolderById( String strId )
122     {
123         return _dilaXmlDAO.findFolderById( strId );
124     }
125 
126     /**
127      * {@inheritDoc}
128      */
129     @Override
130     public String findTitleByIdAndTypesAndAudience( String strIdDossierFrere, List<String> listAvailableTypes,
131         Long lIdAudience )
132     {
133         return _dilaXmlDAO.findTitleByIdAndTypesAndAudience( strIdDossierFrere, listAvailableTypes, lIdAudience );
134     }
135 
136     /**
137      * {@inheritDoc}
138      */
139     @Override
140     public XmlDTO findByIdAndTypesAndAudience( String strId, List<String> listAvailableTypes, Long lIdAudience )
141     {
142         return _dilaXmlDAO.findByIdAndTypesAndAudience( strId, listAvailableTypes, lIdAudience );
143     }
144 
145     /**
146      * {@inheritDoc}
147      */
148     @Override
149     public String findResourceTypeByIdXMLAndAudience( String strIdXml, Long lIdAudience )
150     {
151         return _dilaXmlDAO.findResourceTypeByIdXMLAndAudience( strIdXml, lIdAudience );
152     }
153 
154     /**
155      * {@inheritDoc}
156      */
157     @Override
158     public List<XmlDTO> findAll(  )
159     {
160         return _dilaXmlDAO.findAll(  );
161     }
162 
163     /**
164      * {@inheritDoc}
165      */
166     @Override
167     public Document insertHowToLinks( Long lAudienceId, DocumentBuilder builder, Document document )
168     {
169         List<XmlDTO> xmlList = this.findHowToByAudience( lAudienceId );
170 
171         for ( XmlDTO currentXML : xmlList )
172         {
173             Element newCard = document.createElement( HOW_TO_TAG );
174             newCard.setAttribute( ID_ATTRIBUTE, currentXML.getIdXml(  ) );
175             newCard.setTextContent( currentXML.getTitle(  ) );
176             document.getDocumentElement(  ).appendChild( newCard );
177             document.getDocumentElement(  ).normalize(  );
178         }
179 
180         return document;
181     }
182 
183     /**
184      * {@inheritDoc}
185      */
186     @Override
187     public Long findIdByXmlAndAudience( String strXmlName, Long lAudienceId )
188     {
189         return _dilaXmlDAO.findIdByXmlAndAudience( strXmlName, lAudienceId );
190     }
191 
192     /**
193      * Find all "Comment faire si" resources for audience
194      * @param audienceId the audience to check
195      * @return the list of corresponding {@link XmlDTO}
196      */
197     private List<XmlDTO> findHowToByAudience( Long audienceId )
198     {
199         return _dilaXmlDAO.findHowToByAudience( audienceId );
200     }
201 
202     /**
203      * {@inheritDoc}
204      */
205     public Document insertRssLinks( DocumentBuilder builder, Document document, Locale locale )
206     {
207         CloseableHttpClient client = null;
208         HttpClientBuilder clientBuilder = HttpClients.custom(  );
209         String proxyHost = AppPropertiesService.getProperty( HTTP_ACCESS_PROXY_HOST );
210         Node errorNode = document.createElement( ERROR_TAG );
211         errorNode.setTextContent( I18nService.getLocalizedString( ERROR_RSS_FEED, locale ) );
212 
213         NodeList news = document.getElementsByTagName( ACTUALITE_TAG );
214 
215         for ( int i = 0; i < news.getLength(  ); i++ )
216         {
217             Element newsElement = (Element) news.item( i );
218 
219             if ( ( newsElement != null ) && newsElement.getAttribute( TYPE_ATTR ).contains( TYPE_ATTR_FIL ) )
220             {
221                 String rssUrl = newsElement.getAttribute( URL_ATTR );
222                 HttpGet request = new HttpGet( rssUrl );
223 
224                 // Connection through proxy
225                 if ( StringUtils.isNotBlank( proxyHost ) )
226                 {
227                     String proxyPort = AppPropertiesService.getProperty( HTTP_ACCESS_PROXY_PORT );
228                     String proxyUser = AppPropertiesService.getProperty( HTTP_ACCESS_PROXY_USERNAME );
229                     String proxyPassword = AppPropertiesService.getProperty( HTTP_ACCESS_PROXY_PASSWORD );
230 
231                     //Proxy authentication
232                     if ( StringUtils.isNotBlank( proxyUser ) )
233                     {
234                         CredentialsProvider credsProvider = new BasicCredentialsProvider(  );
235                         credsProvider.setCredentials( new AuthScope( proxyHost, Integer.parseInt( proxyPort ) ),
236                             new UsernamePasswordCredentials( proxyUser, proxyPassword ) );
237                         clientBuilder.setDefaultCredentialsProvider( credsProvider );
238                     }
239 
240                     String strSchema = request.getURI(  ).getScheme(  );
241                     HttpHost proxy = new HttpHost( proxyHost, Integer.parseInt( proxyPort ), strSchema );
242                     RequestConfig config = RequestConfig.custom(  ).setProxy( proxy ).build(  );
243                     request.setConfig( config );
244                 }
245 
246                 client = clientBuilder.build(  );
247 
248                 CloseableHttpResponse response = null;
249 
250                 try
251                 {
252                     response = client.execute( request );
253 
254                     int nResponseStatusCode = response.getStatusLine(  ).getStatusCode(  );
255 
256                     if ( nResponseStatusCode != HttpURLConnection.HTTP_OK )
257                     {
258                         newsElement.appendChild( errorNode );
259 
260                         continue;
261                     }
262 
263                     InputStream rssFeed = response.getEntity(  ).getContent(  );
264                     StringWriter writer = new StringWriter(  );
265                     IOUtils.copy( rssFeed, writer );
266                     rssFeed = new ByteArrayInputStream( writer.toString(  ).getBytes(  ) );
267 
268                     Document rssDoc = builder.parse( rssFeed );
269                     NodeList items = rssDoc.getElementsByTagName( ITEM_TAG );
270 
271                     for ( int j = 0; ( j < items.getLength(  ) ) && ( j < 4 ); j++ )
272                     {
273                         Node currentItem = items.item( j );
274                         Node importedNode = document.importNode( currentItem, true );
275                         newsElement.appendChild( importedNode );
276                         document.getDocumentElement(  ).normalize(  );
277                     }
278                 }
279                 catch ( ClientProtocolException e )
280                 {
281                     AppLogService.error( "Error on HTTP protocol", e );
282                     newsElement.appendChild( errorNode );
283 
284                     continue;
285                 }
286                 catch ( IOException e )
287                 {
288                     AppLogService.error( "Error on execute request", e );
289                     newsElement.appendChild( errorNode );
290 
291                     continue;
292                 }
293                 catch ( SAXException e )
294                 {
295                     AppLogService.error( "Error parsing feed", e );
296                     newsElement.appendChild( errorNode );
297 
298                     continue;
299                 }
300 
301                 try
302                 {
303                     response.close(  );
304                 }
305                 catch ( IOException e )
306                 {
307                     AppLogService.error( "Error closing response", e );
308 
309                     continue;
310                 }
311             }
312         }
313 
314         return document;
315     }
316 
317     /**
318      * {@inheritDoc}
319      */
320     public XmlDTO findHomeHowTo( Long audienceId )
321     {
322         return _dilaXmlDAO.findHomeHowTo( audienceId );
323     }
324 }