001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     *  http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing,
013     * software distributed under the License is distributed on an
014     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     * KIND, either express or implied.  See the License for the
016     * specific language governing permissions and limitations
017     * under the License.
018     */
019    
020    
021    package org.apache.geronimo.system.plugin;
022    
023    import java.io.File;
024    import java.io.IOException;
025    import java.util.ArrayList;
026    import java.util.HashMap;
027    import java.util.List;
028    import java.util.Map;
029    
030    import org.apache.geronimo.gbean.GBeanInfo;
031    import org.apache.geronimo.gbean.GBeanInfoBuilder;
032    import org.apache.geronimo.kernel.config.IOUtil;
033    import org.apache.geronimo.kernel.repository.Artifact;
034    import org.apache.geronimo.system.serverinfo.ServerInfo;
035    import org.codehaus.plexus.archiver.Archiver;
036    import org.codehaus.plexus.archiver.ArchiverException;
037    import org.codehaus.plexus.archiver.UnixStat;
038    import org.codehaus.plexus.archiver.tar.TarArchiver;
039    import org.codehaus.plexus.archiver.tar.TarLongFileMode;
040    import org.codehaus.plexus.archiver.zip.ZipArchiver;
041    //maven inconsistency -- if we can use 1.0-alpha-9 uncomment
042    //import org.codehaus.plexus.archiver.util.DefaultFileSet;
043    
044    /**
045     * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
046     */
047    public class ArchiverGBean implements ServerArchiver {
048    
049        private final ServerInfo serverInfo;
050    
051        private List<String> excludes = new ArrayList<String>();
052    
053        public ArchiverGBean(ServerInfo serverInfo) {
054            this.serverInfo = serverInfo;
055        }
056    
057        public void addExclude(String pattern) {
058            this.excludes.add(pattern);
059        }
060        
061        public void removeExclude(String pattern) {
062            this.excludes.remove(pattern);
063        }
064        
065        private void removeExcludes(File source, Map<String, File> all) {
066            Map<String, File> matches = new HashMap<String, File>();
067            for (String exclude : this.excludes) {
068                IOUtil.find(source, exclude, matches);
069            }
070    
071            for (String exclude : matches.keySet()) {
072                all.remove(exclude);
073            }
074        }
075            
076        public File archive(String sourcePath, String destPath, Artifact artifact) throws ArchiverException, IOException {
077            File source = serverInfo.resolve(sourcePath);
078            File dest = serverInfo.resolve(destPath);
079            String serverName = artifact.getArtifactId() + "-" + artifact.getVersion();
080            dest = new File(dest, serverName + "-bin." + artifact.getType());
081            Archiver archiver;
082            if ("tar.gz".equals(artifact.getType())) {
083                archiver = new TarArchiver();
084                TarArchiver.TarCompressionMethod tarCompressionMethod = new TarArchiver.TarCompressionMethod();
085                tarCompressionMethod.setValue("gzip");
086                ((TarArchiver) archiver).setCompression(tarCompressionMethod);
087                TarLongFileMode fileMode = new TarLongFileMode();
088                fileMode.setValue(TarLongFileMode.GNU);
089                ((TarArchiver) archiver).setLongfile(fileMode);
090            } else if ("zip".equals(artifact.getType())) {
091                archiver = new ZipArchiver();
092            } else {
093                throw new IllegalArgumentException("Unknown target type: " + artifact.getType());
094            }
095            archiver.setIncludeEmptyDirs(true);
096            archiver.setDestFile(dest);
097    /* see if using plexus-archiver 1.0-alpha-7 same as maven lets us share code.  Following is for 1.0-alpha-9
098            DefaultFileSet all = new DefaultFileSet();
099            all.setDirectory(source);
100            archiver.addFileSet(all);
101    */
102            
103            // add in all files and mark them with default file permissions
104            Map<File, Boolean> emptyDirs = new HashMap<File, Boolean>();
105            Map<String, File> all = IOUtil.listAllFileNames(source);
106            removeExcludes(source, all);
107            for (Map.Entry<String, File> entry : all.entrySet()) {
108                String destFileName = serverName + "/" + entry.getKey();
109                File sourceFile = entry.getValue();
110                if (sourceFile.isFile()) {
111                    archiver.addFile(sourceFile, destFileName, UnixStat.DEFAULT_FILE_PERM);
112                    // mark parent directories non-empty
113                    for (File parentDir = sourceFile.getParentFile();
114                         parentDir != null && !parentDir.equals(source);
115                         parentDir = parentDir.getParentFile()) {               
116                        emptyDirs.put(parentDir, Boolean.FALSE);
117                    }
118                    
119                } else if (sourceFile.isDirectory()) {                           
120                    Boolean isEmpty = emptyDirs.get(sourceFile);                
121                    if (isEmpty == null) {       
122                        emptyDirs.put(sourceFile, Boolean.TRUE);
123                        // mark parent directories non-empty
124                        for (File parentDir = sourceFile.getParentFile();
125                             parentDir != null && !parentDir.equals(source);
126                             parentDir = parentDir.getParentFile()) {               
127                            emptyDirs.put(parentDir, Boolean.FALSE);
128                        }
129                    }              
130                }
131            }
132            
133            if (!all.isEmpty()) {
134                emptyDirs.put(source, Boolean.FALSE);
135            }
136                    
137            String sourceDirPath = source.getAbsolutePath();
138            for (Map.Entry<File, Boolean> entry : emptyDirs.entrySet()) {
139                if (entry.getValue().booleanValue()) {                
140                    String emptyDirPath = entry.getKey().getAbsolutePath();
141                    String relativeDir = emptyDirPath.substring(sourceDirPath.length());
142                    relativeDir = relativeDir.replace('\\', '/');
143                    archiver.addDirectory(entry.getKey(), serverName + relativeDir);
144                }
145            }
146            emptyDirs.clear();
147            
148            all.clear();
149            
150            // add execute permissions to all non-batch files in the bin/ directory
151            File bin = new File(source, "bin");
152            if (bin.exists()) {
153                Map<String, File> includes = IOUtil.listAllFileNames(bin);
154                for (Map.Entry<String, File> entry : includes.entrySet()) {
155                    String destFileName = serverName + "/bin/" + entry.getKey();
156                    File sourceFile = entry.getValue();
157                    if (!destFileName.endsWith(".bat") && sourceFile.isFile()) {
158                        archiver.addFile(sourceFile, destFileName, UnixStat.DEFAULT_DIR_PERM);
159                    }
160                }
161            }
162            
163            archiver.createArchive();
164            return dest;
165        }
166    
167        public static final GBeanInfo GBEAN_INFO;
168    
169        static {
170            GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic(ArchiverGBean.class);
171            infoFactory.addReference("ServerInfo", ServerInfo.class, "GBean");
172    
173            infoFactory.setConstructor(new String[]{"ServerInfo"});
174    
175            GBEAN_INFO = infoFactory.getBeanInfo();
176        }
177    
178        public static GBeanInfo getGBeanInfo() {
179            return GBEAN_INFO;
180        }
181    
182    }