Home | History | Annotate | Download | only in asset
      1 /*
      2  * Copyright (c) 2009-2012 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 java.util.ArrayList;
     36 import java.util.HashMap;
     37 import java.util.Iterator;
     38 import java.util.logging.Level;
     39 import java.util.logging.Logger;
     40 
     41 /**
     42  * <code>ImplHandler</code> manages the asset loader and asset locator
     43  * implementations in a thread safe way. This allows implementations
     44  * which store local persistent data to operate with a multi-threaded system.
     45  * This is done by keeping an instance of each asset loader and asset
     46  * locator object in a thread local.
     47  */
     48 public class ImplHandler {
     49 
     50     private static final Logger logger = Logger.getLogger(ImplHandler.class.getName());
     51 
     52     private final AssetManager owner;
     53 
     54     private final ThreadLocal<AssetKey> parentAssetKey
     55             = new ThreadLocal<AssetKey>();
     56 
     57     private final ArrayList<ImplThreadLocal> genericLocators =
     58                 new ArrayList<ImplThreadLocal>();
     59 
     60     private final HashMap<String, ImplThreadLocal> loaders =
     61                 new HashMap<String, ImplThreadLocal>();
     62 
     63     public ImplHandler(AssetManager owner){
     64         this.owner = owner;
     65     }
     66 
     67     protected class ImplThreadLocal extends ThreadLocal {
     68 
     69         private final Class<?> type;
     70         private final String path;
     71 
     72         public ImplThreadLocal(Class<?> type){
     73             this.type = type;
     74             path = null;
     75         }
     76 
     77         public ImplThreadLocal(Class<?> type, String path){
     78             this.type = type;
     79             this.path = path;
     80         }
     81 
     82         public String getPath() {
     83             return path;
     84         }
     85 
     86         public Class<?> getTypeClass(){
     87             return type;
     88         }
     89 
     90         @Override
     91         protected Object initialValue(){
     92             try {
     93                 return type.newInstance();
     94             } catch (InstantiationException ex) {
     95                 logger.log(Level.SEVERE,"Cannot create locator of type {0}, does"
     96                             + " the class have an empty and publically accessible"+
     97                               " constructor?", type.getName());
     98                 logger.throwing(type.getName(), "<init>", ex);
     99             } catch (IllegalAccessException ex) {
    100                 logger.log(Level.SEVERE,"Cannot create locator of type {0}, "
    101                             + "does the class have an empty and publically "
    102                             + "accessible constructor?", type.getName());
    103                 logger.throwing(type.getName(), "<init>", ex);
    104             }
    105             return null;
    106         }
    107     }
    108 
    109     /**
    110      * Establishes the asset key that is used for tracking dependent assets
    111      * that have failed to load. When set, the {@link DesktopAssetManager}
    112      * gets a hint that it should suppress {@link AssetNotFoundException}s
    113      * and instead call the listener callback (if set).
    114      *
    115      * @param parentKey The parent key
    116      */
    117     public void establishParentKey(AssetKey parentKey){
    118         if (parentAssetKey.get() == null){
    119             parentAssetKey.set(parentKey);
    120         }
    121     }
    122 
    123     public void releaseParentKey(AssetKey parentKey){
    124         if (parentAssetKey.get() == parentKey){
    125             parentAssetKey.set(null);
    126         }
    127     }
    128 
    129     public AssetKey getParentKey(){
    130         return parentAssetKey.get();
    131     }
    132 
    133     /**
    134      * Attempts to locate the given resource name.
    135      * @param key The full name of the resource.
    136      * @return The AssetInfo containing resource information required for
    137      * access, or null if not found.
    138      */
    139     public AssetInfo tryLocate(AssetKey key){
    140         synchronized (genericLocators){
    141             if (genericLocators.isEmpty())
    142                 return null;
    143 
    144             for (ImplThreadLocal local : genericLocators){
    145                 AssetLocator locator = (AssetLocator) local.get();
    146                 if (local.getPath() != null){
    147                     locator.setRootPath((String) local.getPath());
    148                 }
    149                 AssetInfo info = locator.locate(owner, key);
    150                 if (info != null)
    151                     return info;
    152             }
    153         }
    154         return null;
    155     }
    156 
    157     public int getLocatorCount(){
    158         synchronized (genericLocators){
    159             return genericLocators.size();
    160         }
    161     }
    162 
    163     /**
    164      * Returns the AssetLoader registered for the given extension
    165      * of the current thread.
    166      * @return AssetLoader registered with addLoader.
    167      */
    168     public AssetLoader aquireLoader(AssetKey key){
    169         synchronized (loaders){
    170             ImplThreadLocal local = loaders.get(key.getExtension());
    171             if (local != null){
    172                 AssetLoader loader = (AssetLoader) local.get();
    173                 return loader;
    174             }
    175             return null;
    176         }
    177     }
    178 
    179     public void addLoader(final Class<?> loaderType, String ... extensions){
    180         ImplThreadLocal local = new ImplThreadLocal(loaderType);
    181         for (String extension : extensions){
    182             extension = extension.toLowerCase();
    183             synchronized (loaders){
    184                 loaders.put(extension, local);
    185             }
    186         }
    187     }
    188 
    189     public void addLocator(final Class<?> locatorType, String rootPath){
    190         ImplThreadLocal local = new ImplThreadLocal(locatorType, rootPath);
    191         synchronized (genericLocators){
    192             genericLocators.add(local);
    193         }
    194     }
    195 
    196     public void removeLocator(final Class<?> locatorType, String rootPath){
    197         synchronized (genericLocators){
    198             Iterator<ImplThreadLocal> it = genericLocators.iterator();
    199             while (it.hasNext()){
    200                 ImplThreadLocal locator = it.next();
    201                 if (locator.getPath().equals(rootPath) &&
    202                     locator.getTypeClass().equals(locatorType)){
    203                     it.remove();
    204                 }
    205             }
    206         }
    207     }
    208 
    209 }
    210