Home | History | Annotate | Download | only in asset
      1 /*
      2  * Copyright (c) 2009-2010 jMonkeyEngine
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are
      7  * met:
      8  *
      9  * * Redistributions of source code must retain the above copyright
     10  *   notice, this list of conditions and the following disclaimer.
     11  *
     12  * * Redistributions in binary form must reproduce the above copyright
     13  *   notice, this list of conditions and the following disclaimer in the
     14  *   documentation and/or other materials provided with the distribution.
     15  *
     16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
     17  *   may be used to endorse or promote products derived from this software
     18  *   without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 package com.jme3.asset;
     34 
     35 import com.jme3.export.*;
     36 import java.io.IOException;
     37 import java.util.LinkedList;
     38 
     39 /**
     40  * <code>AssetKey</code> is a key that is used to
     41  * look up a resource from a cache.
     42  * This class should be immutable.
     43  */
     44 public class AssetKey<T> implements Savable {
     45 
     46     protected String name;
     47     protected transient String folder;
     48     protected transient String extension;
     49 
     50     public AssetKey(String name){
     51         this.name = reducePath(name);
     52         this.extension = getExtension(this.name);
     53     }
     54 
     55     public AssetKey(){
     56     }
     57 
     58     protected static String getExtension(String name){
     59         int idx = name.lastIndexOf('.');
     60         //workaround for filenames ending with xml and another dot ending before that (my.mesh.xml)
     61         if (name.toLowerCase().endsWith(".xml")) {
     62             idx = name.substring(0, idx).lastIndexOf('.');
     63             if (idx == -1) {
     64                 idx = name.lastIndexOf('.');
     65             }
     66         }
     67         if (idx <= 0 || idx == name.length() - 1)
     68             return "";
     69         else
     70             return name.substring(idx+1).toLowerCase();
     71     }
     72 
     73     protected static String getFolder(String name){
     74         int idx = name.lastIndexOf('/');
     75         if (idx <= 0 || idx == name.length() - 1)
     76             return "";
     77         else
     78             return name.substring(0, idx+1);
     79     }
     80 
     81     public String getName() {
     82         return name;
     83     }
     84 
     85     /**
     86      * @return The extension of the <code>AssetKey</code>'s name. For example,
     87      * the name "Interface/Logo/Monkey.png" has an extension of "png".
     88      */
     89     public String getExtension() {
     90         return extension;
     91     }
     92 
     93     public String getFolder(){
     94         if (folder == null)
     95             folder = getFolder(name);
     96 
     97         return folder;
     98     }
     99 
    100     /**
    101      * Do any post-processing on the resource after it has been loaded.
    102      * @param asset
    103      */
    104     public Object postProcess(Object asset){
    105         return asset;
    106     }
    107 
    108     /**
    109      * Create a new instance of the asset, based on a prototype that is stored
    110      * in the cache. Implementations are allowed to return the given parameter
    111      * as-is if it is considered that cloning is not necessary for that particular
    112      * asset type.
    113      *
    114      * @param asset The asset to be cloned.
    115      * @return The asset, possibly cloned.
    116      */
    117     public Object createClonedInstance(Object asset){
    118         return asset;
    119     }
    120 
    121     /**
    122      * @return True if the asset for this key should be cached. Subclasses
    123      * should override this method if they want to override caching behavior.
    124      */
    125     public boolean shouldCache(){
    126         return true;
    127     }
    128 
    129     /**
    130      * @return Should return true, if the asset objects implement the "Asset"
    131      * interface and want to be removed from the cache when no longer
    132      * referenced in user-code.
    133      */
    134     public boolean useSmartCache(){
    135         return false;
    136     }
    137 
    138     /**
    139      * Removes all relative elements of a path (A/B/../C.png and A/./C.png).
    140      * @param path The path containing relative elements
    141      * @return A path without relative elements
    142      */
    143     public static String reducePath(String path) {
    144         if (path == null || path.indexOf("./") == -1) {
    145             return path;
    146         }
    147         String[] parts = path.split("/");
    148         LinkedList<String> list = new LinkedList<String>();
    149         for (int i = 0; i < parts.length; i++) {
    150             String string = parts[i];
    151             if (string.length() == 0 || string.equals(".")) {
    152                 //do nothing
    153             } else if (string.equals("..")) {
    154                 if (list.size() > 0) {
    155                     list.removeLast();
    156                 } else {
    157                     throw new IllegalStateException("Relative path is outside assetmanager root!");
    158                 }
    159             } else {
    160                 list.add(string);
    161             }
    162         }
    163         StringBuilder builder = new StringBuilder();
    164         for (int i = 0; i < list.size(); i++) {
    165             String string = list.get(i);
    166             if (i != 0) {
    167                 builder.append("/");
    168             }
    169             builder.append(string);
    170         }
    171         return builder.toString();
    172     }
    173 
    174     @Override
    175     public boolean equals(Object other){
    176         if (!(other instanceof AssetKey)){
    177             return false;
    178         }
    179         return name.equals(((AssetKey)other).name);
    180     }
    181 
    182     @Override
    183     public int hashCode(){
    184         return name.hashCode();
    185     }
    186 
    187     @Override
    188     public String toString(){
    189         return name;
    190     }
    191 
    192     public void write(JmeExporter ex) throws IOException {
    193         OutputCapsule oc = ex.getCapsule(this);
    194         oc.write(name, "name", null);
    195     }
    196 
    197     public void read(JmeImporter im) throws IOException {
    198         InputCapsule ic = im.getCapsule(this);
    199         name = reducePath(ic.readString("name", null));
    200         extension = getExtension(name);
    201     }
    202 
    203 }
    204