1 /* 2 * Copyright (c) 2010, 2012 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 org.openjdk.jigsaw; 27 28 import java.io.*; 29 import java.lang.module.*; 30 import java.util.*; 31 32 import static org.openjdk.jigsaw.Repository.ModuleType; 33 import static org.openjdk.jigsaw.FileConstants.ModuleFile.HashType; 34 35 36 /** 37 * <p> A {@linkplain Repository module repository's} catalog </p> 38 */ 39 40 public abstract class RepositoryCatalog { 41 42 // ## Elements in this class are public only to enable unit tests 43 44 private static final JigsawModuleSystem jms 45 = JigsawModuleSystem.instance(); 46 47 public abstract void gatherDeclaringModuleIds(Set<ModuleId> mids) 48 throws IOException; 49 50 public abstract void gatherModuleIds(String moduleName, Set<ModuleId> mids) 51 throws IOException; 52 53 public abstract byte[] readModuleInfoBytes(ModuleId mid) 54 throws IOException; 55 56 static class Entry { 57 58 final ModuleType type; 59 final byte[] mibs; 60 final long csize; 61 final long usize; 62 final HashType hashType; 63 final byte[] hash; 64 65 Entry(ModuleType t, byte[] m, long cs, long us, HashType ht, byte[] h) { 66 type = t; 67 mibs = m; 68 csize = cs; 69 usize = us; 70 hashType = ht; 71 hash = h; 72 } 73 74 } 75 76 abstract void add(Entry e); 77 78 public void add(ModuleType t, byte[] mibs, long cs, long us, 79 HashType hashType, byte[] hash) 80 { 81 add(new Entry(t, mibs, cs, us, hashType, hash)); 82 } 83 84 public abstract boolean remove(ModuleId mid); 85 86 abstract Entry get(ModuleId mid); 87 88 89 /** 90 * <p> A {@linkplain RepositoryCatalog repository catalog} which can be 91 * stored to, and then loaded from, a byte stream </p> 92 */ 93 public static class StreamedRepositoryCatalog 94 extends RepositoryCatalog 95 { 96 97 static final int MAJOR_VERSION = 0; 98 static final int MINOR_VERSION = 0; 99 100 private Map<ModuleId,Entry> modules = new HashMap<>(); 101 private Map<ModuleId,ModuleId> moduleForViewId= new HashMap<>(); 102 103 @Override 104 public void gatherDeclaringModuleIds(Set<ModuleId> mids) { 105 mids.addAll(modules.keySet()); 106 } 107 108 @Override 109 public void gatherModuleIds(String moduleName, Set<ModuleId> mids) { 110 for (ModuleId mid : moduleForViewId.keySet()) { 111 if (moduleName == null || mid.name().equals(moduleName)) 112 mids.add(mid); 113 } 114 } 115 116 @Override 117 public byte[] readModuleInfoBytes(ModuleId mid) { 118 Entry e = modules.get(moduleForViewId.get(mid)); 119 return (e != null) ? e.mibs : null; 120 } 121 122 @Override 123 void add(Entry e) { 124 ModuleInfo mi = jms.parseModuleInfo(e.mibs); // ## Need fast path 125 modules.put(mi.id(), e); 126 for (ModuleView mv : mi.views()) { 127 moduleForViewId.put(mv.id(), mi.id()); 128 for (ModuleId alias : mv.aliases()) { 129 moduleForViewId.put(alias, mi.id()); 130 } 131 } 132 } 133 134 @Override 135 public boolean remove(ModuleId mid) { 136 for (Iterator<ModuleId> i = moduleForViewId.values().iterator(); 137 i.hasNext();) 138 { 139 // remove views/aliases defined in the module be removed 140 ModuleId id = i.next(); 141 if (id.equals(mid)) { 142 i.remove(); 143 } 144 } 145 return modules.remove(mid) != null; 146 } 147 148 @Override 149 Entry get(ModuleId mid) { 150 return modules.get(moduleForViewId.get(mid)); 151 } 152 153 /* ## 154 public boolean remove(ModuleIdQuery midq) { 155 int nd = 0; 156 for (Iterator<ModuleId> i = modules.keySet().iterator(); 157 i.hasNext();) 158 { 159 ModuleId mid = i.next(); 160 if (midq.matches(mid)) { 161 i.remove(); 162 nd++; 163 } 164 } 165 return nd != 0; 166 } 167 */ 168 169 private StreamedRepositoryCatalog() { } 170 171 private FileHeader fileHeader() { 172 return (new FileHeader() 173 .type(FileConstants.Type.STREAM_CATALOG) 174 .majorVersion(MAJOR_VERSION) 175 .minorVersion(MINOR_VERSION)); 176 } 177 178 public void store(OutputStream os) throws IOException { 179 OutputStream bos = new BufferedOutputStream(os); 180 try (DataOutputStream out = new DataOutputStream(bos)) { 181 fileHeader().write(out); 182 out.writeInt(modules.size()); 183 for (Map.Entry<ModuleId,Entry> me : modules.entrySet()) { 184 out.writeUTF(me.getKey().toString()); // ## Redundant 185 Entry e = me.getValue(); 186 out.writeUTF(e.type.getFileNameExtension()); 187 out.writeLong(e.csize); 188 out.writeLong(e.usize); 189 out.writeShort(e.hashType.value()); 190 out.writeShort(e.hash.length); 191 out.write(e.hash); 192 out.writeShort(e.mibs.length); 193 out.write(e.mibs); 194 } 195 out.writeInt(moduleForViewId.size()); 196 for (Map.Entry<ModuleId,ModuleId> me : moduleForViewId.entrySet()) { 197 out.writeUTF(me.getKey().toString()); 198 out.writeUTF(me.getValue().toString()); 199 } 200 } 201 } 202 203 public StreamedRepositoryCatalog loadStream(InputStream is) 204 throws IOException 205 { 206 BufferedInputStream bis = new BufferedInputStream(is); 207 DataInputStream in = new DataInputStream(bis); 208 FileHeader fh = fileHeader(); 209 fh.read(in); 210 int nms = in.readInt(); 211 for (int i = 0; i < nms; i++) { 212 ModuleId mid = jms.parseModuleId(in.readUTF()); 213 ModuleType t = ModuleType.fromFileNameExtension(in.readUTF()); 214 long cs = in.readLong(); 215 long us = in.readLong(); 216 HashType ht = HashType.valueOf(in.readShort()); 217 int nb = in.readShort(); 218 byte[] hash = new byte[nb]; 219 in.readFully(hash); 220 nb = in.readShort(); 221 byte[] mibs = new byte[nb]; 222 in.readFully(mibs); 223 modules.put(mid, new Entry(t, mibs, cs, us, ht, hash)); 224 } 225 int nmids = in.readInt(); 226 for (int i = 0; i < nmids; i++) { 227 ModuleId id = jms.parseModuleId(in.readUTF()); 228 ModuleId mid = jms.parseModuleId(in.readUTF()); 229 moduleForViewId.put(id, mid); 230 } 231 return this; 232 } 233 234 } 235 236 public static StreamedRepositoryCatalog load(InputStream in) 237 throws IOException 238 { 239 StreamedRepositoryCatalog src = new StreamedRepositoryCatalog(); 240 if (in != null) { 241 try { 242 src.loadStream(in); 243 } finally { 244 in.close(); 245 } 246 } 247 return src; 248 } 249 250 251 /* 252 253 private static class IndexedRepositoryCatalog { } // ## Later 254 255 static IndexedRepositoryCatalog open(File fn) throws IOException { 256 return new IndexedRepositoryCatalog(...); 257 } 258 259 */ 260 261 }