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

juzu.impl.asset.AssetManager Maven / Gradle / Ivy

There is a newer version: 1.2.0
Show newest version
/*
 * Copyright 2013 eXo Platform SAS
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package juzu.impl.asset;

import juzu.impl.common.Tools;
import juzu.impl.plugin.application.Application;
import juzu.impl.resource.ResourceResolver;

import javax.inject.Inject;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;

/** @author Julien Viet */
public class AssetManager {

  /** . */
  private HashMap assets = new HashMap();

  /** Graph saying which assets depends on which asset. */
  private AssetGraph graph = new AssetGraph();

  /** . */
  protected final String prefix;

  /** . */
  protected final ResourceResolver applicationResolver;

  @Inject
  public AssetManager(Application application) {
    this.prefix = "/" + application.getDescriptor().getPackageName().replace('.', '/') + "/assets/";
    this.applicationResolver = application;
  }

  AssetManager(String prefix, ResourceResolver applicationResolver) {
    this.prefix = prefix;
    this.applicationResolver = applicationResolver;
  }

  public AssetDeployment createDeployment() {
    return new AssetDeployment(this);
  }

  boolean deploy(AssetDeployment deployment) {

    // Clone the state
    AssetGraph graphClone = new AssetGraph(graph);
    HashMap assetsClone = new HashMap(assets);
    for (AssetNode asset : deployment.assets) {
      // Check it was not previously deployed
      if (!assetsClone.keySet().contains(asset.id)) {
        for (AssetNode deployed : assetsClone.values()) {
          if (deployed.iDependOn.contains(asset.id)) {
            if (!graphClone.register(asset.id, deployed.id)) {
              return false;
            }
          }
          if (asset.iDependOn.contains(deployed.id)) {
            if (!graphClone.register(deployed.id, asset.id)) {
              return false;
            }
          }
        }
        assetsClone.put(asset.id, asset);
      } else {
        // log it ?
        return false;
      }
    }

    // Everything went fine we updated the manager
    assets = assetsClone;
    graph = graphClone;
    return true;
  }

  void undeploy(AssetDeployment deployment) {
    for (AssetNode asset : deployment.assets) {
      for (AssetNode deployed : assets.values()) {
        if (deployed.iDependOn.contains(asset.id)) {
          graph.unregister(asset.id, deployed.id);
        }
        if (asset.iDependOn.contains(deployed.id)) {
          graph.unregister(deployed.id, asset.id);
        }
      }
      assets.remove(asset.id);
    }
  }

  /**
   * Resolve an application asset as a resource URL or return null if it cannot be found.
   *
   * @param path the path the path within the application
   * @return the resource
   */
  public AssetResource resolveApplicationAssetResource(String path) {
    for (AssetNode asset : assets.values()) {
      if (asset.value.equals(path) && asset.resource != null) {
        Integer maxAge = asset.asset.getMaxAge();
        return new AssetResource(asset.resource, maxAge);
      }
    }
    if (path.startsWith(prefix)) {
      URL resolved = applicationResolver.resolve(path);
      return new AssetResource(resolved, null);
    } else {
      return null;
    }
  }

  /**
   * Find all assets of the specified type and returns a map of id -> Asset.
   *
   * @param type the asset type
   * @return the asset map
   */
  public Map getAssets(String type) {
    Map ret = Collections.emptyMap();
    for (AssetNode node : assets.values()) {
      if (node.asset.getType().equals(type)) {
        if (ret.isEmpty()) {
          ret = new HashMap();
        }
        ret.put(node.id, node.asset);
      }
    }
    return ret;
  }

  /**
   * Returns the assets forthe specifid id.
   *
   * @param id the asset id
   * @return the corresponding assets
   * @throws NullPointerException
   */
  public Asset getAsset(String id) throws NullPointerException {
    if (id == null) {
      throw new NullPointerException("No null id accepted");
    }
    AssetNode node = assets.get(id);
    return node != null ? node.asset : null;
  }

  /**
   * Perform a topological sort of the provided asset script values.
   *
   * @param ids the asset ids to resolve
   * @return the resolved asset or null
   * @throws NullPointerException if the asset ids argument is null
   * @throws IllegalArgumentException when asset dependencies cannot be resolved
   */
  public Iterable resolveAssets(Iterable ids) throws
    NullPointerException,
    IllegalArgumentException {

    //
    if (ids == null) {
      throw new NullPointerException("No null asset ids accepted");
    }

    // Compute the closure of the assets we need
    LinkedHashMap> sub = new LinkedHashMap>();
    for (LinkedList queue = Tools.addAll(new LinkedList(), ids);!queue.isEmpty();) {
      String id = queue.removeFirst();
      AssetNode asset = this.assets.get(id);
      if (asset != null) {
        sub.put(asset.id, new HashSet(asset.iDependOn));
        for (String depend : asset.iDependOn) {
          if (!sub.containsKey(depend)) {
            queue.addLast(depend);
          }
        }
      }
      else {
        throw new IllegalArgumentException("Cannot resolve asset " + id);
      }
    }

    // Perform the topological sort
    LinkedList resolved = new LinkedList();
    while (sub.size() > 0) {
      boolean found = false;
      for (Iterator>> i = sub.entrySet().iterator();i.hasNext();) {
        Map.Entry> entry = i.next();
        if (entry.getValue().isEmpty()) {
          i.remove();
          AssetNode asset = this.assets.get(entry.getKey());
          resolved.add(asset.asset);
          Set dependencies = graph.get(asset.id);
          if (dependencies != null) {
            for (String dependency : dependencies) {
              HashSet foo = sub.get(dependency);
              if (foo != null) {
                foo.remove(entry.getKey());
              }
            }
          }
          found = true;
          break;
        }
      }
      if (!found) {
        StringBuilder sb = new StringBuilder("Cannot satisfy asset dependencies:\n");
        for (Map.Entry> entry : sub.entrySet()) {
          sb.append(entry.getKey()).append(" -> ").append(entry.getValue());
        }
        throw new IllegalArgumentException(sb.toString());
      }
    }

    //
    return resolved;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy