Java-Gaming.org    
Featured games (79)
games approved by the League of Dukes
Games in Showcase (477)
Games in Android Showcase (109)
games submitted by our members
Games in WIP (536)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Auto-detect if files are stored locally or in the classpath  (Read 1702 times)
0 Members and 1 Guest are viewing this topic.
Offline Mr. Gol

Senior Member


Medals: 1



« Posted 2010-01-28 23:09:55 »

Anyone who has used Web Start has come across the problem that it forces you to store everything in JAR files. This is especially annoying because there are multiple ways to load a file from the classpath (MyClass.class.getClassLoader.getResource(...) and Thread.currentThread().getContextClassLoader().getResource(...)). Also, when you're developing it's more convenient to only have to change a local file, instead of having to create the JARs again every time you make a change.

The class below allows you to develop using local files, and to load them from the classpath when deployed as Web Start application. This works without code changes, so you don't have to have DEVELOP_MODE = true flags in your code. I guess a lot of people who will read this already have a similar (and probably better) way to tackle this problem, but it might just help one guy who is trying to figure out Web Start.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
131  
132  
133  
134  
135  
136  
137  
138  
139  
140  
141  
142  
143  
144  
145  
146  
147  
148  
149  
150  
151  
152  
153  
154  
155  
156  
157  
158  
159  
160  
161  
162  
163  
164  
165  
166  
167  
168  
169  
170  
171  
172  
173  
174  
175  
176  
177  
178  
179  
180  
181  
182  
183  
184  
185  
186  
187  
188  
189  
190  
191  
192  
193  
194  
195  
196  
197  
198  
199  
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

/**
 * Represents the link to a resource file located at a relative path. When the
 * file's contents are requested (as an {@code InputStream}, URL or byte array)
 * the local file system is checked first. If the file does not exist there,
 * the classpath is checked.
 * <p>
 * This class can be used for situations where a fallback mechanism for resource
 * files is required. For example, applications can be developed using the local
 * file system, and use files stored in JARs when deployed using Java Web Start.  
 */

public class ResourceFile {
   
    private String path;
    private File localFile;
    private URL classpath;

    /**
     * Creates a new {@code ResourceFile} located at the specified path.
     * @param path The relative location of the file.
     * @throws IllegalArgumentException if the path is an empty string.
     */

    public ResourceFile(String path) {
       
        path = path.trim();
       
        if (path.length() == 0) {
            throw new IllegalArgumentException("Path is empty. If you want to " +
                    "indicate the current directory use \".\"");
        }
       
        // Normalize the path and make sure it uses slashes as delimiters
       path = path.replace('\\', '/');    
        if (path.endsWith("/")) {
            path = path.substring(0, path.length() - 1);
        }
       
        // If the path starts with "./" the file is in the current directory. Remove
       // the useless prefix in such cases.
       if ((path.length() > 2) && (path.startsWith("./"))) {
            path = path.substring(2);
        }
   
        this.path = path;
        localFile = new File(path);
        classpath = getClass().getClassLoader().getResource(path);
    }
   
    /**
     * Creates a {@code ResourceFile} that is within the specified directory.
     * @param dir The file's parent directory.
     * @param name The file's name.
     */

    public ResourceFile(ResourceFile dir, String name) {
        this(dir.getPath() + "/" + name);
    }
   
    /**
     * Creates a {@code ResourceFile} from the specified local file. The path of
     * the file will be the absolute path of the local file.
     */

    public ResourceFile(File file) {
        this(file.getAbsolutePath());
    }
   
    public String getPath() {
        return path;
    }
   
    public String getName() {
        int slashIndex = path.lastIndexOf('/');
        if (slashIndex == -1) {
            return path;
        }
        return path.substring(slashIndex + 1);
    }
   
    /**
     * Returns if this file exists, either in the local file system or in the
     * classpath.
     */

    public boolean exists() {
        return (existsLocal() || existsClassPath());
    }
   
    public boolean existsLocal() {
        return localFile.exists();
    }
   
    public boolean existsClassPath() {
        return (classpath != null);
    }
   
    /**
     * Returns an {@code InputStream} for this resource file.
     * @throws ResourceNotFoundException if the file could not be located.
     */

    public InputStream getStream() {
       
        if (existsLocal()) {
            try {
                return new FileInputStream(localFile);
            } catch (FileNotFoundException e) {
                // File was removed since construction
               throw new ResourceNotFoundException(this);
            }
        } else if (existsClassPath()) {
            try {
                return classpath.openStream();
            } catch (IOException e) {
                // Classpath was changed since construction
               throw new ResourceNotFoundException(this);
            }
        } else {
            throw new ResourceNotFoundException(this);
        }
    }
   
