1/*
2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24import java.io.IOException;
25import java.io.OutputStream;
26import java.nio.file.Files;
27import java.nio.file.Paths;
28import java.util.ArrayList;
29import java.util.List;
30import java.util.jar.Attributes;
31import java.util.jar.JarEntry;
32import java.util.jar.JarOutputStream;
33import java.util.jar.Manifest;
34
35public class JarBuilder {
36    final private String name;
37    final private Attributes attributes = new Attributes();
38    final private List<Entry> entries = new ArrayList<>();
39
40    public JarBuilder(String name) {
41        this.name = name;
42        attributes.putValue("Manifest-Version", "1.0");
43        attributes.putValue("Created-By", "1.9.0-internal (Oracle Corporation)");
44    }
45
46    public JarBuilder addAttribute(String name, String value) {
47        attributes.putValue(name, value);
48        return this;
49    }
50
51    public JarBuilder addEntry(String name, byte[] bytes) {
52        entries.add(new Entry(name, bytes));
53        return this;
54    }
55
56    public void build() throws IOException {
57        try (OutputStream os = Files.newOutputStream(Paths.get(name));
58             JarOutputStream jos = new JarOutputStream(os)) {
59            JarEntry me = new JarEntry("META-INF/MANIFEST.MF");
60            jos.putNextEntry(me);
61            Manifest manifest = new Manifest();
62            manifest.getMainAttributes().putAll(attributes);
63            manifest.write(jos);
64            jos.closeEntry();
65            entries.forEach(e -> {
66                JarEntry je = new JarEntry(e.name);
67                try {
68                    jos.putNextEntry(je);
69                    jos.write(e.bytes);
70                    jos.closeEntry();
71                } catch (IOException iox) {
72                    throw new RuntimeException(iox);
73                }
74            });
75        } catch (RuntimeException x) {
76            Throwable t = x.getCause();
77            if (t instanceof IOException) {
78                IOException iox = (IOException)t;
79                throw iox;
80            }
81            throw x;
82        }
83    }
84
85    private static class Entry {
86        String name;
87        byte[] bytes;
88
89        Entry(String name, byte[] bytes) {
90            this.name = name;
91            this.bytes = bytes;
92        }
93    }
94
95    public static void main(String[] args) throws IOException {
96        JarBuilder jb = new JarBuilder("version.jar");
97        jb.addAttribute("Multi-Release", "true");
98        String s = "something to say";
99        byte[] bytes = s.getBytes();
100        jb.addEntry("version/Version.class", bytes);
101        jb.addEntry("README", bytes);
102        jb.addEntry("version/Version.java", bytes);
103        jb.build();
104    }
105}
106