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 AssetKey(String name)50 public AssetKey(String name){ 51 this.name = reducePath(name); 52 this.extension = getExtension(this.name); 53 } 54 AssetKey()55 public AssetKey(){ 56 } 57 getExtension(String name)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 getFolder(String name)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 getName()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 */ getExtension()89 public String getExtension() { 90 return extension; 91 } 92 getFolder()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 */ postProcess(Object asset)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 */ createClonedInstance(Object asset)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 */ shouldCache()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 */ useSmartCache()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 */ reducePath(String path)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 equals(Object other)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 hashCode()183 public int hashCode(){ 184 return name.hashCode(); 185 } 186 187 @Override toString()188 public String toString(){ 189 return name; 190 } 191 write(JmeExporter ex)192 public void write(JmeExporter ex) throws IOException { 193 OutputCapsule oc = ex.getCapsule(this); 194 oc.write(name, "name", null); 195 } 196 read(JmeImporter im)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