1 /* 2 * Copyright (c) 2014, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.tools.jlink.internal; 27 28 import java.io.IOException; 29 import java.io.InputStream; 30 import java.io.UncheckedIOException; 31 import java.nio.file.Path; 32 import java.util.Objects; 33 import java.util.stream.Stream; 34 35 import jdk.internal.jmod.JmodFile; 36 import jdk.tools.jlink.internal.Archive.Entry.EntryType; 37 38 /** 39 * An Archive backed by a jmod file. 40 */ 41 public class JmodArchive implements Archive { 42 private static final String JMOD_EXT = ".jmod"; 43 44 /** 45 * An entry located in a jmod file. 46 */ 47 public class JmodEntry extends Entry { 48 private final JmodFile.Entry entry; 49 50 JmodEntry(String path, String name, EntryType type, 51 JmodFile.Entry entry) { 52 super(JmodArchive.this, path, name, type); 53 this.entry = Objects.requireNonNull(entry); 54 } 55 56 /** 57 * Returns the number of uncompressed bytes for this entry. 58 */ 59 @Override 60 public long size() { 61 return entry.size(); 62 } 63 64 @Override 65 public InputStream stream() throws IOException { 66 return jmodFile.getInputStream(entry.section(), entry.name()); 67 } 68 } 69 70 private final Path file; 71 private final String moduleName; 72 private JmodFile jmodFile; 73 74 public JmodArchive(String mn, Path jmod) { 75 Objects.requireNonNull(mn); 76 Objects.requireNonNull(jmod.getFileName()); 77 String filename = jmod.toString(); 78 if (!filename.endsWith(JMOD_EXT)) { 79 throw new UnsupportedOperationException("Unsupported format: " + filename); 80 } 81 this.moduleName = mn; 82 this.file = jmod; 83 } 84 85 @Override 86 public String moduleName() { 87 return moduleName; 88 } 89 90 @Override 91 public Path getPath() { 92 return file; 93 } 94 95 @Override 96 public Stream<Entry> entries() { 97 ensureOpen(); 98 return jmodFile.stream() 99 .map(this::toEntry); 100 } 101 102 @Override 103 public void open() throws IOException { 104 if (jmodFile != null) { 105 jmodFile.close(); 106 } 107 this.jmodFile = new JmodFile(file); 108 } 109 110 @Override 111 public void close() throws IOException { 112 if (jmodFile != null) { 113 jmodFile.close(); 114 } 115 } 116 117 private void ensureOpen() { 118 if (jmodFile == null) { 119 try { 120 open(); 121 } catch(IOException ioe){ 122 throw new UncheckedIOException(ioe); 123 } 124 } 125 } 126 127 private EntryType toEntryType(JmodFile.Section section) { 128 switch (section) { 129 case CLASSES: 130 return EntryType.CLASS_OR_RESOURCE; 131 case CONFIG: 132 return EntryType.CONFIG; 133 case HEADER_FILES: 134 return EntryType.HEADER_FILE; 135 case LEGAL_NOTICES: 136 return EntryType.LEGAL_NOTICE; 137 case MAN_PAGES: 138 return EntryType.MAN_PAGE; 139 case NATIVE_LIBS: 140 return EntryType.NATIVE_LIB; 141 case NATIVE_CMDS: 142 return EntryType.NATIVE_CMD; 143 default: 144 throw new InternalError("unexpected entry: " + section); 145 } 146 } 147 148 private Entry toEntry(JmodFile.Entry entry) { 149 EntryType type = toEntryType(entry.section()); 150 String prefix = entry.section().jmodDir(); 151 String name = entry.name(); 152 String path = prefix + "/" + name; 153 String resourceName = name; 154 155 // The resource name represents the path of ResourcePoolEntry 156 // and its subpath defines the ultimate path to be written 157 // to the image relative to the directory corresponding to that 158 // resource type. 159 // 160 // For classes and resources, the resource name does not have 161 // a prefix (<package>/<name>). They will be written to the jimage. 162 // 163 // For other kind of entries, it will keep the section name as 164 // the prefix for unique identification. The subpath (taking 165 // out the section name) is the pathname to be written to the 166 // corresponding directory in the image. 167 // 168 if (type == EntryType.LEGAL_NOTICE) { 169 // legal notices are written to per-module directory 170 resourceName = prefix + "/" + moduleName + "/" + name; 171 } else if (type != EntryType.CLASS_OR_RESOURCE) { 172 resourceName = path; 173 } 174 175 return new JmodEntry(path, resourceName, type, entry); 176 } 177 }