001    /**
002     *  Licensed to the Apache Software Foundation (ASF) under one or more
003     *  contributor license agreements.  See the NOTICE file distributed with
004     *  this work for additional information regarding copyright ownership.
005     *  The ASF licenses this file to You under the Apache License, Version 2.0
006     *  (the "License"); you may not use this file except in compliance with
007     *  the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    package org.apache.geronimo.system.configuration;
018    
019    import java.io.File;
020    import java.io.FileInputStream;
021    import java.io.FileOutputStream;
022    import java.io.IOException;
023    import java.io.InputStream;
024    import java.io.OutputStream;
025    import java.io.OutputStreamWriter;
026    import java.io.PrintWriter;
027    import java.io.FileWriter;
028    import java.io.Writer;
029    import java.net.URI;
030    import java.util.Collection;
031    import java.util.Collections;
032    import java.util.Iterator;
033    import java.util.LinkedList;
034    import java.util.Arrays;
035    import java.util.jar.JarOutputStream;
036    import java.util.jar.Manifest;
037    import java.util.zip.ZipEntry;
038    
039    import org.apache.geronimo.kernel.config.ConfigurationData;
040    import org.apache.geronimo.kernel.config.ConfigurationUtil;
041    
042    /**
043     * @version $Rev: 476049 $ $Date: 2006-11-16 23:35:17 -0500 (Thu, 16 Nov 2006) $
044     */
045    public final class ExecutableConfigurationUtil {
046        private static final String META_INF = "META-INF";
047        private static final String CONFIG_SER = "config.ser";
048        private static final String CONFIG_INFO = "config.info";
049        private static final String META_INF_STARTUP_JAR = META_INF + "/startup-jar";
050        private static final String META_INF_CONFIG_SER = META_INF + "/" + CONFIG_SER;
051        private static final String META_INF_CONFIG_SER_SHA1 = META_INF_CONFIG_SER + ".sha1";
052        private static final String META_INF_CONFIG_INFO = META_INF + "/" + CONFIG_INFO;
053    
054        private static final Collection EXCLUDED = Arrays.asList(new String[] {META_INF_STARTUP_JAR, META_INF_CONFIG_SER, META_INF_CONFIG_SER_SHA1, META_INF_CONFIG_INFO});
055    
056        private ExecutableConfigurationUtil() {
057        }
058    
059        public static void createExecutableConfiguration(ConfigurationData configurationData, Manifest manifest, File destinationFile) throws IOException {
060            File configurationDir = configurationData.getConfigurationDir();
061            
062            // ensure parent directories have been created
063            File parent = destinationFile.getParentFile();
064            if (parent != null && !parent.exists()) parent.mkdirs();
065            
066            FileOutputStream fos = null;
067            JarOutputStream out = null;
068            try {
069                byte[] buffer = new byte[4096];
070    
071                fos = new FileOutputStream(destinationFile, false);
072                
073                if (manifest != null) {
074                    out = new JarOutputStream(fos, manifest); 
075    
076                    // add the startup file which allows us to locate the startup directory
077                    out.putNextEntry(new ZipEntry(META_INF_STARTUP_JAR));
078                    // intentionally empty ZipEntry
079                    out.closeEntry();
080                } else {
081                    out = new JarOutputStream(fos);
082                }
083    
084                // write the configurationData
085                ExecutableConfigurationUtil.writeConfiguration(configurationData, out);
086    
087                URI baseURI = configurationDir.getAbsoluteFile().toURI();
088                Collection files = listRecursiveFiles(configurationDir);
089                for (Iterator iterator = files.iterator(); iterator.hasNext();) {
090                    File file = (File) iterator.next();
091                    String relativePath = baseURI.relativize(file.toURI()).getPath();
092                    if (!EXCLUDED.contains(relativePath)) {
093                        InputStream in = new FileInputStream(file);
094                        try {
095                            out.putNextEntry(new ZipEntry(relativePath));
096                            try {
097                                int count;
098                                while ((count = in.read(buffer)) > 0) {
099                                    out.write(buffer, 0, count);
100                                }
101                            } finally {
102                                out.closeEntry();
103                            }
104                        } finally {
105                            close(in);
106                        }
107                    }
108                }
109            } finally {
110                close(out);
111                close(fos); // do this in case JarOutputStream contructor threw an exception
112            }
113        }
114    
115        public static void writeConfiguration(ConfigurationData configurationData, JarOutputStream out) throws IOException {
116            // save the persisted form in the source directory
117            out.putNextEntry(new ZipEntry(META_INF_CONFIG_SER));
118            ConfigurationStoreUtil.ChecksumOutputStream sumOut = null;
119            try {
120                sumOut = new ConfigurationStoreUtil.ChecksumOutputStream(out);
121                ConfigurationUtil.writeConfigurationData(configurationData, sumOut);
122            } finally {
123                out.closeEntry();
124            }
125    
126            // write the checksum file
127            out.putNextEntry(new ZipEntry(META_INF_CONFIG_SER_SHA1));
128            try {
129                OutputStreamWriter writer = new OutputStreamWriter(out);
130                writer.write(sumOut.getChecksum());
131                writer.flush();
132            } finally {
133                out.closeEntry();
134            }
135    
136            // write the info file
137            out.putNextEntry(new ZipEntry(META_INF_CONFIG_INFO));
138            try {
139                PrintWriter writer = new PrintWriter(new OutputStreamWriter(out));
140                ConfigurationUtil.writeConfigInfo(writer, configurationData);
141                writer.flush();
142            } finally {
143                out.closeEntry();
144            }
145        }
146    
147        public static void writeConfiguration(ConfigurationData configurationData, File source) throws IOException {
148            // save the persisted form in the source directory
149            File metaInf = new File(source, META_INF);
150            metaInf.mkdirs();
151            File configSer = new File(metaInf, CONFIG_SER);
152    
153            OutputStream out = new FileOutputStream(configSer);
154            try {
155                ConfigurationUtil.writeConfigurationData(configurationData, out);
156            } finally {
157                flush(out);
158                close(out);
159            }
160    
161            // write the check sum file
162            ConfigurationStoreUtil.writeChecksumFor(configSer);
163    
164            // write the info file
165            PrintWriter writer = null;
166            try {
167                writer = new PrintWriter(new FileWriter(new File(metaInf, CONFIG_INFO)));
168                ConfigurationUtil.writeConfigInfo(writer, configurationData);
169            } finally {
170                flush(writer);
171                close(writer);
172            }
173        }
174    
175        private static Collection listRecursiveFiles(File file) {
176            LinkedList list = new LinkedList();
177            listRecursiveFiles(file, list);
178            return Collections.unmodifiableCollection(list);
179        }
180    
181        private static void listRecursiveFiles(File file, Collection collection) {
182            File[] files = file.listFiles();
183            if (null == files) {
184                return;
185            }
186            for (int i = 0; i < files.length; i++) {
187                if (files[i].isDirectory()) {
188                    listRecursiveFiles(files[i], collection);
189                } else {
190                    collection.add(files[i]);
191                }
192            }
193        }
194    
195        private static void flush(OutputStream thing) {
196            if (thing != null) {
197                try {
198                    thing.flush();
199                } catch (Exception ignored) {
200                }
201            }
202        }
203    
204        private static void flush(Writer thing) {
205            if (thing != null) {
206                try {
207                    thing.flush();
208                } catch (Exception ignored) {
209                }
210            }
211        }
212    
213        private static void close(InputStream thing) {
214            if (thing != null) {
215                try {
216                    thing.close();
217                } catch (Exception ignored) {
218                }
219            }
220        }
221    
222        private static void close(OutputStream thing) {
223            if (thing != null) {
224                try {
225                    thing.close();
226                } catch (Exception ignored) {
227                }
228            }
229        }
230    
231        private static void close(Writer thing) {
232            if (thing != null) {
233                try {
234                    thing.close();
235                } catch (Exception ignored) {
236                }
237            }
238        }
239    }