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.
   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 
  24 // Compiled and invoked by pubrepo.sh
  25 
  26 import java.io.*;
  27 import java.util.*;
  28 import java.lang.module.*;
  29 import java.nio.*;
  30 import java.nio.channels.*;
  31 import java.nio.file.Files;
  32 import java.nio.file.*;
  33 import org.openjdk.jigsaw.*;
  34 
  35 import static java.lang.System.out;
  36 import static java.nio.file.StandardOpenOption.*;
  37 import org.openjdk.jigsaw.Repository.ModuleFileType;
  38 
  39 
  40 public class _PublishedRepository {
  41 
  42     private static ModuleSystem ms = ModuleSystem.base();
  43 
  44     private static <T> boolean eq(Collection<T> c1, Collection<T> c2) {
  45         return c1.containsAll(c2) && c2.containsAll(c1);
  46     }
  47 
  48     static final Path REPO = Paths.get("z.repo");
  49 
  50     static Set<ModuleId> mids = null;
  51 
  52     static Set<Path> mpaths = null;
  53 
  54     static void check(PublishedRepository pr) throws Exception {
  55         if (!pr.validate(null)) {
  56             throw new Exception("Repo invalid");
  57         }
  58         if (mids != null) {
  59             Collection<ModuleId> fmids = pr.listLocalModuleIds();
  60             assert eq(mids, fmids)
  61                 : String.format("expected %s; found %s", mids, fmids);
  62         }
  63     }
  64 
  65     static void create() throws Exception {
  66         PublishedRepository pr = PublishedRepository.open(REPO, true);
  67         check(pr);
  68     }
  69 
  70     static PublishedRepository open() throws IOException {
  71         return PublishedRepository.open(REPO, false);
  72     }
  73 
  74     static ModuleId toModuleId(Path p) {
  75         String fn = p.getFileName().toString();
  76         if (fn.endsWith(ModuleFileType.JAR.getFileNameSuffix())) {
  77             return ms.parseModuleId(fn.replace(ModuleFileType.JAR.getFileNameSuffix(), ""));
  78         } else {
  79             return ms.parseModuleId(fn.replace(ModuleFileType.JMOD.getFileNameSuffix(), ""));
  80         }
  81     }
  82 
  83     static Path toModulePath(Path repo, ModuleId mid) {
  84         Path m = toModulePath(repo, mid, ModuleFileType.JAR);
  85         if (m == null) {
  86             m = toModulePath(repo, mid, ModuleFileType.JMOD);
  87         }
  88         return m;
  89     }
  90 
  91     private static Path toModulePath(Path repo, ModuleId mid, ModuleFileType type) {
  92         Path m = repo.resolve(mid.toString() + type.getFileNameSuffix());
  93         return m.toFile().exists() ? m : null;
  94     }
  95 
  96     static byte[] readStream(InputStream in)
  97         throws Exception
  98     {
  99         ByteArrayOutputStream out = new ByteArrayOutputStream();
 100         byte[] buf = new byte[8192];
 101         int n = 0;
 102         while ((n = in.read(buf)) > 0)
 103             out.write(buf, 0, n);
 104         return out.toByteArray();
 105     }
 106 
 107     static boolean equals(InputStream ia, InputStream ib)
 108         throws Exception
 109     {
 110         return Arrays.equals(readStream(ia), readStream(ib));
 111     }
 112 
 113     static Set<ModuleId> add(String[] args, boolean checkAll)
 114         throws Exception
 115     {
 116         PublishedRepository pr = PublishedRepository.open(REPO, false);
 117         mids = new HashSet<>();
 118         mpaths = new HashSet<>();
 119         for (String a : args) {
 120             Path p = Paths.get(a);
 121             mpaths.add(p);
 122             pr.publish(p);
 123             mids.add(toModuleId(p));
 124         }
 125         check(pr);
 126         if (!checkAll)
 127             return mids;
 128         for (Path p : mpaths) {
 129             ModuleId mid = toModuleId(p);
 130             try (InputStream ia = Files.newInputStream(p);
 131                  InputStream ib = pr.fetch(mid)) {
 132                 assert equals(ia, ib)
 133                     : String.format("%s %s", mid, p);
 134             }
 135         }
 136         return mids;
 137     }
 138 
 139     static void delete() throws Exception {
 140         PublishedRepository pr = PublishedRepository.open(REPO, false);
 141         for (ModuleId mid : new ArrayList<ModuleId>(mids)) {
 142             pr.remove(mid);
 143             mids.remove(mid);
 144             check(pr);
 145         }
 146     }
 147 
 148     static void corrupt() throws Exception {
 149 
 150         // Corrupt the catalog: s/twisty/twosty/g
 151         FileChannel cat = FileChannel.open(REPO.resolve("%catalog"),
 152                                            READ, WRITE);
 153         ByteBuffer bb = ByteBuffer.allocate((int)cat.size());
 154         assert cat.read(bb) == (int)cat.size();
 155         bb.flip();
 156         while (bb.hasRemaining()) {
 157             if (bb.get() == (int)'t') {
 158                 if (bb.hasRemaining() && bb.get() == (int)'w') {
 159                     if (bb.hasRemaining() && bb.get() == (int)'i') {
 160                         bb.position(bb.position() - 1);
 161                         bb.put((byte)'o');
 162                     }
 163                 }
 164             }
 165         }
 166         bb.flip();
 167         cat.position(0);
 168         assert cat.write(bb) == (int)cat.size();
 169         cat.close();
 170 
 171         // Remove a module file
 172         ModuleId dmid = null;
 173         for (ModuleId mid : mids) {
 174             if (!mid.name().equals("twisty")) {
 175                 dmid = mid;
 176                 break;
 177             }
 178         }
 179         Path p = toModulePath(REPO, dmid);
 180         out.format("Deleting %s%n", p);
 181         Files.delete(p);
 182         mids.remove(dmid);
 183 
 184         PublishedRepository pr = PublishedRepository.open(REPO, false);
 185         assert !pr.validate(null);
 186     }
 187 
 188     static void recat() throws Exception {
 189         PublishedRepository pr = PublishedRepository.open(REPO, false);
 190         pr.reCatalog();
 191         check(pr);
 192     }
 193 
 194     public static void main(String[] args)
 195         throws Exception
 196     {
 197         create();
 198         add(args, true);
 199         delete();
 200         add(args, false);
 201         corrupt();
 202         recat();
 203         out.format("All tests passed%n");
 204     }
 205 
 206 }