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. 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 package jdk.tools.jlink.internal; 26 27 import java.io.File; 28 import java.io.IOException; 29 import java.io.InputStream; 30 import java.nio.file.Files; 31 import java.nio.file.Path; 32 import java.util.ArrayList; 33 import java.util.List; 34 import java.util.Objects; 35 import java.util.function.Consumer; 36 import java.util.stream.Stream; 37 38 /** 39 * An Archive backed by a directory. 40 */ 41 public class DirArchive implements Archive { 42 43 /** 44 * A File located in a Directory. 45 */ 46 private class FileEntry extends Archive.Entry { 47 48 private final long size; 49 private final Path path; 50 51 FileEntry(Path path, String name) { 52 super(DirArchive.this, getPathName(path), name, 53 Archive.Entry.EntryType.CLASS_OR_RESOURCE); 54 this.path = path; 55 try { 56 size = Files.size(path); 57 } catch (IOException ex) { 58 throw new RuntimeException(ex); 59 } 60 } 61 62 /** 63 * Returns the number of bytes of this file. 64 */ 65 @Override 66 public long size() { 67 return size; 68 } 69 70 @Override 71 public InputStream stream() throws IOException { 72 InputStream stream = Files.newInputStream(path); 73 open.add(stream); 74 return stream; 75 } 76 } 77 78 private static final String MODULE_INFO = "module-info.class"; 79 80 private final Path dirPath; 81 private final String moduleName; 82 private final List<InputStream> open = new ArrayList<>(); 83 private final int chop; 84 private final Consumer<String> log; 85 private static final Consumer<String> noopConsumer = (String t) -> { 86 }; 87 88 public DirArchive(Path dirPath) { 89 this(dirPath, noopConsumer); 90 } 91 92 public DirArchive(Path dirPath, Consumer<String> log) { 93 Objects.requireNonNull(dirPath); 94 if (!Files.isDirectory(dirPath)) { 95 throw new IllegalArgumentException("Not a directory"); 96 } 97 chop = dirPath.toString().length() + 1; 98 this.moduleName = Objects.requireNonNull(dirPath.getFileName()).toString(); 99 this.dirPath = dirPath; 100 this.log = log; 101 } 102 103 @Override 104 public String moduleName() { 105 return moduleName; 106 } 107 108 @Override 109 public Path getPath() { 110 return dirPath; 111 } 112 113 @Override 114 public Stream<Entry> entries() { 115 try { 116 return Files.walk(dirPath).map(this::toEntry).filter(n -> n != null); 117 } catch (IOException ex) { 118 throw new RuntimeException(ex); 119 } 120 } 121 122 private Archive.Entry toEntry(Path p) { 123 if (Files.isDirectory(p)) { 124 return null; 125 } 126 String name = getPathName(p).substring(chop); 127 if (name.startsWith("_")) { 128 return null; 129 } 130 log.accept(moduleName + "/" + name); 131 if (name.equals(MODULE_INFO)) { 132 name = moduleName + "/" + MODULE_INFO; 133 } 134 return new FileEntry(p, name); 135 } 136 137 @Override 138 public void close() throws IOException { 139 IOException e = null; 140 for (InputStream stream : open) { 141 try { 142 stream.close(); 143 } catch (IOException ex) { 144 if (e == null) { 145 e = ex; 146 } else { 147 e.addSuppressed(ex); 148 } 149 } 150 } 151 if (e != null) { 152 throw e; 153 } 154 } 155 156 @Override 157 public void open() throws IOException { 158 // NOOP 159 } 160 161 private static String getPathName(Path path) { 162 return path.toString().replace(File.separatorChar, '/'); 163 } 164 }