KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > codehaus > loom > components > installer > DefaultInstaller


1 /* ====================================================================
2  * Loom Software License, version 1.1
3  *
4  * Copyright (c) 2003, Loom Group. All rights reserved.
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
10  * notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in
14  * the documentation and/or other materials provided with the
15  * distribution.
16  *
17  * 3. Neither the name of the Loom Group nor the name "Loom" nor
18  * the names of its contributors may be used to endorse or promote
19  * products derived from this software without specific prior
20  * written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *
35  * ====================================================================
36  *
37  * Loom includes code from the Apache Software Foundation
38  *
39  * ====================================================================
40  * The Apache Software License, Version 1.1
41  *
42  * Copyright (c) 1997-2003 The Apache Software Foundation. All rights
43  * reserved.
44  *
45  * Redistribution and use in source and binary forms, with or without
46  * modification, are permitted provided that the following conditions
47  * are met:
48  *
49  * 1. Redistributions of source code must retain the above copyright
50  * notice, this list of conditions and the following disclaimer.
51  *
52  * 2. Redistributions in binary form must reproduce the above copyright
53  * notice, this list of conditions and the following disclaimer in
54  * the documentation and/or other materials provided with the
55  * distribution.
56  *
57  * 3. The end-user documentation included with the redistribution,
58  * if any, must include the following acknowledgment:
59  * "This product includes software developed by the
60  * Apache Software Foundation (http://www.apache.org/)."
61  * Alternately, this acknowledgment may appear in the software
62  * itself, if and wherever such third-party acknowledgments
63  * normally appear.
64  *
65  * 4. The names "Jakarta", "Avalon", and "Apache Software Foundation"
66  * must not be used to endorse or promote products derived from this
67  * software without prior written permission. For written
68  * permission, please contact apache@apache.org.
69  *
70  * 5. Products derived from this software may not be called "Apache",
71  * nor may "Apache" appear in their name, without prior written
72  * permission of the Apache Software Foundation.
73  *
74  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
75  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
76  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
77  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
78  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
79  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
80  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
81  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
82  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
83  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
84  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
85  * SUCH DAMAGE.
86  */

87 package org.codehaus.loom.components.installer;
88
89 import java.io.File JavaDoc;
90 import java.io.FileOutputStream JavaDoc;
91 import java.io.IOException JavaDoc;
92 import java.io.InputStream JavaDoc;
93 import java.io.OutputStream JavaDoc;
94 import java.net.MalformedURLException JavaDoc;
95 import java.net.URL JavaDoc;
96 import java.util.Enumeration JavaDoc;
97 import java.util.HashMap JavaDoc;
98 import java.util.Map JavaDoc;
99 import java.util.zip.ZipEntry JavaDoc;
100 import java.util.zip.ZipFile JavaDoc;
101
102 import org.codehaus.loom.interfaces.ContainerConstants;
103 import org.codehaus.loom.interfaces.Installer;
104 import org.codehaus.loom.interfaces.LoomException;
105 import org.codehaus.spice.salt.i18n.ResourceManager;
106 import org.codehaus.spice.salt.i18n.Resources;
107 import org.codehaus.spice.salt.io.FileUtil;
108 import org.codehaus.spice.salt.io.IOUtil;
109 import org.codehaus.dna.AbstractLogEnabled;
110 import org.codehaus.dna.Active;
111 import org.codehaus.dna.Configurable;
112 import org.codehaus.dna.Configuration;
113 import org.codehaus.dna.ConfigurationException;
114
115 /**
116  * An Installer is responsible for taking a URL for Sar and installing it as
117  * appropriate.
118  *
119  * @author Peter Donald
120  * @version $Revision: 1.3 $ $Date: 2004/08/17 23:14:32 $
121  */

