Package aQute.library.bnd

Source Code of aQute.library.bnd.StoredRevisionCache

package aQute.library.bnd;

import java.io.*;
import java.net.*;
import java.security.*;
import java.security.cert.*;
import java.util.*;

import javax.net.ssl.*;

import aQute.lib.hex.*;
import aQute.lib.io.*;
import aQute.lib.json.*;
import aQute.lib.settings.*;
import aQute.rest.urlclient.*;
import aQute.service.library.Library.Program;
import aQute.service.library.Library.RevisionRef;

public class StoredRevisionCache {
  private static TrustManager[]  trustAllCerts;
  private static HostnameVerifier  trustAnyHost;
  private static SSLContext    sslContext;
  private static SSLSocketFactory  sslSocketFactory;
  private final File        root;
  final File            tmpdir;
  final File            repodir;
  final File            programdir;
  final Settings          settings;
  boolean              sign;
  final Map<File,Exception>    errors    = new HashMap<File,Exception>();
  private Map<String,Program>    programs  = new HashMap<String,Program>();
  private static final JSONCodec  codec    = new JSONCodec();
  File              refresh;
  final URLClient          urlc;

  public StoredRevisionCache(File root, Settings settings) throws Exception {
    this.root = root;
    this.settings = settings;
    this.getRoot().mkdirs();
    this.tmpdir = new File(root, "tmp");
    this.tmpdir.mkdir();
    this.repodir = new File(root, "shas");
    this.repodir.mkdir();
    this.programdir = new File(root, "programs");
    this.programdir.mkdir();
    this.refresh = new File(root, ".refreshed");
    if (!this.refresh.isFile())
      this.refresh.createNewFile();
    urlc = new URLClient("");
    if (settings != null)
      urlc.credentials(settings.getEmail(), InetAddress.getLocalHost().toString(), settings.getPublicKey(),
          settings.getPrivateKey());
    else
      System.out.println("no settings");
  }

  /*
   * We create a path that ends in a readable name since Eclipse shows the
   * last segement. The name is superfluous
   */

  public File getPath(String bsn, String version, byte[] sha) {
    return getPath(bsn, version, sha, false);
  }

  public File getPath(String bsn, String version, byte[] sha, boolean withsource) {
    if (withsource)
      return IO.getFile(repodir, Hex.toHexString(sha) + "/+" + bsn + "-" + version + ".jar");
    else
      return IO.getFile(repodir, Hex.toHexString(sha) + "/" + bsn + "-" + version + ".jar");
  }

  /*
   * Delete a revision
   */
  public void delete(byte[] sha) {
    File f = IO.getFile(getRoot(), Hex.toHexString(sha));
    IO.delete(f);
  }

  /*
   * Actually download a file. First in a temp directory, then it is renamed
   */
  public void download(final File file, final Set<URI> urls, byte[] sha) throws Exception {
    if (errors.containsKey(file))
      throw errors.get(file);

    if (urls.isEmpty())
      throw new Exception("No URLs to download " + file);

    File tmp = IO.createTempFile(tmpdir, "tmp", ".tmp");
    for (URI url : urls) {

      // Fixup for older bug that put the file url in the urls :-(
      if (url.getScheme().equals("file"))
        continue;

      try {
        System.out.println("Download " + url);
        HttpURLConnection connection = getConnection(url);

        MessageDigest digest = MessageDigest.getInstance("SHA1");
        DigestInputStream din = new DigestInputStream(connection.getInputStream(), digest);
        IO.copy(din, tmp);

        byte[] receivedsha = digest.digest();

        if (!Arrays.equals(sha, receivedsha))
          throw new Exception("Shas did not match (expected)" + Hex.toHexString(sha) + " (downloaded)" + tmp
              + " (" + Hex.toHexString(receivedsha) + ")");

        file.getParentFile().mkdirs();
        if (!tmp.renameTo(file)) {
          // We must have had a race condition
          // on a system where we have not destructive
          // rename. Since we are in a SHA name dir
          // the content must ALWAYS be the same. So if
          // we have a name clash we can throw away the newly download
          // one since we seem to have lost.
          tmp.delete();
        } else {
          long modified = connection.getLastModified();
          if (modified > 0)
            file.setLastModified(modified);
        }
        return;
      }
      catch (Exception e) {
        errors.put(file, e);
        throw e;
      }
      finally {
        tmp.delete();
      }
    }
  }

