View Javadoc
1   /*
2    * Copyright (c) 2002-2020, 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.plugins.lutecetools.web.rs;
35  
36  import com.fasterxml.jackson.core.JsonProcessingException;
37  import com.fasterxml.jackson.databind.JsonNode;
38  import com.fasterxml.jackson.databind.node.ArrayNode;
39  import com.fasterxml.jackson.databind.node.ObjectNode;
40  import com.fasterxml.jackson.databind.ObjectMapper;
41  import fr.paris.lutece.plugins.lutecetools.business.Component;
42  import fr.paris.lutece.plugins.lutecetools.service.JiraService;
43  import fr.paris.lutece.plugins.lutecetools.service.MavenRepoService;
44  import fr.paris.lutece.plugins.lutecetools.service.SonarService;
45  import fr.paris.lutece.plugins.rest.service.RestConstants;
46  import fr.paris.lutece.plugins.rest.util.json.JSONUtil;
47  import fr.paris.lutece.plugins.rest.util.xml.XMLUtil;
48  import fr.paris.lutece.portal.service.i18n.I18nService;
49  import fr.paris.lutece.util.xml.XmlUtil;
50  
51  import java.io.IOException;
52  import java.util.HashMap;
53  import java.util.HashSet;
54  import java.util.List;
55  import java.util.Locale;
56  import java.util.Map;
57  import java.util.Set;
58  
59  import javax.ws.rs.GET;
60  import javax.ws.rs.HeaderParam;
61  import javax.ws.rs.Path;
62  import javax.ws.rs.PathParam;
63  import javax.ws.rs.QueryParam;
64  import javax.ws.rs.core.HttpHeaders;
65  import javax.ws.rs.core.MediaType;
66  import javax.ws.rs.core.Response;
67  import fr.paris.lutece.portal.service.util.AppLogService;
68  
69  /**
70   * Page resource
71   */
72  @Path( RestConstants.BASE_PATH + Constants.PATH_PLUGIN )
73  public class ComponentRest
74  {
75      private static final String KEY_COMPONENTS = "components";
76      private static final String KEY_COMPONENT = "component";
77      private static final String KEY_ID = "artifact_id";
78      private static final String KEY_VERSION = "version";
79      private static final String KEY_CORE_VERSION = "core_version";
80      private static final String KEY_PARENT_POM_VERSION = "parent_pom_version";
81      private static final String KEY_SNAPSHOT_VERSION = "snapshot_version";
82      private static final String KEY_SNAPSHOT_CORE_VERSION = "snapshot_core_version";
83      private static final String KEY_SNAPSHOT_PARENT_POM_VERSION = "snapshot_parent_pom_version";
84      private static final String KEY_SONAR_NB_LINES = "sonar_nb_lines";
85      private static final String KEY_SONAR_RCI = "sonar_rci";
86      private static final String KEY_JIRA_CODE = "jira_code";
87      private static final String KEY_JIRA_ROADMAP_URL = "jira_roadmap_url";
88      private static final String KEY_JIRA_CURRENT_VERSION_CLOSED_ISSUES = "jira_current_version_closed_issues";
89      private static final String KEY_JIRA_CURRENT_VERSION_OPENED_ISSUES = "jira_current_version_opened_issues";
90      private static final String KEY_SCM_URL = "scm_url";
91      private static final String KEY_SCM_SNAPSHOT_URL = "scm_snapshot_url";
92      private static final String KEY_SCM_CONNECTION = "scm_connection";
93      private static final String KEY_SCM_DEVELOPER_CONNECTION = "scm_developer_connection";
94      private static final String KEY_KEYWORDS = "keywords";
95      private static final String KEY_KEYWORD = "keyword";
96      private static final String KEY_INTRODUCTION = "description";
97      private static final String KEY_METADATA = "metadata";
98      private static final String KEY_LANG = "lang";
99  
100     private static final ObjectMapper _mapper = new ObjectMapper( );
101 
102     @GET
103     @Path( Constants.PATH_COMPONENT + Constants.PATH_ALL )
104     public Response getComponents( @HeaderParam( HttpHeaders.ACCEPT ) String accept, @QueryParam( Constants.PARAMETER_FORMAT ) String format )
105     {
106         String entity;
107         String mediaType;
108 
109         if ( ( ( accept != null ) && accept.contains( MediaType.APPLICATION_JSON ) ) || ( ( format != null ) && format.equals( Constants.MEDIA_TYPE_JSON ) ) )
110         {
111             entity = getComponentsJson( );
112             mediaType = MediaType.APPLICATION_JSON;
113         }
114         else
115         {
116             entity = getComponentsXml( );
117             mediaType = MediaType.APPLICATION_XML;
118         }
119 
120         return Response.ok( entity, mediaType ).build( );
121     }
122 
123     /**
124      * Gets all components list in XML format
125      * 
126      * @return The list
127      */
128     public String getComponentsXml( )
129     {
130         StringBuffer sbXML = new StringBuffer( XmlUtil.getXmlHeader( ) );
131         XmlUtil.beginElement( sbXML, KEY_COMPONENTS );
132 
133         for ( String strArtifactId : MavenRepoService.instance( ).getComponentsListFromRepository( ) )
134         {
135             XmlUtil.addElement( sbXML, KEY_ID, strArtifactId );
136         }
137 
138         XmlUtil.endElement( sbXML, KEY_COMPONENTS );
139 
140         return sbXML.toString( );
141     }
142 
143     /**
144      * Gets all components list in JSON format
145      * 
146      * @return The list
147      */
148     public String getComponentsJson( )
149     {
150         JsonNode json = _mapper.createObjectNode( );
151         ArrayNode jsonComponents = _mapper.createArrayNode( );
152 
153         for ( String strArtifactId : MavenRepoService.instance( ).getComponentsListFromRepository( ) )
154         {
155             JsonNode jsonComponent = _mapper.createObjectNode( );
156             ( (ObjectNode) jsonComponent ).put( KEY_ID, strArtifactId );
157             jsonComponents.add( jsonComponent );
158         }
159 
160         ( (ObjectNode) json ).set( KEY_COMPONENTS, jsonComponents );
161 
162         return json.toString( );
163     }
164 
165     /**
166      * Gets a component by its artifact ID
167      * 
168      * @param strArtifactId
169      * @param accept
170      *            The Accept header parameter
171      * @param format
172      *            The format
173      * @param bCache
174      *            false if the component informations must be recalculated
175      * @param strType
176      *            the compoent type(lutece-plugin,lutece-site,...)
177      * @return The response
178      * @throws IOException
179      *             if an error occurs
180      */
181     @GET
182     @Path( Constants.PATH_COMPONENT + "/{" + Constants.PATH_ID + "}" )
183     public Response getComponent( @PathParam( Constants.PATH_ID ) String strArtifactId, @HeaderParam( HttpHeaders.ACCEPT ) String accept,
184             @QueryParam( Constants.PARAMETER_FORMAT ) String format, @QueryParam( Constants.PARAMETER_CACHE ) Boolean bCache,
185             @QueryParam( Constants.PARAMETER_TYPE ) String strType ) throws IOException
186     {
187         String entity;
188         String mediaType;
189         
190         boolean cache = true;
191         if ( bCache != null )
192         {
193             cache = bCache;
194         }
195 
196         if ( ( ( accept != null ) && accept.contains( MediaType.APPLICATION_JSON ) ) || ( ( format != null ) && format.equals( Constants.MEDIA_TYPE_JSON ) ) )
197         {
198             entity = getComponentJson( strArtifactId, cache, strType );
199             mediaType = MediaType.APPLICATION_JSON;
200         }
201         else
202         {
203             entity = getComponentXml( strArtifactId, cache, strType );
204             mediaType = MediaType.APPLICATION_XML;
205         }
206 
207         return Response.ok( entity, mediaType ).build( );
208     }
209 
210     /**
211      * Gets a component in XML format
212      * 
213      * @param strArtifactId
214      *            The artifact ID
215      * @param bCache
216      *            false if the component informations must be recalculated
217      * @param strType
218      *            the compoent type(lutece-plugin,lutece-site,...)
219      * @return The XML output
220      */
221     public String getComponentXml( String strArtifactId, boolean bCache, String strType )
222     {
223         StringBuffer sbXML = new StringBuffer( );
224 
225         try
226         {
227             Component component = MavenRepoService.instance( ).getComponent( strArtifactId, true, !bCache, strType );
228 
229             if ( component != null )
230             {
231                 sbXML.append( "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" );
232                 addComponentXml( sbXML, component );
233             }
234         }
235         catch( NumberFormatException e )
236         {
237             sbXML.append( XMLUtil.formatError( "Invalid component number", 3 ) );
238         }
239         catch( Exception e )
240         {
241             sbXML.append( XMLUtil.formatError( "Component not found", 1 ) );
242         }
243 
244         return sbXML.toString( );
245     }
246 
247     /**
248      * Gets a component in JSON format
249      * 
250      * @param strArtifactId
251      *            The artifact ID
252      * @param bCache
253      *            false if the component informations must be recalculated
254      * @param strType
255      *            the compoent type(lutece-plugin,lutece-site,...)
256      * @return The JSON output
257      */
258     public String getComponentJson( String strArtifactId, boolean bCache, String strType )
259     {
260         JsonNode json = _mapper.createObjectNode( );
261         String strJson = "";
262 
263         try
264         {
265 
266             Component component = MavenRepoService.instance( ).getComponent( strArtifactId, true, !bCache, strType );
267 
268             if ( component != null )
269             {
270                 // Jackson automatic serialization to allow automatic deserialization
271                 addComponentJsonAuto( json, component );
272                 strJson = json.toString( );
273             }
274         }
275         catch( NumberFormatException e )
276         {
277             strJson = JSONUtil.formatError( "Invalid component number", 3 );
278         }
279         catch( Exception e )
280         {
281             strJson = JSONUtil.formatError( "Component not found", 1 );
282         }
283 
284         return strJson;
285     }
286 
287     /**
288      * Write a component into a buffer
289      * 
290      * @param sbXML
291      *            The buffer
292      * @param component
293      *            The component
294      */
295     private void addComponentXml( StringBuffer sbXML, Component component )
296     {
297         XmlUtil.beginElement( sbXML, KEY_COMPONENT );
298         XmlUtil.addElement( sbXML, KEY_ID, component.getArtifactId( ) );
299         XmlUtil.addElement( sbXML, KEY_VERSION, component.getVersion( ) );
300         XmlUtil.addElement( sbXML, KEY_CORE_VERSION, component.get( Component.CORE_VERSION ) );
301         XmlUtil.addElement( sbXML, KEY_PARENT_POM_VERSION, component.get( Component.PARENT_POM_VERSION ) );
302         XmlUtil.addElement( sbXML, KEY_SNAPSHOT_VERSION, component.get( Component.SNAPSHOT_VERSION ) );
303         XmlUtil.addElement( sbXML, KEY_SNAPSHOT_CORE_VERSION, component.get( Component.SNAPSHOT_CORE_VERSION ) );
304         XmlUtil.addElement( sbXML, KEY_SNAPSHOT_PARENT_POM_VERSION, component.get( Component.SNAPSHOT_PARENT_POM_VERSION ) );
305         XmlUtil.addElement( sbXML, KEY_SONAR_NB_LINES, component.get( SonarService.SONAR_NB_LINES ) );
306         XmlUtil.addElement( sbXML, KEY_SONAR_RCI, component.get( SonarService.SONAR_RCI ) );
307         XmlUtil.addElement( sbXML, KEY_JIRA_CODE, component.get( Component.JIRA_KEY ) );
308         XmlUtil.addElement( sbXML, KEY_JIRA_ROADMAP_URL, "https://dev.lutece.paris.fr/jira/projects/" + component.get( Component.JIRA_KEY )
309                 + "/?selectedTab=com.atlassian.jira.jira-projects-plugin:roadmap-panel" );
310         XmlUtil.addElement( sbXML, KEY_JIRA_CURRENT_VERSION_CLOSED_ISSUES,
311                 component.getInt( JiraService.JIRA_ISSUES_COUNT ) - component.getInt( JiraService.JIRA_UNRESOLVED_ISSUES_COUNT ) );
312         XmlUtil.addElement( sbXML, KEY_JIRA_CURRENT_VERSION_OPENED_ISSUES, component.getInt( JiraService.JIRA_UNRESOLVED_ISSUES_COUNT ) );
313         XmlUtil.addElement( sbXML, KEY_SCM_URL, component.get( Component.SCM_URL ) );
314         XmlUtil.addElement( sbXML, KEY_SCM_SNAPSHOT_URL, component.get( Component.SNAPSHOT_SCM_URL ) );
315         XmlUtil.addElement( sbXML, KEY_SCM_CONNECTION, component.get( Component.SCM_CONNECTION ) );
316         XmlUtil.addElement( sbXML, KEY_SCM_DEVELOPER_CONNECTION, component.get( Component.SCM_DEVELOPER_CONNECTION ) );
317 
318         List<Locale> locales = I18nService.getAdminAvailableLocales( );
319         for ( Locale locale : locales )
320         {
321             Map<String, String> attributeList = new HashMap<>( );
322             attributeList.put( KEY_LANG, locale.getLanguage( ) );
323 
324             XmlUtil.beginElement( sbXML, KEY_METADATA, attributeList );
325             XmlUtil.addElementHtml( sbXML, KEY_INTRODUCTION, ( component.get( Component.SITE_INTRODUCTION + "_" + locale.getLanguage( ) ) == null ? ""
326                     : component.get( Component.SITE_INTRODUCTION + "_" + locale.getLanguage( ) ) ) );
327 
328             Set<String> keywords = (HashSet<String>) component.getObject( Component.SITE_KEYWORDS + "_" + locale.getLanguage( ) );
329             if ( keywords != null )
330             {
331                 XmlUtil.beginElement( sbXML, KEY_KEYWORDS );
332                 for ( String keyword : keywords )
333                 {
334                     XmlUtil.addElement( sbXML, KEY_KEYWORD, keyword );
335                 }
336                 XmlUtil.endElement( sbXML, KEY_KEYWORDS );
337             }
338 
339             XmlUtil.endElement( sbXML, KEY_METADATA );
340         }
341 
342         XmlUtil.endElement( sbXML, KEY_COMPONENT );
343     }
344 
345     /**
346      * Write a component into a JSON Object
347      * 
348      * @param json
349      *            The JSON Object
350      * @param component
351      *            The component
352      */
353     private void addComponentJsonAuto( JsonNode json, Component component )
354     {
355         try
356         {
357 
358             String strJson = _mapper.writeValueAsString( component );
359 
360             JsonNode jsonComponent = null;
361 
362             try
363             {
364                 jsonComponent = _mapper.readTree( strJson );
365             }
366             catch( IOException e )
367             {
368                 AppLogService.error( "ERROR serializing component", e );
369             }
370 
371             ( (ObjectNode) json ).set( KEY_COMPONENT, jsonComponent );
372 
373         }
374         catch( JsonProcessingException e )
375         {
376             AppLogService.error( "ERROR serializing component", e );
377         }
378 
379     }
380 
381 }