122 public class DefaultInstaller
123     extends AbstractLogEnabled
124     implements Installer, Configurable, Active
125 {
126     private static final Resources REZ =
127         ResourceManager.getPackageResources( DefaultInstaller.class );
128
129     private static final String JavaDoc META_INF = "META-INF";
130     private static final String JavaDoc SAR_INF = "SAR-INF";
131     private static final String JavaDoc LIB = "SAR-INF/lib";
132     private static final String JavaDoc CLASSES = "SAR-INF/classes/";
133
134     //The names on the native filesystem
135
private static final String JavaDoc FS_CONFIG_XML = "SAR-INF" +
136         File.separator +
137         "config.xml";
138     private static final String JavaDoc FS_ASSEMBLY_XML = "SAR-INF" +
139         File.separator +
140         "assembly.xml";
141     private static final String JavaDoc FS_ENV_XML = "SAR-INF" +
142         File.separator +
143         "environment.xml";
144     private static final String JavaDoc FS_CLASSES =
145         "SAR-INF" + File.separator + "classes" + File.separator;
146
147     /**
148      * The directory which is used as the base for extracting all temporary
149      * files from archives. It is expected that the temporary files will be
150      * deleted when the .sar file is undeployed.
151      */

152     private File JavaDoc m_baseWorkDirectory;
153
154     /** The base directory in which applications are deployed. */
155     private File JavaDoc m_baseDirectory;
156
157     public void configure( final Configuration configuration )
158         throws ConfigurationException
159     {
160         final String JavaDoc workDir =
161             configuration.getChild( "base-work-dir" ).getValue();
162         final String JavaDoc appDir =
163             configuration.getChild( "base-application-dir" ).getValue();
164         m_baseWorkDirectory = new File JavaDoc( workDir );
165         m_baseDirectory = new File JavaDoc( appDir );
166     }
167
168     public void initialize()
169         throws Exception JavaDoc
170     {
171         initWorkDirectory();
172         try
173         {
174             FileUtil.cleanDirectory( m_baseWorkDirectory );
175         }
176         catch( final IOException JavaDoc ioe )
177         {
178             final String JavaDoc message =
179                 REZ.format( "nodelete-workdir.error",
180                             m_baseWorkDirectory,
181                             ioe.getMessage() );
182             getLogger().warn( message, ioe );
183         }
184     }
185
186     public void dispose()
187         throws Exception JavaDoc
188     {
189     }
190
191     /**
192      * Uninstall the Sar designated installation.
193      *
194      * @param installation the installation
195      * @throws LoomException if an error occurs
196      */

197     public void uninstall( final Map JavaDoc installation )
198         throws LoomException
199     {
200         final File JavaDoc work =
201             (File JavaDoc)installation.get( ContainerConstants.INSTALL_WORK );
202         deleteWorkDir( work );
203     }
204
205     /**
206      * Utility method to delete the working directory.
207      *
208      * @param dir the working directory
209      */

210     private void deleteWorkDir( final File JavaDoc dir )
211     {
212         try
213         {
214             FileUtil.deleteDirectory( dir );
215         }
216         catch( final IOException JavaDoc ioe )
217         {
218             try
219             {
220                 //If can't delete them now (damn windows locking!)
221
//then schedule them for deletion when JVM exits
222
FileUtil.forceDeleteOnExit( dir );
223             }
224             catch( final IOException JavaDoc ioe2 )
225             {
226                 //ignore
227
}
228             final String JavaDoc message =
229                 REZ.format( "nodelete-workdir.error",
230                             dir,
231                             ioe.getMessage() );
232             getLogger().warn( message, ioe );
233         }
234     }
235
236     /**
237      * Install the Sar designated by url.
238      *
239      * @param url the url of instalation
240      * @throws LoomException if an error occurs
241      */

242     public Map JavaDoc install( final String JavaDoc name, final URL JavaDoc url )
243         throws LoomException
244     {
245         lock();
246         try
247         {
248             final String JavaDoc notice = REZ.format( "installing-sar", url );
249             getLogger().info( notice );
250
251             final File JavaDoc file = getFileFor( url );
252             if( file.isDirectory() )
253             {
254                 final String JavaDoc message =
255                     REZ.format( "install.sar-isa-dir.error", name, url );
256                 throw new LoomException( message );
257             }
258
259             //Get Zipfile representing .sar file
260
final ZipFile JavaDoc zipFile = new ZipFile JavaDoc( file );
261             return installArchive( name, url, file, zipFile );
262         }
263         catch( final IOException JavaDoc ioe )
264         {
265             final String JavaDoc message = REZ.format( "bad-zip-file", url );
266             throw new LoomException( message, ioe );
267         }
268         finally
269         {
270             unlock();
271         }
272     }
273
274     /**
275      * Utility method to lock repository to disallow other installers to access
276      * it. Currently a no-op.
277      */

278     private void lock()
279     {
280     }
281
282     /**
283      * Utility method to unlock repository to allow other installers to access
284      * it. Currently a no-op.
285      */

286     private void unlock()
287     {
288     }
289
290     /**
291      * Install a new style sar.
292      *
293      * @param url the url designator of sar
294      * @param file the file of sar
295      * @param zipFile the ZipFile representing sar
296      * @return the Installation object
297      */

298     private Map JavaDoc installArchive( final String JavaDoc name,
299                                 final URL JavaDoc url,
300                                 final File JavaDoc file,
301                                 final ZipFile JavaDoc zipFile )
302         throws LoomException
303     {
304         final File JavaDoc directory =
305             new File JavaDoc( m_baseDirectory, name ).getAbsoluteFile();
306
307         //Question: Should we be making sure that
308
//this directory is created?
309
directory.mkdirs();
310
311         final File JavaDoc workDir = getRelativeWorkDir( name );
312         boolean success = false;
313         try
314         {
315             workDir.mkdirs();
316             expandZipFile( zipFile, directory, workDir, url );
317
318             //Prepare and create Installation
319
final String JavaDoc assembly = getURLAsString(
320                 new File JavaDoc( directory, FS_ASSEMBLY_XML ) );
321             final String JavaDoc config = getURLAsString(
322                 new File JavaDoc( directory, FS_CONFIG_XML ) );
323             final String JavaDoc environment = getURLAsString(
324                 new File JavaDoc( directory, FS_ENV_XML ) );
325
326             success = true;
327             final Map JavaDoc install = new HashMap JavaDoc();
328             install.put( ContainerConstants.INSTALL_SOURCE, file );
329             install.put( ContainerConstants.INSTALL_HOME, directory );
330             install.put( ContainerConstants.INSTALL_WORK, workDir );
331             install.put( ContainerConstants.INSTALL_CONFIG, config );
332             install.put( ContainerConstants.INSTALL_ASSEMBLY, assembly );
333             install.put( ContainerConstants.INSTALL_ENVIRONMENT, environment );
334             return install;
335         }
336         finally
337         {
338             if( !success )
339             {
340                 deleteWorkDir( workDir );
341             }
342         }
343     }
344
345     /**
346      * Expand the specified Zip file.
347      *
348      * @param zipFile the zip file
349      * @param directory the directory where to extract non-jar, non-classes
350      * files
351      * @param workDir the directory to extract classes/jar files
352      * @param url the url of deployment (for error reporting purposes)
353      * @throws LoomException if an error occurs extracting files
354      */

355     private void expandZipFile( final ZipFile JavaDoc zipFile,
356                                 final File JavaDoc directory,
357                                 final File JavaDoc workDir,
358                                 final URL JavaDoc url )
359         throws LoomException
360     {
361         final Enumeration JavaDoc entries = zipFile.entries();
362         while( entries.hasMoreElements() )
363         {
364             final ZipEntry JavaDoc entry = (ZipEntry JavaDoc)entries.nextElement();
365             final String JavaDoc name = fixName( entry.getName() );
366
367             if( name.startsWith( META_INF ) )
368             {
369                 continue;
370             }
371
372             if( handleDirs( entry, name, directory ) )
373             {
374                 continue;
375             }
376
377             if( handleClasses( zipFile,
378                                entry,
379                                name,
380                                workDir ) )
381             {
382                 continue;
383             }
384
385             if( handleJars( zipFile, entry, name, workDir ) )
386             {
387                 continue;
388             }
389
390             //Expand the file if necesasry and issue a warning
391
//if there is a file in the way
392
final File JavaDoc destination = new File JavaDoc( directory, name );
393             handleFile( zipFile, entry, destination, url );
394         }
395     }
396
397     /**
398      * Handle the extraction of normal resources from zip file/
399      */

400     private void handleFile( final ZipFile JavaDoc zipFile,
401                              final ZipEntry JavaDoc entry,
402                              final File JavaDoc destination,
403                              final URL JavaDoc url )
404         throws LoomException
405     {
406         if( !destination.exists() )
407         {
408             expandFile( zipFile, entry, destination );
409         }
410         else
411         {
412             final String JavaDoc message =
413                 REZ.format( "file-in-the-way",
414                             url,
415                             entry.getName(),
416                             destination );
417             getLogger().warn( message );
418         }
419     }
420
421     /**
422      * Handle extraction of jars.
423      *
424      * @param zipFile the zipFIle to exrtact from
425      * @param entry the entry to extract
426      * @param name the normalized name of entry
427      * @param workDir the working directory to extract to
428      * @return true if handled, false otherwise
429      */

430     private boolean handleJars( final ZipFile JavaDoc zipFile,
431                                 final ZipEntry JavaDoc entry,
432                                 final String JavaDoc name,
433                                 final File JavaDoc workDir )
434         throws LoomException
435     {
436         if( name.startsWith( LIB )
437             &&
438             name.endsWith( ".jar" )
439             && LIB.length() == name.lastIndexOf( "/" ) )
440         {
441             final File JavaDoc file = new File JavaDoc( workDir, name );
442             expandFile( zipFile, entry, file );
443             return true;
444         }
445         else
446         {
447             return false;
448         }
449     }
450
451     /**
452      * Handle extraction of jars.
453      *
454      * @param zipFile the zipFIle to exrtact from
455      * @param entry the entry to extract
456      * @param name the normalized name of entry
457      * @param workDir the working directory to extract to
458      * @return true if handled, false otherwise
459      */

460     private boolean handleClasses( final ZipFile JavaDoc zipFile,
461                                    final ZipEntry JavaDoc entry,
462                                    final String JavaDoc name,
463                                    final File JavaDoc workDir )
464         throws LoomException
465     {
466         if( name.startsWith( CLASSES ) )
467         {
468             final File JavaDoc classDir = new File JavaDoc( workDir, FS_CLASSES );
469             if( !classDir.exists() )
470             {
471                 final File JavaDoc file = new File JavaDoc( workDir, name );
472                 expandFile( zipFile, entry, file );
473             }
474             return true;
475         }
476         else
477         {
478             return false;
479         }
480     }
481
482     /**
483      * Handle expansion of dirs in the zipfile.
484      *
485      * @param entry the current ZipEntry
486      * @param name the name of entry
487      * @param directory the base directory extraacting to
488      * @return true if handled, false otherwise
489      */

490     private boolean handleDirs( final ZipEntry JavaDoc entry,
491                                 final String JavaDoc name,
492                                 final File JavaDoc directory )
493     {
494         if( entry.isDirectory() )
495         {
496             if( !name.startsWith( SAR_INF ) )
497             {
498                 final File JavaDoc newDir =
499                     new File JavaDoc( directory, name );
500                 newDir.mkdirs();
501             }
502             return true;
503         }
504         else
505         {
506             return false;
507         }
508     }
509
510     /**
511      * Create working directory inside baseWorkDir for specified application.
512      *
513      * @param name the name of the application
514      * @return the working directory for app
515      */

516     private File JavaDoc getRelativeWorkDir( final String JavaDoc name )
517     {
518         final String JavaDoc filename =
519             name + "-" + System.currentTimeMillis();
520         return new File JavaDoc( m_baseWorkDirectory, filename );
521     }
522
523     /**
524      * Fix the specified name so that it does not start with a "/" character.
525      *
526      * @param name the name to fix
527      * @return the name stripped of initial "/" if necessary
528      */

529     private String JavaDoc fixName( final String JavaDoc name )
530     {
531         if( name.startsWith( "/" ) )
532         {
533             return name.substring( 1 );
534         }
535         else
536         {
537             return name;
538         }
539     }
540
541     /**
542      * Get File object for URL. Currently it assumes that URL is a file URL but
543      * in the future it will allow downloading of remote URLs thus enabling a
544      * deploy from anywhere functionality.
545      *
546      * @param url the url of deployment
547      * @return the File for deployment
548      * @throws LoomException if an error occurs
549      */

550     private File JavaDoc getFileFor( final URL JavaDoc url )
551         throws LoomException
552     {
553         if( !url.getProtocol().equals( "file" ) )
554         {
555             final String JavaDoc message = REZ.format( "install-nonlocal", url );
556             throw new LoomException( message );
557         }
558
559         File JavaDoc file = new File JavaDoc( url.getFile() );
560         file = file.getAbsoluteFile();
561
562         if( !file.exists() )
563         {
564             final String JavaDoc message = REZ.format( "install-nourl", file );
565             throw new LoomException( message );
566         }
567
568         return file;
569     }
570
571     /**
572      * Expand a single zipEntry to a file.
573      */

574     private void expandFile( final ZipFile JavaDoc zipFile,
575                              final ZipEntry JavaDoc entry,
576                              final File JavaDoc file )
577         throws LoomException
578     {
579         InputStream JavaDoc input = null;
580         OutputStream JavaDoc output = null;
581
582         try
583         {
584             file.getParentFile().mkdirs();
585             output = new FileOutputStream JavaDoc( file );
586             input = zipFile.getInputStream( entry );
587             IOUtil.copy( input, output );
588         }
589         catch( final IOException JavaDoc ioe )
590         {
591             final String JavaDoc message =
592                 REZ.format( "failed-to-expand",
593                             entry.getName(),
594                             file,
595                             ioe.getMessage() );
596             throw new LoomException( message, ioe );
597         }
598         finally
599         {
600             IOUtil.shutdownStream( input );
601             IOUtil.shutdownStream( output );
602         }
603     }
604
605     /**
606      * Utility method to extract URL from file in safe manner.
607      *
608      * @param file the file
609      * @return the URL representation of file
610      */

611     private String JavaDoc getURLAsString( final File JavaDoc file )
612     {
613         try
614         {
615             return file.toURL().toExternalForm();
616         }
617         catch( final MalformedURLException JavaDoc mue )
618         {
619             return null;
620             //should never occur
621
}
622     }
623
624     /**
625      * Make sure that the work directory is created and not a file.
626      *
627      * @throws Exception if work directory can not be created or is a file
628      */

629     private void initWorkDirectory()
630         throws Exception JavaDoc
631     {
632         if( !m_baseWorkDirectory.exists() )
633         {
634             final String JavaDoc message =
635                 REZ.format( "install.create-dir.notice",
636                             m_baseWorkDirectory );
637             getLogger().info( message );
638
639             if( !m_baseWorkDirectory.mkdirs() )
640             {
641                 final String JavaDoc error =
642                     REZ.format( "install.workdir-nocreate.error",
643                                 m_baseWorkDirectory );
644                 throw new Exception JavaDoc( error );
645             }
646         }
647
648         if( !m_baseWorkDirectory.isDirectory() )
649         {
650             final String JavaDoc message =
651                 REZ.format( "install.workdir-notadir.error",
652                             m_baseWorkDirectory );
653             throw new Exception JavaDoc( message );
654         }
655     }
656 }
657
Popular Tags