  public void add(RevisionRef d, File file) throws IOException {
    File path = getPath(d.bsn, d.version, d.revision);
    path.getParentFile().mkdirs();
    IO.copy(file, path);
    long modified = file.lastModified();
    if (modified > 0)
      path.setLastModified(modified);
  }

  private HttpURLConnection getConnection(URI url) throws Exception {
    int count = 4;
    while (count-- > 0) {
      URLConnection urlc = url.toURL().openConnection();
      if (!(urlc instanceof HttpURLConnection)) {
        System.out.println(url);

      }
      HttpURLConnection connection = (HttpURLConnection) urlc;
      authenticate(connection);
      if (connection.getResponseCode() / 100 == 2)
        return connection;

      if (connection.getResponseCode() == 301 || connection.getResponseCode() == 302) {
        String u = connection.getHeaderField("Location");
        if (u == null)
          throw new IOException("Had a url redirect but no location was set");
        url = new URI(u.trim());

      } else {

        throw new IOException("Could not open URL, [" + connection.getResponseCode() + "] "
            + connection.getResponseMessage() + " for '" + connection.getURL() + "'");
      }

    }
    throw new IOException("Could not open URL, too many redirects ");
  }

  protected void authenticate(URLConnection connection) throws Exception {
    if (connection instanceof HttpURLConnection) {
      urlc.sign(connection);
    }
  }

  static void disableTrust(HttpsURLConnection httpsConnection) throws GeneralSecurityException {
    if (sslSocketFactory == null) {
      trustAllCerts = new TrustManager[] {
        new X509TrustManager() {
          public X509Certificate[] getAcceptedIssuers() {
            return null;
          }

          public void checkServerTrusted(X509Certificate[] certs, String authType)
              throws CertificateException {}

          public void checkClientTrusted(X509Certificate[] certs, String authType)
              throws CertificateException {}
        }
      };

      trustAnyHost = new HostnameVerifier() {
        public boolean verify(String string, SSLSession session) {
          return true;
        }
      };
      sslContext = SSLContext.getInstance("TLS");
      sslContext.init(null, trustAllCerts, new SecureRandom());
      sslSocketFactory = sslContext.getSocketFactory();
    }
    httpsConnection.setSSLSocketFactory(sslSocketFactory);
    httpsConnection.setHostnameVerifier(trustAnyHost);
  }

  public File getRoot() {
    return root;
  }

  public void refresh() {
    errors.clear();
    refresh.setLastModified(System.currentTimeMillis());
  }

  public void deleteAll() {
    IO.delete(root);
    root.mkdirs();
  }

  public Program getProgram(String bsn) {
    Program p = programs.get(bsn);
    if (p != null)
      return p;

    File pf = IO.getFile(programdir, bsn + ".json");
    if (pf != null && pf.isFile() && pf.lastModified() >= refresh.lastModified()) {
      try {
        p = codec.dec().from(pf).get(Program.class);
        programs.put(bsn, p);
        return p;
      }
      catch (Exception e) {
        //
        return null;
      }
    } else
      return null;
  }

  public void putProgram(String bsn, Program p) throws IOException, Exception {
    programs.put(bsn, p);
    File pf = IO.getFile(root, bsn + ".json");
    codec.enc().to(pf).put(p);
  }

  /**
   * Check if a revision has sources ...
   *
   * @param revision
   * @return
   */
  public boolean hasSources(String bsn, String version, byte[] sha) {
    return getPath(bsn, version, sha, true).isFile();
  }

  /**
   * Remove the sources from the cache.
   *
   * @param bsn
   * @param string
   * @param revision
   */
  public void removeSources(String bsn, String version, byte[] sha) {
    getPath(bsn, version, sha, true).delete();
  }

}
TOP

Related Classes of aQute.library.bnd.StoredRevisionCache

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.