    /**
     * Returns a {@code URL} pointing to this resource file.
     * @throws ResourceNotFoundException if the file could not be located.
     */

    public URL getURL() {
        if (existsLocal()) {
           try {
               return localFile.toURI().toURL();
           } catch (IOException e) {
               // Should be impossible
              throw new AssertionError(e);
           }
        } else if (existsClassPath()) {
            return classpath;
        } else {
            throw new ResourceNotFoundException(this);
        }
    }
   
    /**
     * Returns the contents of this resource file as a byte array.
     * @throws ResourceNotFoundException if the file could not be located.
     * @throws IllegalStateException if the file could not be converted to bytes.
     */

    public final byte[] getBytes() {
        try {
            return toByteArray(getStream());
        } catch (IOException e) {
            throw new IllegalStateException("Could not convert file to bytes", e);
        }
    }
   
    private byte[] toByteArray(InputStream input) throws IOException {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        toStream(input, output);
        input.close();
        output.close();
        return output.toByteArray();
    }
   
    private void toStream(InputStream input, OutputStream output) throws IOException {
        byte[] buffer = new byte[2048];
        int length = -1;
        while ((length = input.read(buffer, 0, buffer.length)) != -1) {
            output.write(buffer, 0, length);
        }
    }
   
    /**
     * Returns the local file that is represented by this resource file. Note that
     * the local file might not actually exist, this can be checked by calling
     * {@link #existsLocal()}.
     */

    public File toLocalFile() {
        return localFile;
    }
   
    @Override
    public boolean equals(Object o) {
        if (o instanceof ResourceFile) {
            return path.equals(((ResourceFile) o).path);
        }
        return false;
    }
   
    @Override
    public int hashCode() {
        return path.hashCode();
    }
   
    @Override
    public String toString() {
        return path;
    }
}

Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #1 - Posted 2010-01-28 23:22:19 »

That's nifty! I have indeed had many problems with this in the past. It looks like a good solution.

See my work:
OTC Software
Offline Nate

JGO Kernel


Medals: 145
Projects: 4
Exp: 14 years


Esoteric Software


« Reply #2 - Posted 2010-01-29 06:48:47 »

Cool. Looks like a useful class.

Here is a little related snippet that might come in useful:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
   static private Boolean isJWS;
   static public boolean isJWS () {
      if (isJWS == null) {
         try {
            Method method = Class.forName("javax.jnlp.ServiceManager").getDeclaredMethod("lookup", new Class[] {String.class});
            method.invoke(null, "javax.jnlp.PersistenceService");
            isJWS = Boolean.TRUE;
         } catch (Throwable ex) {
            isJWS = Boolean.FALSE;
         }
      }
      return isJWS;
   }

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline ryanm

Senior Member


Projects: 1
Exp: 15 years


Used to be bleb


« Reply #3 - Posted 2010-01-29 10:06:52 »

Can't you just add the folder containing your resource files to the classpath when developing?
Offline Mr. Gol

Senior Member


Medals: 1



« Reply #4 - Posted 2010-01-29 12:34:32 »

Cool. Looks like a useful class.

Here is a little related snippet that might come in useful:
(...)

Thanks! I've been wondering how to detect if you're running under Web Start. I currently just check if a certain file exists locally, but obviously this solution is far more elegant.
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

CogWheelz (18 views)
2014-07-30 21:08:39

Riven (26 views)
2014-07-29 18:09:19

Riven (15 views)
2014-07-29 18:08:52

Dwinin (13 views)
2014-07-29 10:59:34

E.R. Fleming (34 views)
2014-07-29 03:07:13

E.R. Fleming (12 views)
2014-07-29 03:06:25

pw (43 views)
2014-07-24 01:59:36

Riven (44 views)
2014-07-23 21:16:32

Riven (30 views)
2014-07-23 21:07:15

Riven (31 views)
2014-07-23 20:56:16
List of Learning Resources
by SilverTiger
2014-07-31 18:29:50

List of Learning Resources
by SilverTiger
2014-07-31 18:26:06

List of Learning Resources
by SilverTiger
2014-07-31 13:54:12

HotSpot Options
by dleskov
2014-07-08 03:59:08

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:58:24

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:47:22

How do I start Java Game Development?
by ra4king
2014-05-17 11:13:37

HotSpot Options
by Roquen
2014-05-15 09:59:54
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!