1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package fr.paris.lutece.plugins.updater.service;
35
36 import fr.paris.lutece.plugins.updater.business.version.InvalidVersionException;
37 import fr.paris.lutece.plugins.updater.business.version.Version;
38 import fr.paris.lutece.plugins.updater.service.catalog.CatalogInfos;
39 import fr.paris.lutece.plugins.updater.service.catalog.ICatalogService;
40 import fr.paris.lutece.plugins.updater.service.catalog.UpgradeInfos;
41 import fr.paris.lutece.portal.service.init.AppInfo;
42 import fr.paris.lutece.portal.service.plugin.Plugin;
43 import fr.paris.lutece.portal.service.spring.SpringContextService;
44 import fr.paris.lutece.portal.service.util.AppLogService;
45 import fr.paris.lutece.portal.service.util.AppPathService;
46 import fr.paris.lutece.util.httpaccess.HttpAccess;
47 import fr.paris.lutece.util.httpaccess.HttpAccessException;
48
49 import org.apache.commons.io.FileUtils;
50
51 import java.io.BufferedInputStream;
52 import java.io.BufferedOutputStream;
53 import java.io.File;
54 import java.io.FileOutputStream;
55 import java.io.IOException;
56 import java.io.InputStream;
57 import java.io.OutputStream;
58
59 import java.util.ArrayList;
60 import java.util.Collection;
61 import java.util.Enumeration;
62 import java.util.List;
63 import java.util.zip.ZipEntry;
64 import java.util.zip.ZipException;
65 import java.util.zip.ZipFile;
66
67
68
69
70
71 public class UpdateService implements IUpdateService
72 {
73 private static final String PATH_DOWNLOADED = "/plugins/updater/downloaded/";
74 private static final String FOLDER_WEBAPP = "/webapp";
75 private static final String FOLDER_SQL = "/sql";
76 private static final String PLUGIN_NAME = "updater";
77 private static final String BEAN_CATALOG_SERVICE = "updater.catalogService";
78 private static Version _currentCoreVersion;
79 private static int _nStatus;
80 private static int _nRegularUpdateCount;
81 private static int _nCriticalUpdateCount;
82
83
84
85
86
87
88 @Override
89 public List<UpdateInfos> getUpdateInfos( Collection<Plugin> listPlugins )
90 {
91 ICatalogService catalogService = (ICatalogService) SpringContextService.getBean( BEAN_CATALOG_SERVICE );
92 List<CatalogInfos> listCatalogInfos = catalogService.getCatalogInfos( );
93 List<UpdateInfos> listUpdatesInfos = new ArrayList<UpdateInfos>( );
94
95 if ( listPlugins != null )
96 {
97 for ( Plugin plugin : listPlugins )
98 {
99 for ( CatalogInfos ci : listCatalogInfos )
100 {
101 if ( ci.getPluginName( ).equals( plugin.getName( ) ) )
102 {
103 try
104 {
105 Version vCurrent = Version.parse( plugin.getVersion( ) );
106 Version vRepository = Version.parse( ci.getVersion( ) );
107
108
109 if ( vRepository.compareTo( vCurrent ) > 0 )
110 {
111 for ( UpgradeInfos upgrade : ci.getUpgrades( ) )
112 {
113
114 if ( upgrade.getVersionFrom( ).equals( plugin.getVersion( ) ) &&
115 isCompliantWithCurrentCore( ci ) )
116 {
117 UpdateInfos ui = new UpdateInfos( ci.getPluginName( ) );
118 ui.setCurrentVersion( plugin.getVersion( ) );
119 ui.setTargetVersion( ci.getVersion( ) );
120 ui.setCriticalUpdate( upgrade.getCriticalUpdate( ) );
121 ui.setDownloaded( checkDownloaded( ci.getPluginName( ), ci.getVersion( ) ) );
122 ui.setInstallInProgress( PluginManagerService.getInstance( )
123 .checkInstallInProgress( ci.getPluginName( ) ) );
124 listUpdatesInfos.add( ui );
125 }
126 }
127 }
128 }
129 catch ( InvalidVersionException ex )
130 {
131 AppLogService.error( "Invalid version number for plugin : " + ci.getPluginName( ), ex );
132 }
133 }
134 }
135 }
136 }
137
138 return listUpdatesInfos;
139 }
140
141
142
143
144
145
146 @Override
147 public List<NewInfos> getNewPluginsInfos( Collection<Plugin> listPlugins )
148 {
149 ICatalogService catalogService = (ICatalogService) SpringContextService.getPluginBean( PLUGIN_NAME, BEAN_CATALOG_SERVICE );
150 List<CatalogInfos> listCatalogInfos = catalogService.getCatalogInfos( );
151 List<NewInfos> listNewPluginInfos = new ArrayList<NewInfos>( );
152
153 for ( CatalogInfos ci : listCatalogInfos )
154 {
155 if ( !isInstalled( ci.getPluginName( ), listPlugins ) && isCompliantWithCurrentCore( ci ) )
156 {
157 NewInfos ni = new NewInfos( ci.getPluginName( ) );
158 ni.setDescription( ci.getDescription( ) );
159 ni.setVersion( ci.getVersion( ) );
160 ni.setAuthor( ci.getAuthor( ) );
161 ni.setHomepageUrl( ci.getHomepageUrl( ) );
162 ni.setDownloaded( checkDownloaded( ci.getPluginName( ), ci.getVersion( ) ) );
163 ni.setInstallInProgress( PluginManagerService.getInstance( )
164 .checkInstallInProgress( ci.getPluginName( ) ) );
165 listNewPluginInfos.add( ni );
166 }
167 }
168
169 return listNewPluginInfos;
170 }
171
172
173
174
175
176
177 @Override
178 public void deployPlugin( String strPluginName, String strVersion )
179 {
180 AppLogService.info( "deploy plugin : " + strPluginName );
181
182 try
183 {
184
185 File fileSource = new File( AppPathService.getWebAppPath( ) + PATH_DOWNLOADED + strPluginName + "/" +
186 strVersion + FOLDER_WEBAPP );
187 File fileDest = new File( PluginManagerService.getInstance( ).getDeployWebappPath( strPluginName ) );
188
189 if ( fileDest.exists( ) )
190 {
191 FileUtils.deleteDirectory( fileDest );
192 }
193
194 FileUtils.copyDirectory( fileSource, fileDest );
195
196
197 fileSource = new File( AppPathService.getWebAppPath( ) + PATH_DOWNLOADED + strPluginName + "/" +
198 strVersion + FOLDER_SQL );
199 fileDest = new File( PluginManagerService.getInstance( ).getDeploySqlPath( strPluginName ) );
200
201 if ( fileDest.exists( ) )
202 {
203 FileUtils.deleteDirectory( fileDest );
204 }
205
206 FileUtils.copyDirectory( fileSource, fileDest );
207 }
208 catch ( IOException ex )
209 {
210 AppLogService.error( "error deploying plugin : ", ex );
211 }
212 }
213
214
215
216
217
218
219 boolean isCompliantWithCurrentCore( CatalogInfos ci )
220 {
221 if ( _currentCoreVersion == null )
222 {
223 try
224 {
225 _currentCoreVersion = Version.parse( AppInfo.getVersion( ) );
226 }
227 catch ( InvalidVersionException ex )
228 {
229 AppLogService.error( "Invalid core version ", ex );
230
231 return false;
232 }
233 }
234
235 try
236 {
237
238 Version requiredMinCoreVersion = Version.parse( ci.getCoreVersionMin( ) );
239
240 if ( _currentCoreVersion.compareTo( requiredMinCoreVersion ) < 0 )
241 {
242 return false;
243 }
244
245
246 if ( ci.getCoreVersionMax( ) != null )
247 {
248 Version requiredMaxCoreVersion = Version.parse( ci.getCoreVersionMax( ) );
249
250 if ( _currentCoreVersion.compareTo( requiredMaxCoreVersion ) > 0 )
251 {
252 return false;
253 }
254 }
255 }
256 catch ( InvalidVersionException ex )
257 {
258 AppLogService.error( "Invalid version : " + ci.getPluginName( ), ex );
259
260 return false;
261 }
262
263 return true;
264 }
265
266
267
268
269
270
271 @Override
272 public int getStatus( )
273 {
274 return _nStatus;
275 }
276
277
278
279
280
281 @Override
282 public int getRegularUpdateCount()
283 {
284 return _nRegularUpdateCount;
285 }
286
287
288
289
290
291 @Override
292 public int getCriticalUpdateCount()
293 {
294 return _nCriticalUpdateCount;
295 }
296
297
298
299
300
301 @Override
302 public void checkUpdate( Collection<Plugin> listPlugins )
303 {
304 _nStatus = STATUS_NO_UPDATE;
305 _nRegularUpdateCount = 0;
306 _nCriticalUpdateCount = 0;
307
308 List<UpdateInfos> listUpdatesInfos = getUpdateInfos( listPlugins );
309
310 if ( listUpdatesInfos.size( ) > 0 )
311 {
312 _nStatus = STATUS_REGULAR_UPDATE;
313
314 for ( UpdateInfos ui : listUpdatesInfos )
315 {
316 if ( ui.isCriticalUpdate( ) )
317 {
318 _nStatus = STATUS_CRITICAL_UPDATE;
319 _nCriticalUpdateCount++;
320 }
321 else
322 {
323 _nRegularUpdateCount++;
324 }
325 }
326 }
327 }
328
329
330
331
332
333
334
335 private boolean isInstalled( String strPluginName, Collection<Plugin> listPlugins )
336 {
337 for ( Plugin plugin : listPlugins )
338 {
339 if ( strPluginName.equals( plugin.getName( ) ) )
340 {
341 return true;
342 }
343 }
344
345 return false;
346 }
347
348
349
350
351
352
353
354 private boolean checkDownloaded( String strPluginName, String strVersion )
355 {
356 String strReleasesDirectory = AppPathService.getWebAppPath( ) + PATH_DOWNLOADED + strPluginName + "/" +
357 strVersion;
358 File fReleasesDirectory = new File( strReleasesDirectory );
359
360 return fReleasesDirectory.exists( );
361 }
362
363
364
365
366
367
368
369 @Override
370 public void downloadPlugin( String strPluginName, String strVersion )
371 throws UpdaterDownloadException
372 {
373 CatalogInfos ci = getCatalogInfos( strPluginName );
374
375 if ( ci != null )
376 {
377 downloadPackage( strPluginName, strVersion, ci.getDownloadUrl( ) );
378 }
379 }
380
381
382
383
384
385
386
387
388 @Override
389 public void downloadPluginUpgrade( String strPluginName, String strVersion, String strVersionFrom )
390 throws UpdaterDownloadException
391 {
392 CatalogInfos ci = getCatalogInfos( strPluginName );
393
394 if ( ci != null )
395 {
396 for ( UpgradeInfos ui : ci.getUpgrades( ) )
397 {
398 if ( ui.getVersionFrom( ).equals( strVersionFrom ) )
399 {
400 downloadPackage( strPluginName, strVersion, ui.getDownloadUrl( ) );
401 }
402 }
403 }
404 }
405
406
407
408
409
410
411
412
413 private void downloadPackage( String strPluginName, String strVersion, String strPackageFileUrl )
414 throws UpdaterDownloadException
415 {
416 try
417 {
418 HttpAccess httpAccess = new HttpAccess( );
419 String strPluginDirectory = AppPathService.getWebAppPath( ) + PATH_DOWNLOADED + strPluginName;
420 File directory = new File( strPluginDirectory );
421
422 if ( !directory.exists( ) )
423 {
424 FileUtils.forceMkdir( directory );
425 }
426
427 String strPackageFile = strPluginDirectory + "/" + strPluginName + ".zip";
428 httpAccess.downloadFile( strPackageFileUrl, strPackageFile );
429
430 String strVersionDirectory = strPluginDirectory + "/" + strVersion;
431 extractPackage( strPackageFile, strVersionDirectory );
432 }
433 catch ( HttpAccessException e )
434 {
435 AppLogService.error( "Error downloading file : " + e.getMessage( ), e );
436 throw new UpdaterDownloadException( "Error downloading file : " + e.getMessage( ), e );
437 }
438 catch ( IOException e )
439 {
440 AppLogService.error( "Error creating downloaded file : " + e.getMessage( ), e );
441 throw new UpdaterDownloadException( "Error creating downloaded file : " + e.getMessage( ), e );
442 }
443 }
444
445
446
447
448
449
450
451 private void extractPackage( String strZipFile, String strDirectory )
452 throws UpdaterDownloadException
453 {
454 try
455 {
456 File file = new File( strZipFile );
457 ZipFile zipFile = new ZipFile( file );
458
459
460 Enumeration zipEntries = zipFile.entries( );
461
462 while ( zipEntries.hasMoreElements( ) )
463 {
464 ZipEntry zipEntry = (ZipEntry) zipEntries.nextElement( );
465
466
467 String strEntryName = zipEntry.getName( );
468
469
470 File destFile = new File( strDirectory, strEntryName );
471
472
473 destFile.getParentFile( ).mkdirs( );
474
475 if ( !zipEntry.isDirectory( ) )
476 {
477
478 InputStream inZipStream = null;
479
480 try
481 {
482 AppLogService.debug( "unzipping " + strEntryName + " to " + destFile.getName( ) );
483 inZipStream = zipFile.getInputStream( zipEntry );
484
485
486 OutputStream outDestStream = new FileOutputStream( destFile );
487
488
489 copyStream( inZipStream, outDestStream );
490
491 inZipStream.close( );
492 outDestStream.close( );
493 }
494 catch ( IOException e )
495 {
496 AppLogService.error( "Error extracting file : " + e.getMessage( ), e );
497 }
498 finally
499 {
500 try
501 {
502 inZipStream.close( );
503 }
504 catch ( IOException e )
505 {
506 AppLogService.error( "Error extracting file : " + e.getMessage( ), e );
507 }
508 }
509 }
510 else
511 {
512 AppLogService.debug( "skipping directory " + strEntryName );
513 }
514 }
515 }
516 catch ( ZipException e )
517 {
518 AppLogService.error( "Error extracting file : " + e.getMessage( ), e );
519 throw new UpdaterDownloadException( "Error extracting package ", e );
520 }
521 catch ( IOException e )
522 {
523 AppLogService.error( "Error extracting file : " + e.getMessage( ), e );
524 }
525 }
526
527
528
529
530
531
532
533 private static void copyStream( InputStream inStream, OutputStream outStream )
534 throws IOException
535 {
536 BufferedInputStream inBufferedStream = new BufferedInputStream( inStream );
537 BufferedOutputStream outBufferedStream = new BufferedOutputStream( outStream );
538
539 int nByte;
540
541 while ( ( nByte = inBufferedStream.read( ) ) > -1 )
542 {
543 outBufferedStream.write( nByte );
544 }
545
546 outBufferedStream.close( );
547 inBufferedStream.close( );
548 }
549
550
551
552
553
554
555 private CatalogInfos getCatalogInfos( String strPluginName )
556 {
557 ICatalogService catalogService = (ICatalogService) SpringContextService.getPluginBean( PLUGIN_NAME, BEAN_CATALOG_SERVICE );
558 List<CatalogInfos> listCatalogInfos = catalogService.getCatalogInfos( );
559
560 for ( CatalogInfos ci : listCatalogInfos )
561 {
562 if ( ci.getPluginName( ).equals( strPluginName ) )
563 {
564 return ci;
565 }
566 }
567
568 return null;
569 }
570 }