All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.vertx.stack.utils.Cache Maven / Gradle / Ivy

/*
 *  Copyright (c) 2011-2015 The original author or authors
 *  ------------------------------------------------------
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the Eclipse Public License v1.0
 *  and Apache License v2.0 which accompanies this distribution.
 *
 *       The Eclipse Public License is available at
 *       http://www.eclipse.org/legal/epl-v10.html
 *
 *       The Apache License v2.0 is available at
 *       http://www.opensource.org/licenses/apache2.0.php
 *
 *  You may elect to redistribute this code under either of these licenses.
 */

package io.vertx.stack.utils;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleModule;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;
import io.vertx.stack.resolver.ResolutionOptions;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.artifact.DefaultArtifact;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * A cache storing the resolution result.
 *
 * @author Clement Escoffier
 */
public class Cache {
  private final static Logger LOGGER = LoggerFactory.getLogger("stack-manager-cache");

  // We don't use the MAPPEr from vert.x because it requires some tuning.
  private static final ObjectMapper MAPPER = new ObjectMapper().registerModule(
      new SimpleModule("artifact-module").addDeserializer(Artifact.class, new JsonDeserializer() {
    @Override
    public Artifact deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
      JsonNode node = p.getCodec().readTree(p);
      Artifact artifact;
      if (node.get("classifier") != null) {
        artifact = new DefaultArtifact(node.get("groupId").asText(), node.get("artifactId").asText(),
            node.get("classifier").asText(), node.get("extension").asText(), node.get("version").asText());
      } else {
        artifact = new DefaultArtifact(node.get("groupId").asText(), node.get("artifactId").asText(),
            node.get("extension").asText(), node.get("version").asText());
      }
      artifact = artifact.setFile(new File(node.get("file").asText()));
      return artifact;
    }
  }));

  private final boolean disabled;
  private final boolean disabledForSnapshot;

  List cache = new ArrayList<>();
  private File cacheFile;


  public Cache(boolean disabled, boolean disabledForSnapshot, File cacheFile) {
    this.disabled = disabled;
    this.disabledForSnapshot = disabledForSnapshot;
    this.cacheFile = cacheFile;

    // Load cache.
    if (this.cacheFile == null && Home.getVertxHome() != null) {
      this.cacheFile = new File(Home.getVertxHome(), ".stack-manager-cache.json");
      LOGGER.info("Set resolver cache to " + this.cacheFile.getAbsolutePath());
    }

    if (this.cacheFile != null && !this.cacheFile.isFile()) {
      this.cacheFile.getParentFile().mkdirs();
    }

    if (!disabled && this.cacheFile != null && this.cacheFile.isFile()) {
      LOGGER.info("Loading resolver cache from " + this.cacheFile.getAbsolutePath());
      JavaType type = MAPPER.getTypeFactory().
          constructCollectionType(List.class, CacheEntry.class);
      try {
        cache.addAll(MAPPER.readValue(this.cacheFile, type));
      } catch (IOException e) {
        LOGGER.error("Cannot read the cache entries from " + this.cacheFile.getAbsolutePath() + ": " + e.getMessage());
      }
    }
  }

  public void writeCacheOnFile() {
    if (disabled) {
      return;
    }
    if (cacheFile != null) {
      try {
        MAPPER.writer().writeValue(cacheFile, cache);
      } catch (IOException e) {
        LOGGER.error("Cannot write the cache entries to " + cacheFile.getAbsolutePath() + ": " + e.getMessage());
      }
    }
  }

  public List get(String gacv, ResolutionOptions resolutionOptions) {
    if (disabled) {
      return null;
    }

    if (disabledForSnapshot && gacv.contains("SNAPSHOT")) {
      return null;
    }

    Optional entry = find(gacv, resolutionOptions);
    if (entry.isPresent()) {
      if (isValid(entry.get())) {
        return entry.get().getArtifacts();
      } else {
        // cleanup required
        cache.remove(entry.get());
        return null;
      }
    }
    return null;
  }

  private boolean isValid(CacheEntry entry) {
    // If valid check two aspects:
    // All artifact files must be existing and non empty
    // If the dependency is a snapshot, it must check the insertion date.
    if (entry.getArtifacts().isEmpty()) {
      return false;
    }

    if (entry.getArtifacts().stream().filter(artifact -> !artifact.getFile().isFile())
        .findAny().isPresent()) {
      return false;
    }

    if (entry.gacv.contains("SNAPSHOT")) {
      long now = System.currentTimeMillis();
      long insertion = entry.getInsertionTime();
      return now - insertion < 24 * 60 * 60 * 1000; // 24 hours of 60 minutes composed by 60 seconds.
    }
    return true;
  }


  public void put(String gacv, ResolutionOptions resolutionOptions, List list) {
    if (disabled) {
      return;
    }

    if (disabledForSnapshot && gacv.contains("SNAPSHOT")) {
      return;
    }

    Optional entry = find(gacv, resolutionOptions);
    if (entry.isPresent()) {
      CacheEntry cached = entry.get();
      cached.setInsertionTime(System.currentTimeMillis()).setArtifacts(list);
    } else {
      CacheEntry cached = new CacheEntry();
      cached.setArtifacts(list)
          .setGacv(gacv)
          .setOptions(resolutionOptions)
          .setInsertionTime(System.currentTimeMillis());
      cache.add(cached);
    }
  }

  public Optional find(String gacv, ResolutionOptions options) {
    return cache.stream().filter(entry -> entry.gacv.equals(gacv)
        && entry.options.equals(options)).findFirst();
  }

  public int size() {
    return cache.size();
  }

  public static class CacheEntry {
    String gacv;
    ResolutionOptions options;
    List artifacts = new ArrayList<>();

    long insertionTime;

    public CacheEntry() {
    }

    public List getArtifacts() {
      return artifacts;
    }

    public CacheEntry setArtifacts(List artifacts) {
      this.artifacts = artifacts;
      return this;
    }

    public String getGacv() {
      return gacv;
    }

    public CacheEntry setGacv(String gacv) {
      this.gacv = gacv;
      return this;
    }

    public long getInsertionTime() {
      return insertionTime;
    }

    public CacheEntry setInsertionTime(long insertionTime) {
      this.insertionTime = insertionTime;
      return this;
    }

    public ResolutionOptions getOptions() {
      return options;
    }

    public CacheEntry setOptions(ResolutionOptions options) {
      this.options = options;
      return this;
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy