Extract FileResourceBundle into a separate subclass and hide it away from the
rest of the world. git-svn-id: svn+ssh://src.earth.threerings.net/nenya/trunk@312 ed5b42cb-e716-0410-a449-f6a68f950b19
This commit is contained in:
@@ -29,27 +29,24 @@ import java.io.ObjectInputStream;
|
|||||||
import com.samskivert.io.StreamUtil;
|
import com.samskivert.io.StreamUtil;
|
||||||
|
|
||||||
import com.threerings.cast.Log;
|
import com.threerings.cast.Log;
|
||||||
|
import com.threerings.resource.FileResourceBundle;
|
||||||
import com.threerings.resource.ResourceBundle;
|
import com.threerings.resource.ResourceBundle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility functions related to creating and manipulating component
|
* Utility functions related to creating and manipulating component bundles.
|
||||||
* bundles.
|
|
||||||
*/
|
*/
|
||||||
public class BundleUtil
|
public class BundleUtil
|
||||||
{
|
{
|
||||||
/** The path in the metadata bundle to the serialized action table. */
|
/** The path in the metadata bundle to the serialized action table. */
|
||||||
public static final String ACTIONS_PATH = "actions.dat";
|
public static final String ACTIONS_PATH = "actions.dat";
|
||||||
|
|
||||||
/** The path in the metadata bundle to the serialized action tile sets
|
/** The path in the metadata bundle to the serialized action tile sets table. */
|
||||||
* table. */
|
|
||||||
public static final String ACTION_SETS_PATH = "action_sets.dat";
|
public static final String ACTION_SETS_PATH = "action_sets.dat";
|
||||||
|
|
||||||
/** The path in the metadata bundle to the serialized component class
|
/** The path in the metadata bundle to the serialized component class table. */
|
||||||
* table. */
|
|
||||||
public static final String CLASSES_PATH = "classes.dat";
|
public static final String CLASSES_PATH = "classes.dat";
|
||||||
|
|
||||||
/** The path in the component bundle to the serialized component id to
|
/** The path in the component bundle to the serialized component id to class/type mapping. */
|
||||||
* class/type mapping. */
|
|
||||||
public static final String COMPONENTS_PATH = "components.dat";
|
public static final String COMPONENTS_PATH = "components.dat";
|
||||||
|
|
||||||
/** The file extension of our action tile images. */
|
/** The file extension of our action tile images. */
|
||||||
@@ -59,22 +56,19 @@ public class BundleUtil
|
|||||||
public static final String TILESET_EXTENSION = ".dat";
|
public static final String TILESET_EXTENSION = ".dat";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to load an object from the supplied resource bundle with
|
* Attempts to load an object from the supplied resource bundle with the specified path.
|
||||||
* the specified path.
|
|
||||||
*
|
*
|
||||||
* @param wipeBundleOnFailure if there is an error reading the object
|
* @param wipeOnFailure if there is an error reading the object from the bundle and this
|
||||||
* from the bundle and this parameter is true, we will instruct the
|
* parameter is true, we will instruct the bundle to delete its underlying jar file before
|
||||||
* bundle to delete its underlying jar file before propagating the
|
* propagating the exception with the expectation that it will be redownloaded and repaired the
|
||||||
* exception with the expectation that it will be redownloaded and
|
* next time the application is run.
|
||||||
* repaired the next time the application is run.
|
|
||||||
*
|
*
|
||||||
* @return the unserialized object in question.
|
* @return the unserialized object in question.
|
||||||
*
|
*
|
||||||
* @exception IOException thrown if an I/O error occurs while reading
|
* @exception IOException thrown if an I/O error occurs while reading the object from the
|
||||||
* the object from the bundle.
|
* bundle.
|
||||||
*/
|
*/
|
||||||
public static Object loadObject (ResourceBundle bundle, String path,
|
public static Object loadObject (ResourceBundle bundle, String path, boolean wipeOnFailure)
|
||||||
boolean wipeBundleOnFailure)
|
|
||||||
throws IOException, ClassNotFoundException
|
throws IOException, ClassNotFoundException
|
||||||
{
|
{
|
||||||
InputStream bin = null;
|
InputStream bin = null;
|
||||||
@@ -86,20 +80,19 @@ public class BundleUtil
|
|||||||
return new ObjectInputStream(bin).readObject();
|
return new ObjectInputStream(bin).readObject();
|
||||||
|
|
||||||
} catch (InvalidClassException ice) {
|
} catch (InvalidClassException ice) {
|
||||||
Log.warning("Aiya! Serialized object is hosed " +
|
Log.warning("Aiya! Serialized object is hosed [bundle=" + bundle +
|
||||||
"[bundle=" + bundle.getSource().getPath() +
|
", element=" + path + ", error=" + ice.getMessage() + "].");
|
||||||
", element=" + path +
|
|
||||||
", error=" + ice.getMessage() + "].");
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
Log.warning("Error reading resource from bundle " +
|
Log.warning("Error reading resource from bundle [bundle=" + bundle + ", path=" + path +
|
||||||
"[bundle=" + bundle + ", path=" + path +
|
", wiping?=" + wipeOnFailure + "].");
|
||||||
", wiping?=" + wipeBundleOnFailure + "].");
|
if (wipeOnFailure) {
|
||||||
if (wipeBundleOnFailure) {
|
|
||||||
StreamUtil.close(bin);
|
StreamUtil.close(bin);
|
||||||
bin = null;
|
bin = null;
|
||||||
bundle.wipeBundle(false);
|
if (bundle instanceof FileResourceBundle) {
|
||||||
|
((FileResourceBundle)bundle).wipeBundle(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
throw ioe;
|
throw ioe;
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import com.samskivert.util.IntIntMap;
|
|||||||
import com.samskivert.util.Predicate;
|
import com.samskivert.util.Predicate;
|
||||||
import com.samskivert.util.Tuple;
|
import com.samskivert.util.Tuple;
|
||||||
|
|
||||||
|
import com.threerings.resource.FileResourceBundle;
|
||||||
import com.threerings.resource.ResourceBundle;
|
import com.threerings.resource.ResourceBundle;
|
||||||
import com.threerings.resource.ResourceManager;
|
import com.threerings.resource.ResourceManager;
|
||||||
|
|
||||||
@@ -270,7 +271,7 @@ public class BundledComponentRepository
|
|||||||
// from interface ImageDataProvider
|
// from interface ImageDataProvider
|
||||||
public String getIdent ()
|
public String getIdent ()
|
||||||
{
|
{
|
||||||
return "bcr:" + _bundle.getSource();
|
return "bcr:" + _bundle.getIdent();
|
||||||
}
|
}
|
||||||
|
|
||||||
// from interface ImageDataProvider
|
// from interface ImageDataProvider
|
||||||
@@ -331,8 +332,8 @@ public class BundledComponentRepository
|
|||||||
!StandardActions.SHADOW_TYPE.equals(type)) {
|
!StandardActions.SHADOW_TYPE.equals(type)) {
|
||||||
Log.warning("Unable to locate tileset for action '" + imgpath + "' " +
|
Log.warning("Unable to locate tileset for action '" + imgpath + "' " +
|
||||||
component + ".");
|
component + ".");
|
||||||
if (_wipeOnFailure) {
|
if (_wipeOnFailure && _bundle instanceof FileResourceBundle) {
|
||||||
_bundle.wipeBundle(false);
|
((FileResourceBundle)_bundle).wipeBundle(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -29,8 +29,9 @@ import java.util.Map;
|
|||||||
import com.samskivert.util.HashIntMap;
|
import com.samskivert.util.HashIntMap;
|
||||||
import com.samskivert.util.StringUtil;
|
import com.samskivert.util.StringUtil;
|
||||||
|
|
||||||
import com.threerings.resource.ResourceBundle;
|
|
||||||
import com.threerings.cast.bundle.BundleUtil;
|
import com.threerings.cast.bundle.BundleUtil;
|
||||||
|
import com.threerings.resource.FileResourceBundle;
|
||||||
|
import com.threerings.resource.ResourceBundle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dumps the contents of a component bundle to stdout.
|
* Dumps the contents of a component bundle to stdout.
|
||||||
@@ -48,7 +49,7 @@ public class DumpBundle
|
|||||||
for (int i = 0; i < args.length; i++) {
|
for (int i = 0; i < args.length; i++) {
|
||||||
File file = new File(args[i]);
|
File file = new File(args[i]);
|
||||||
try {
|
try {
|
||||||
ResourceBundle bundle = new ResourceBundle(file);
|
ResourceBundle bundle = new FileResourceBundle(file);
|
||||||
|
|
||||||
HashMap actions = (HashMap)BundleUtil.loadObject(
|
HashMap actions = (HashMap)BundleUtil.loadObject(
|
||||||
bundle, BundleUtil.ACTIONS_PATH, false);
|
bundle, BundleUtil.ACTIONS_PATH, false);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
package com.threerings.media.tile.bundle;
|
package com.threerings.media.tile.bundle;
|
||||||
|
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.ObjectInputStream;
|
import java.io.ObjectInputStream;
|
||||||
import java.io.ObjectOutputStream;
|
import java.io.ObjectOutputStream;
|
||||||
@@ -36,30 +36,21 @@ import com.threerings.media.image.ImageDataProvider;
|
|||||||
import com.threerings.media.tile.TileSet;
|
import com.threerings.media.tile.TileSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A tileset bundle is used to load up tilesets by id from a persistent
|
* A tileset bundle is used to load up tilesets by id from a persistent bundle of tilesets stored
|
||||||
* bundle of tilesets stored on the local filesystem.
|
* on the local filesystem.
|
||||||
*/
|
*/
|
||||||
public class TileSetBundle extends HashIntMap
|
public class TileSetBundle extends HashIntMap
|
||||||
implements Serializable, ImageDataProvider
|
implements Serializable, ImageDataProvider
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Initializes this resource bundle with a reference to the jarfile
|
* Initializes this resource bundle with a reference to the jarfile from which it was loaded
|
||||||
* from which it was loaded and from which it can load image data. The
|
* and from which it can load image data. The image manager will be used to decode the images.
|
||||||
* image manager will be used to decode the images.
|
|
||||||
*/
|
*/
|
||||||
public void init (ResourceBundle bundle)
|
public void init (ResourceBundle bundle)
|
||||||
{
|
{
|
||||||
_bundle = bundle;
|
_bundle = bundle;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the bundle file from which our tiles are fetched.
|
|
||||||
*/
|
|
||||||
public File getSource ()
|
|
||||||
{
|
|
||||||
return _bundle.getSource();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a tileset to this tileset bundle.
|
* Adds a tileset to this tileset bundle.
|
||||||
*/
|
*/
|
||||||
@@ -95,7 +86,7 @@ public class TileSetBundle extends HashIntMap
|
|||||||
// documentation inherited from interface
|
// documentation inherited from interface
|
||||||
public String getIdent ()
|
public String getIdent ()
|
||||||
{
|
{
|
||||||
return "tsb:" + _bundle.getSource();
|
return "tsb:" + _bundle.getIdent();
|
||||||
}
|
}
|
||||||
|
|
||||||
// documentation inherited from interface
|
// documentation inherited from interface
|
||||||
@@ -135,7 +126,7 @@ public class TileSetBundle extends HashIntMap
|
|||||||
/** That from which we load our tile images. */
|
/** That from which we load our tile images. */
|
||||||
protected transient ResourceBundle _bundle;
|
protected transient ResourceBundle _bundle;
|
||||||
|
|
||||||
/** Increase this value when object's serialized state is impacted by
|
/** Increase this value when object's serialized state is impacted by a class change
|
||||||
* a class change (modification of fields, inheritance). */
|
* (modification of fields, inheritance). */
|
||||||
private static final long serialVersionUID = 2;
|
private static final long serialVersionUID = 2;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ package com.threerings.media.tile.bundle.tools;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import com.threerings.resource.FileResourceBundle;
|
||||||
import com.threerings.resource.ResourceManager;
|
import com.threerings.resource.ResourceManager;
|
||||||
import com.threerings.resource.ResourceBundle;
|
import com.threerings.resource.ResourceBundle;
|
||||||
|
|
||||||
@@ -63,7 +64,7 @@ public class DumpBundle
|
|||||||
try {
|
try {
|
||||||
TileSetBundle tsb = null;
|
TileSetBundle tsb = null;
|
||||||
if (args[i].endsWith(".jar")) {
|
if (args[i].endsWith(".jar")) {
|
||||||
ResourceBundle bundle = new ResourceBundle(file);
|
ResourceBundle bundle = new FileResourceBundle(file);
|
||||||
tsb = BundleUtil.extractBundle(bundle);
|
tsb = BundleUtil.extractBundle(bundle);
|
||||||
tsb.init(bundle);
|
tsb.init(bundle);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -0,0 +1,422 @@
|
|||||||
|
//
|
||||||
|
// $Id: ResourceBundle.java 310 2007-10-26 19:50:53Z mdb $
|
||||||
|
//
|
||||||
|
// Nenya library - tools for developing networked games
|
||||||
|
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
|
||||||
|
// http://www.threerings.net/code/nenya/
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Lesser General Public License as published
|
||||||
|
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
package com.threerings.resource;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
|
import java.io.BufferedOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import java.util.jar.JarEntry;
|
||||||
|
import java.util.jar.JarFile;
|
||||||
|
|
||||||
|
import com.samskivert.util.FileUtil;
|
||||||
|
import com.samskivert.util.StringUtil;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A resource bundle provides access to the resources in a jar file.
|
||||||
|
*/
|
||||||
|
public class FileResourceBundle extends ResourceBundle
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Constructs a resource bundle with the supplied jar file.
|
||||||
|
*
|
||||||
|
* @param source a file object that references our source jar file.
|
||||||
|
*/
|
||||||
|
public FileResourceBundle (File source)
|
||||||
|
{
|
||||||
|
this(source, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a resource bundle with the supplied jar file.
|
||||||
|
*
|
||||||
|
* @param source a file object that references our source jar file.
|
||||||
|
* @param delay if true, the bundle will wait until someone calls
|
||||||
|
* {@link #sourceIsReady} before allowing access to its resources.
|
||||||
|
* @param unpack if true the bundle will unpack itself into a
|
||||||
|
* temporary directory
|
||||||
|
*/
|
||||||
|
public FileResourceBundle (File source, boolean delay, boolean unpack)
|
||||||
|
{
|
||||||
|
_source = source;
|
||||||
|
if (unpack) {
|
||||||
|
String root = stripSuffix(source.getPath());
|
||||||
|
_unpacked = new File(root + ".stamp");
|
||||||
|
_cache = new File(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!delay) {
|
||||||
|
sourceIsReady();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override // from ResourceBundle
|
||||||
|
public String getIdent ()
|
||||||
|
{
|
||||||
|
return _source.getPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override // from ResourceBundle
|
||||||
|
public InputStream getResource (String path)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
// unpack our resources into a temp directory so that we can load
|
||||||
|
// them quickly and the file system can cache them sensibly
|
||||||
|
File rfile = getResourceFile(path);
|
||||||
|
return (rfile == null) ? null : new FileInputStream(rfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override // from ResourceBundle
|
||||||
|
public BufferedImage getImageResource (String path)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
return ResourceManager.loadImage(getResourceFile(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link File} from which resources are fetched for this
|
||||||
|
* bundle.
|
||||||
|
*/
|
||||||
|
public File getSource ()
|
||||||
|
{
|
||||||
|
return _source;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if the bundle is fully downloaded and successfully
|
||||||
|
* unpacked.
|
||||||
|
*/
|
||||||
|
public boolean isUnpacked ()
|
||||||
|
{
|
||||||
|
return (_source.exists() && _unpacked != null &&
|
||||||
|
_unpacked.lastModified() == _source.lastModified());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by the resource manager once it has ensured that our
|
||||||
|
* resource jar file is up to date and ready for reading.
|
||||||
|
*
|
||||||
|
* @return true if we successfully unpacked our resources, false if we
|
||||||
|
* encountered errors in doing so.
|
||||||
|
*/
|
||||||
|
public boolean sourceIsReady ()
|
||||||
|
{
|
||||||
|
// make a note of our source's last modification time
|
||||||
|
_sourceLastMod = _source.lastModified();
|
||||||
|
|
||||||
|
// if we are unpacking files, the time to do so is now
|
||||||
|
if (_unpacked != null && _unpacked.lastModified() != _sourceLastMod) {
|
||||||
|
try {
|
||||||
|
resolveJarFile();
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
Log.warning("Failure resolving jar file '" + _source +
|
||||||
|
"': " + ioe + ".");
|
||||||
|
wipeBundle(true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.info("Unpacking into " + _cache + "...");
|
||||||
|
if (!_cache.exists()) {
|
||||||
|
if (!_cache.mkdir()) {
|
||||||
|
Log.warning("Failed to create bundle cache directory '" +
|
||||||
|
_cache + "'.");
|
||||||
|
closeJar();
|
||||||
|
// we are hopelessly fucked
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
FileUtil.recursiveClean(_cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
// unpack the jar file (this will close the jar when it's done)
|
||||||
|
if (!FileUtil.unpackJar(_jarSource, _cache)) {
|
||||||
|
// if something went awry, delete everything in the hopes
|
||||||
|
// that next time things will work
|
||||||
|
wipeBundle(true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if everything unpacked smoothly, create our unpack stamp
|
||||||
|
try {
|
||||||
|
_unpacked.createNewFile();
|
||||||
|
if (!_unpacked.setLastModified(_sourceLastMod)) {
|
||||||
|
Log.warning("Failed to set last mod on stamp file '" +
|
||||||
|
_unpacked + "'.");
|
||||||
|
}
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
Log.warning("Failure creating stamp file '" + _unpacked +
|
||||||
|
"': " + ioe + ".");
|
||||||
|
// no need to stick a fork in things at this point
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears out everything associated with this resource bundle in the
|
||||||
|
* hopes that we can download it afresh and everything will work the
|
||||||
|
* next time around.
|
||||||
|
*/
|
||||||
|
public void wipeBundle (boolean deleteJar)
|
||||||
|
{
|
||||||
|
// clear out our cache directory
|
||||||
|
if (_cache != null) {
|
||||||
|
FileUtil.recursiveClean(_cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete our unpack stamp file
|
||||||
|
if (_unpacked != null) {
|
||||||
|
_unpacked.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear out any .jarv file that Getdown might be maintaining so
|
||||||
|
// that we ensure that it is revalidated
|
||||||
|
File vfile = new File(FileUtil.resuffix(_source, ".jar", ".jarv"));
|
||||||
|
if (vfile.exists() && !vfile.delete()) {
|
||||||
|
Log.warning("Failed to delete " + vfile + ".");
|
||||||
|
}
|
||||||
|
|
||||||
|
// close and delete our source jar file
|
||||||
|
if (deleteJar && _source != null) {
|
||||||
|
closeJar();
|
||||||
|
if (!_source.delete()) {
|
||||||
|
Log.warning("Failed to delete " + _source +
|
||||||
|
" [exists=" + _source.exists() + "].");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a file from which the specified resource can be loaded.
|
||||||
|
* This method will unpack the resource into a temporary directory and
|
||||||
|
* return a reference to that file.
|
||||||
|
*
|
||||||
|
* @param path the path to the resource in this jar file.
|
||||||
|
*
|
||||||
|
* @return a file from which the resource can be loaded or null if no
|
||||||
|
* such resource exists.
|
||||||
|
*/
|
||||||
|
public File getResourceFile (String path)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
if (resolveJarFile()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we have been unpacked, return our unpacked file
|
||||||
|
if (_cache != null) {
|
||||||
|
File cfile = new File(_cache, path);
|
||||||
|
if (cfile.exists()) {
|
||||||
|
return cfile;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise, we unpack resources as needed into a temp directory
|
||||||
|
String tpath = StringUtil.md5hex(_source.getPath() + "%" + path);
|
||||||
|
File tfile = new File(getCacheDir(), tpath);
|
||||||
|
if (tfile.exists() && (tfile.lastModified() > _sourceLastMod)) {
|
||||||
|
return tfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
JarEntry entry = _jarSource.getJarEntry(path);
|
||||||
|
if (entry == null) {
|
||||||
|
// Log.info("Couldn't locate " + path + " in " + _jarSource + ".");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy the resource into the temporary file
|
||||||
|
BufferedOutputStream fout = new BufferedOutputStream(new FileOutputStream(tfile));
|
||||||
|
InputStream jin = _jarSource.getInputStream(entry);
|
||||||
|
IOUtils.copy(jin, fout);
|
||||||
|
jin.close();
|
||||||
|
fout.close();
|
||||||
|
|
||||||
|
return tfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this resource bundle contains the resource with the
|
||||||
|
* specified path. This avoids actually loading the resource, in the
|
||||||
|
* event that the caller only cares to know that the resource exists.
|
||||||
|
*/
|
||||||
|
public boolean containsResource (String path)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (resolveJarFile()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return (_jarSource.getJarEntry(path) != null);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representation of this resource bundle.
|
||||||
|
*/
|
||||||
|
public String toString ()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
resolveJarFile();
|
||||||
|
return (_jarSource == null) ? "[file=" + _source + "]" :
|
||||||
|
"[path=" + _jarSource.getName() + "]";
|
||||||
|
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
return "[file=" + _source + ", ioe=" + ioe + "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the internal jar file reference if we've not already got
|
||||||
|
* it; we do this lazily so as to avoid any jar- or zip-file-related
|
||||||
|
* antics until and unless doing so is required, and because the
|
||||||
|
* resource manager would like to be able to create bundles before the
|
||||||
|
* associated files have been fully downloaded.
|
||||||
|
*
|
||||||
|
* @return true if the jar file could not yet be resolved because we
|
||||||
|
* haven't yet heard from the resource manager that it is ready for us
|
||||||
|
* to access, false if all is cool.
|
||||||
|
*/
|
||||||
|
protected boolean resolveJarFile ()
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
// if we don't yet have our resource bundle's last mod time, we
|
||||||
|
// have not yet been notified that it is ready
|
||||||
|
if (_sourceLastMod == -1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_source.exists()) {
|
||||||
|
throw new IOException("Missing jar file for resource bundle: " +
|
||||||
|
_source + ".");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (_jarSource == null) {
|
||||||
|
_jarSource = new JarFile(_source);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
String msg = "Failed to resolve resource bundle jar file '" +
|
||||||
|
_source + "'";
|
||||||
|
Log.warning(msg + ".");
|
||||||
|
Log.logStackTrace(ioe);
|
||||||
|
throw (IOException) new IOException(msg).initCause(ioe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes our (possibly opened) jar file.
|
||||||
|
*/
|
||||||
|
protected void closeJar ()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (_jarSource != null) {
|
||||||
|
_jarSource.close();
|
||||||
|
}
|
||||||
|
} catch (Exception ioe) {
|
||||||
|
Log.warning("Failed to close jar file [path=" + _source +
|
||||||
|
", error=" + ioe + "].");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the cache directory used for unpacked resources.
|
||||||
|
*/
|
||||||
|
public static File getCacheDir ()
|
||||||
|
{
|
||||||
|
if (_tmpdir == null) {
|
||||||
|
String tmpdir = System.getProperty("java.io.tmpdir");
|
||||||
|
if (tmpdir == null) {
|
||||||
|
Log.info("No system defined temp directory. Faking it.");
|
||||||
|
tmpdir = System.getProperty("user.home");
|
||||||
|
}
|
||||||
|
setCacheDir(new File(tmpdir));
|
||||||
|
}
|
||||||
|
return _tmpdir;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the directory in which our temporary resource files should be stored.
|
||||||
|
*/
|
||||||
|
public static void setCacheDir (File tmpdir)
|
||||||
|
{
|
||||||
|
String rando = Long.toHexString((long)(Math.random() * Long.MAX_VALUE));
|
||||||
|
_tmpdir = new File(tmpdir, "narcache_" + rando);
|
||||||
|
if (!_tmpdir.exists()) {
|
||||||
|
if (_tmpdir.mkdirs()) {
|
||||||
|
Log.debug("Created narya temp cache directory '" + _tmpdir + "'.");
|
||||||
|
} else {
|
||||||
|
Log.warning("Failed to create temp cache directory '" + _tmpdir + "'.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add a hook to blow away the temp directory when we exit
|
||||||
|
Runtime.getRuntime().addShutdownHook(new Thread() {
|
||||||
|
public void run () {
|
||||||
|
Log.info("Clearing narya temp cache '" + _tmpdir + "'.");
|
||||||
|
FileUtil.recursiveDelete(_tmpdir);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Strips the .jar off of jar file paths. */
|
||||||
|
protected static String stripSuffix (String path)
|
||||||
|
{
|
||||||
|
if (path.endsWith(".jar")) {
|
||||||
|
return path.substring(0, path.length()-4);
|
||||||
|
} else {
|
||||||
|
// we have to change the path somehow
|
||||||
|
return path + "-cache";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The file from which we construct our jar file. */
|
||||||
|
protected File _source;
|
||||||
|
|
||||||
|
/** The last modified time of our source jar file. */
|
||||||
|
protected long _sourceLastMod = -1;
|
||||||
|
|
||||||
|
/** A file whose timestamp indicates whether or not our existing jar
|
||||||
|
* file has been unpacked. */
|
||||||
|
protected File _unpacked;
|
||||||
|
|
||||||
|
/** A directory into which we unpack files from our bundle. */
|
||||||
|
protected File _cache;
|
||||||
|
|
||||||
|
/** The jar file from which we load resources. */
|
||||||
|
protected JarFile _jarSource;
|
||||||
|
|
||||||
|
/** A directory in which we temporarily unpack our resource files. */
|
||||||
|
protected static File _tmpdir;
|
||||||
|
}
|
||||||
@@ -21,411 +21,39 @@
|
|||||||
|
|
||||||
package com.threerings.resource;
|
package com.threerings.resource;
|
||||||
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
|
|
||||||
import java.io.BufferedOutputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
import java.util.jar.JarEntry;
|
import java.awt.image.BufferedImage;
|
||||||
import java.util.jar.JarFile;
|
|
||||||
|
|
||||||
import com.samskivert.util.FileUtil;
|
|
||||||
import com.samskivert.util.StringUtil;
|
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A resource bundle provides access to the resources in a jar file.
|
* A resource bundle provides access to media resources.
|
||||||
*/
|
*/
|
||||||
public class ResourceBundle
|
public abstract class ResourceBundle
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Constructs a resource bundle with the supplied jar file.
|
* Uniquely identifies this resource bundle. Used to create cache keys.
|
||||||
*
|
|
||||||
* @param source a file object that references our source jar file.
|
|
||||||
*/
|
*/
|
||||||
public ResourceBundle (File source)
|
public abstract String getIdent ();
|
||||||
{
|
|
||||||
this(source, false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a resource bundle with the supplied jar file.
|
* Fetches the named resource from this bundle. The path should be specified as a relative,
|
||||||
*
|
* platform independent path (forward slashes). For example <code>sounds/scream.au</code>.
|
||||||
* @param source a file object that references our source jar file.
|
|
||||||
* @param delay if true, the bundle will wait until someone calls
|
|
||||||
* {@link #sourceIsReady} before allowing access to its resources.
|
|
||||||
* @param unpack if true the bundle will unpack itself into a
|
|
||||||
* temporary directory
|
|
||||||
*/
|
|
||||||
public ResourceBundle (File source, boolean delay, boolean unpack)
|
|
||||||
{
|
|
||||||
_source = source;
|
|
||||||
if (unpack) {
|
|
||||||
String root = stripSuffix(source.getPath());
|
|
||||||
_unpacked = new File(root + ".stamp");
|
|
||||||
_cache = new File(root);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!delay) {
|
|
||||||
sourceIsReady();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the {@link File} from which resources are fetched for this
|
|
||||||
* bundle.
|
|
||||||
*/
|
|
||||||
public File getSource ()
|
|
||||||
{
|
|
||||||
return _source;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if the bundle is fully downloaded and successfully
|
|
||||||
* unpacked.
|
|
||||||
*/
|
|
||||||
public boolean isUnpacked ()
|
|
||||||
{
|
|
||||||
return (_source.exists() && _unpacked != null &&
|
|
||||||
_unpacked.lastModified() == _source.lastModified());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called by the resource manager once it has ensured that our
|
|
||||||
* resource jar file is up to date and ready for reading.
|
|
||||||
*
|
|
||||||
* @return true if we successfully unpacked our resources, false if we
|
|
||||||
* encountered errors in doing so.
|
|
||||||
*/
|
|
||||||
public boolean sourceIsReady ()
|
|
||||||
{
|
|
||||||
// make a note of our source's last modification time
|
|
||||||
_sourceLastMod = _source.lastModified();
|
|
||||||
|
|
||||||
// if we are unpacking files, the time to do so is now
|
|
||||||
if (_unpacked != null && _unpacked.lastModified() != _sourceLastMod) {
|
|
||||||
try {
|
|
||||||
resolveJarFile();
|
|
||||||
} catch (IOException ioe) {
|
|
||||||
Log.warning("Failure resolving jar file '" + _source +
|
|
||||||
"': " + ioe + ".");
|
|
||||||
wipeBundle(true);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.info("Unpacking into " + _cache + "...");
|
|
||||||
if (!_cache.exists()) {
|
|
||||||
if (!_cache.mkdir()) {
|
|
||||||
Log.warning("Failed to create bundle cache directory '" +
|
|
||||||
_cache + "'.");
|
|
||||||
closeJar();
|
|
||||||
// we are hopelessly fucked
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
FileUtil.recursiveClean(_cache);
|
|
||||||
}
|
|
||||||
|
|
||||||
// unpack the jar file (this will close the jar when it's done)
|
|
||||||
if (!FileUtil.unpackJar(_jarSource, _cache)) {
|
|
||||||
// if something went awry, delete everything in the hopes
|
|
||||||
// that next time things will work
|
|
||||||
wipeBundle(true);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if everything unpacked smoothly, create our unpack stamp
|
|
||||||
try {
|
|
||||||
_unpacked.createNewFile();
|
|
||||||
if (!_unpacked.setLastModified(_sourceLastMod)) {
|
|
||||||
Log.warning("Failed to set last mod on stamp file '" +
|
|
||||||
_unpacked + "'.");
|
|
||||||
}
|
|
||||||
} catch (IOException ioe) {
|
|
||||||
Log.warning("Failure creating stamp file '" + _unpacked +
|
|
||||||
"': " + ioe + ".");
|
|
||||||
// no need to stick a fork in things at this point
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears out everything associated with this resource bundle in the
|
|
||||||
* hopes that we can download it afresh and everything will work the
|
|
||||||
* next time around.
|
|
||||||
*/
|
|
||||||
public void wipeBundle (boolean deleteJar)
|
|
||||||
{
|
|
||||||
// clear out our cache directory
|
|
||||||
if (_cache != null) {
|
|
||||||
FileUtil.recursiveClean(_cache);
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete our unpack stamp file
|
|
||||||
if (_unpacked != null) {
|
|
||||||
_unpacked.delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
// clear out any .jarv file that Getdown might be maintaining so
|
|
||||||
// that we ensure that it is revalidated
|
|
||||||
File vfile = new File(FileUtil.resuffix(_source, ".jar", ".jarv"));
|
|
||||||
if (vfile.exists() && !vfile.delete()) {
|
|
||||||
Log.warning("Failed to delete " + vfile + ".");
|
|
||||||
}
|
|
||||||
|
|
||||||
// close and delete our source jar file
|
|
||||||
if (deleteJar && _source != null) {
|
|
||||||
closeJar();
|
|
||||||
if (!_source.delete()) {
|
|
||||||
Log.warning("Failed to delete " + _source +
|
|
||||||
" [exists=" + _source.exists() + "].");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches the named resource from this bundle. The path should be
|
|
||||||
* specified as a relative, platform independent path (forward
|
|
||||||
* slashes). For example <code>sounds/scream.au</code>.
|
|
||||||
*
|
*
|
||||||
* @param path the path to the resource in this jar file.
|
* @param path the path to the resource in this jar file.
|
||||||
*
|
*
|
||||||
* @return an input stream from which the resource can be loaded or
|
* @return an input stream from which the resource can be loaded or null if no such resource
|
||||||
* null if no such resource exists.
|
* exists.
|
||||||
*
|
*
|
||||||
* @exception IOException thrown if an error occurs locating the
|
* @exception IOException thrown if an error occurs locating the resource in the jar file.
|
||||||
* resource in the jar file.
|
|
||||||
*/
|
*/
|
||||||
public InputStream getResource (String path)
|
public abstract InputStream getResource (String path)
|
||||||
throws IOException
|
throws IOException;
|
||||||
{
|
|
||||||
// unpack our resources into a temp directory so that we can load
|
|
||||||
// them quickly and the file system can cache them sensibly
|
|
||||||
File rfile = getResourceFile(path);
|
|
||||||
return (rfile == null) ? null : new FileInputStream(rfile);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a file from which the specified resource can be loaded.
|
|
||||||
* This method will unpack the resource into a temporary directory and
|
|
||||||
* return a reference to that file.
|
|
||||||
*
|
|
||||||
* @param path the path to the resource in this jar file.
|
|
||||||
*
|
|
||||||
* @return a file from which the resource can be loaded or null if no
|
|
||||||
* such resource exists.
|
|
||||||
*/
|
|
||||||
public File getResourceFile (String path)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
if (resolveJarFile()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we have been unpacked, return our unpacked file
|
|
||||||
if (_cache != null) {
|
|
||||||
File cfile = new File(_cache, path);
|
|
||||||
if (cfile.exists()) {
|
|
||||||
return cfile;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// otherwise, we unpack resources as needed into a temp directory
|
|
||||||
String tpath = StringUtil.md5hex(_source.getPath() + "%" + path);
|
|
||||||
File tfile = new File(getCacheDir(), tpath);
|
|
||||||
if (tfile.exists() && (tfile.lastModified() > _sourceLastMod)) {
|
|
||||||
return tfile;
|
|
||||||
}
|
|
||||||
|
|
||||||
JarEntry entry = _jarSource.getJarEntry(path);
|
|
||||||
if (entry == null) {
|
|
||||||
// Log.info("Couldn't locate " + path + " in " + _jarSource + ".");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy the resource into the temporary file
|
|
||||||
BufferedOutputStream fout = new BufferedOutputStream(new FileOutputStream(tfile));
|
|
||||||
InputStream jin = _jarSource.getInputStream(entry);
|
|
||||||
IOUtils.copy(jin, fout);
|
|
||||||
jin.close();
|
|
||||||
fout.close();
|
|
||||||
|
|
||||||
return tfile;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decodes and returns the specified image resource. Returns null if no resource exists at the
|
* Decodes and returns the specified image resource. Returns null if no resource exists at the
|
||||||
* specified path.
|
* specified path.
|
||||||
*/
|
*/
|
||||||
public BufferedImage getImageResource (String path)
|
public abstract BufferedImage getImageResource (String path)
|
||||||
throws IOException
|
throws IOException;
|
||||||
{
|
|
||||||
return ResourceManager.loadImage(getResourceFile(path));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if this resource bundle contains the resource with the
|
|
||||||
* specified path. This avoids actually loading the resource, in the
|
|
||||||
* event that the caller only cares to know that the resource exists.
|
|
||||||
*/
|
|
||||||
public boolean containsResource (String path)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
if (resolveJarFile()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return (_jarSource.getJarEntry(path) != null);
|
|
||||||
} catch (IOException ioe) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a string representation of this resource bundle.
|
|
||||||
*/
|
|
||||||
public String toString ()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
resolveJarFile();
|
|
||||||
return (_jarSource == null) ? "[file=" + _source + "]" :
|
|
||||||
"[path=" + _jarSource.getName() + "]";
|
|
||||||
|
|
||||||
} catch (IOException ioe) {
|
|
||||||
return "[file=" + _source + ", ioe=" + ioe + "]";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates the internal jar file reference if we've not already got
|
|
||||||
* it; we do this lazily so as to avoid any jar- or zip-file-related
|
|
||||||
* antics until and unless doing so is required, and because the
|
|
||||||
* resource manager would like to be able to create bundles before the
|
|
||||||
* associated files have been fully downloaded.
|
|
||||||
*
|
|
||||||
* @return true if the jar file could not yet be resolved because we
|
|
||||||
* haven't yet heard from the resource manager that it is ready for us
|
|
||||||
* to access, false if all is cool.
|
|
||||||
*/
|
|
||||||
protected boolean resolveJarFile ()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
// if we don't yet have our resource bundle's last mod time, we
|
|
||||||
// have not yet been notified that it is ready
|
|
||||||
if (_sourceLastMod == -1) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_source.exists()) {
|
|
||||||
throw new IOException("Missing jar file for resource bundle: " +
|
|
||||||
_source + ".");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (_jarSource == null) {
|
|
||||||
_jarSource = new JarFile(_source);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
|
|
||||||
} catch (IOException ioe) {
|
|
||||||
String msg = "Failed to resolve resource bundle jar file '" +
|
|
||||||
_source + "'";
|
|
||||||
Log.warning(msg + ".");
|
|
||||||
Log.logStackTrace(ioe);
|
|
||||||
throw (IOException) new IOException(msg).initCause(ioe);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Closes our (possibly opened) jar file.
|
|
||||||
*/
|
|
||||||
protected void closeJar ()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
if (_jarSource != null) {
|
|
||||||
_jarSource.close();
|
|
||||||
}
|
|
||||||
} catch (Exception ioe) {
|
|
||||||
Log.warning("Failed to close jar file [path=" + _source +
|
|
||||||
", error=" + ioe + "].");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the cache directory used for unpacked resources.
|
|
||||||
*/
|
|
||||||
public static File getCacheDir ()
|
|
||||||
{
|
|
||||||
if (_tmpdir == null) {
|
|
||||||
String tmpdir = System.getProperty("java.io.tmpdir");
|
|
||||||
if (tmpdir == null) {
|
|
||||||
Log.info("No system defined temp directory. Faking it.");
|
|
||||||
tmpdir = System.getProperty("user.home");
|
|
||||||
}
|
|
||||||
setCacheDir(new File(tmpdir));
|
|
||||||
}
|
|
||||||
return _tmpdir;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specifies the directory in which our temporary resource files should be stored.
|
|
||||||
*/
|
|
||||||
public static void setCacheDir (File tmpdir)
|
|
||||||
{
|
|
||||||
String rando = Long.toHexString((long)(Math.random() * Long.MAX_VALUE));
|
|
||||||
_tmpdir = new File(tmpdir, "narcache_" + rando);
|
|
||||||
if (!_tmpdir.exists()) {
|
|
||||||
if (_tmpdir.mkdirs()) {
|
|
||||||
Log.debug("Created narya temp cache directory '" + _tmpdir + "'.");
|
|
||||||
} else {
|
|
||||||
Log.warning("Failed to create temp cache directory '" + _tmpdir + "'.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// add a hook to blow away the temp directory when we exit
|
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread() {
|
|
||||||
public void run () {
|
|
||||||
Log.info("Clearing narya temp cache '" + _tmpdir + "'.");
|
|
||||||
FileUtil.recursiveDelete(_tmpdir);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Strips the .jar off of jar file paths. */
|
|
||||||
protected static String stripSuffix (String path)
|
|
||||||
{
|
|
||||||
if (path.endsWith(".jar")) {
|
|
||||||
return path.substring(0, path.length()-4);
|
|
||||||
} else {
|
|
||||||
// we have to change the path somehow
|
|
||||||
return path + "-cache";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The file from which we construct our jar file. */
|
|
||||||
protected File _source;
|
|
||||||
|
|
||||||
/** The last modified time of our source jar file. */
|
|
||||||
protected long _sourceLastMod = -1;
|
|
||||||
|
|
||||||
/** A file whose timestamp indicates whether or not our existing jar
|
|
||||||
* file has been unpacked. */
|
|
||||||
protected File _unpacked;
|
|
||||||
|
|
||||||
/** A directory into which we unpack files from our bundle. */
|
|
||||||
protected File _cache;
|
|
||||||
|
|
||||||
/** The jar file from which we load resources. */
|
|
||||||
protected JarFile _jarSource;
|
|
||||||
|
|
||||||
/** A directory in which we temporarily unpack our resource files. */
|
|
||||||
protected static File _tmpdir;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -248,7 +248,7 @@ public class ResourceManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
// resolve the configured resource sets
|
// resolve the configured resource sets
|
||||||
ArrayList dlist = new ArrayList();
|
List<ResourceBundle> dlist = new ArrayList<ResourceBundle>();
|
||||||
Enumeration names = config.propertyNames();
|
Enumeration names = config.propertyNames();
|
||||||
while (names.hasMoreElements()) {
|
while (names.hasMoreElements()) {
|
||||||
String key = (String)names.nextElement();
|
String key = (String)names.nextElement();
|
||||||
@@ -326,7 +326,7 @@ public class ResourceManager
|
|||||||
public boolean checkBundle (String path)
|
public boolean checkBundle (String path)
|
||||||
{
|
{
|
||||||
File bfile = getResourceFile(path);
|
File bfile = getResourceFile(path);
|
||||||
return (bfile == null) ? false : new ResourceBundle(bfile, true, _unpack).isUnpacked();
|
return (bfile == null) ? false : new FileResourceBundle(bfile, true, _unpack).isUnpacked();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -345,7 +345,7 @@ public class ResourceManager
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ResourceBundle bundle = new ResourceBundle(bfile, true, _unpack);
|
final FileResourceBundle bundle = new FileResourceBundle(bfile, true, _unpack);
|
||||||
if (bundle.isUnpacked()) {
|
if (bundle.isUnpacked()) {
|
||||||
if (bundle.sourceIsReady()) {
|
if (bundle.sourceIsReady()) {
|
||||||
listener.requestCompleted(bundle);
|
listener.requestCompleted(bundle);
|
||||||
@@ -404,8 +404,8 @@ public class ResourceManager
|
|||||||
InputStream in = null;
|
InputStream in = null;
|
||||||
|
|
||||||
// first look for this resource in our default resource bundle
|
// first look for this resource in our default resource bundle
|
||||||
for (int i = 0; i < _default.length; i++) {
|
for (ResourceBundle bundle : _default) {
|
||||||
in = _default[i].getResource(path);
|
in = bundle.getResource(path);
|
||||||
if (in != null) {
|
if (in != null) {
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
@@ -458,10 +458,10 @@ public class ResourceManager
|
|||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
// first look for this resource in our default resource bundle
|
// first look for this resource in our default resource bundle
|
||||||
for (int i = 0; i < _default.length; i++) {
|
for (ResourceBundle bundle : _default) {
|
||||||
File file = _default[i].getResourceFile(path);
|
BufferedImage image = bundle.getImageResource(path);
|
||||||
if (file != null) {
|
if (image != null) {
|
||||||
return loadImage(file);
|
return image;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -624,13 +624,15 @@ public class ResourceManager
|
|||||||
/**
|
/**
|
||||||
* Loads up a resource set based on the supplied definition information.
|
* Loads up a resource set based on the supplied definition information.
|
||||||
*/
|
*/
|
||||||
protected void resolveResourceSet (String setName, String definition, List dlist)
|
protected void resolveResourceSet (
|
||||||
|
String setName, String definition, List<ResourceBundle> dlist)
|
||||||
{
|
{
|
||||||
ArrayList set = new ArrayList();
|
List<ResourceBundle> set = new ArrayList<ResourceBundle>();
|
||||||
StringTokenizer tok = new StringTokenizer(definition, ":");
|
StringTokenizer tok = new StringTokenizer(definition, ":");
|
||||||
while (tok.hasMoreTokens()) {
|
while (tok.hasMoreTokens()) {
|
||||||
String path = tok.nextToken().trim();
|
String path = tok.nextToken().trim();
|
||||||
ResourceBundle bundle = new ResourceBundle(getResourceFile(path), true, _unpack);
|
FileResourceBundle bundle =
|
||||||
|
new FileResourceBundle(getResourceFile(path), true, _unpack);
|
||||||
set.add(bundle);
|
set.add(bundle);
|
||||||
if (bundle.isUnpacked() && bundle.sourceIsReady()) {
|
if (bundle.isUnpacked() && bundle.sourceIsReady()) {
|
||||||
continue;
|
continue;
|
||||||
@@ -639,8 +641,7 @@ public class ResourceManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
// convert our array list into an array and stick it in the table
|
// convert our array list into an array and stick it in the table
|
||||||
ResourceBundle[] setvec = new ResourceBundle[set.size()];
|
ResourceBundle[] setvec = set.toArray(new ResourceBundle[set.size()]);
|
||||||
set.toArray(setvec);
|
|
||||||
_sets.put(setName, setvec);
|
_sets.put(setName, setvec);
|
||||||
|
|
||||||
// if this is our default resource bundle, keep a reference to it
|
// if this is our default resource bundle, keep a reference to it
|
||||||
@@ -693,7 +694,7 @@ public class ResourceManager
|
|||||||
/** Used to unpack bundles on a separate thread. */
|
/** Used to unpack bundles on a separate thread. */
|
||||||
protected static class Unpacker extends Thread
|
protected static class Unpacker extends Thread
|
||||||
{
|
{
|
||||||
public Unpacker (List bundles, InitObserver obs)
|
public Unpacker (List<ResourceBundle> bundles, InitObserver obs)
|
||||||
{
|
{
|
||||||
_bundles = bundles;
|
_bundles = bundles;
|
||||||
_obs = obs;
|
_obs = obs;
|
||||||
@@ -708,9 +709,9 @@ public class ResourceManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (Iterator iter = _bundles.iterator(); iter.hasNext(); ) {
|
for (ResourceBundle bundle : _bundles) {
|
||||||
ResourceBundle bundle = (ResourceBundle)iter.next();
|
if (bundle instanceof FileResourceBundle &&
|
||||||
if (!bundle.sourceIsReady()) {
|
!((FileResourceBundle)bundle).sourceIsReady()) {
|
||||||
Log.warning("Bundle failed to initialize " + bundle + ".");
|
Log.warning("Bundle failed to initialize " + bundle + ".");
|
||||||
}
|
}
|
||||||
if (_obs != null) {
|
if (_obs != null) {
|
||||||
@@ -732,7 +733,7 @@ public class ResourceManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List _bundles;
|
protected List<ResourceBundle> _bundles;
|
||||||
protected InitObserver _obs;
|
protected InitObserver _obs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user