1 8 package org.apache.avalon.phoenix.components.deployer.installer; 9 10 import java.io.File ; 11 import java.io.FileInputStream ; 12 import java.io.FileOutputStream ; 13 import java.io.IOException ; 14 import java.io.InputStream ; 15 import java.io.OutputStream ; 16 import java.net.MalformedURLException ; 17 import java.net.URL ; 18 import java.util.ArrayList ; 19 import java.util.Enumeration ; 20 import java.util.zip.CRC32 ; 21 import java.util.zip.CheckedInputStream ; 22 import java.util.zip.Checksum ; 23 import java.util.zip.ZipEntry ; 24 import java.util.zip.ZipFile ; 25 import org.apache.avalon.excalibur.i18n.ResourceManager; 26 import org.apache.avalon.excalibur.i18n.Resources; 27 import org.apache.avalon.excalibur.io.FileUtil; 28 import org.apache.avalon.excalibur.io.IOUtil; 29 import org.apache.avalon.framework.logger.AbstractLogEnabled; 30 31 38 public class Installer 39 extends AbstractLogEnabled 40 { 41 private static final Resources REZ = 42 ResourceManager.getPackageResources( Installer.class ); 43 44 private static final String META_INF = "META-INF"; 45 46 private static final String SAR_INF = "SAR-INF"; 47 48 private static final String LIB = "SAR-INF/lib"; 49 50 private static final String CLASSES = "SAR-INF/classes/"; 51 52 private static final String FS_CONFIG_XML = "SAR-INF" + File.separator + "config.xml"; 54 55 private static final String FS_ASSEMBLY_XML = "SAR-INF" + File.separator + "assembly.xml"; 56 57 private static final String FS_ENV_XML = "SAR-INF" + File.separator + "environment.xml"; 58 59 private static final String FS_CLASSES = 60 "SAR-INF" + File.separator + "classes" + File.separator; 61 62 65 private File m_baseDirectory; 66 67 70 private File m_baseWorkDirectory; 71 72 77 public void setBaseDirectory( File baseDirectory ) 78 { 79 m_baseDirectory = baseDirectory; 80 } 81 82 87 public void setBaseWorkDirectory( File baseWorkDirectory ) 88 { 89 m_baseWorkDirectory = baseWorkDirectory; 90 } 91 92 98 public void uninstall( final Installation installation ) 99 throws InstallationException 100 { 101 final FileDigest[] infos = installation.getFileDigests(); 102 final Checksum checksum = new CRC32 (); 103 104 if( infos != null ) 105 { 106 for( int i = 0; i < infos.length; i++ ) 107 { 108 final File file = infos[ i ].getFile(); 109 final File parent = file.getParentFile(); 110 111 final String message = REZ.getString( "skip-removal", file ); 112 113 if( file.exists() ) 114 { 115 if( file.lastModified() <= installation.getTimestamp() ) 116 { 117 getLogger().debug( message ); 118 continue; 119 } 120 121 checksum( file, checksum ); 122 123 if( checksum.getValue() != infos[ i ].getChecksum() ) 124 { 125 getLogger().debug( message ); 126 continue; 127 } 128 129 file.delete(); 130 if( 0 == parent.list().length ) 131 { 132 parent.delete(); 133 } 134 } 135 } 136 } 137 138 deleteWorkDir( installation.getWorkDirectory() ); 139 } 140 141 146 private void deleteWorkDir( final File dir ) 147 { 148 try 149 { 150 FileUtil.deleteDirectory( dir ); 151 } 152 catch( final IOException ioe ) 153 { 154 try 155 { 156 FileUtil.forceDeleteOnExit( dir ); 159 } 160 catch( final IOException ioe2 ) 161 { 162 } 164 final String message = 165 REZ.getString( "nodelete-workdir.error", 166 dir, 167 ioe.getMessage() ); 168 getLogger().warn( message, ioe ); 169 } 170 } 171 172 178 public Installation install( final String name, final URL url ) 179 throws InstallationException 180 { 181 lock(); 182 try 183 { 184 final String notice = REZ.getString( "installing-sar", url ); 185 getLogger().info( notice ); 186 187 final File file = getFileFor( url ); 188 if( file.isDirectory() ) 189 { 190 final String message = 191 REZ.getString( "install.sar-isa-dir.error", name, url ); 192 throw new InstallationException( message ); 193 } 194 195 final ZipFile zipFile = new ZipFile ( file ); 197 return install( name, url, file, zipFile ); 198 } 199 catch( final IOException ioe ) 200 { 201 final String message = REZ.getString( "bad-zip-file", url ); 202 throw new InstallationException( message, ioe ); 203 } 204 finally 205 { 206 unlock(); 207 } 208 } 209 210 215 private void checksum( final File file, final Checksum checksum ) 216 { 217 checksum.reset(); 218 219 InputStream input = null; 220 try 221 { 222 input = new CheckedInputStream ( new FileInputStream ( file ), checksum ); 223 IOUtil.toByteArray( input ); 224 } 225 catch( final IOException ioe ) 226 { 227 final String message = REZ.getString( "checksum-failure", file ); 228 getLogger().warn( message ); 229 } 230 finally 231 { 232 IOUtil.shutdownStream( input ); 233 } 234 } 235 236 240 private void lock() 241 { 242 } 243 244 248 private void unlock() 249 { 250 } 251 252 260 private Installation install( final String name, 261 final URL url, 262 final File file, 263 final ZipFile zipFile ) 264 throws InstallationException 265 { 266 final File directory = 267 new File ( m_baseDirectory, name ).getAbsoluteFile(); 268 269 directory.mkdirs(); 272 273 final ArrayList digests = new ArrayList (); 274 final ArrayList jars = new ArrayList (); 275 276 final File workDir = 277 getRelativeWorkDir( m_baseWorkDirectory, name ); 278 boolean success = false; 279 try 280 { 281 expandZipFile( zipFile, directory, workDir, jars, digests, url ); 282 283 final File envFile = new File ( directory, FS_ENV_XML ); 286 287 final String [] classPath = 289 (String [])jars.toArray( new String [ jars.size() ] ); 290 291 final String assembly = getURLAsString( new File ( directory, FS_ASSEMBLY_XML ) ); 292 final String config = getURLAsString( new File ( directory, FS_CONFIG_XML ) ); 293 final String environment = getURLAsString( envFile ); 294 final FileDigest[] fileDigests = (FileDigest[])digests.toArray( new FileDigest[ 0 ] ); 295 final long timestamp = System.currentTimeMillis(); 296 297 success = true; 298 return new Installation( file, directory, workDir, 299 config, assembly, environment, 300 classPath, fileDigests, timestamp ); 301 } 302 finally 303 { 304 if( !success ) 305 { 306 deleteWorkDir( workDir ); 307 } 308 } 309 } 310 311 323 private void expandZipFile( final ZipFile zipFile, 324 final File directory, 325 final File workDir, 326 final ArrayList classpath, 327 final ArrayList digests, 328 final URL url ) 329 throws InstallationException 330 { 331 final Enumeration entries = zipFile.entries(); 332 while( entries.hasMoreElements() ) 333 { 334 final ZipEntry entry = (ZipEntry )entries.nextElement(); 335 final String name = fixName( entry.getName() ); 336 337 if( name.startsWith( META_INF ) ) 338 { 339 continue; 340 } 341 342 if( handleDirs( entry, name, directory ) ) 343 { 344 continue; 345 } 346 347 if( handleClasses( zipFile, 348 entry, 349 name, 350 workDir, 351 classpath ) ) 352 { 353 continue; 354 } 355 356 if( handleJars( zipFile, entry, name, workDir, classpath ) ) 357 { 358 continue; 359 } 360 361 final File destination = new File ( directory, name ); 364 handleFile( zipFile, entry, destination, digests, url ); 365 } 366 } 367 368 372 private void handleFile( final ZipFile zipFile, 373 final ZipEntry entry, 374 final File destination, 375 final ArrayList digests, 376 final URL url ) 377 throws InstallationException 378 { 379 if( !destination.exists() ) 380 { 381 expandFile( zipFile, entry, destination ); 382 calculateDigest( entry, destination, digests ); 383 } 384 else 385 { 386 final String message = 387 REZ.getString( "file-in-the-way", 388 url, 389 entry.getName(), 390 destination ); 391 getLogger().warn( message ); 392 } 393 } 394 395 405 private boolean handleJars( final ZipFile zipFile, 406 final ZipEntry entry, 407 final String name, 408 final File workDir, 409 final ArrayList jars ) 410 throws InstallationException 411 { 412 if( name.startsWith( LIB ) 413 && name.endsWith( ".jar" ) 414 && LIB.length() == name.lastIndexOf( "/" ) ) 415 { 416 final File jar = new File ( workDir, name ); 417 jars.add( getURLAsString( jar ) ); 418 419 final File file = new File ( workDir, name ); 420 expandFile( zipFile, entry, file ); 421 return true; 422 } 423 else 424 { 425 return false; 426 } 427 } 428 429 439 private boolean handleClasses( final ZipFile zipFile, 440 final ZipEntry entry, 441 final String name, 442 final File workDir, 443 final ArrayList jars ) 444 throws InstallationException 445 { 446 if( name.startsWith( CLASSES ) ) 447 { 448 final File classDir = new File ( workDir, FS_CLASSES ); 449 if( !classDir.exists() ) 450 { 451 jars.add( getURLAsString( classDir ) ); 452 final File file = new File ( workDir, name ); 453 expandFile( zipFile, entry, file ); 454 } 455 return true; 456 } 457 else 458 { 459 return false; 460 } 461 } 462 463 471 private boolean handleDirs( final ZipEntry entry, 472 final String name, 473 final File directory ) 474 { 475 if( entry.isDirectory() ) 476 { 477 if( !name.startsWith( SAR_INF ) ) 478 { 479 final File newDir = 480 new File ( directory, name ); 481 newDir.mkdirs(); 482 } 483 return true; 484 } 485 else 486 { 487 return false; 488 } 489 } 490 491 499 private File getRelativeWorkDir( final File baseWorkDir, 500 final String name ) 501 { 502 final String filename = 503 name + "-" + System.currentTimeMillis(); 504 return new File ( baseWorkDir, filename ); 505 } 506 507 514 private String fixName( final String name ) 515 { 516 if( name.startsWith( "/" ) ) 517 { 518 return name.substring( 1 ); 519 } 520 else 521 { 522 return name; 523 } 524 } 525 526 536 private File getFileFor( final URL url ) 537 throws InstallationException 538 { 539 if( !url.getProtocol().equals( "file" ) ) 540 { 541 final String message = REZ.getString( "install-nonlocal", url ); 542 throw new InstallationException( message ); 543 } 544 545 File file = new File ( url.getFile() ); 546 file = file.getAbsoluteFile(); 547 548 if( !file.exists() ) 549 { 550 final String message = REZ.getString( "install-nourl", file ); 551 throw new InstallationException( message ); 552 } 553 554 return file; 555 } 556 557 565 private void calculateDigest( final ZipEntry entry, 566 final File file, 567 final ArrayList digests ) 568 { 569 final long checksum = entry.getCrc(); 570 digests.add( new FileDigest( file, checksum ) ); 571 } 572 573 576 private void expandFile( final ZipFile zipFile, 577 final ZipEntry entry, 578 final File file ) 579 throws InstallationException 580 { 581 InputStream input = null; 582 OutputStream output = null; 583 584 try 585 { 586 file.getParentFile().mkdirs(); 587 output = new FileOutputStream ( file ); 588 input = zipFile.getInputStream( entry ); 589 IOUtil.copy( input, output ); 590 } 591 catch( final IOException ioe ) 592 { 593 final String message = 594 REZ.getString( "failed-to-expand", 595 entry.getName(), 596 file, 597 ioe.getMessage() ); 598 throw new InstallationException( message, ioe ); 599 } 600 finally 601 { 602 IOUtil.shutdownStream( input ); 603 IOUtil.shutdownStream( output ); 604 } 605 } 606 607 613 private String getURLAsString( final File file ) 614 { 615 try 616 { 617 return file.toURL().toExternalForm(); 618 } 619 catch( final MalformedURLException mue ) 620 { 621 return null; 622 } 624 } 625 } 626 | Popular Tags |