OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 19 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
18 ilm 1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
7
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
8
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
9
 * language governing permissions and limitations under the License.
10
 *
11
 * When distributing the software, include this License Header Notice in each file.
12
 */
13
 
14
 package org.openconcerto.erp.modules;
15
 
16
import org.openconcerto.utils.StreamUtils;
17
 
18
import java.io.BufferedInputStream;
19
import java.io.BufferedOutputStream;
20
import java.io.File;
21
import java.io.FileInputStream;
22
import java.io.FileOutputStream;
23
import java.io.IOException;
24
import java.io.InputStream;
25
import java.util.ArrayList;
26
import java.util.List;
27
import java.util.jar.JarEntry;
28
import java.util.jar.JarOutputStream;
29
 
30
/**
31
 * Package a module from its properties and classes.
32
 *
33
 * @author Sylvain CUAZ
34
 */
35
public class ModulePackager {
36
    public static final String MODULE_PROPERTIES_PATH = "META-INF/openConcertoModule.properties";
37
 
38
    private final List<File> classesDirs;
39
    private final File propsFile;
40
 
41
    public ModulePackager(final File propsFile, final File classes) {
42
        this.propsFile = propsFile;
43
        this.classesDirs = new ArrayList<File>(8);
44
        this.classesDirs.add(classes);
45
    }
46
 
47
    public final void addDir(final File classesDir) {
48
        this.classesDirs.add(classesDir);
49
    }
50
 
51
    /**
52
     * Write the package to the passed directory.
53
     *
54
     * @param dir where to create the package (its name will contain its id and version).
55
     * @throws IOException if the package cannot be created.
56
     */
57
    public final void writeToDir(final File dir) throws IOException {
58
        final RuntimeModuleFactory f = new RuntimeModuleFactory(this.propsFile);
59
        final File jarFile = new File(dir, f.getID() + "-" + f.getMajorVersion() + "." + f.getMinorVersion() + ".jar");
60
        final JarOutputStream jarStream = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(jarFile)));
61
        try {
62
            if (!this.zipExistingFile(jarStream, this.propsFile, MODULE_PROPERTIES_PATH))
63
                throw new IllegalStateException("Missing properties file : " + this.propsFile);
64
            for (final File classesDir : this.classesDirs)
65
                this.zipBelow(jarStream, classesDir);
66
        } finally {
67
            jarStream.close();
68
        }
69
    }
70
 
71
    // doesn't zip f
72
    protected void zipBelow(JarOutputStream jarStream, File f) throws IOException {
73
        this.zipRec(jarStream, f, "");
74
    }
75
 
76
    private String getPath(File f) throws IOException {
77
        String res = f.getAbsolutePath();
78
        if (f.isDirectory() && !res.endsWith("/"))
79
            res += '/';
80
        return res;
81
    }
82
 
83
    private String getEntryName(File f, File base) throws IOException {
84
        // needed otherwise we could pass ('abc', 'a')
85
        // but if base is a directory then its path is 'a/'
86
        if (!base.isDirectory())
87
            throw new IllegalArgumentException("Base not a directory : " + base);
88
        final String fPath = getPath(f);
89
        final String basePath = getPath(base);
90
        if (!fPath.startsWith(basePath))
91
            throw new IllegalArgumentException("Base is not a parent :\n" + base + "\n" + f);
92
        return fPath.substring(basePath.length()).replace('\\', '/');
93
    }
94
 
95
    protected void zipRec(JarOutputStream jarStream, File f, File base) throws IOException {
96
        zipRec(jarStream, f, getEntryName(f, base));
97
    }
98
 
99
    protected void zipRec(JarOutputStream jarStream, File f, final String entryName) throws IOException {
100
        if (entryName.length() > 0)
101
            this.zipExistingFile(jarStream, f, entryName);
102
        if (f.isDirectory())
103
            for (final File child : f.listFiles()) {
104
                this.zipRec(jarStream, child, entryName + '/' + child.getName());
105
            }
106
    }
107
 
108
    protected boolean zipExistingFile(JarOutputStream jarStream, File f, File base) throws IOException {
109
        return this.zipExistingFile(jarStream, f, getEntryName(f, base));
110
    }
111
 
112
    protected boolean zipExistingFile(JarOutputStream jarStream, File f, final String entryName) throws IOException {
113
        if (!f.exists())
114
            return false;
115
        final boolean isDir = f.isDirectory();
116
 
117
        String name = entryName;
118
        if (name.startsWith("/"))
119
            name = name.substring(1);
120
        if (isDir && !name.endsWith("/"))
121
            name += "/";
122
        final JarEntry entry = new JarEntry(name);
123
        entry.setTime(f.lastModified());
124
        if (!isDir)
125
            entry.setSize(f.length());
126
 
127
        final InputStream in = isDir ? null : new BufferedInputStream(new FileInputStream(f));
128
        try {
129
            zip(jarStream, entry, in);
130
        } finally {
131
            if (in != null)
132
                in.close();
133
        }
134
        return true;
135
    }
136
 
137
    private void zip(JarOutputStream jarStream, final JarEntry entry, InputStream in) throws IOException {
138
        jarStream.putNextEntry(entry);
139
        if (in != null) {
140
            StreamUtils.copy(in, jarStream);
141
        }
142
        jarStream.closeEntry();
143
    }
144
}