petraframe-svn Mailing List for PetraGameFrame
Status: Pre-Alpha
Brought to you by:
janet-h
You can subscribe to this list here.
2011 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(8) |
Jul
(6) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
---|
From: <ja...@us...> - 2011-07-11 17:38:40
|
Revision: 15 http://petraframe.svn.sourceforge.net/petraframe/?rev=15&view=rev Author: janet-h Date: 2011-07-11 17:38:33 +0000 (Mon, 11 Jul 2011) Log Message: ----------- roundup on preloading manager added preloading event listening to resource manager Modified Paths: -------------- PETRA1/trunk/src/net/petraframe/res/data/PGFResourceManager.java PETRA1/trunk/src/net/petraframe/res/data/PGFResourceManagerImpl.java Added Paths: ----------- PETRA1/trunk/src/net/petraframe/event/ PETRA1/trunk/src/net/petraframe/event/PGFPreloadEvent.java PETRA1/trunk/src/net/petraframe/event/PGFPreloadEventListener.java Added: PETRA1/trunk/src/net/petraframe/event/PGFPreloadEvent.java =================================================================== --- PETRA1/trunk/src/net/petraframe/event/PGFPreloadEvent.java (rev 0) +++ PETRA1/trunk/src/net/petraframe/event/PGFPreloadEvent.java 2011-07-11 17:38:33 UTC (rev 15) @@ -0,0 +1,93 @@ +package net.petraframe.event; + +import java.util.EventObject; + +import net.petraframe.res.data.PGFDataResource; + +public class PGFPreloadEvent extends EventObject { + private static final long serialVersionUID = 9205167344938402777L; + + public static enum PreloadEventType {FAILED, STARTED, PERFORMED}; + + private PGFDataResource resource; + private long timestamp; + private int duration; + private PreloadEventType type; + private Throwable error; + + /** + * Create a preload event. + * + * @param source Object (may be <b>null</b>) + * @param type PreloadEventType type of this event + * @param res PGFDataResource the data resource associated with this event + * @param time long epoch milliseconds when this event occurred (may be 0) + * @param duration int milliseconds of loading duration (may be 0) + * @throws NullPointerException if type or res are null + */ + public PGFPreloadEvent( + Object source, + PreloadEventType type, + PGFDataResource res, + long time, + int duration ) { + + super(source); + if (type == null | res == null) { + throw new NullPointerException(); + } + this.type = type; + this.resource = res; + this.timestamp = time == 0 ? System.currentTimeMillis() : time; + this.duration = duration; + } + + /** The data resource associated with this event. + * + * @return <code>PGFDataResource</code> data resource + */ + public PGFDataResource getResource() { + return resource; + } + + /** Time when this event occurred. + * + * @return long epoch milliseconds + */ + public long getTimestamp() { + return timestamp; + } + + /** Duration of data loading. May be 0 to indicate unavailability. + * + * @return int milliseconds + */ + public int getDuration() { + return duration; + } + + /** Event type. + * + * @return PGFPreloadEvent.PreloadEventType + */ + public PreloadEventType getType() { + return type; + } + + /** Error message in case of a failure event. + * + * @return <code>Throwable</code> or <b>null</b> + */ + public Throwable getError() { + return error; + } + + /** Sets the error message for this event. + * + * @param error <code>Throwable</code> or <b>null</b> + */ + public void setError (Throwable error) { + this.error = error; + } + +} Property changes on: PETRA1/trunk/src/net/petraframe/event/PGFPreloadEvent.java ___________________________________________________________________ Added: svn:mime-type + text/x-java Added: svn:eol-style + native Added: PETRA1/trunk/src/net/petraframe/event/PGFPreloadEventListener.java =================================================================== --- PETRA1/trunk/src/net/petraframe/event/PGFPreloadEventListener.java (rev 0) +++ PETRA1/trunk/src/net/petraframe/event/PGFPreloadEventListener.java 2011-07-11 17:38:33 UTC (rev 15) @@ -0,0 +1,14 @@ +package net.petraframe.event; + +public interface PGFPreloadEventListener { + + /** + * Called for any of the preloading event types. + * This method is expected to terminate quickly. + * Implementation should analyse the event type! + * + * @param evt <code>PGFPreloadEvent</code> + */ + public void resourcePreloadingEventPerformed (PGFPreloadEvent evt); + +} Property changes on: PETRA1/trunk/src/net/petraframe/event/PGFPreloadEventListener.java ___________________________________________________________________ Added: svn:mime-type + text/x-java Added: svn:eol-style + native Modified: PETRA1/trunk/src/net/petraframe/res/data/PGFResourceManager.java =================================================================== --- PETRA1/trunk/src/net/petraframe/res/data/PGFResourceManager.java 2011-07-04 19:32:34 UTC (rev 14) +++ PETRA1/trunk/src/net/petraframe/res/data/PGFResourceManager.java 2011-07-11 17:38:33 UTC (rev 15) @@ -8,6 +8,17 @@ import javax.swing.ImageIcon; import javax.swing.event.ChangeListener; +import net.petraframe.event.PGFPreloadEventListener; + +/** + * The Resource Manager makes available read-only external data resources + * of the application by call of their names, which are free to design. + * Furthermore resources can be selected to be kept in a cache for quick + * access and preloaded automatically when the manager starts. + * + * @author janet-h + * + */ public interface PGFResourceManager { /** @@ -70,14 +81,14 @@ * changes (valid/invalid), or when the set of mappings has been * modified. * - * @param listener <code>ChangeListener</code> + * @param listener <code>javax.swing.event.ChangeListener</code> */ public void addChangeListener (ChangeListener listener); /** * Removes a change listener from this manager. * - * @param listener + * @param listener <code>javax.swing.event.ChangeListener</code> */ public void removeChangeListener (ChangeListener listener); @@ -149,4 +160,21 @@ */ public ImageIcon getImageIcon (String name) throws IOException; +/** + * Adds a preloading listener to this manager. A preloading event + * is issued for each resource a) when preloading started, b) when + * preloading finished successfully (performed), and c) when + * preloading failed. + * + * @param listener {@link PGFPreloadEventListener} + */ +public void addPreloadEventListener(PGFPreloadEventListener listener); + +/** + * Removes a preloading listener to this manager. + * + * @param listener {@link PGFPreloadEventListener} + */ +public void removePreloadEventListener(PGFPreloadEventListener listener); + } Modified: PETRA1/trunk/src/net/petraframe/res/data/PGFResourceManagerImpl.java =================================================================== --- PETRA1/trunk/src/net/petraframe/res/data/PGFResourceManagerImpl.java 2011-07-04 19:32:34 UTC (rev 14) +++ PETRA1/trunk/src/net/petraframe/res/data/PGFResourceManagerImpl.java 2011-07-11 17:38:33 UTC (rev 15) @@ -19,6 +19,8 @@ import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; +import net.petraframe.event.PGFPreloadEvent; +import net.petraframe.event.PGFPreloadEventListener; import net.petraframe.exception.PGFPreloadFailureException; public class PGFResourceManagerImpl implements PGFResourceManager { @@ -29,6 +31,8 @@ public static int maxCacheEntries = 0; + public static int initialCacheCapacity = 500; + public static long maxCacheDataSize = 10000000; // 10 MB public static int maxJobsParallel = 10; @@ -42,13 +46,17 @@ /** The map referring to resource directory objects. Realises all available resource directory paths. */ private TreeMap<String, PGFResourceDirectory> directoryMap = new TreeMap<String, PGFResourceDirectory>(); + /** The map that realises the preloaded resources data cache. Entries in this cache + * are not removed except by <code>invalidateResources()</code>. */ private Hashtable<String, byte[]> preloadCache = new Hashtable<String, byte[]>(); + /** Structure realising the "live" data cache. */ private DataCache dataCache = new DataCache(maxCacheEntries, maxCacheDataSize); private PreloadingManager preloadingManager; private List<URL> mappingSources; private ArrayList<ChangeListener> changeListeners; + private ArrayList<PGFPreloadEventListener> preloadEventListeners; private boolean isValid = false; @@ -103,7 +111,9 @@ /** * Searches for a cache data entry for the given resource - * and returns the cached data when found. + * and returns the cached data when found. (The search goes + * into preload or "live" data cache, depending on what + * is logically set in the resource.) * * @param resource <code>PGFDataResource</code> * @return <code>byte[]</code> or <b>null</b> if entry is not found @@ -158,6 +168,7 @@ throw new PGFPreloadFailureException(); } // access resource data directly and cache the results if opted + // otherwise the input stream is returned as is input = resource.getResourceURL().openStream(); if (resource.isCachable()) { // if resource is cachable, create data block and add to cache @@ -166,7 +177,7 @@ } } - // serialise a cached data block + // serialise into a stream if a data block has been cached if (block != null) { input = new ByteArrayInputStream(block); } @@ -261,13 +272,13 @@ } /** - * Analyses a mapping definition file under the given url + * Analyses a mapping definition file under the given URL * and fills mappings into both single and complex resource maps. * * @param url URL of the mapping file * @throws Exception */ - private void analyseMappings (URL url) throws Exception { + protected void analyseMappings (URL url) throws Exception { // TODO Analyse an external mapping definition file @@ -301,8 +312,12 @@ } } + /** + * Distributes a <code>javax.swing.event.ChangeEvent</code> to all change + * listeners of this manager. (Buffered list execution) + */ @SuppressWarnings("unchecked") - private synchronized void fireChangeEvent () { + protected synchronized void fireChangeEvent () { List<ChangeListener> copy; if (changeListeners != null) { @@ -401,8 +416,11 @@ * @param v boolean <b>true</b> == cachable, <b>false</b> == not cachable * @return boolean <b>true</b> if and only if the resource is registered for caching */ - protected boolean setCachableResource (PGFDataResourceImpl resource, boolean v) { - return false; + protected boolean setCachableResource (PGFDataResource resource, boolean v) { + if (!v) { + dataCache.removeEntry(resource.getName()); + } + return v; } /** @@ -414,7 +432,7 @@ * @return boolean <b>true</b> if and only if the resource is registered for * preloading */ - protected boolean setPreloadingResource (PGFDataResourceImpl resource, boolean v) { + protected boolean setPreloadingResource (PGFDataResource resource, boolean v) { String key = resource.getName(); boolean hasData = preloadCache.containsKey(key); @@ -438,10 +456,21 @@ return preload; } + /** + * Puts a resource's block of data into the "live" cache of this manager. + * + * @param resource <code>PGFDataResource</code> associated resource + * @param data byte[] data block to go into the cache + */ private void addDataCacheEntry(PGFDataResource resource, byte[] data) { dataCache.addEntry(resource.getName(), data); } + /** + * Adds a preloading job for the given data resource. + * + * @param resource + */ private void addPreloadingJob(PGFDataResource resource) { if (resource == null) { throw new NullPointerException(); @@ -452,35 +481,156 @@ preloadingManager.createPreloadingJob(resource); } + /** + * Distributes a <code>PGFPreloadEvent</code> to all preload listeners of + * this manager. (Buffered list execution) + */ + @SuppressWarnings("unchecked") + private void runPreloadEvent (PGFPreloadEvent evt) { + List<PGFPreloadEventListener> copy; + + if (preloadEventListeners != null) { + synchronized (preloadEventListeners) { + copy = (List<PGFPreloadEventListener>)preloadEventListeners.clone(); + } + for (PGFPreloadEventListener l : copy) { + l.resourcePreloadingEventPerformed(evt); + } + } + } + + @Override + public synchronized void addPreloadEventListener(PGFPreloadEventListener listener) { + if (listener != null) { + // late creation of list + if (preloadEventListeners == null) { + preloadEventListeners = new ArrayList<PGFPreloadEventListener>(); + } + // synchronized list modification + synchronized(preloadEventListeners) { + if (listener != null && !preloadEventListeners.contains(listener)) { + preloadEventListeners.add(listener); + } + } + } + } + + @Override + public void removePreloadEventListener(PGFPreloadEventListener listener) { + if (preloadEventListeners != null & listener != null) { + // synchronized list modification + synchronized(preloadEventListeners) { + if (listener != null) { + preloadEventListeners.remove(listener); + } + } + } + } + + /** + * Fires a preloading event of type <code>PGFPreloadEvent.PreloadEventType.PERFORMED</code> + * to all preload listeners of this manager. + * + * @param resource PGFDataResource data resource + * @param time long epoch milliseconds when this event occurred (may be 0 for auto-completion) + * @param duration int milliseconds of loading duration (may be 0) + */ + protected synchronized void fireResourcePreloadedEvent(PGFDataResource resource, long time, int duration) { + PGFPreloadEvent event = new PGFPreloadEvent(this, PGFPreloadEvent.PreloadEventType.PERFORMED, + resource, time, duration); + runPreloadEvent(event); + } + + /** + * Fires a preloading event of type <code>PGFPreloadEvent.PreloadEventType.STARTED</code> + * to all preload listeners of this manager. + * + * @param resource PGFDataResource data resource + * @param time long epoch milliseconds when this event occurred (may be 0 for auto-completion) + */ + protected synchronized void firePreloadStartedEvent(PGFDataResource resource, long time) { + PGFPreloadEvent event = new PGFPreloadEvent(this, PGFPreloadEvent.PreloadEventType.STARTED, + resource, time, 0); + runPreloadEvent(event); + } + + /** + * Fires a preloading event of type <code>PGFPreloadEvent.PreloadEventType.FAILED</code> + * to all preload listeners of this manager. + * + * @param resource PGFDataResource data resource + * @param time long epoch milliseconds when this event occurred (may be 0 for auto-completion) + * @param error Throwable (may be <b>null</b>) + */ + protected synchronized void firePreloadingFailureEvent(PGFDataResource resource, + long time, Throwable error) { + PGFPreloadEvent event = new PGFPreloadEvent(this, PGFPreloadEvent.PreloadEventType.FAILED, + resource, time, 0); + event.setError(error); + runPreloadEvent(event); + } + // + + + + + + + + CLASSES + + + + + + + + + + + +/** The Preloading Manager organises fetching of external data for resources + * which have been marked as "preload=true" in the resource definition files (XML). + * Once the data has been fetched, an entry with the block is put into the + * <code>preloadCache</code> of the resource manager. + * The manager has a single public method, namely "createPreloadingJob" with a resource + * as argument. Any number of preloading jobs can be filed instantly and will get + * processed by the manager in an orderly way. Up to x URL loading jobs are + * performed simultaneously, where x is defined by global value <i>maxJobsParallel</i> + * of PGFResourceManagerImpl. + * <p>A controller daemon thread owned by this manager is created on demand and + * kept alive only as long as needed to organise the list of waiting jobs. Each + * loading job for a resource runs in a separate thread. + * <p>Also see: {@link PreloadingJob} + */ private class PreloadingManager { private List<PGFDataResource> waiting = new LinkedList<PGFDataResource>(); private List<PreloadingJob> running = new LinkedList<PreloadingJob>(); + private boolean modified; private Thread controller; + private void setJobFinished () { + modified = true; + } + + /** + * Unconditionally creates a preloading job for the given data resource. + * + * @param res <code>PGFDataResource</code> + */ public synchronized void createPreloadingJob (PGFDataResource res) { - // add resource to the waiting queue + if (res == null) { + throw new NullPointerException(); + } + // add given resource to the waiting queue synchronized (waiting) { waiting.add(res); } - // create the controller of jobs + // create the controller of jobs (service daemon) if not alive if (controller == null || !controller.isAlive()) { controller = new Thread("PGF preloading controller") { @Override public void run() { + // starting controller: make sure we clean the job list first boolean terminate = false; - while (!terminate) { - // clean the job list + modified = true; + + // service loop until terminated by waiting.size==0 + while (!terminate & modified) { + // step 1: clean the job list + modified = false; for (Iterator<PreloadingJob> it = running.iterator(); it.hasNext();) { if (!it.next().isAlive()) { it.remove(); } } - // create new jobs as allowed + // step 2: create new jobs as allowed and available synchronized (waiting) { while (waiting.size() > 0 && running.size() < maxJobsParallel) { PGFDataResource resource = waiting.remove(0); @@ -490,62 +640,81 @@ } } - // always sleep for a while + // step 3: sleep for a while try { - sleep(2000); + sleep(1000); } catch (InterruptedException e) {} - // terminate controller if there is nothing to distribute + // check to terminate controller if there is nothing to distribute terminate = waiting.size() == 0; } } }; + // start the controller controller.setDaemon(true); controller.setPriority(Thread.MAX_PRIORITY); controller.start(); } } -} -private class PreloadingJob extends Thread { - private PGFDataResource resource; - private Exception error; - - public PreloadingJob (PGFDataResource resource) { - super("PGF Preloading - ".concat(resource.getName())); - setDaemon(true); - setPriority(MAX_PRIORITY-1); - this.resource = resource; - } + /** + * The Preloading Job performs retrieval of external data + * of a resource, given by its URL. After reading from a stream, + * the obtained data block is put into the <b>preloading cache</b> + * of the resource manager, and the job gracefully exits. + * <p>The Job also performs issuing of three types of events + * concerning the loading phase. Preload-Started, Preload-Terminated + * and Preload-Failure. These events are available for the user at + * the resource manager's interface. A Preloading Job runs with a high + * priority of Thread.MAX_PRIORITY-1. + * + */ + private class PreloadingJob extends Thread { + private PGFDataResource resource; + + public PreloadingJob (PGFDataResource resource) { + super("PGF Preloading - ".concat(resource.getName())); + setDaemon(true); + setPriority(MAX_PRIORITY-1); + this.resource = resource; + } - @Override - public void run() { - try { - // issue started event - long h = System.currentTimeMillis(); - firePreloadStartedEvent(resource, h); + @Override + public void run() { + try { + // issue started event + long h = System.currentTimeMillis(); + firePreloadStartedEvent(resource, h); - // retrieve external data block and cache - InputStream in = resource.getResourceURL().openStream(); - byte[] data = inputToByteBlock(in); - preloadCache.put(resource.getName(), data); - - // issue finished event - long j = System.currentTimeMillis(); - fireResourcePreloadedEvent(resource, j, (int)(j-h)); - } - catch (Exception e) { - error = e; - e.printStackTrace(); - firePreloadingFailureEvent(resource, e); + // retrieve external data block and cache + InputStream in = resource.getResourceURL().openStream(); + byte[] data = inputToByteBlock(in); + preloadCache.put(resource.getName(), data); + + // issue finished event + long j = System.currentTimeMillis(); + fireResourcePreloadedEvent(resource, j, (int)(j-h)); + } + catch (Exception e) { + long h = System.currentTimeMillis(); + e.printStackTrace(); + firePreloadingFailureEvent(resource, h, e); + } + setJobFinished(); } - } - - public Exception getErrorException () { - return error; - } -} - + + } // PreloadingJob +} // PreloadingManager + +/** + * Data cache for byte array data blocks referenced through + * a name string. The cache is realised through a <code>LinkedHashMap</code> + * instance whose aging method is driven in "access mode". + * <p>The cache can be limited by number of entries or total stored data size + * or both. The initial capacity is ruled by the global value "initialCacheCapacity" + * of PGFResourceManagerImpl. The load factor is 0.66 which gives a small + * advantage to access speed. + */ private static class DataCache { private LinkedHashMap<String, byte[]> cMap; private int maxEntries; @@ -563,8 +732,10 @@ { this.maxEntries = Math.max(0, maxEntries); this.maxDataSize = Math.max(0, maxData); + int capacity = this.maxEntries == 0 ? initialCacheCapacity : + Math.min(initialCacheCapacity, this.maxEntries*2); - cMap = new LinkedHashMap<String, byte[]>( this.maxEntries * 2, (float)0.50, true ) + cMap = new LinkedHashMap<String, byte[]>( capacity, (float)0.66, true ) { @Override protected boolean removeEldestEntry(Entry<String, byte[]> eldest) { @@ -689,18 +860,4 @@ } } -public synchronized void fireResourcePreloadedEvent(PGFDataResource resource, long time, int duration) { - // TODO fireResourcePreloadedEvent - } - -public synchronized void firePreloadStartedEvent(PGFDataResource resource, long time) { - // TODO Auto-generated method stub - -} - -public synchronized void firePreloadingFailureEvent(PGFDataResource resource, Exception e) { - // TODO firePreloadingFailureEvent - -} -} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ja...@us...> - 2011-07-04 19:32:41
|
Revision: 14 http://petraframe.svn.sourceforge.net/petraframe/?rev=14&view=rev Author: janet-h Date: 2011-07-04 19:32:34 +0000 (Mon, 04 Jul 2011) Log Message: ----------- added data caching and preloading logic to resource manager Modified Paths: -------------- PETRA1/trunk/src/net/petraframe/res/data/PGFDataResource.java PETRA1/trunk/src/net/petraframe/res/data/PGFDataResourceImpl.java PETRA1/trunk/src/net/petraframe/res/data/PGFResourceManagerImpl.java PETRA1/trunk/src/net/petraframe/res/data/Test_DataResource.java Added Paths: ----------- PETRA1/trunk/src/net/petraframe/exception/PGFPreloadFailureException.java Added: PETRA1/trunk/src/net/petraframe/exception/PGFPreloadFailureException.java =================================================================== --- PETRA1/trunk/src/net/petraframe/exception/PGFPreloadFailureException.java (rev 0) +++ PETRA1/trunk/src/net/petraframe/exception/PGFPreloadFailureException.java 2011-07-04 19:32:34 UTC (rev 14) @@ -0,0 +1,35 @@ +package net.petraframe.exception; + +import java.io.IOException; + +/** + * Exception to indicate that a resource's data was expected to reside + * in a preload cache but wasn't found to be there. This may indicate + * either a temporary failure state (e.g. if preloading is still under + * progress) or a permanent failure (if data couldn't be retrieved from + * an URL.) + * <p>Subclass of <code>java.io.IOException</code>. + * + * @author janet-h + * + */ +public class PGFPreloadFailureException extends IOException { + + private static final long serialVersionUID = -4803945156842328156L; + + public PGFPreloadFailureException() { + } + + public PGFPreloadFailureException(String message) { + super(message); + } + + public PGFPreloadFailureException(Throwable cause) { + super(cause); + } + + public PGFPreloadFailureException(String message, Throwable cause) { + super(message, cause); + } + +} Property changes on: PETRA1/trunk/src/net/petraframe/exception/PGFPreloadFailureException.java ___________________________________________________________________ Added: svn:mime-type + text/x-java Added: svn:eol-style + native Modified: PETRA1/trunk/src/net/petraframe/res/data/PGFDataResource.java =================================================================== --- PETRA1/trunk/src/net/petraframe/res/data/PGFDataResource.java 2011-07-01 16:00:03 UTC (rev 13) +++ PETRA1/trunk/src/net/petraframe/res/data/PGFDataResource.java 2011-07-04 19:32:34 UTC (rev 14) @@ -1,11 +1,13 @@ package net.petraframe.res.data; -import java.io.BufferedInputStream; import java.io.IOException; +import java.io.InputStream; import java.net.URL; import java.util.List; import java.util.Map; +import net.petraframe.exception.PGFPreloadFailureException; + /** * Interface that represents a data resource on an external medium and allows * to access its data and feature set. @@ -40,21 +42,29 @@ /** * Returns the content of this resource as an input data stream. + * In case of advantage the returned stream can be a + * <code>BufferedInputStream</code>. * - * @return <code>BufferedInputStream</code> data stream + * @return <code>InputStream</code> data stream * @throws IOException + * @throws PGFPreloadFailureException (IOException) if resource was opted for + * preloading but no data was cached until now */ - public BufferedInputStream getDataStream () throws IOException; + public InputStream getDataStream () throws IOException; /** * Returns the content of this resource as an input data stream * with a given buffering size. + * In case of advantage the returned stream can be a + * <code>BufferedInputStream</code>. * * @param bufferSize int stream buffer size - * @return <code>BufferedInputStream</code> data stream + * @return <code>InputStream</code> data stream * @throws IOException + * @throws PGFPreloadFailureException (IOException) if resource was opted for + * preloading but no data was cached until now */ - public BufferedInputStream getDataStream (int bufferSize) throws IOException; + public InputStream getDataStream (int bufferSize) throws IOException; /** * Returns the complete data of this resource as a single block (array of @@ -64,6 +74,8 @@ * * @return array of byte * @throws IOException + * @throws PGFPreloadFailureException (IOException) if resource was opted for + * preloading but no data was cached until now */ public byte[] getContent () throws IOException; @@ -92,6 +104,15 @@ public URL getPackageURL (); /** + * Returns the resource manager that functions to organise collective + * aspects of this resource. The resource manager is also the namespace for + * a resource. + * + * @return <code>PGFResourceManager</code> + */ + public PGFResourceManager getManager (); + + /** * Returns the data type information of this resource. This normally consists * of a MIME type expression. * @@ -120,14 +141,41 @@ * Attempts to set this resource into a data cache in order to * increase access speed. * - * @param v boolean requested cached state: <b>true</b> == cached, - * <b>false</b> == not cached - * @return boolean actual cached state: <b>true</b> == cached, - * <b>false</b> == not cached + * @param v boolean requested cached state: <b>true</b> == cachable, + * <b>false</b> == not cachable + * @return boolean actual cachable state: <b>true</b> == cachable, + * <b>false</b> == not cachable */ public boolean setCachable (boolean v); /** + * Whether this resource is set to be cached if possible. + * + * @return boolean <b>true</b> == cachable resource + */ + public boolean isCachable (); + + /** + * Sets the resource feature to preload into a data cache of its resource + * manager. The return value reflects a logical state, not a "preload completed" state; + * it may be different to the parameter value if the layer decides it cannot hold + * any more preloading objects. + * + * @param v boolean new preloading feature: <b>true</b> == preload, + * <b>false</b> == don't preload + * @return boolean actual preloading feature: <b>true</b> == preload, + * <b>false</b> == don't preload + */ + public boolean setPreloading (boolean v); + + /** + * Whether this resource's feature to preload into data cache is set active. + * + * @return boolean <b>true</b> == preloading resource + */ + public boolean isPreloading (); + + /** * Returns the list of resource directories in which this resource is listed * (shallow clone). If this resource is not assigned to a directory, * <b>null</b> is returned. @@ -136,4 +184,22 @@ */ public List<PGFResourceDirectory> getDirectories (); + /** + * Returns a shallow clone of this resource instance. + * + * @return Object clone + */ + public Object clone(); + + /** + * Whether this resource instance equals the parameter object. + * Returns <b>true</b> if and only if the compare object is not <b>null</b>, + * implements the <code>PGFDataResource</code> interface, shares the same + * namespace and has the same name as this instance. + * + * @param obj Object object to compare + * @return boolean + */ + public boolean equals (Object obj); + } Modified: PETRA1/trunk/src/net/petraframe/res/data/PGFDataResourceImpl.java =================================================================== --- PETRA1/trunk/src/net/petraframe/res/data/PGFDataResourceImpl.java 2011-07-01 16:00:03 UTC (rev 13) +++ PETRA1/trunk/src/net/petraframe/res/data/PGFDataResourceImpl.java 2011-07-04 19:32:34 UTC (rev 14) @@ -1,6 +1,7 @@ package net.petraframe.res.data; import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -16,13 +17,15 @@ public class PGFDataResourceImpl implements PGFDataResource, Cloneable { - public static int readBufferSize = 2048 * 4; + public static int readBufferSize = PGFResourceManagerImpl.readBufferSize; + + protected PGFResourceManagerImpl manager; /** URL for external data of this resource; never null. */ protected URL url; /** mapping key for this resource; never null. */ - protected String name; + protected String name; /** data type of this resource; normally a MIME type expression. */ protected String dataType; @@ -35,6 +38,12 @@ /** list of virtual directories where this resource is listed. */ protected ArrayList<PGFResourceDirectory> directories; + /** Whether this resource should be preferably kept in a cache. */ + protected boolean cachable; + + /** Whether this resource should be preferably preloaded into a cache. */ + protected boolean preloading; + /** * Implementation internal constructor rendering an invalid instance * which has to be assigned name and url to become valid! @@ -47,49 +56,67 @@ * data type. Properties and directories features are left void. * (In the context of a resource manager the resource name is dealt with * as unique entry. A uniqueness check is not performed by this constructor.) - * + * * @param url URL resource data access address * @param name String resource key (<b>null</b> is translated to "") * @param type String MIME type of resource; may be <b>null</b> for void * @throws NullPointerException if url is <b>null</b> */ public PGFDataResourceImpl (URL url, String name, String type) { + this(null, url, name, type); + } + + /** + * Creates a <code>PGFDataResource</code> with the given name, url and + * data type. Properties and directories features are left void. + * (In the context of a resource manager the resource name is dealt with + * as unique entry. A uniqueness check is not performed by this constructor.) + * + * @param man <code>PGFResourceManagerImpl</code> the governing resource manager + * for this resource, or <b>null</b> + * @param url URL resource data access address + * @param name String resource key (<b>null</b> is translated to "") + * @param type String MIME type of resource; may be <b>null</b> for void + * @throws NullPointerException if url is <b>null</b> + */ + public PGFDataResourceImpl (PGFResourceManagerImpl man, + URL url, String name, String type) { if (url == null) { throw new NullPointerException(); } + this.manager = man; this.url = url; this.name = name == null ? "" : name; this.dataType = type; } @Override - public BufferedInputStream getDataStream() throws IOException { + public InputStream getDataStream() throws IOException { return getDataStream(0); } @Override - public BufferedInputStream getDataStream(int bufferSize) throws IOException { - InputStream in = url.openStream(); + public InputStream getDataStream(int bufferSize) throws IOException { + InputStream in = manager == null ? url.openStream() : manager.getResourceInputStream(this); + if (in instanceof ByteArrayInputStream || in instanceof BufferedInputStream) { + return in; + } return bufferSize == 0 ? new BufferedInputStream(in) : new BufferedInputStream(in, bufferSize); } @Override public byte[] getContent() throws IOException { - // prepare data streams - InputStream in = url.openStream(); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - - // transfer input stream data to byte array - int len; - byte[] buffer = new byte[readBufferSize]; - while ((len=in.read(buffer)) != -1 ) { - out.write(buffer, 0, len); + // attempt to get cached data block from resource manager + byte[] data = manager == null ? null : manager.getResourceCachedData(this); + + // if no cached data found, read from input stream + if (data == null) { + // prepare data streams + InputStream in = getDataStream(readBufferSize); + data = PGFResourceManagerImpl.inputToByteBlock(in); } - - // close input and return buffered data - in.close(); - return out.toByteArray(); + return data; } @Override @@ -99,7 +126,7 @@ @Override public URL getPackageURL() { - // TODO Auto-generated method stub + // TODO analyse package URL throw new UnsupportedOperationException(); } @@ -110,11 +137,33 @@ @Override public boolean setCachable(boolean v) { - // TODO Auto-generated method stub - return false; + cachable = v & manager != null; + if (manager != null) { + cachable = manager.setCachableResource(this, v); + } + return cachable; } @Override + public boolean isCachable() { + return cachable; + } + + @Override + public boolean isPreloading() { + return preloading; + } + + @Override + public boolean setPreloading (boolean v) { + preloading = v & manager != null; + if (manager != null) { + preloading = manager.setPreloadingResource(this, v); + } + return preloading; + } + + @Override public List<PGFResourceDirectory> getDirectories() { return directories == null ? null : new ArrayList<PGFResourceDirectory>(directories); } @@ -129,7 +178,10 @@ return properties == null ? null : properties.get(name); } - + @Override + public PGFResourceManager getManager() { + return manager; + } @SuppressWarnings("unchecked") @Override @@ -203,9 +255,10 @@ @Override public boolean equals(Object obj) { - if (obj != null & obj instanceof PGFDataResourceImpl) { - PGFDataResource s = (PGFDataResourceImpl)obj; - return s.getName().equals(this.getName()); + if (obj != null & obj instanceof PGFDataResource) { + PGFDataResource s = (PGFDataResource)obj; + return s.getManager() == this.getManager() && + s.getName().equals(this.getName()); } return false; } Modified: PETRA1/trunk/src/net/petraframe/res/data/PGFResourceManagerImpl.java =================================================================== --- PETRA1/trunk/src/net/petraframe/res/data/PGFResourceManagerImpl.java 2011-07-01 16:00:03 UTC (rev 13) +++ PETRA1/trunk/src/net/petraframe/res/data/PGFResourceManagerImpl.java 2011-07-04 19:32:34 UTC (rev 14) @@ -1,21 +1,38 @@ package net.petraframe.res.data; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; +import java.util.Hashtable; import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedList; import java.util.List; import java.util.TreeMap; +import java.util.Map.Entry; import javax.swing.ImageIcon; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; +import net.petraframe.exception.PGFPreloadFailureException; + public class PGFResourceManagerImpl implements PGFResourceManager { public static String nameSeparatorChar = "/"; + public static int readBufferSize = 2048 * 4; + + public static int maxCacheEntries = 0; + + public static long maxCacheDataSize = 10000000; // 10 MB + + public static int maxJobsParallel = 10; + /** The map referring to basic (single) resource objects. Realises namespace "SINGLE". */ private HashMap<String, PGFDataResourceImpl> baseMap = new HashMap<String, PGFDataResourceImpl> (); @@ -24,7 +41,12 @@ /** The map referring to resource directory objects. Realises all available resource directory paths. */ private TreeMap<String, PGFResourceDirectory> directoryMap = new TreeMap<String, PGFResourceDirectory>(); + + private Hashtable<String, byte[]> preloadCache = new Hashtable<String, byte[]>(); + + private DataCache dataCache = new DataCache(maxCacheEntries, maxCacheDataSize); + private PreloadingManager preloadingManager; private List<URL> mappingSources; private ArrayList<ChangeListener> changeListeners; @@ -79,12 +101,115 @@ return null; } + /** + * Searches for a cache data entry for the given resource + * and returns the cached data when found. + * + * @param resource <code>PGFDataResource</code> + * @return <code>byte[]</code> or <b>null</b> if entry is not found + * @throws NullPointerException + */ + protected byte[] getResourceCachedData (PGFDataResource resource) { + if (resource == null) { + throw new NullPointerException(); + } + // search in preload cache (only if "preload" is opted on the resource) + byte[] data = null; + if (resource.isPreloading()) { + data = preloadCache.get(resource.getName()); + } + else if (resource.isCachable()) { + // search in live cache + data = dataCache.getDataBlock(resource.getName()); + } + return data; + } + + /** + * Attempts to obtain an input stream for the data of the given resource, + * preferring a data block cached in this resource manager, if possible. + * (Furthermore, this method ensures data loading into the manager's + * resource cache.) + * + * @param resource <code>PGFDataResource</code> + * @return <code>InputStream</code> + * @throws NullPointerException + * @throws IllegalArgumentException if resource does not belong to this manger + * @throws IOException + * @throws PGFPreloadFailureException (IOException) if resource was opted for + * preloading but no data was cached until now + */ + protected InputStream getResourceInputStream (PGFDataResource resource) throws IOException { + if (resource == null) { + throw new NullPointerException(); + } + InputStream input = null; + if (resource != null) { + // test resource for namespace + if (resource.getManager() != this) { + throw new IllegalArgumentException("resource is alien to this manager"); + } + + // try to get cached data of the resource + byte[] block = getResourceCachedData(resource); + if (block == null) { + // throw failure exception if preloading is set + if (resource.isPreloading()) { + throw new PGFPreloadFailureException(); + } + // access resource data directly and cache the results if opted + input = resource.getResourceURL().openStream(); + if (resource.isCachable()) { + // if resource is cachable, create data block and add to cache + block = inputToByteBlock(input); + addDataCacheEntry(resource, block); + } + } + + // serialise a cached data block + if (block != null) { + input = new ByteArrayInputStream(block); + } + } + return input; + } + + /** + * Transforms all data available in the given input stream + * into a byte array data block. After reading is completed + * the input stream is closed. + * + * @param in <code>InputStream</code> + * @return byte[] + * @throws IOException + * @throws NullPointerException + */ + public static byte[] inputToByteBlock (InputStream in) throws IOException { + if (in == null) { + throw new NullPointerException(); + } + + // transfer input stream data to byte array + ByteArrayOutputStream out = new ByteArrayOutputStream(); + byte[] buffer = new byte[readBufferSize]; + int len; + while ((len=in.read(buffer)) != -1 ) { + out.write(buffer, 0, len); + } + + // close input and return buffered data + in.close(); + return out.toByteArray(); + } + @Override public synchronized void invalidateResources() { isValid = false; baseMap.clear(); complMap.clear(); directoryMap.clear(); + dataCache.clear(); + preloadCache.clear(); fireChangeEvent(); } @@ -177,7 +302,7 @@ } @SuppressWarnings("unchecked") - private void fireChangeEvent () { + private synchronized void fireChangeEvent () { List<ChangeListener> copy; if (changeListeners != null) { @@ -267,5 +392,315 @@ } return childDir; } + + /** + * Attempts to add or remove the given data resource to or from the list of + * cachable resources of this manager. + * + * @param resource <code>PGFDataResourceImpl</code> resource to be cached + * @param v boolean <b>true</b> == cachable, <b>false</b> == not cachable + * @return boolean <b>true</b> if and only if the resource is registered for caching + */ + protected boolean setCachableResource (PGFDataResourceImpl resource, boolean v) { + return false; + } + /** + * Attempts to add or remove the given data resource to or from the list of + * preloading resources of this manager. + * + * @param resource <code>PGFDataResourceImpl</code> resource to be preloaded + * @param v boolean <b>true</b> == preloading, <b>false</b> == not preloading + * @return boolean <b>true</b> if and only if the resource is registered for + * preloading + */ + protected boolean setPreloadingResource (PGFDataResourceImpl resource, boolean v) { + + String key = resource.getName(); + boolean hasData = preloadCache.containsKey(key); + boolean preload = hasData; + + // positive branch: add preloading job (if not data present) + if (v & !hasData) { + addPreloadingJob(resource); + preload = true; + } + + // negative branch: remove preloaded data + if (!v & hasData) { + byte[] data = preloadCache.remove(key); + if (resource.isCachable()) { + addDataCacheEntry(resource, data); + } + preload = false; + } + + return preload; + } + + private void addDataCacheEntry(PGFDataResource resource, byte[] data) { + dataCache.addEntry(resource.getName(), data); + } + + private void addPreloadingJob(PGFDataResource resource) { + if (resource == null) { + throw new NullPointerException(); + } + if (preloadingManager == null) { + preloadingManager = new PreloadingManager(); + } + preloadingManager.createPreloadingJob(resource); + } + +// + + + + + + + + CLASSES + + + + + + + + + + + + +private class PreloadingManager { + private List<PGFDataResource> waiting = new LinkedList<PGFDataResource>(); + private List<PreloadingJob> running = new LinkedList<PreloadingJob>(); + + private Thread controller; + + public synchronized void createPreloadingJob (PGFDataResource res) { + // add resource to the waiting queue + synchronized (waiting) { + waiting.add(res); + } + // create the controller of jobs + if (controller == null || !controller.isAlive()) { + controller = new Thread("PGF preloading controller") { + + @Override + public void run() { + boolean terminate = false; + while (!terminate) { + // clean the job list + for (Iterator<PreloadingJob> it = running.iterator(); it.hasNext();) { + if (!it.next().isAlive()) { + it.remove(); + } + } + + // create new jobs as allowed + synchronized (waiting) { + while (waiting.size() > 0 && running.size() < maxJobsParallel) { + PGFDataResource resource = waiting.remove(0); + PreloadingJob job = new PreloadingJob(resource); + running.add(job); + job.start(); + } + } + + // always sleep for a while + try { + sleep(2000); + } catch (InterruptedException e) {} + + // terminate controller if there is nothing to distribute + terminate = waiting.size() == 0; + } + } + }; + controller.setDaemon(true); + controller.setPriority(Thread.MAX_PRIORITY); + controller.start(); + } + } } + +private class PreloadingJob extends Thread { + private PGFDataResource resource; + private Exception error; + + public PreloadingJob (PGFDataResource resource) { + super("PGF Preloading - ".concat(resource.getName())); + setDaemon(true); + setPriority(MAX_PRIORITY-1); + this.resource = resource; + } + + @Override + public void run() { + try { + // issue started event + long h = System.currentTimeMillis(); + firePreloadStartedEvent(resource, h); + + // retrieve external data block and cache + InputStream in = resource.getResourceURL().openStream(); + byte[] data = inputToByteBlock(in); + preloadCache.put(resource.getName(), data); + + // issue finished event + long j = System.currentTimeMillis(); + fireResourcePreloadedEvent(resource, j, (int)(j-h)); + } + catch (Exception e) { + error = e; + e.printStackTrace(); + firePreloadingFailureEvent(resource, e); + } + } + + public Exception getErrorException () { + return error; + } +} + +private static class DataCache { + private LinkedHashMap<String, byte[]> cMap; + private int maxEntries; + private long maxDataSize; + private long cachedDataSize; + + /** Constructor. + * @param maxEntries int the maximum amount of entries in this Manager + * (0 means no limit) + * @param maxData long maximum total data size in bytes (all cached blocks) + * (0 means no limit) + */ + @SuppressWarnings("serial") + public DataCache ( int maxEntries, long maxData ) + { + this.maxEntries = Math.max(0, maxEntries); + this.maxDataSize = Math.max(0, maxData); + + cMap = new LinkedHashMap<String, byte[]>( this.maxEntries * 2, (float)0.50, true ) + { + @Override + protected boolean removeEldestEntry(Entry<String, byte[]> eldest) { + int maxE = DataCache.this.maxEntries; + long maxD = DataCache.this.maxDataSize; + boolean removeOne = maxE > 0 & size() > maxE; + boolean removeSize = maxD > 0 & dataSize() > maxD; + + // if total data size has overflow, remove a set of eldest entries + // (which is nicely provided by LinkedHashMap's iterators) + if (removeSize) synchronized (cMap) { + Iterator<Entry<String, byte[]>> it = this.entrySet().iterator(); + while (it.hasNext() & dataSize() > maxD) { + Entry<String, byte[]> e = it.next(); + it.remove(); + cachedDataSize -= e.getValue().length; + } + } + // if number of entries has overflow, just remove eldest entry + else if (removeOne) { + removeEntry(eldest.getKey()); + } + return false; + } + }; + } // constructor + + /** + * The number of current cache entries. + * + * @return int cache entries + */ + @SuppressWarnings("unused") + public int size () { + return cMap.size(); + } + + /** + * Total sum of stored bytes (all entry data blocks). + * + * @return long total data size + */ + public long dataSize () { + return cachedDataSize; + } + + /** + * Removes all entries from this cache. + */ + public void clear () { + synchronized (cMap) { + cMap.clear(); + cachedDataSize = 0; + } + } + + /** + * Returns the cached data block for an entry name. + * + * @param key String entry name + * @return byte[] data block or <b>null</b> if the entry was not found + */ + public byte[] getDataBlock (String key) { + // check parameter + if (key == null) { + throw new NullPointerException(); + } + synchronized (cMap) { + return cMap.get(key); + } + } + + /** + * Adds a new cache entry. An existing entry is substituted. + * Returns <b>false</b> if the entering data block is larger + * than the cache allows. + * + * @param key String entry name + * @param value byte[] entry data block + * @return boolean <b>true</b> if and only if the entry was accepted + */ + public boolean addEntry (String key, byte[] value) { + // check parameters + if (key == null | value == null) { + throw new NullPointerException(); + } + synchronized (cMap) { + if (value.length <= maxDataSize / 4) { + // remove trace of any old entry + byte[] v = cMap.get(key); + if (v != null) { + cachedDataSize -= v.length; + } + // integrate new entry (can trigger removal of stale entries) + cachedDataSize += value.length; + cMap.put(key, value); + return true; + } + return false; + } + } + + /** + * Removes a cache entry called by its name. + * + * @param key String entry name + * @return byte[] data block of the removed entry or <b>null</b> + * if the was no such entry + */ + public byte[] removeEntry (String key) { + // check parameter + if (key == null) { + throw new NullPointerException(); + } + synchronized (cMap) { + byte[] v = cMap.remove(key); + if (v != null) { + cachedDataSize -= v.length; + } + return v; + } + } +} + +public synchronized void fireResourcePreloadedEvent(PGFDataResource resource, long time, int duration) { + // TODO fireResourcePreloadedEvent + +} + +public synchronized void firePreloadStartedEvent(PGFDataResource resource, long time) { + // TODO Auto-generated method stub + +} + +public synchronized void firePreloadingFailureEvent(PGFDataResource resource, Exception e) { + // TODO firePreloadingFailureEvent + +} +} Modified: PETRA1/trunk/src/net/petraframe/res/data/Test_DataResource.java =================================================================== --- PETRA1/trunk/src/net/petraframe/res/data/Test_DataResource.java 2011-07-01 16:00:03 UTC (rev 13) +++ PETRA1/trunk/src/net/petraframe/res/data/Test_DataResource.java 2011-07-04 19:32:34 UTC (rev 14) @@ -126,15 +126,17 @@ } + @Test public void test_content () throws IOException { + PGFResourceManagerImpl man = new PGFResourceManagerImpl(); PGFDataResourceImpl res, res2, res3, cl1, cl2; String resName = "canopia/wolfsounds"; byte[] data; - res = new PGFDataResourceImpl(url, resName, resType); + res = new PGFDataResourceImpl(man, url, resName, resType); data = res.getContent(); assertNotNull(data); assertTrue(data.length > 0); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ja...@us...> - 2011-07-01 16:00:11
|
Revision: 13 http://petraframe.svn.sourceforge.net/petraframe/?rev=13&view=rev Author: janet-h Date: 2011-07-01 16:00:03 +0000 (Fri, 01 Jul 2011) Log Message: ----------- copy the trunk branch to module name PETRA1 Added Paths: ----------- PETRA1/trunk/ Removed Paths: ------------- trunk/ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ja...@us...> - 2011-07-01 15:57:50
|
Revision: 12 http://petraframe.svn.sourceforge.net/petraframe/?rev=12&view=rev Author: janet-h Date: 2011-07-01 15:57:43 +0000 (Fri, 01 Jul 2011) Log Message: ----------- compiling update, added test case for DataResource Modified Paths: -------------- trunk/src/net/petraframe/res/data/PGFDataResource.java trunk/src/net/petraframe/res/data/PGFDataResourceImpl.java trunk/src/net/petraframe/res/data/PGFResourceDirectory.java trunk/src/net/petraframe/res/data/PGFResourceDirectoryImpl.java trunk/src/net/petraframe/res/data/PGFResourceManager.java trunk/src/net/petraframe/res/data/Test_ResourceDir.java trunk/src/net/petraframe/res/sound/PGFSoundImpl.java Added Paths: ----------- trunk/src/net/petraframe/res/data/Test_DataResource.java Modified: trunk/src/net/petraframe/res/data/PGFDataResource.java =================================================================== --- trunk/src/net/petraframe/res/data/PGFDataResource.java 2011-07-01 15:42:53 UTC (rev 11) +++ trunk/src/net/petraframe/res/data/PGFDataResource.java 2011-07-01 15:57:43 UTC (rev 12) @@ -4,17 +4,63 @@ import java.io.IOException; import java.net.URL; import java.util.List; +import java.util.Map; +/** + * Interface that represents a data resource on an external medium and allows + * to access its data and feature set. + * <p>Data resources in this conception are read-only resources. + * Each resource is identified by its unique name (in the context of its resource + * manager, or namespace, as you might put it). Beside the name a resource has + * the following features: + * <p><b>Resource Features</b> + * <br>- an URL of the external data (not necessarily a file). + * <br>- a package URL (if the resource is contained within a package file) + * <br>- a data type (String), optional. This is expected to be a MIME type expression. + * <br>- any set of properties (String-String mapping), optional. + * <br>- any set of virtual directories (PGFResourceDirectory), optional. + * + * <p>All these features are designed to be immutable in the context of an application, + * so that implemented instances can be used as "constant values" in various data + * structures, leaving aside the need to care for data integrity issues. + * + * <p><b>Usage</b> + * <br>The intended usage of a data resource is as follows: + * <br>- identify a resource (name or listing in virtual directories) + * <br>- verify usability or specification of a resource (data type, properties) + * <br>- retrieve data from the resource (get input stream or data block) + * + * <p>See also: {@link PGFResourceManager} + * + * @author janet-h + * + */ + public interface PGFDataResource { + /** + * Returns the content of this resource as an input data stream. + * + * @return <code>BufferedInputStream</code> data stream + * @throws IOException + */ public BufferedInputStream getDataStream () throws IOException; + /** + * Returns the content of this resource as an input data stream + * with a given buffering size. + * + * @param bufferSize int stream buffer size + * @return <code>BufferedInputStream</code> data stream + * @throws IOException + */ public BufferedInputStream getDataStream (int bufferSize) throws IOException; /** * Returns the complete data of this resource as a single block (array of * bytes). If the size of the resource exceeds the maximum possible array - * size, an IOException is thrown. + * size, an IOException is thrown. This method blocks until the complete + * set of data is fetched from the external medium. * * @return array of byte * @throws IOException @@ -29,12 +75,20 @@ public String getName (); /** - * Returns the URL of this resource. + * Returns the URL of this resource. The URL is the place where + * the data of this resource can be fetched. * * @return <code>URL</code> */ public URL getResourceURL (); + /** + * Returns the first enclosing data package file which contains this resource + * or <b>null</b> if such a package does not exist. The resource itself + * is never a value of this feature. + * + * @return <code>URL</b> enclosing data package (file) + */ public URL getPackageURL (); /** @@ -55,6 +109,14 @@ public String getProperty (String name); /** + * Returns the property map of this resource or <b>null</b> if + * there is no property defined. (Shallow clone.) + * + * @return <code>Map</code> String into String or <b>null</b> + */ + public Map<String, String> getProperties (); + + /** * Attempts to set this resource into a data cache in order to * increase access speed. * @@ -66,8 +128,9 @@ public boolean setCachable (boolean v); /** - * Returns the list of resource directories in which this resource is listed. - * If this resource is not assigned to a directory, <b>null</b> is returned. + * Returns the list of resource directories in which this resource is listed + * (shallow clone). If this resource is not assigned to a directory, + * <b>null</b> is returned. * * @return List of <code>PGFResourceDirectory</code> or <b>null</b> */ Modified: trunk/src/net/petraframe/res/data/PGFDataResourceImpl.java =================================================================== --- trunk/src/net/petraframe/res/data/PGFDataResourceImpl.java 2011-07-01 15:42:53 UTC (rev 11) +++ trunk/src/net/petraframe/res/data/PGFDataResourceImpl.java 2011-07-01 15:57:43 UTC (rev 12) @@ -9,26 +9,50 @@ import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import java.util.Map; -public class PGFDataResourceImpl implements PGFDataResource { +import net.petraframe.res.sound.PGFSound; +import net.petraframe.res.sound.PGFSoundImpl; + +public class PGFDataResourceImpl implements PGFDataResource, Cloneable { public static int readBufferSize = 2048 * 4; /** URL for external data of this resource; never null. */ protected URL url; - /** mapping token for this resource; never null. */ + /** mapping key for this resource; never null. */ protected String name; + /** data type of this resource; normally a MIME type expression. */ protected String dataType; + /** set of properties defined for this resource, where each property is + * a relation of key into value. + */ protected HashMap<String, String> properties; - protected List<PGFResourceDirectory> directories; + /** list of virtual directories where this resource is listed. */ + protected ArrayList<PGFResourceDirectory> directories; + /** + * Implementation internal constructor rendering an invalid instance + * which has to be assigned name and url to become valid! + */ protected PGFDataResourceImpl () { } + /** + * Creates a <code>PGFDataResource</code> with the given name, url and + * data type. Properties and directories features are left void. + * (In the context of a resource manager the resource name is dealt with + * as unique entry. A uniqueness check is not performed by this constructor.) + * + * @param url URL resource data access address + * @param name String resource key (<b>null</b> is translated to "") + * @param type String MIME type of resource; may be <b>null</b> for void + * @throws NullPointerException if url is <b>null</b> + */ public PGFDataResourceImpl (URL url, String name, String type) { if (url == null) { throw new NullPointerException(); @@ -76,7 +100,7 @@ @Override public URL getPackageURL() { // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException(); } @Override @@ -104,7 +128,16 @@ public String getProperty(String name) { return properties == null ? null : properties.get(name); } + + + @SuppressWarnings("unchecked") + @Override + public Map<String, String> getProperties() { + return (Map<String, String>) (properties == null ? null : + ((HashMap)properties).clone()); + } + /** * Adds a property mapping to this resource's properties list. * @@ -114,17 +147,78 @@ */ protected String addProperty (String key, String value) { if (properties == null) { - properties = new HashMap<String, String>(); + properties = new HashMap<String, String>(4); } - return properties.put(key, value); + synchronized (properties) { + return properties.put(key, value); + } } - protected void addDirectory (PGFResourceDirectory dir) { + /** + * Adds a new entry into the list of virtual directories of + * this resource. Double entries are ignored. + * (This does not automatically include this resource into the directory! + * The directory must contain this resource.) + * + * @param dir <code>PGFResourceDirectory</code> virtual directory to be added + * @return boolean <b>true</b> if and only if the list of directories has + * changed as a result of this call + * @throws IllegalArgumentException if the parameter does not contain this resource + */ + protected boolean addDirectory (PGFResourceDirectory dir) { if (directories == null) { - directories = new LinkedList<PGFResourceDirectory>(); + directories = new ArrayList<PGFResourceDirectory>(4); } - if (!directories.contains(dir)) { - directories.add(dir); + // check if directory holds this resource + if (!dir.hasResource(getName())) { + throw new IllegalArgumentException("directory must contain this resource"); } + synchronized (directories) { + if (!directories.contains(dir)) { + return directories.add(dir); + } + return false; + } } + + @SuppressWarnings("unchecked") + @Override + public Object clone() { + try { + PGFDataResourceImpl c =(PGFDataResourceImpl)super.clone(); + if (directories != null) + synchronized(directories) { + c.directories = (ArrayList<PGFResourceDirectory>)directories.clone(); + } + if (properties != null) + synchronized(properties) { + c.properties = (HashMap<String, String>)properties.clone(); + } + return c; + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + return null; + } + } + + @Override + public boolean equals(Object obj) { + if (obj != null & obj instanceof PGFDataResourceImpl) { + PGFDataResource s = (PGFDataResourceImpl)obj; + return s.getName().equals(this.getName()); + } + return false; + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public String toString() { + return name; + } + + } Modified: trunk/src/net/petraframe/res/data/PGFResourceDirectory.java =================================================================== --- trunk/src/net/petraframe/res/data/PGFResourceDirectory.java 2011-07-01 15:42:53 UTC (rev 11) +++ trunk/src/net/petraframe/res/data/PGFResourceDirectory.java 2011-07-01 15:57:43 UTC (rev 12) @@ -22,7 +22,8 @@ /** * Returns the element name of this directory. This is the last * name segment in the directory path. This value should never be - * <b>null</b> or empty for all paths higher than root. + * <b>null</b> or empty for all paths higher than root. For root + * an empty string is returned. * * @return String directory element name or empty string if this * directory is the root directory @@ -76,6 +77,15 @@ public List<String> list (); /** + * Returns whether this directory holds the given resource path. + * + * @param name String resource path + * @return boolean <b>true</b> if and only if the resource is contained + * in the list of resources (<code>list()</code>) + */ +public boolean hasResource (String name); + +/** * Whether this directory holds resource path content. * * @return boolean <b>true</b> == content available Modified: trunk/src/net/petraframe/res/data/PGFResourceDirectoryImpl.java =================================================================== --- trunk/src/net/petraframe/res/data/PGFResourceDirectoryImpl.java 2011-07-01 15:42:53 UTC (rev 11) +++ trunk/src/net/petraframe/res/data/PGFResourceDirectoryImpl.java 2011-07-01 15:57:43 UTC (rev 12) @@ -202,6 +202,11 @@ return resourceList == null ? new LinkedList<String>() : new ArrayList<String>(resourceList); } + @Override + public boolean hasResource(String name) { + return resourceList == null | name == null ? false : resourceList.contains(name); + } + /** * Convenience method to add a child directory of the given element name * to this directory. Does nothing if the name is already contained as Modified: trunk/src/net/petraframe/res/data/PGFResourceManager.java =================================================================== --- trunk/src/net/petraframe/res/data/PGFResourceManager.java 2011-07-01 15:42:53 UTC (rev 11) +++ trunk/src/net/petraframe/res/data/PGFResourceManager.java 2011-07-01 15:57:43 UTC (rev 12) @@ -35,10 +35,10 @@ public List<PGFDataResource> getListResource (String name); /** - * Returns the resource directory of the given name. + * Returns the virtual resource directory of the given name. * (Value <b>null</b> is not defined as a directory name.) * - * @param name String the name of the directory (full path); if value + * @param name String the name of the virtual directory (full path); if value * is empty or the nameSeparatorChar, the root directory is returned * @return <code>PGFResourceDirectory</code> or <b>null</b> if no such * directory is defined @@ -46,8 +46,8 @@ public PGFResourceDirectory getDirectory (String name); /** - * Searches the tree of resource directories in this manager and returns - * the first match of element name to the given search string. + * Searches the tree of virtual resource directories in this manager and + * returns the first match of element name to the given search string. * (Search goes breadth first in the tree.) * * @param name String element name of searched directory (not the full path); Added: trunk/src/net/petraframe/res/data/Test_DataResource.java =================================================================== --- trunk/src/net/petraframe/res/data/Test_DataResource.java (rev 0) +++ trunk/src/net/petraframe/res/data/Test_DataResource.java 2011-07-01 15:57:43 UTC (rev 12) @@ -0,0 +1,206 @@ +package net.petraframe.res.data; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.List; +import java.util.Map; + +import net.petraframe.exception.PGFDoubleListEntryException; + +import org.junit.Test; + +public class Test_DataResource { + + private static final String SEP = PGFResourceManagerImpl.nameSeparatorChar; + + private String resName = "canopia/wolfsounds"; + private String resType = "text/html"; + private String urlStr = "http://sourceforge.net/apps/mediawiki/petraframe/index.php?title=Main_Page"; + private String url2Str = "http://sourceforge.net/apps/mediawiki/petraframe/index.php?title=Developing_Aids"; + private URL url, url2; + + public Test_DataResource () { + try { + url = new URL(urlStr); + url2 = new URL(url2Str); + } catch (MalformedURLException e) { + e.printStackTrace(); + url = url2 = null; + } + } + + @Test + public void create_basics () { + + PGFDataResourceImpl res, res2, res3, cl1, cl2; + + res = new PGFDataResourceImpl(url, resName, resType); + + assertTrue(res.getName().equals(resName)); + assertTrue(res.getDataType().equals(resType)); + assertTrue(res.getResourceURL().equals(url)); + assertNull(res.getDirectories()); + assertNull(res.getProperties()); + assertEquals(res.toString(), resName); + + assertNull(res.getProperty(null)); + assertNull(res.getProperty("")); + assertNull(res.getProperty("andreas")); + + + // don't rely on URLs for identity + res2 = new PGFDataResourceImpl(url, "birdsounds", resType); + assertFalse(res2.equals(res)); + assertFalse(res2.hashCode() == res.hashCode()); + + // rely on names for identity + res3 = new PGFDataResourceImpl(url2, resName, null); + assertTrue(res3.equals(res)); + assertTrue(res3.hashCode() == res.hashCode()); + + // test the clones + cl1 = (PGFDataResourceImpl)res.clone(); + assertEquals(cl1, res); + assertEquals(cl1, res3); + assertTrue(cl1.getName().equals(resName)); + assertTrue(cl1.getDataType().equals(resType)); + assertTrue(cl1.getResourceURL().equals(url)); + assertNull(cl1.getDirectories()); + assertNull(cl1.getProperties()); + assertEquals(cl1.toString(), resName); + assertNull(cl1.getProperty(null)); + assertNull(cl1.getProperty("")); + assertNull(cl1.getProperty("andreas")); + + + cl2 = (PGFDataResourceImpl)res2.clone(); + assertFalse(cl2.equals(res)); + assertFalse(cl2.equals(res3)); + } + + @Test + public void test_properties () { + + PGFDataResourceImpl res, res2, res3, cl1, cl2; + Map<String, String> pm; + + res = new PGFDataResourceImpl(url, resName, resType); + + // add one property + res.addProperty("sound", "Yes"); + assertNotNull(res.getProperty("sound")); + assertNotNull(res.getProperties()); + assertNull(res.getProperty(null)); + assertNull(res.getProperty("")); + assertNull(res.getProperty("hund")); + pm = res.getProperties(); + assertTrue(pm.size() == 1); + assertEquals(pm.get("sound"), "Yes"); + + // add three properties + res.addProperty("music", "No"); + res.addProperty("author", "King David"); + + pm = res.getProperties(); + assertTrue(pm.size() == 3); + assertEquals(pm.get("music"), "No"); + assertEquals(res.getProperty("sound"), "Yes"); + assertEquals(res.getProperty("author"), "King David"); + assertEquals(res.getProperty("music"), "No"); + assertNull(res.getProperty("hund")); + assertNull(res.getProperty("")); + assertNull(res.getProperty(null)); + + // test encapsulation + pm.put("title", "Rosanna"); + assertNull(res.getProperty("title")); + pm.clear(); + assertNotNull(res.getProperty("sound")); + + } + + public void test_content () throws IOException { + + PGFDataResourceImpl res, res2, res3, cl1, cl2; + + String resName = "canopia/wolfsounds"; + + byte[] data; + + res = new PGFDataResourceImpl(url, resName, resType); + data = res.getContent(); + assertNotNull(data); + assertTrue(data.length > 0); + + System.out.println("Content-1 length == " + data.length); + System.out.println(new String(data)); + + } + + @Test + public void test_directories () throws PGFDoubleListEntryException { + + PGFDataResourceImpl res, res2, res3, cl1, cl2; + PGFResourceDirectoryImpl root, dir, dir1, dir2, dir3; + List<PGFResourceDirectory> list1; + + res = new PGFDataResourceImpl(url, resName, resType); + assertNull(res.getDirectories()); + + // create directory tree + root = new PGFResourceDirectoryImpl(); + dir1 = new PGFResourceDirectoryImpl("music", root); + dir2 = new PGFResourceDirectoryImpl("animals", dir1); + dir3 = new PGFResourceDirectoryImpl("flowers", root); + root.addResource(resName); + dir1.addResource(resName); + dir2.addResource(resName); + dir3.addResource(resName); + + // add one directory + res.addDirectory(root); + list1 = res.getDirectories(); + + assertNotNull(list1); + assertTrue(list1.size() == 1); + dir = (PGFResourceDirectoryImpl) list1.get(0); + assertEquals(dir.getName(), SEP); +/* + assertNotNull(res.getProperties()); + assertNull(res.getProperty(null)); + assertNull(res.getProperty("")); + assertNull(res.getProperty("hund")); + pm = res.getProperties(); + assertTrue(pm.size() == 1); + assertEquals(pm.get("sound"), "Yes"); + + // add three properties + res.addProperty("music", "No"); + res.addProperty("author", "King David"); + + pm = res.getProperties(); + assertTrue(pm.size() == 3); + assertEquals(pm.get("music"), "No"); + assertEquals(res.getProperty("sound"), "Yes"); + assertEquals(res.getProperty("author"), "King David"); + assertEquals(res.getProperty("music"), "No"); + assertNull(res.getProperty("hund")); + assertNull(res.getProperty("")); + assertNull(res.getProperty(null)); +*/ + // test encapsulation + int h = res.getDirectories().size(); + list1.add(dir3); + assertTrue(res.getDirectories().size() == h); + list1.clear(); + assertTrue(res.getDirectories().size() == h); + + } +} \ No newline at end of file Property changes on: trunk/src/net/petraframe/res/data/Test_DataResource.java ___________________________________________________________________ Added: svn:mime-type + text/x-java Added: svn:eol-style + native Modified: trunk/src/net/petraframe/res/data/Test_ResourceDir.java =================================================================== --- trunk/src/net/petraframe/res/data/Test_ResourceDir.java 2011-07-01 15:42:53 UTC (rev 11) +++ trunk/src/net/petraframe/res/data/Test_ResourceDir.java 2011-07-01 15:57:43 UTC (rev 12) @@ -25,6 +25,9 @@ assertTrue(root.getName().equals(SEP)); assertTrue(root.getParent() == null); assertTrue(root.hasContent() == false); + assertFalse(root.hasResource(null)); + assertFalse(root.hasResource("")); + assertFalse(root.hasResource("lisa_m")); List<String> resL = root.list(); assertTrue(resL != null); assertTrue(resL.size() == 0); Modified: trunk/src/net/petraframe/res/sound/PGFSoundImpl.java =================================================================== --- trunk/src/net/petraframe/res/sound/PGFSoundImpl.java 2011-07-01 15:42:53 UTC (rev 11) +++ trunk/src/net/petraframe/res/sound/PGFSoundImpl.java 2011-07-01 15:57:43 UTC (rev 12) @@ -2,18 +2,21 @@ import java.net.URL; import java.util.ArrayList; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Random; import net.petraframe.res.data.PGFDataResource; import net.petraframe.res.data.PGFDataResourceImpl; +import net.petraframe.res.data.PGFResourceDirectory; public class PGFSoundImpl extends PGFDataResourceImpl implements PGFSound { private static final Random random = new Random(); ArrayList<PGFSound> complex; + int singleIndex = -1; boolean isComplex = false; @@ -32,15 +35,14 @@ * * @param resource <code>PGFDataResource</code> sound resource */ - public PGFSoundImpl (PGFDataResourceImpl resource) { + public PGFSoundImpl (PGFDataResource resource) { this(resource.getResourceURL(), resource.getName(), resource.getDataType()); - this.directories = resource.directories; - this.properties = resource.properties; + this.directories = (ArrayList<PGFResourceDirectory>)resource.getDirectories(); + this.properties = (HashMap<String, String>)resource.getProperties(); } - /** - * Creates a complex sound from a list of sound resources. + * Creates a complex sound from a list of data resources. * * @param dlist List of <code>PGFDataResource</code> */ @@ -63,59 +65,22 @@ initComplex(slist); } - /** - * Creates a complex sound from a list of sound resources. - * The length of <code>names</code> must be the same as of <code>urls</code> - * and elements of the lists may not be <b>null</b>. Only as - * many resources will be listed as there are different names - * in the names list. If there are identical names in the names - * list, the first occurrence counts. - * - * @param urls List of <ode>URL</code> - * @param names List of <ode>String</code> - public PGFSoundImpl (List<URL> urls, List<String> names) { - // check validity of parameters - if (urls == null | names == null) { - throw new NullPointerException(); - } - if (urls.size() != names.size()) { - throw new IllegalArgumentException("urls and names must be of same size"); - } - // create the complex sound list - ArrayList<PGFSound>list = new ArrayList<PGFSound>(urls.size()); - int index = 0; - for (URL u : urls) { - if (u == null) { - throw new IllegalArgumentException("parameter urls: illegal null value for URL, index = " + index); - } - PGFSoundImpl sound = new PGFSoundImpl(u, names.get(index)); - if (!list.contains(sound)) { - list.add(sound); - } - index++; - } - - // initialise complex list - initComplex(list); - } - */ - /** Initialises this object's complex sound list and assigns a random * specialisation sound. * * @param list ArrayList of <code>PGFSound</code>, sound list to assign */ private void initComplex (ArrayList<PGFSound> list) { - complex = list; - isComplex = true; - - // single out a specialisation (single sound aspect) synchronized(random) { + complex = list; + + // single out a specialisation (single sound aspect) int index = random.nextInt(complex.size()); PGFSound s = list.get(index); this.url = s.getResourceURL(); - this.name = s.getName(); + this.singleIndex = index; + isComplex = true; } } @@ -130,7 +95,7 @@ @Override public PGFSound getSingle() { - return isComplex() ? new PGFSoundImpl(url, name, dataType) : this; + return isComplex() ? complex.get(singleIndex).getSingle() : this; } @Override @@ -140,24 +105,22 @@ @Override public boolean skipElement() { - List<PGFSound> list = getList(); - if (list != null && list.size() > 1) { - // reduce the list with the current assignment - PGFSound assignedSound = this.getSingle(); - list.remove(assignedSound); - - // pick a random element (next assignment) - synchronized(random) { - int i = random.nextInt(list.size()); - PGFSound sound = list.get(i); - this.url = sound.getResourceURL(); - this.name = sound.getName(); - } + if (complex != null && complex.size() > 1) { + // create new single sound assignment + int oldIndex = singleIndex; + do { + initComplex(complex); + } while (singleIndex == oldIndex); return true; } return false; } + /** Returns a new list of sounds which is a randomised shake-up of the parameter list. + * + * @param sounds List of <code>PGFSound</code> + * @return List of <code>PGFSound</code> + */ private List<PGFSound> randomized (List<PGFSound> sounds) { List<PGFSound> s1 = new ArrayList<PGFSound>(sounds); List<PGFSound> list = new ArrayList<PGFSound>(sounds.size()); @@ -176,7 +139,7 @@ public List<PGFSound> getShuffle() { List<PGFSound> list; if (isComplex()) { - list = randomized(getList()); + list = randomized(complex); } else { list = new LinkedList<PGFSound>(); list.add(this); @@ -197,8 +160,9 @@ list.add(sound); } } - // randomize the list + // randomise the list list = randomized(list); + } else { list = new LinkedList<PGFSound>(); list.add(this); @@ -208,21 +172,17 @@ /** * Creates a shallow clone of this sound. + * * @return <code>PGFSound</code> */ @SuppressWarnings("unchecked") @Override - protected PGFSound clone() { - try { - PGFSoundImpl c =(PGFSoundImpl)super.clone(); - if (complex != null) { - c.complex = (ArrayList<PGFSound>)this.complex.clone(); - } - return c; - } catch (CloneNotSupportedException e) { - e.printStackTrace(); - return null; + public Object clone() { + PGFSoundImpl c =(PGFSoundImpl)super.clone(); + if (complex != null) { + c.complex = (ArrayList<PGFSound>)this.complex.clone(); } + return c; } /** @@ -233,7 +193,7 @@ */ @Override public boolean equals(Object obj) { - if (obj != null) { + if (obj != null & obj instanceof PGFSoundImpl) { PGFSoundImpl s = (PGFSoundImpl)obj; return s.isComplex() == this.isComplex() && s.getName().equals(this.getName()); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ja...@us...> - 2011-07-01 15:43:00
|
Revision: 11 http://petraframe.svn.sourceforge.net/petraframe/?rev=11&view=rev Author: janet-h Date: 2011-07-01 15:42:53 +0000 (Fri, 01 Jul 2011) Log Message: ----------- added primary directory for PetraGameFrame 1 Added Paths: ----------- PETRA1/ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ja...@us...> - 2011-07-01 15:41:39
|
Revision: 10 http://petraframe.svn.sourceforge.net/petraframe/?rev=10&view=rev Author: janet-h Date: 2011-07-01 15:41:33 +0000 (Fri, 01 Jul 2011) Log Message: ----------- added primary directory for test application 1 Added Paths: ----------- TESTAPP1/ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ja...@us...> - 2011-06-25 08:57:32
|
Revision: 9 http://petraframe.svn.sourceforge.net/petraframe/?rev=9&view=rev Author: janet-h Date: 2011-06-25 08:57:25 +0000 (Sat, 25 Jun 2011) Log Message: ----------- safety copy (unstable) Modified Paths: -------------- trunk/src/net/petraframe/res/data/PGFDataResource.java trunk/src/net/petraframe/res/data/PGFDataResourceImpl.java trunk/src/net/petraframe/res/data/PGFResourceDirectory.java trunk/src/net/petraframe/res/data/PGFResourceDirectoryImpl.java trunk/src/net/petraframe/res/data/PGFResourceManager.java trunk/src/net/petraframe/res/data/PGFResourceManagerImpl.java trunk/src/net/petraframe/res/data/Test_ResourceDir.java trunk/src/net/petraframe/res/sound/PGFSoundImpl.java Added Paths: ----------- trunk/data/ trunk/test/ trunk/test/example/ Modified: trunk/src/net/petraframe/res/data/PGFDataResource.java =================================================================== --- trunk/src/net/petraframe/res/data/PGFDataResource.java 2011-06-22 06:49:39 UTC (rev 8) +++ trunk/src/net/petraframe/res/data/PGFDataResource.java 2011-06-25 08:57:25 UTC (rev 9) @@ -21,18 +21,49 @@ */ public byte[] getContent () throws IOException; + /** Returns the key which has been assigned to this resource. (This is + * the key that is used to fetch this from the resource manager.) + * + * @return String resource key (name) + */ + public String getName (); + + /** + * Returns the URL of this resource. + * + * @return <code>URL</code> + */ public URL getResourceURL (); public URL getPackageURL (); + + /** + * Returns the data type information of this resource. This normally consists + * of a MIME type expression. + * + * @return String data type or <b>null</b> if not defined + */ + public String getDataType (); - public boolean setCachable (boolean v); + /** + * Returns a property expression of this resource. Properties are mapped + * key into value. + * + * @param name String the property key + * @return String the property value or <b>null</b> if not defined + */ + public String getProperty (String name); - /** Returns the key which has been assigned to this resource. (This is - * the key that is used to fetch this from the resource manager.) + /** + * Attempts to set this resource into a data cache in order to + * increase access speed. * - * @return String resource key (name) + * @param v boolean requested cached state: <b>true</b> == cached, + * <b>false</b> == not cached + * @return boolean actual cached state: <b>true</b> == cached, + * <b>false</b> == not cached */ - public String getName (); + public boolean setCachable (boolean v); /** * Returns the list of resource directories in which this resource is listed. Modified: trunk/src/net/petraframe/res/data/PGFDataResourceImpl.java =================================================================== --- trunk/src/net/petraframe/res/data/PGFDataResourceImpl.java 2011-06-22 06:49:39 UTC (rev 8) +++ trunk/src/net/petraframe/res/data/PGFDataResourceImpl.java 2011-06-25 08:57:25 UTC (rev 9) @@ -5,6 +5,9 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; import java.util.List; public class PGFDataResourceImpl implements PGFDataResource { @@ -17,15 +20,22 @@ /** mapping token for this resource; never null. */ protected String name; + protected String dataType; + + protected HashMap<String, String> properties; + + protected List<PGFResourceDirectory> directories; + protected PGFDataResourceImpl () { } - public PGFDataResourceImpl (URL url, String name) { + public PGFDataResourceImpl (URL url, String name, String type) { if (url == null) { throw new NullPointerException(); } this.url = url; this.name = name == null ? "" : name; + this.dataType = type; } @Override @@ -82,8 +92,39 @@ @Override public List<PGFResourceDirectory> getDirectories() { - // TODO Auto-generated method stub - return null; + return directories == null ? null : new ArrayList<PGFResourceDirectory>(directories); } + @Override + public String getDataType() { + return dataType; + } + + @Override + public String getProperty(String name) { + return properties == null ? null : properties.get(name); + } + + /** + * Adds a property mapping to this resource's properties list. + * + * @param key String + * @param value String + * @return String the previous mapping value or <b>null</b> + */ + protected String addProperty (String key, String value) { + if (properties == null) { + properties = new HashMap<String, String>(); + } + return properties.put(key, value); + } + + protected void addDirectory (PGFResourceDirectory dir) { + if (directories == null) { + directories = new LinkedList<PGFResourceDirectory>(); + } + if (!directories.contains(dir)) { + directories.add(dir); + } + } } Modified: trunk/src/net/petraframe/res/data/PGFResourceDirectory.java =================================================================== --- trunk/src/net/petraframe/res/data/PGFResourceDirectory.java 2011-06-22 06:49:39 UTC (rev 8) +++ trunk/src/net/petraframe/res/data/PGFResourceDirectory.java 2011-06-25 08:57:25 UTC (rev 9) @@ -24,7 +24,7 @@ * name segment in the directory path. This value should never be * <b>null</b> or empty for all paths higher than root. * - * @return String directory element name or <b>null</b> if this + * @return String directory element name or empty string if this * directory is the root directory */ public String getElementName (); @@ -48,13 +48,25 @@ /** * Returns the child directory (to this directory) of the given name. * - * @param name String element name of the child directory + * @param name String element name of the child directory; + * may be <b>null</b> * @return <code>PGFResourceDirectory</code> child directory or <b>null</b> * if not present */ public PGFResourceDirectory getChild (String name); /** + * Starting from this directory (inclusive) searches the tree of sub-directories + * and returns the first directory that matches its element name to the given + * search string. (Search goes breadth first.) + * + * @param name String element name of searched directory (not the full path); + * may be <b>null</b> + * @return <code>PGFResourceDirectory</code> or <b>null</b> if not found + */ +public PGFResourceDirectory findDirectory (String name); + +/** * Returns the list of names of the resources contained in this directory. * (This does not include sub-directories or resource names in sub-directories.) * If there are no resources defined, an empty list is returned. @@ -74,7 +86,7 @@ * Two resource directories are regarded equal if and only if their * names (full paths) are equal. * - * @param obj Object + * @param obj Object; may be <b>null</b> * @return boolean */ public boolean equals (Object obj); Modified: trunk/src/net/petraframe/res/data/PGFResourceDirectoryImpl.java =================================================================== --- trunk/src/net/petraframe/res/data/PGFResourceDirectoryImpl.java 2011-06-22 06:49:39 UTC (rev 8) +++ trunk/src/net/petraframe/res/data/PGFResourceDirectoryImpl.java 2011-06-25 08:57:25 UTC (rev 9) @@ -50,22 +50,11 @@ public PGFResourceDirectoryImpl (String name, PGFResourceDirectoryImpl parent) throws PGFDoubleListEntryException { // test the parameters - if (name == null) { - throw new NullPointerException("missing directory name"); - } if (parent == null) { throw new NullPointerException("missing parent directory"); } + checkElementName(name); - // check element name value - if (name.length() == 0) { - throw new IllegalArgumentException("directory name must not be empty"); - } - String sep = PGFResourceManagerImpl.nameSeparatorChar; - if (name.indexOf(sep) != -1) { - throw new IllegalArgumentException("directory name must not contain separator: ".concat(sep)); - } - this.dirParent = parent; this.dirPath = parent.appendName(name); @@ -84,6 +73,28 @@ } /** + * Tests the given elemental directory name for correctness. + * On error throws exceptions. + * + * @param name + * @throws NullPointerException if any parameter is missing + * @throws IllegalArgumentException if element name is illegal + */ + private void checkElementName (String name) { + if (name == null) { + throw new NullPointerException("missing directory name"); + } + // check element name value + if (name.length() == 0) { + throw new IllegalArgumentException("directory name must not be empty"); + } + String sep = PGFResourceManagerImpl.nameSeparatorChar; + if (name.indexOf(sep) != -1) { + throw new IllegalArgumentException("directory name must not contain separator: ".concat(sep)); + } + } + + /** * Whether this directory has a child with identity of the given directory. * @param dir PGFResourceDirectory test dir * @return boolean @@ -101,8 +112,9 @@ private String appendName (String element) { String name = getName(); if (element != null) { - if (!name.endsWith(PGFResourceManagerImpl.nameSeparatorChar)) { - name = name.concat(PGFResourceManagerImpl.nameSeparatorChar); + String sep = PGFResourceManagerImpl.nameSeparatorChar; + if (!name.endsWith(sep)) { + name = name.concat(sep); } name = name.concat(element); } @@ -130,6 +142,33 @@ } @Override + public PGFResourceDirectory findDirectory (String name) { + if (name != null) { + // check if this directory is the target + if (getElementName().equals(name)) { + return this; + } + + if (dirChildren != null) { + // first search: direct children + for (PGFResourceDirectory dir : dirChildren) { + if (dir.getElementName().equals(name)) { + return dir; + } + } + // second search: recurse into children + for (PGFResourceDirectory dir : dirChildren) { + PGFResourceDirectory dir2 = dir.findDirectory(name); + if (dir2 != null) { + return dir2; + } + } + } + } + return null; + } + + @Override public String getName() { return dirPath; } @@ -145,10 +184,9 @@ return element; } } - return null; + return ""; } - @Override public PGFResourceDirectory getParent() { return dirParent; Modified: trunk/src/net/petraframe/res/data/PGFResourceManager.java =================================================================== --- trunk/src/net/petraframe/res/data/PGFResourceManager.java 2011-06-22 06:49:39 UTC (rev 8) +++ trunk/src/net/petraframe/res/data/PGFResourceManager.java 2011-06-25 08:57:25 UTC (rev 9) @@ -45,6 +45,16 @@ */ public PGFResourceDirectory getDirectory (String name); +/** + * Searches the tree of resource directories in this manager and returns + * the first match of element name to the given search string. + * (Search goes breadth first in the tree.) + * + * @param name String element name of searched directory (not the full path); + * may be <b>null</b> + * @return <code>PGFResourceDirectory</code> or <b>null</b> if not found + */ +public PGFResourceDirectory findDirectory (String name); /** * Returns an <code>Iterator</code> over all available content directories Modified: trunk/src/net/petraframe/res/data/PGFResourceManagerImpl.java =================================================================== --- trunk/src/net/petraframe/res/data/PGFResourceManagerImpl.java 2011-06-22 06:49:39 UTC (rev 8) +++ trunk/src/net/petraframe/res/data/PGFResourceManagerImpl.java 2011-06-25 08:57:25 UTC (rev 9) @@ -17,7 +17,7 @@ public static String nameSeparatorChar = "/"; /** The map referring to basic (single) resource objects. Realises namespace "SINGLE". */ - private HashMap<String, URL> baseMap = new HashMap<String, URL> (); + private HashMap<String, PGFDataResourceImpl> baseMap = new HashMap<String, PGFDataResourceImpl> (); /** The map referring to complex (lists of) resource objects. Realises namespace "COMPLEX". */ private HashMap<String, List<String>> complMap = new HashMap<String, List<String>> (); @@ -51,12 +51,8 @@ public PGFDataResource getResource (String name) { if (name != null & isValid) { // lookup resource in basic map - URL url = baseMap.get(name); - if (url != null) { - // create and return a resource object - PGFDataResource res = new PGFDataResourceImpl(url, name); - return res; - } + PGFDataResource res = baseMap.get(name); + return res; } return null; } @@ -88,6 +84,7 @@ isValid = false; baseMap.clear(); complMap.clear(); + directoryMap.clear(); fireChangeEvent(); } @@ -206,6 +203,12 @@ return directoryMap.get(name); } + @Override + public PGFResourceDirectory findDirectory(String name) { + PGFResourceDirectory root = getDirectory(nameSeparatorChar); + return root == null ? null : root.findDirectory(name); + } + /** * Adds a directory to the mapping of this resource manager if * it isn't listed (ADD-IF-NOT-PRESENT). Always returns the named directory, Modified: trunk/src/net/petraframe/res/data/Test_ResourceDir.java =================================================================== --- trunk/src/net/petraframe/res/data/Test_ResourceDir.java 2011-06-22 06:49:39 UTC (rev 8) +++ trunk/src/net/petraframe/res/data/Test_ResourceDir.java 2011-06-25 08:57:25 UTC (rev 9) @@ -19,7 +19,7 @@ assertTrue(root.getChild("") == null); assertTrue(root.getChild(null) == null); assertTrue(root.getChildren() == null); - assertTrue(root.getElementName() == null); + assertTrue(root.getElementName().equals("")); assertTrue(root.getName() != null); assertEquals(root.getName(), root.toString()); assertTrue(root.getName().equals(SEP)); @@ -66,6 +66,17 @@ assertTrue(root.getName().equals(SEP)); assertEquals(root.getName(), root.toString()); assertTrue(root.hashCode() == hc1); + + // find directory + PGFResourceDirectory dir2 = root.findDirectory("image resources"); + assertNotNull(dir2); + assertEquals(dir2, dir); + dir2 = root.findDirectory(SEP); + assertNull(dir2); + dir2 = root.findDirectory("something"); + assertNull(dir2); + dir2 = root.findDirectory(null); + assertNull(dir2); } @Test @@ -112,6 +123,25 @@ assertTrue(dir.getChild("") == null); assertTrue(dir.getChild(null) == null); + // find directory + PGFResourceDirectory dirH = root.findDirectory(s2Name); + assertNotNull(dirH); + assertEquals(dirS2, dirH); + + dirH = dir.findDirectory(s2Name); + assertNotNull(dirH); + assertEquals(dirS2, dirH); + + dirH = dirS2.findDirectory(s2Name); + assertNotNull(dirH); + assertEquals(dirS2, dirH); + + dirH = root.findDirectory(SEP); + assertNull(dirH); + dirH = root.findDirectory("something"); + assertNull(dirH); + dirH = root.findDirectory(null); + assertNull(dirH); } @Test(expected = NullPointerException.class) Modified: trunk/src/net/petraframe/res/sound/PGFSoundImpl.java =================================================================== --- trunk/src/net/petraframe/res/sound/PGFSoundImpl.java 2011-06-22 06:49:39 UTC (rev 8) +++ trunk/src/net/petraframe/res/sound/PGFSoundImpl.java 2011-06-25 08:57:25 UTC (rev 9) @@ -23,8 +23,8 @@ * @param url <code>URL</code> sound resource location * @param name String name of the sound (key) */ - public PGFSoundImpl (URL url, String name) { - super(url, name); + public PGFSoundImpl (URL url, String name, String type) { + super(url, name, type); } /** @@ -32,8 +32,10 @@ * * @param resource <code>PGFDataResource</code> sound resource */ - public PGFSoundImpl (PGFDataResource resource) { - this(resource.getResourceURL(), resource.getName()); + public PGFSoundImpl (PGFDataResourceImpl resource) { + this(resource.getResourceURL(), resource.getName(), resource.getDataType()); + this.directories = resource.directories; + this.properties = resource.properties; } @@ -71,7 +73,6 @@ * * @param urls List of <ode>URL</code> * @param names List of <ode>String</code> - */ public PGFSoundImpl (List<URL> urls, List<String> names) { // check validity of parameters if (urls == null | names == null) { @@ -98,6 +99,7 @@ // initialise complex list initComplex(list); } + */ /** Initialises this object's complex sound list and assigns a random * specialisation sound. @@ -128,7 +130,7 @@ @Override public PGFSound getSingle() { - return isComplex() ? new PGFSoundImpl(url, name) : this; + return isComplex() ? new PGFSoundImpl(url, name, dataType) : this; } @Override This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ja...@us...> - 2011-06-22 06:49:45
|
Revision: 8 http://petraframe.svn.sourceforge.net/petraframe/?rev=8&view=rev Author: janet-h Date: 2011-06-22 06:49:39 +0000 (Wed, 22 Jun 2011) Log Message: ----------- added Junit lib and test for PGFResourceDirectory Modified Paths: -------------- trunk/.classpath trunk/src/net/petraframe/res/data/PGFResourceDirectory.java trunk/src/net/petraframe/res/data/PGFResourceDirectoryImpl.java Added Paths: ----------- trunk/lib/junit-4.8.2-src.jar trunk/lib/junit-4.8.2.jar trunk/src/net/petraframe/res/data/Test_ResourceDir.java Modified: trunk/.classpath =================================================================== --- trunk/.classpath 2011-06-19 23:57:46 UTC (rev 7) +++ trunk/.classpath 2011-06-22 06:49:39 UTC (rev 8) @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <classpath> <classpathentry kind="src" path="src"/> + <classpathentry kind="lib" path="lib/junit-4.8.2.jar" sourcepath="lib/junit-4.8.2-src.jar"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/> <classpathentry kind="output" path="classes"/> </classpath> Added: trunk/lib/junit-4.8.2-src.jar =================================================================== (Binary files differ) Property changes on: trunk/lib/junit-4.8.2-src.jar ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Added: trunk/lib/junit-4.8.2.jar =================================================================== (Binary files differ) Property changes on: trunk/lib/junit-4.8.2.jar ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Modified: trunk/src/net/petraframe/res/data/PGFResourceDirectory.java =================================================================== --- trunk/src/net/petraframe/res/data/PGFResourceDirectory.java 2011-06-19 23:57:46 UTC (rev 7) +++ trunk/src/net/petraframe/res/data/PGFResourceDirectory.java 2011-06-22 06:49:39 UTC (rev 8) @@ -47,6 +47,7 @@ /** * Returns the child directory (to this directory) of the given name. + * * @param name String element name of the child directory * @return <code>PGFResourceDirectory</code> child directory or <b>null</b> * if not present @@ -56,9 +57,33 @@ /** * Returns the list of names of the resources contained in this directory. * (This does not include sub-directories or resource names in sub-directories.) + * If there are no resources defined, an empty list is returned. * * @return List of String, list of resource names */ public List<String> list (); +/** + * Whether this directory holds resource path content. + * + * @return boolean <b>true</b> == content available + */ +public boolean hasContent (); + +/** + * Two resource directories are regarded equal if and only if their + * names (full paths) are equal. + * + * @param obj Object + * @return boolean + */ +public boolean equals (Object obj); + +/** + * The "to-string" method returns the name (full path) of this directory. + * + * @return String directory name + */ +public String toString (); + } Modified: trunk/src/net/petraframe/res/data/PGFResourceDirectoryImpl.java =================================================================== --- trunk/src/net/petraframe/res/data/PGFResourceDirectoryImpl.java 2011-06-19 23:57:46 UTC (rev 7) +++ trunk/src/net/petraframe/res/data/PGFResourceDirectoryImpl.java 2011-06-22 06:49:39 UTC (rev 8) @@ -11,8 +11,8 @@ * allows the definition of a hierarchical tree of directories, starting from a * root directory. Creation of a directory is only possible in relation to a * parent directory (except for the root directory, which is available through - * the empty constructor.) Equality of two instances refers to the treepath - * value. + * the empty constructor.) Equality of two instances refers, exclusively, to the + * treepath value. * <p><b>Content</b> * <p>The data content of a directory is a list of strings without any rule * restrictions except that no list value must become <b>null</b> or occur double. @@ -155,18 +155,26 @@ } @Override + public boolean hasContent() { + return resourceList == null ? false : resourceList.size() != 0; + } + + @Override public List<String> list() { return resourceList == null ? new LinkedList<String>() : new ArrayList<String>(resourceList); } /** - * Adds a child directory of the given element name to this directory. - * (Does nothing if the name is already contained as sub-directory. This - * returns the child directory regardless of whether it has been newly created.) + * Convenience method to add a child directory of the given element name + * to this directory. Does nothing if the name is already contained as + * sub-directory. This returns the child directory regardless of whether + * it has been newly created. * - * @param name String child name, not the full path. May not be <b>null</b> or empty - * or contain the name separator string + * @param name String child element name (not the full path). May not be <b>null</b> + * or empty or contain the name separator string * @return <code>PGFResourceDirectoryImpl</code> the child directory of the specified name + * @throws NullPointerException if parameter is null + * @throws IllegalArgumentException if child name is illegal */ PGFResourceDirectoryImpl addChildDirectory (String name) { PGFResourceDirectoryImpl dir; @@ -218,6 +226,10 @@ public int hashCode() { return dirPath.hashCode(); } + + @Override + public String toString() { + return getName(); + } - } Added: trunk/src/net/petraframe/res/data/Test_ResourceDir.java =================================================================== --- trunk/src/net/petraframe/res/data/Test_ResourceDir.java (rev 0) +++ trunk/src/net/petraframe/res/data/Test_ResourceDir.java 2011-06-22 06:49:39 UTC (rev 8) @@ -0,0 +1,153 @@ +package net.petraframe.res.data; + +import static org.junit.Assert.*; + +import java.util.List; + +import org.junit.Test; + +public class Test_ResourceDir { + + private static final String SEP = PGFResourceManagerImpl.nameSeparatorChar; + + @Test + public void create_tree_root () { + // root blank + PGFResourceDirectoryImpl root = new PGFResourceDirectoryImpl(); + assertTrue(root != null); + assertTrue(root.equals(root)); + assertTrue(root.getChild("") == null); + assertTrue(root.getChild(null) == null); + assertTrue(root.getChildren() == null); + assertTrue(root.getElementName() == null); + assertTrue(root.getName() != null); + assertEquals(root.getName(), root.toString()); + assertTrue(root.getName().equals(SEP)); + assertTrue(root.getParent() == null); + assertTrue(root.hasContent() == false); + List<String> resL = root.list(); + assertTrue(resL != null); + assertTrue(resL.size() == 0); + int hc1 = root.hashCode(); + assertTrue(hc1 != 0); + assertTrue(root.getParent() == null); + + // filling root with resource paths + root.addResource(""); + assertTrue(root.hasContent()); + resL = root.list(); + assertTrue(resL != null); + assertTrue(resL.size() == 1); + assertEquals(resL.get(0), ""); + assertTrue(root.getChildren() == null); + assertTrue(root.getName().equals(SEP)); + + root.addResource("hans heinrich"); + assertTrue(root.hasContent()); + resL = root.list(); + assertTrue(resL != null); + assertTrue(resL.size() == 2); + assertEquals(resL.get(0), ""); + assertEquals(resL.get(1), "hans heinrich"); + assertTrue(root.getChildren() == null); + assertTrue(root.getName().equals(SEP)); + assertTrue(root.hashCode() == hc1); + + // add child directory + PGFResourceDirectory dir = root.addChildDirectory("image resources"); + assertTrue(root.getChildren() != null); + assertEquals(dir.getParent(), root); + assertTrue(root.hasContent()); + resL = root.list(); + assertTrue(resL != null); + assertTrue(resL.size() == 2); + assertEquals(resL.get(0), ""); + assertEquals(resL.get(1), "hans heinrich"); + assertTrue(root.getName().equals(SEP)); + assertEquals(root.getName(), root.toString()); + assertTrue(root.hashCode() == hc1); + } + + @Test + public void create_tree_dir () { + + PGFResourceDirectoryImpl root = new PGFResourceDirectoryImpl(); + + // root and first level subdir + PGFResourceDirectory dir = root.addChildDirectory("image resources"); + assertEquals(dir.getName(), SEP.concat("image resources")); + assertEquals(dir.getElementName(), "image resources"); + assertEquals(dir.getName(), dir.toString()); + assertTrue(dir.hasContent() == false); + assertTrue(dir.getChildren() == null); + assertTrue(dir.getChild("") == null); + assertTrue(dir.getChild(null) == null); + assertTrue(dir.getChild("image resources") == null); + List<String> resL = dir.list(); + assertTrue(resL != null); + assertTrue(resL.size() == 0); + assertSame(root, dir.getParent()); + PGFResourceDirectory dir2 = root.getChild("image resources"); + assertEquals(dir, dir2); + assertTrue(root.getChild("") == null); + assertTrue(root.getChild(null) == null); + + // second level subdir + String s2Name = "crazy pinks"; + PGFResourceDirectory dirS2 = ((PGFResourceDirectoryImpl)dir).addChildDirectory(s2Name); + assertEquals(dirS2.getName(), SEP + "image resources" + SEP + s2Name); + assertEquals(dirS2.getElementName(), s2Name); + assertEquals(dirS2.getName(), dirS2.toString()); + assertTrue(dirS2.hasContent() == false); + assertTrue(dirS2.getChildren() == null); + assertTrue(dirS2.getChild("") == null); + assertTrue(dirS2.getChild(null) == null); + assertTrue(dirS2.getChild(s2Name) == null); + resL = dirS2.list(); + assertTrue(resL != null); + assertTrue(resL.size() == 0); + assertSame(dir, dirS2.getParent()); + dir2 = dir.getChild(s2Name); + assertEquals(dirS2, dir2); + assertTrue(dir.getChild("") == null); + assertTrue(dir.getChild(null) == null); + + } + + @Test(expected = NullPointerException.class) + public void throw_null_rootAddResource () { + PGFResourceDirectoryImpl root = new PGFResourceDirectoryImpl(); + root.addResource(null); + } + + @Test(expected = NullPointerException.class) + public void throw_null_rootAddChild () { + PGFResourceDirectoryImpl root = new PGFResourceDirectoryImpl(); + root.addChildDirectory(null); + } + + @Test(expected = IllegalArgumentException.class) + public void throw_illegal1_rootAddChild () { + PGFResourceDirectoryImpl root = new PGFResourceDirectoryImpl(); + root.addChildDirectory(""); + } + + @Test(expected = IllegalArgumentException.class) + public void throw_illegal2_rootAddChild () { + PGFResourceDirectoryImpl root = new PGFResourceDirectoryImpl(); + root.addChildDirectory(SEP); + } + + @Test(expected = IllegalArgumentException.class) + public void throw_illegal3_rootAddChild () { + PGFResourceDirectoryImpl root = new PGFResourceDirectoryImpl(); + root.addChildDirectory(SEP.concat("wild horses")); + } + + @Test(expected = IllegalArgumentException.class) + public void throw_illegal4_rootAddChild () { + PGFResourceDirectoryImpl root = new PGFResourceDirectoryImpl(); + root.addChildDirectory("wild horses" + SEP + "grumble"); + } + +} Property changes on: trunk/src/net/petraframe/res/data/Test_ResourceDir.java ___________________________________________________________________ Added: svn:mime-type + text/x-java Added: svn:eol-style + native This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ja...@us...> - 2011-06-19 23:57:52
|
Revision: 7 http://petraframe.svn.sourceforge.net/petraframe/?rev=7&view=rev Author: janet-h Date: 2011-06-19 23:57:46 +0000 (Sun, 19 Jun 2011) Log Message: ----------- added resource directory implementation Added Paths: ----------- trunk/src/net/petraframe/res/data/PGFResourceDirectoryImpl.java Added: trunk/src/net/petraframe/res/data/PGFResourceDirectoryImpl.java =================================================================== --- trunk/src/net/petraframe/res/data/PGFResourceDirectoryImpl.java (rev 0) +++ trunk/src/net/petraframe/res/data/PGFResourceDirectoryImpl.java 2011-06-19 23:57:46 UTC (rev 7) @@ -0,0 +1,223 @@ +package net.petraframe.res.data; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import net.petraframe.exception.PGFDoubleListEntryException; + +/** + * This implementation of {@link PGFResourceDirectory} creates a structure that + * allows the definition of a hierarchical tree of directories, starting from a + * root directory. Creation of a directory is only possible in relation to a + * parent directory (except for the root directory, which is available through + * the empty constructor.) Equality of two instances refers to the treepath + * value. + * <p><b>Content</b> + * <p>The data content of a directory is a list of strings without any rule + * restrictions except that no list value must become <b>null</b> or occur double. + * This implementation allows adding string content in a package local method only. + * <p> + * + * @author janet-h + * + */ +public class PGFResourceDirectoryImpl implements PGFResourceDirectory { + + private String dirPath; + private PGFResourceDirectoryImpl dirParent; + private List<PGFResourceDirectoryImpl> dirChildren; + private List<String> resourceList; + + /** + * Creates a root directory. + */ + public PGFResourceDirectoryImpl () { + dirPath = PGFResourceManagerImpl.nameSeparatorChar; + } + + /** + * Creates a new directory depending on a parent directory. + * (This can only create a child to the given parent.) + * + * @param name the element name of the new directory (not the full path) + * @param parent <code>PGFResourceDirectoryImpl</code> the parent directory + * @throws PGFDoubleListEntryException if a directory of the given name + * already exists in the parent + * @throws NullPointerException if any parameter is missing + * @throws IllegalArgumentException if element name is illegal + */ + public PGFResourceDirectoryImpl (String name, PGFResourceDirectoryImpl parent) + throws PGFDoubleListEntryException { + // test the parameters + if (name == null) { + throw new NullPointerException("missing directory name"); + } + if (parent == null) { + throw new NullPointerException("missing parent directory"); + } + + // check element name value + if (name.length() == 0) { + throw new IllegalArgumentException("directory name must not be empty"); + } + String sep = PGFResourceManagerImpl.nameSeparatorChar; + if (name.indexOf(sep) != -1) { + throw new IllegalArgumentException("directory name must not contain separator: ".concat(sep)); + } + + this.dirParent = parent; + this.dirPath = parent.appendName(name); + + // invalid if child already exists with this name + if (parent.hasChild(this)) { + throw new PGFDoubleListEntryException("directory already exists in parent"); + } + + // integrate this as a child to parent + if (parent.dirChildren == null) { + parent.dirChildren = new ArrayList<PGFResourceDirectoryImpl>(); + } + synchronized (parent.dirChildren) { + parent.dirChildren.add(this); + } + } + + /** + * Whether this directory has a child with identity of the given directory. + * @param dir PGFResourceDirectory test dir + * @return boolean + */ + private boolean hasChild (PGFResourceDirectory dir) { + return dirChildren == null ? false : dirChildren.contains(dir); + } + + /** + * Appends a last element name to the path of this directory. + * + * @param element String last element name + * @return String resulting path (full path) + */ + private String appendName (String element) { + String name = getName(); + if (element != null) { + if (!name.endsWith(PGFResourceManagerImpl.nameSeparatorChar)) { + name = name.concat(PGFResourceManagerImpl.nameSeparatorChar); + } + name = name.concat(element); + } + return name; + } + + @Override + public List<PGFResourceDirectory> getChildren() { + return dirChildren == null ? null : new ArrayList<PGFResourceDirectory>(dirChildren); + } + + @Override + public PGFResourceDirectory getChild(String name) { + if (name != null & dirChildren != null) { + synchronized (dirChildren) { + PGFResourceDirectoryImpl dir = new PGFResourceDirectoryImpl(); + dir.dirPath = appendName(name); + int index = dirChildren.indexOf(dir); + // return the listed child directory + dir = index == -1 ? null : (PGFResourceDirectoryImpl)dirChildren.get(index); + return dir; + } + } + return null; + } + + @Override + public String getName() { + return dirPath; + } + + @Override + public String getElementName() { + if (getParent() != null) { + String path = getName(); + String sep = PGFResourceManagerImpl.nameSeparatorChar; + int index = path.lastIndexOf(sep); + if (index != -1) { + String element = path.substring(index + sep.length()); + return element; + } + } + return null; + } + + + @Override + public PGFResourceDirectory getParent() { + return dirParent; + } + + @Override + public List<String> list() { + return resourceList == null ? new LinkedList<String>() : new ArrayList<String>(resourceList); + } + + /** + * Adds a child directory of the given element name to this directory. + * (Does nothing if the name is already contained as sub-directory. This + * returns the child directory regardless of whether it has been newly created.) + * + * @param name String child name, not the full path. May not be <b>null</b> or empty + * or contain the name separator string + * @return <code>PGFResourceDirectoryImpl</code> the child directory of the specified name + */ + PGFResourceDirectoryImpl addChildDirectory (String name) { + PGFResourceDirectoryImpl dir; + + // create and append directory to this' child list + // or return an already existing child of that name + try { + // create and append child (also tests for name validity) + dir = new PGFResourceDirectoryImpl(name, this); + } catch (PGFDoubleListEntryException e) { + // return the child that was reported to exist + dir = (PGFResourceDirectoryImpl) getChild(name); + } + return dir; + } + + /** + * Adds a resource name to the content of this directory. + * + * @param name String resource name + * @throws NullPointerException if name is null + */ + void addResource (String name) { + if (name == null) { + throw new NullPointerException(); + } + if (resourceList == null) { + resourceList = new ArrayList<String>(); + } + synchronized (resourceList) { + if (!resourceList.contains(name)) { + resourceList.add(name); + } + } + } + + + @Override + public boolean equals(Object obj) { + if (obj != null && obj instanceof PGFResourceDirectoryImpl) { + PGFResourceDirectoryImpl dir = (PGFResourceDirectoryImpl) obj; + return dir.getName().equals(this.getName()); + } + return false; + } + + + @Override + public int hashCode() { + return dirPath.hashCode(); + } + + +} Property changes on: trunk/src/net/petraframe/res/data/PGFResourceDirectoryImpl.java ___________________________________________________________________ Added: svn:mime-type + text/x-java Added: svn:eol-style + native This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ja...@us...> - 2011-06-19 23:52:12
|
Revision: 6 http://petraframe.svn.sourceforge.net/petraframe/?rev=6&view=rev Author: janet-h Date: 2011-06-19 23:52:04 +0000 (Sun, 19 Jun 2011) Log Message: ----------- added resource directory implementation Modified Paths: -------------- trunk/src/net/petraframe/res/data/PGFDataResource.java trunk/src/net/petraframe/res/data/PGFDataResourceImpl.java trunk/src/net/petraframe/res/data/PGFResourceManager.java trunk/src/net/petraframe/res/data/PGFResourceManagerImpl.java Added Paths: ----------- trunk/src/net/petraframe/exception/ trunk/src/net/petraframe/exception/PGFDoubleListEntryException.java trunk/src/net/petraframe/exception/PGFException.java trunk/src/net/petraframe/res/data/PGFResourceDirectory.java Added: trunk/src/net/petraframe/exception/PGFDoubleListEntryException.java =================================================================== --- trunk/src/net/petraframe/exception/PGFDoubleListEntryException.java (rev 0) +++ trunk/src/net/petraframe/exception/PGFDoubleListEntryException.java 2011-06-19 23:52:04 UTC (rev 6) @@ -0,0 +1,30 @@ +package net.petraframe.exception; + +/** + * An exception indicating that an attempt was made to illegally insert + * a list element whose identity was already present in the list. + * + * @author janet-h + * + */ + +public class PGFDoubleListEntryException extends PGFException { + + private static final long serialVersionUID = 1307684224313522724L; + + public PGFDoubleListEntryException() { + } + + public PGFDoubleListEntryException(String message) { + super(message); + } + + public PGFDoubleListEntryException(Throwable cause) { + super(cause); + } + + public PGFDoubleListEntryException(String message, Throwable cause) { + super(message, cause); + } + +} Property changes on: trunk/src/net/petraframe/exception/PGFDoubleListEntryException.java ___________________________________________________________________ Added: svn:mime-type + text/x-java Added: svn:eol-style + native Added: trunk/src/net/petraframe/exception/PGFException.java =================================================================== --- trunk/src/net/petraframe/exception/PGFException.java (rev 0) +++ trunk/src/net/petraframe/exception/PGFException.java 2011-06-19 23:52:04 UTC (rev 6) @@ -0,0 +1,26 @@ +package net.petraframe.exception; + +/** + * The base class for all PetraGameFrame exceptions. + * + */ +public class PGFException extends Exception { + + private static final long serialVersionUID = -9070710489998880512L; + + public PGFException() { + } + + public PGFException(String message) { + super(message); + } + + public PGFException(Throwable cause) { + super(cause); + } + + public PGFException(String message, Throwable cause) { + super(message, cause); + } + +} Property changes on: trunk/src/net/petraframe/exception/PGFException.java ___________________________________________________________________ Added: svn:mime-type + text/x-java Added: svn:eol-style + native Modified: trunk/src/net/petraframe/res/data/PGFDataResource.java =================================================================== --- trunk/src/net/petraframe/res/data/PGFDataResource.java 2011-06-15 01:54:46 UTC (rev 5) +++ trunk/src/net/petraframe/res/data/PGFDataResource.java 2011-06-19 23:52:04 UTC (rev 6) @@ -3,6 +3,7 @@ import java.io.BufferedInputStream; import java.io.IOException; import java.net.URL; +import java.util.List; public interface PGFDataResource { @@ -27,10 +28,18 @@ public boolean setCachable (boolean v); /** Returns the key which has been assigned to this resource. (This is - * the key that is used to fetch from the resource manager.) + * the key that is used to fetch this from the resource manager.) * * @return String resource key (name) */ public String getName (); + + /** + * Returns the list of resource directories in which this resource is listed. + * If this resource is not assigned to a directory, <b>null</b> is returned. + * + * @return List of <code>PGFResourceDirectory</code> or <b>null</b> + */ + public List<PGFResourceDirectory> getDirectories (); } Modified: trunk/src/net/petraframe/res/data/PGFDataResourceImpl.java =================================================================== --- trunk/src/net/petraframe/res/data/PGFDataResourceImpl.java 2011-06-15 01:54:46 UTC (rev 5) +++ trunk/src/net/petraframe/res/data/PGFDataResourceImpl.java 2011-06-19 23:52:04 UTC (rev 6) @@ -5,6 +5,7 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; +import java.util.List; public class PGFDataResourceImpl implements PGFDataResource { @@ -79,4 +80,10 @@ return false; } + @Override + public List<PGFResourceDirectory> getDirectories() { + // TODO Auto-generated method stub + return null; + } + } Added: trunk/src/net/petraframe/res/data/PGFResourceDirectory.java =================================================================== --- trunk/src/net/petraframe/res/data/PGFResourceDirectory.java (rev 0) +++ trunk/src/net/petraframe/res/data/PGFResourceDirectory.java 2011-06-19 23:52:04 UTC (rev 6) @@ -0,0 +1,64 @@ +package net.petraframe.res.data; + +import java.util.List; + +/** + * + * + * + * @author Janet Hunt + * + */ +public interface PGFResourceDirectory { + +/** + * Returns the name of this directory. This is the full + * path name. This value should never be <b>null</b> or empty. + * + * @return String directory name + */ +public String getName (); + +/** + * Returns the element name of this directory. This is the last + * name segment in the directory path. This value should never be + * <b>null</b> or empty for all paths higher than root. + * + * @return String directory element name or <b>null</b> if this + * directory is the root directory + */ +public String getElementName (); + +/** + * Returns the parent directory of this directory. The topmost directory + * is the root directory which should hold only the separator string as path + * and is signified by a parent value of <b>null</b>. + * + * @return <code>PGFResourceDirectory</code> parent directory or <b>null</b> + */ +public PGFResourceDirectory getParent (); + +/** + * Returns the list of sub-directories to this directory. + * + * @return List of <code>PGFResourceDirectory</code>, list of sub-directories or <b>null</b> + */ +public List<PGFResourceDirectory> getChildren (); + +/** + * Returns the child directory (to this directory) of the given name. + * @param name String element name of the child directory + * @return <code>PGFResourceDirectory</code> child directory or <b>null</b> + * if not present + */ +public PGFResourceDirectory getChild (String name); + +/** + * Returns the list of names of the resources contained in this directory. + * (This does not include sub-directories or resource names in sub-directories.) + * + * @return List of String, list of resource names + */ +public List<String> list (); + +} Property changes on: trunk/src/net/petraframe/res/data/PGFResourceDirectory.java ___________________________________________________________________ Added: svn:mime-type + text/x-java Added: svn:eol-style + native Modified: trunk/src/net/petraframe/res/data/PGFResourceManager.java =================================================================== --- trunk/src/net/petraframe/res/data/PGFResourceManager.java 2011-06-15 01:54:46 UTC (rev 5) +++ trunk/src/net/petraframe/res/data/PGFResourceManager.java 2011-06-19 23:52:04 UTC (rev 6) @@ -2,6 +2,7 @@ import java.io.IOException; import java.net.URL; +import java.util.Iterator; import java.util.List; import javax.swing.ImageIcon; @@ -34,6 +35,26 @@ public List<PGFDataResource> getListResource (String name); /** + * Returns the resource directory of the given name. + * (Value <b>null</b> is not defined as a directory name.) + * + * @param name String the name of the directory (full path); if value + * is empty or the nameSeparatorChar, the root directory is returned + * @return <code>PGFResourceDirectory</code> or <b>null</b> if no such + * directory is defined + */ +public PGFResourceDirectory getDirectory (String name); + + +/** + * Returns an <code>Iterator</code> over all available content directories + * in this manager, listed in a sorted order. + * + * @return Iterator of <code>String</code> (names of directories) + */ +public Iterator<String> getDirectoryIterator (); + +/** * Adds a listener for change events of this manager. Change events * are issued when the VALIDITY property of the resource mappings * changes (valid/invalid), or when the set of mappings has been Modified: trunk/src/net/petraframe/res/data/PGFResourceManagerImpl.java =================================================================== --- trunk/src/net/petraframe/res/data/PGFResourceManagerImpl.java 2011-06-15 01:54:46 UTC (rev 5) +++ trunk/src/net/petraframe/res/data/PGFResourceManagerImpl.java 2011-06-19 23:52:04 UTC (rev 6) @@ -4,23 +4,38 @@ import java.net.URL; import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; import java.util.List; +import java.util.TreeMap; import javax.swing.ImageIcon; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; public class PGFResourceManagerImpl implements PGFResourceManager { + + public static String nameSeparatorChar = "/"; + /** The map referring to basic (single) resource objects. Realises namespace "SINGLE". */ private HashMap<String, URL> baseMap = new HashMap<String, URL> (); + + /** The map referring to complex (lists of) resource objects. Realises namespace "COMPLEX". */ private HashMap<String, List<String>> complMap = new HashMap<String, List<String>> (); + /** The map referring to resource directory objects. Realises all available resource directory paths. */ + private TreeMap<String, PGFResourceDirectory> directoryMap = new TreeMap<String, PGFResourceDirectory>(); + private List<URL> mappingSources; private ArrayList<ChangeListener> changeListeners; private boolean isValid = false; + public PGFResourceManagerImpl () { + // create the root directory + directoryMap.put(nameSeparatorChar, new PGFResourceDirectoryImpl()); + } + @Override public ImageIcon getImageIcon (String name) throws IOException { PGFDataResource res = getResource(name); @@ -178,5 +193,76 @@ } } } + + public Iterator<String> getDirectoryIterator () { + return directoryMap.keySet().iterator(); + } + @Override + public PGFResourceDirectory getDirectory(String name) { + if (name == null) { + throw new NullPointerException(); + } + return directoryMap.get(name); + } + + /** + * Adds a directory to the mapping of this resource manager if + * it isn't listed (ADD-IF-NOT-PRESENT). Always returns the named directory, + * if the name is of proper format. + * The path name can be any valid value of unrestricted complexity; + * unknown element directories are automatically created when + * inserting a path. + * + * @param path String the directory name (full path) + * @return <code>PGFResourceDirectoryImpl</code> the child directory named by parameter + * @throws NullPointerException if path is <b>null</b> + * @throws IllegalArgumentException if path holds an illegal value + */ + @SuppressWarnings("unused") + private PGFResourceDirectoryImpl addDirectory (final String path) { + // check for root sign + int index = path.indexOf(nameSeparatorChar); + if (index != 0) { + throw new IllegalArgumentException("the path must start with the separator string"); + } + + // look for presence first + PGFResourceDirectoryImpl childDir = (PGFResourceDirectoryImpl) directoryMap.get(path); + if (childDir == null) { + + // separate parent and element name (excluding the separator string) + index = path.lastIndexOf(nameSeparatorChar); + String name = path.substring(index + nameSeparatorChar.length()); + String trunk = path.substring(0, index); + + // check element name value + if (name.length() == 0) { + throw new IllegalArgumentException("the path contains an illegal element name of zero length"); + } + + // supply root trunk if necessary + if (trunk.length() == 0) { + trunk = nameSeparatorChar; + } + + // catch from map or create the trunk directory + PGFResourceDirectoryImpl trunkDir = (PGFResourceDirectoryImpl) getDirectory(trunk); + if (trunkDir == null) { + // create the trunk directory (recursive) + trunkDir = addDirectory(trunk); + } + + // now that we have the trunk directory.. + // update its children list, and create the child + childDir = trunkDir.addChildDirectory(name); + + // map the declared directory + synchronized (directoryMap) { + directoryMap.put(path, childDir); + } + } + return childDir; + } + } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ja...@us...> - 2011-06-15 01:54:52
|
Revision: 5 http://petraframe.svn.sourceforge.net/petraframe/?rev=5&view=rev Author: janet-h Date: 2011-06-15 01:54:46 +0000 (Wed, 15 Jun 2011) Log Message: ----------- implemented sound ticket and sound manager classes (first edition) Modified Paths: -------------- trunk/src/net/petraframe/res/data/PGFDataResource.java trunk/src/net/petraframe/res/data/PGFDataResourceImpl.java trunk/src/net/petraframe/res/data/PGFResourceManagerImpl.java trunk/src/net/petraframe/res/sound/PGFSound.java Added Paths: ----------- trunk/src/net/petraframe/res/sound/PGFSoundImpl.java trunk/src/net/petraframe/res/sound/PGFSoundManagerImpl.java Modified: trunk/src/net/petraframe/res/data/PGFDataResource.java =================================================================== --- trunk/src/net/petraframe/res/data/PGFDataResource.java 2011-06-13 21:33:40 UTC (rev 4) +++ trunk/src/net/petraframe/res/data/PGFDataResource.java 2011-06-15 01:54:46 UTC (rev 5) @@ -26,10 +26,10 @@ public boolean setCachable (boolean v); - /** Returns the token which has been assigned to this resource. (This is - * the token that is used to fetch from the resource manager.) + /** Returns the key which has been assigned to this resource. (This is + * the key that is used to fetch from the resource manager.) * - * @return String resource token + * @return String resource key (name) */ public String getName (); Modified: trunk/src/net/petraframe/res/data/PGFDataResourceImpl.java =================================================================== --- trunk/src/net/petraframe/res/data/PGFDataResourceImpl.java 2011-06-13 21:33:40 UTC (rev 4) +++ trunk/src/net/petraframe/res/data/PGFDataResourceImpl.java 2011-06-15 01:54:46 UTC (rev 5) @@ -11,11 +11,14 @@ public static int readBufferSize = 2048 * 4; /** URL for external data of this resource; never null. */ - URL url; + protected URL url; /** mapping token for this resource; never null. */ - String name; + protected String name; + protected PGFDataResourceImpl () { + } + public PGFDataResourceImpl (URL url, String name) { if (url == null) { throw new NullPointerException(); Modified: trunk/src/net/petraframe/res/data/PGFResourceManagerImpl.java =================================================================== --- trunk/src/net/petraframe/res/data/PGFResourceManagerImpl.java 2011-06-13 21:33:40 UTC (rev 4) +++ trunk/src/net/petraframe/res/data/PGFResourceManagerImpl.java 2011-06-15 01:54:46 UTC (rev 5) @@ -166,8 +166,12 @@ @SuppressWarnings("unchecked") private void fireChangeEvent () { + List<ChangeListener> copy; + if (changeListeners != null) { - List<ChangeListener> copy = (List<ChangeListener>)changeListeners.clone(); + synchronized (changeListeners) { + copy = (List<ChangeListener>)changeListeners.clone(); + } ChangeEvent event = new ChangeEvent(this); for (ChangeListener l : copy) { l.stateChanged(event); Modified: trunk/src/net/petraframe/res/sound/PGFSound.java =================================================================== --- trunk/src/net/petraframe/res/sound/PGFSound.java 2011-06-13 21:33:40 UTC (rev 4) +++ trunk/src/net/petraframe/res/sound/PGFSound.java 2011-06-15 01:54:46 UTC (rev 5) @@ -14,7 +14,8 @@ * <p>Note that the returned list of sounds may contain * elements which are again complex sounds. Note also that a return * value not null does not imply that the returned list contains - * more than one element. + * more than one element. The returned list is a shallow clone and may + * get modified by the caller. * * @return <code>List of PGFSound</code> or <b>null</b> if this sound is not a complex */ @@ -25,7 +26,8 @@ * single sound object. Otherwise <b>this</b> sound is returned. * <p>It is always true that the returned sound produces the same data stream, * or the same loading error, as <b>this</b> sound does. If a different object - * is returned, it will hold a different resource name (token). + * is returned, it will likely, but not necessarily, hold a different resource + * name (key) as the sound will belong to a different name space. * * @return PGFSound this sound as a single sound (may be identical object) */ @@ -41,23 +43,22 @@ public boolean isComplex (); /** - * Convenience method for retrieving a variant of this sound - * if such a variant is defined (i.e. if this sound is a complex sound with - * more than one true element sound). If no variant is defined, <b>this</b> - * sound is returned. - * <p>The contract is that, if this sound is complex and holds more than one - * element, the returned sound is a single sound taken at random from the list - * of available element sounds and is different from the sound that has been - * returned by this method on its most recent call on this sound object. + * Method to modify the specialisation of this sound in case it is a complex + * sound. If this sound is a single sound or the complex holds only one + * element, no modification occurs. + * <p>The contract is that a new single sound assignment (specialisation) + * will be a random selection from the rest of the element set, excluding + * the current assignment. * - * @return <code>PGFSound</code> a single sound + * @return boolean, <b>true</b> if and only if sound specialisation has changed */ -public PGFSound getAlternate (); +public boolean skipElement (); /** * Returns the list of element sounds of this sound, if it is complex, * in a random order. Repeated calls to this method may likely produce - * different sorting orders of the same set of sounds. + * different sorting orders of the same set of sounds. The returned list + * is a shallow clone and may get modified by the caller. * * @return <code>List of PGFSound</code> */ @@ -66,7 +67,8 @@ /** * Returns the list of all reachable single sounds of this sound, if it is complex, * in a random order. Repeated calls to this method may likely produce - * different sorting orders of the same set of sounds. + * different sorting orders of the same set of sounds. The returned list is a shallow + * clone and may get modified by the caller. * <p>Other than <code>getShuffle()</code> this method performs a full tree scan * into the elements of this sound and all returned list elements are guaranteed * to be single sounds. Added: trunk/src/net/petraframe/res/sound/PGFSoundImpl.java =================================================================== --- trunk/src/net/petraframe/res/sound/PGFSoundImpl.java (rev 0) +++ trunk/src/net/petraframe/res/sound/PGFSoundImpl.java 2011-06-15 01:54:46 UTC (rev 5) @@ -0,0 +1,247 @@ +package net.petraframe.res.sound; + +import java.net.URL; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Random; + +import net.petraframe.res.data.PGFDataResource; +import net.petraframe.res.data.PGFDataResourceImpl; + +public class PGFSoundImpl extends PGFDataResourceImpl implements PGFSound { + + private static final Random random = new Random(); + + ArrayList<PGFSound> complex; + + boolean isComplex = false; + + /** + * Creates a single (non-complex) sound. + * + * @param url <code>URL</code> sound resource location + * @param name String name of the sound (key) + */ + public PGFSoundImpl (URL url, String name) { + super(url, name); + } + + /** + * Creates a single (non-complex) sound from a given data resource. + * + * @param resource <code>PGFDataResource</code> sound resource + */ + public PGFSoundImpl (PGFDataResource resource) { + this(resource.getResourceURL(), resource.getName()); + } + + + /** + * Creates a complex sound from a list of sound resources. + * + * @param dlist List of <code>PGFDataResource</code> + */ + public PGFSoundImpl (List<PGFDataResource> dlist) { + // check validity of parameter + if (dlist.size() < 1) { + throw new IllegalArgumentException("empty resource list"); + } + + // create sound list from data list + ArrayList<PGFSound> slist = new ArrayList<PGFSound>(dlist.size()); + for (PGFDataResource res : dlist) { + PGFSound sound = new PGFSoundImpl(res); + if (!slist.contains(sound)) { + slist.add(sound); + } + } + + // initialise complex list + initComplex(slist); + } + + /** + * Creates a complex sound from a list of sound resources. + * The length of <code>names</code> must be the same as of <code>urls</code> + * and elements of the lists may not be <b>null</b>. Only as + * many resources will be listed as there are different names + * in the names list. If there are identical names in the names + * list, the first occurrence counts. + * + * @param urls List of <ode>URL</code> + * @param names List of <ode>String</code> + */ + public PGFSoundImpl (List<URL> urls, List<String> names) { + // check validity of parameters + if (urls == null | names == null) { + throw new NullPointerException(); + } + if (urls.size() != names.size()) { + throw new IllegalArgumentException("urls and names must be of same size"); + } + + // create the complex sound list + ArrayList<PGFSound>list = new ArrayList<PGFSound>(urls.size()); + int index = 0; + for (URL u : urls) { + if (u == null) { + throw new IllegalArgumentException("parameter urls: illegal null value for URL, index = " + index); + } + PGFSoundImpl sound = new PGFSoundImpl(u, names.get(index)); + if (!list.contains(sound)) { + list.add(sound); + } + index++; + } + + // initialise complex list + initComplex(list); + } + + /** Initialises this object's complex sound list and assigns a random + * specialisation sound. + * + * @param list ArrayList of <code>PGFSound</code>, sound list to assign + */ + private void initComplex (ArrayList<PGFSound> list) { + complex = list; + isComplex = true; + + // single out a specialisation (single sound aspect) + synchronized(random) { + int index = random.nextInt(complex.size()); + PGFSound s = list.get(index); + this.url = s.getResourceURL(); + this.name = s.getName(); + } + } + + @SuppressWarnings("unchecked") + @Override + public List<PGFSound> getList() { + if (isComplex()) { + return (ArrayList<PGFSound>)complex.clone(); + } + return null; + } + + @Override + public PGFSound getSingle() { + return isComplex() ? new PGFSoundImpl(url, name) : this; + } + + @Override + public boolean isComplex() { + return isComplex; + } + + @Override + public boolean skipElement() { + List<PGFSound> list = getList(); + if (list != null && list.size() > 1) { + // reduce the list with the current assignment + PGFSound assignedSound = this.getSingle(); + list.remove(assignedSound); + + // pick a random element (next assignment) + synchronized(random) { + int i = random.nextInt(list.size()); + PGFSound sound = list.get(i); + this.url = sound.getResourceURL(); + this.name = sound.getName(); + } + return true; + } + return false; + } + + private List<PGFSound> randomized (List<PGFSound> sounds) { + List<PGFSound> s1 = new ArrayList<PGFSound>(sounds); + List<PGFSound> list = new ArrayList<PGFSound>(sounds.size()); + synchronized(random) { + while (s1.size() > 0) { + int i = random.nextInt(s1.size()); + PGFSound sound = s1.get(i); + list.add(sound); + s1.remove(i); + } + } + return list; + } + + @Override + public List<PGFSound> getShuffle() { + List<PGFSound> list; + if (isComplex()) { + list = randomized(getList()); + } else { + list = new LinkedList<PGFSound>(); + list.add(this); + } + return list; + } + + @Override + public List<PGFSound> getDeepShuffle() { + List<PGFSound> list; + if (isComplex()) { + // create a list of all "deep down" single sounds (recursive function) + list = new ArrayList<PGFSound>(); + for (PGFSound sound : complex) { + if (sound.isComplex()) { + list.addAll(sound.getDeepShuffle()); + } else { + list.add(sound); + } + } + // randomize the list + list = randomized(list); + } else { + list = new LinkedList<PGFSound>(); + list.add(this); + } + return list; + } + + /** + * Creates a shallow clone of this sound. + * @return <code>PGFSound</code> + */ + @SuppressWarnings("unchecked") + @Override + protected PGFSound clone() { + try { + PGFSoundImpl c =(PGFSoundImpl)super.clone(); + if (complex != null) { + c.complex = (ArrayList<PGFSound>)this.complex.clone(); + } + return c; + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + return null; + } + } + + /** + * Two sounds are equal if and only if they share the same complex + * status and the same name. + * + * @return boolean + */ + @Override + public boolean equals(Object obj) { + if (obj != null) { + PGFSoundImpl s = (PGFSoundImpl)obj; + return s.isComplex() == this.isComplex() && + s.getName().equals(this.getName()); + } + return false; + } + + @Override + public int hashCode() { + return super.name.hashCode() | (isComplex?357:0); + } + +} Property changes on: trunk/src/net/petraframe/res/sound/PGFSoundImpl.java ___________________________________________________________________ Added: svn:mime-type + text/x-java Added: svn:eol-style + native Added: trunk/src/net/petraframe/res/sound/PGFSoundManagerImpl.java =================================================================== --- trunk/src/net/petraframe/res/sound/PGFSoundManagerImpl.java (rev 0) +++ trunk/src/net/petraframe/res/sound/PGFSoundManagerImpl.java 2011-06-15 01:54:46 UTC (rev 5) @@ -0,0 +1,78 @@ +package net.petraframe.res.sound; + +import java.util.ArrayList; +import java.util.List; + +import net.petraframe.res.data.PGFDataResource; +import net.petraframe.res.data.PGFResourceManager; + +public class PGFSoundManagerImpl implements PGFSoundManager { + + private List<PGFResourceManager> resourceMans = new ArrayList<PGFResourceManager>(); + + /** + * Creates a new sound manager with reference to a single resource manager. + * + * @param resMan <code>PGFResourceManager</code> the referenced resource manager + */ + public PGFSoundManagerImpl (PGFResourceManager resMan) { + if (resMan == null) { + throw new NullPointerException(); + } + resourceMans.add(resMan); + } + + @Override + public PGFSound getSound(String key) { + PGFSound sound = null; + + // first look into the complex resource maps + List<PGFDataResource> list = getListResource(key); + if (list != null) { + sound = new PGFSoundImpl(list); + } + + // second: look into single resources maps + PGFDataResource res = getSingleResource(key); + if (res != null) { + sound = new PGFSoundImpl(res); + } + + return sound; + } + + /** + * Checks through all registered resource managers and returns the first occurrence of + * a resource list of the given name. + * + * @param name String resource list name + * @return List of <code>PGFDataResource</code> + */ + private List<PGFDataResource> getListResource (String name) { + for (PGFResourceManager man : resourceMans) { + List<PGFDataResource> list = man.getListResource(name); + if (list != null) { + return list; + } + } + return null; + } + + /** + * Checks through all registered resource managers and returns the first occurrence of + * a single resource of the given name. + * + * @param name String single resource name + * @return <code>PGFDataResource</code> + */ + private PGFDataResource getSingleResource (String name) { + for (PGFResourceManager man : resourceMans) { + PGFDataResource resource = man.getResource(name); + if (resource != null) { + return resource; + } + } + return null; + } + +} Property changes on: trunk/src/net/petraframe/res/sound/PGFSoundManagerImpl.java ___________________________________________________________________ Added: svn:mime-type + text/x-java Added: svn:eol-style + native This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ja...@us...> - 2011-06-13 21:33:46
|
Revision: 4 http://petraframe.svn.sourceforge.net/petraframe/?rev=4&view=rev Author: janet-h Date: 2011-06-13 21:33:40 +0000 (Mon, 13 Jun 2011) Log Message: ----------- ResourceManager improvements Modified Paths: -------------- trunk/src/net/petraframe/res/data/PGFResourceManager.java trunk/src/net/petraframe/res/data/PGFResourceManagerImpl.java Added Paths: ----------- trunk/src/net/petraframe/res/sound/PGFSoundManager.java Modified: trunk/src/net/petraframe/res/data/PGFResourceManager.java =================================================================== --- trunk/src/net/petraframe/res/data/PGFResourceManager.java 2011-06-11 09:36:50 UTC (rev 3) +++ trunk/src/net/petraframe/res/data/PGFResourceManager.java 2011-06-13 21:33:40 UTC (rev 4) @@ -1,9 +1,11 @@ package net.petraframe.res.data; import java.io.IOException; +import java.net.URL; import java.util.List; import javax.swing.ImageIcon; +import javax.swing.event.ChangeListener; public interface PGFResourceManager { @@ -13,7 +15,7 @@ * to cause any IO-exception. If the resource is not defined, not found * or otherwise not available, <b>null</b> is returned. * - * @param name String the token for the resource + * @param name String the key for the resource * @return <code>PGFDataResource</code> or <b>null</b> */ public PGFDataResource getResource (String name); @@ -23,18 +25,36 @@ * Though depending on the implementation, this method is not expected * to cause any IO-exception. If the resource list is not defined, not found * or otherwise not available, <b>null</b> is returned. - * <p>Note that resource lists have a mapping separate from single resources. + * <p>Note that resource lists have a mapping separate from single resources, + * hence occupy a separate name space. * - * @param name String the token for the resource list + * @param name String the key for the resource list * @return List of <code>PGFDataResource</code> or <b>null</b> */ public List<PGFDataResource> getListResource (String name); /** - * Invalidates the current mapping of tokens into resources. + * Adds a listener for change events of this manager. Change events + * are issued when the VALIDITY property of the resource mappings + * changes (valid/invalid), or when the set of mappings has been + * modified. + * + * @param listener <code>ChangeListener</code> + */ +public void addChangeListener (ChangeListener listener); + +/** + * Removes a change listener from this manager. + * + * @param listener + */ +public void removeChangeListener (ChangeListener listener); + +/** + * Invalidates the current mapping of keys into resources. * After call to this method, and prior to a reconstruction - * having taken place, all calls to retrieve a resource - * should return <b>null</b>. + * having taken place (<code>validate()</code>), all calls + * to retrieve a resource should return <b>null</b>. * <p>Depending on the implementation this action may include * physical destruction of external data files. */ @@ -44,32 +64,58 @@ * If resource mapping of this manager is currently invalid * (call to <code>invalidateResources()</code> then action * is taken up to restore validity. This may cause a lengthy operation - * and may involve operations on external media. This method + * and involves analysing external data. This method * blocks until all required operations are completed or a failure * has occurred. * - * @return boolean <b>true</b> if and only if the resulting state - * is a valid resource mapping. + * @param sources List of <code>URL</code> the source files that define + * the mappings (special format) + * @throws Exception if a breaking error occurred during analysing of the sources */ -public boolean validateResources (); +public void validateResources (List<URL> sources) throws Exception; /** + * If resource mapping of this manager is currently invalid + * (call to <code>invalidateResources()</code> then action + * is taken up to restore validity by using the same list of + * source files which were transmitted in the most recent call + * to <code>validateResources (List<URL> sources)</code>. This + * may cause a lengthy operation. This method + * blocks until all required operations are completed or a failure + * has occurred. If there is no list of sources available, an + * exception is thrown. + * + * @throws Exception if a breaking error occurred during analysing of the sources + */ +public void validateResources () throws Exception; + +/** + * Returns whether this manager holds the VALIDITY == true property + * concerning its resource mappings. + * + * @return boolean <b>true</b> == valid mappings + */ +public boolean isValidMappings (); + +/** * Returns a text which gives a human readable report on the physical - * availability of all resources defined in the mapping. + * availability of all resources defined in the resource mappings. * + * @param onlyMissing boolean, if <b>true</b> only missing or inaccessible + * resources are reported * @return String report text (line breaks according to native setting) */ -public String reportOnMapping (); +public String reportOnMapping (boolean onlyMissing); /** * Returns a Swing <code>ImageIcon</code> from the data of the (single) * resource specified by name. If the resource is not defined, not found * or otherwise not available, <b>null</b> is returned. * - * @param token String resource name + * @param name String resource key * @return <code>javax.swing.ImageIcon</code> * @throws IOException */ -public ImageIcon getImageIcon (String token) throws IOException; +public ImageIcon getImageIcon (String name) throws IOException; } Modified: trunk/src/net/petraframe/res/data/PGFResourceManagerImpl.java =================================================================== --- trunk/src/net/petraframe/res/data/PGFResourceManagerImpl.java 2011-06-11 09:36:50 UTC (rev 3) +++ trunk/src/net/petraframe/res/data/PGFResourceManagerImpl.java 2011-06-13 21:33:40 UTC (rev 4) @@ -1,28 +1,32 @@ package net.petraframe.res.data; import java.io.IOException; -import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import javax.swing.ImageIcon; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; public class PGFResourceManagerImpl implements PGFResourceManager { private HashMap<String, URL> baseMap = new HashMap<String, URL> (); private HashMap<String, List<String>> complMap = new HashMap<String, List<String>> (); + + private List<URL> mappingSources; + private ArrayList<ChangeListener> changeListeners; private boolean isValid = false; @Override - public ImageIcon getImageIcon (String token) throws IOException { - PGFDataResource res = getResource(token); + public ImageIcon getImageIcon (String name) throws IOException { + PGFDataResource res = getResource(name); if (res != null) { byte[] data = res.getContent(); - ImageIcon icon = new ImageIcon(data, token); + ImageIcon icon = new ImageIcon(data, name); return icon; } return null; @@ -69,18 +73,106 @@ isValid = false; baseMap.clear(); complMap.clear(); + fireChangeEvent(); } @Override - public synchronized String reportOnMapping() { - // TODO Auto-generated method stub + public synchronized String reportOnMapping(boolean onlyMissing) { + // TODO mapping report return null; } @Override - public synchronized boolean validateResources() { - // TODO Auto-generated method stub - return false; + public synchronized void validateResources(List<URL> sources) throws Exception { + Exception ex = null; + + // use parameter source files or previous definition of these files + if (sources == null & mappingSources == null) { + throw new NullPointerException("missing mapping source files definition"); + } + mappingSources = sources != null ? sources : mappingSources; + + for (URL url : mappingSources) { + try { + analyseMappings(url); + } catch (Exception e) { + if (ex == null) { + ex = e; + } + } + } + + // throw an exception if there was an error during analysing files + if (ex != null) { + throw ex; + } + + // TODO check if we don't need an error tolerant approach to validity, perhaps parameter option? Perhaps return a list of exceptions? + // valid + isValid = true; + fireChangeEvent(); } + @Override + public void validateResources() throws Exception { + validateResources(null); + } + + @Override + public boolean isValidMappings() { + return isValid; + } + + /** + * Analyses a mapping definition file under the given url + * and fills mappings into both single and complex resource maps. + * + * @param url URL of the mapping file + * @throws Exception + */ + private void analyseMappings (URL url) throws Exception { + // TODO Analyse an external mapping definition file + + + } + + @Override + public synchronized void addChangeListener(ChangeListener listener) { + if (listener != null) { + // late creation of list + if (changeListeners == null) { + changeListeners = new ArrayList<ChangeListener>(); + } + // synchronized list modification + synchronized(changeListeners) { + if (listener != null && !changeListeners.contains(listener)) { + changeListeners.add(listener); + } + } + } + } + + @Override + public void removeChangeListener(ChangeListener listener) { + if (changeListeners != null & listener != null) { + // synchronized list modification + synchronized(changeListeners) { + if (listener != null) { + changeListeners.remove(listener); + } + } + } + } + + @SuppressWarnings("unchecked") + private void fireChangeEvent () { + if (changeListeners != null) { + List<ChangeListener> copy = (List<ChangeListener>)changeListeners.clone(); + ChangeEvent event = new ChangeEvent(this); + for (ChangeListener l : copy) { + l.stateChanged(event); + } + } + } + } Added: trunk/src/net/petraframe/res/sound/PGFSoundManager.java =================================================================== --- trunk/src/net/petraframe/res/sound/PGFSoundManager.java (rev 0) +++ trunk/src/net/petraframe/res/sound/PGFSoundManager.java 2011-06-13 21:33:40 UTC (rev 4) @@ -0,0 +1,13 @@ +package net.petraframe.res.sound; + +public interface PGFSoundManager { + +/** + * Returns a sound ticket for a name. + * + * @param key String, the name of the sound (in the resource mappings) + * @return <code>PGFSound</code> + */ +public PGFSound getSound (String key); + +} Property changes on: trunk/src/net/petraframe/res/sound/PGFSoundManager.java ___________________________________________________________________ Added: svn:mime-type + text/x-java Added: svn:eol-style + native This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ja...@us...> - 2011-06-11 09:36:57
|
Revision: 3 http://petraframe.svn.sourceforge.net/petraframe/?rev=3&view=rev Author: janet-h Date: 2011-06-11 09:36:50 +0000 (Sat, 11 Jun 2011) Log Message: ----------- added classes for resource handling Modified Paths: -------------- trunk/src/net/petraframe/res/data/PGFDataResource.java trunk/src/net/petraframe/res/sound/PGFSound.java Added Paths: ----------- trunk/src/net/petraframe/res/data/PGFDataResourceImpl.java trunk/src/net/petraframe/res/data/PGFResourceManager.java trunk/src/net/petraframe/res/data/PGFResourceManagerImpl.java Property Changed: ---------------- trunk/ Property changes on: trunk ___________________________________________________________________ Added: svn:ignore + .settings Modified: trunk/src/net/petraframe/res/data/PGFDataResource.java =================================================================== --- trunk/src/net/petraframe/res/data/PGFDataResource.java 2011-06-09 12:51:26 UTC (rev 2) +++ trunk/src/net/petraframe/res/data/PGFDataResource.java 2011-06-11 09:36:50 UTC (rev 3) @@ -1,17 +1,36 @@ package net.petraframe.res.data; import java.io.BufferedInputStream; +import java.io.IOException; import java.net.URL; public interface PGFDataResource { - public BufferedInputStream getDataStream (); + public BufferedInputStream getDataStream () throws IOException; + public BufferedInputStream getDataStream (int bufferSize) throws IOException; + + /** + * Returns the complete data of this resource as a single block (array of + * bytes). If the size of the resource exceeds the maximum possible array + * size, an IOException is thrown. + * + * @return array of byte + * @throws IOException + */ + public byte[] getContent () throws IOException; + public URL getResourceURL (); public URL getPackageURL (); public boolean setCachable (boolean v); + + /** Returns the token which has been assigned to this resource. (This is + * the token that is used to fetch from the resource manager.) + * + * @return String resource token + */ + public String getName (); - } Added: trunk/src/net/petraframe/res/data/PGFDataResourceImpl.java =================================================================== --- trunk/src/net/petraframe/res/data/PGFDataResourceImpl.java (rev 0) +++ trunk/src/net/petraframe/res/data/PGFDataResourceImpl.java 2011-06-11 09:36:50 UTC (rev 3) @@ -0,0 +1,79 @@ +package net.petraframe.res.data; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +public class PGFDataResourceImpl implements PGFDataResource { + + public static int readBufferSize = 2048 * 4; + + /** URL for external data of this resource; never null. */ + URL url; + + /** mapping token for this resource; never null. */ + String name; + + public PGFDataResourceImpl (URL url, String name) { + if (url == null) { + throw new NullPointerException(); + } + this.url = url; + this.name = name == null ? "" : name; + } + + @Override + public BufferedInputStream getDataStream() throws IOException { + return getDataStream(0); + } + + @Override + public BufferedInputStream getDataStream(int bufferSize) throws IOException { + InputStream in = url.openStream(); + return bufferSize == 0 ? new BufferedInputStream(in) : + new BufferedInputStream(in, bufferSize); + } + + @Override + public byte[] getContent() throws IOException { + // prepare data streams + InputStream in = url.openStream(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + + // transfer input stream data to byte array + int len; + byte[] buffer = new byte[readBufferSize]; + while ((len=in.read(buffer)) != -1 ) { + out.write(buffer, 0, len); + } + + // close input and return buffered data + in.close(); + return out.toByteArray(); + } + + @Override + public String getName() { + return name; + } + + @Override + public URL getPackageURL() { + // TODO Auto-generated method stub + return null; + } + + @Override + public URL getResourceURL() { + return url; + } + + @Override + public boolean setCachable(boolean v) { + // TODO Auto-generated method stub + return false; + } + +} Property changes on: trunk/src/net/petraframe/res/data/PGFDataResourceImpl.java ___________________________________________________________________ Added: svn:mime-type + text/x-java Added: svn:eol-style + native Added: trunk/src/net/petraframe/res/data/PGFResourceManager.java =================================================================== --- trunk/src/net/petraframe/res/data/PGFResourceManager.java (rev 0) +++ trunk/src/net/petraframe/res/data/PGFResourceManager.java 2011-06-11 09:36:50 UTC (rev 3) @@ -0,0 +1,75 @@ +package net.petraframe.res.data; + +import java.io.IOException; +import java.util.List; + +import javax.swing.ImageIcon; + +public interface PGFResourceManager { + +/** + * Returns a resource ticket for the given resource name. + * Though depending on the implementation, this method is not expected + * to cause any IO-exception. If the resource is not defined, not found + * or otherwise not available, <b>null</b> is returned. + * + * @param name String the token for the resource + * @return <code>PGFDataResource</code> or <b>null</b> + */ +public PGFDataResource getResource (String name); + +/** + * Returns a ticket for a resource list for the given resource list name. + * Though depending on the implementation, this method is not expected + * to cause any IO-exception. If the resource list is not defined, not found + * or otherwise not available, <b>null</b> is returned. + * <p>Note that resource lists have a mapping separate from single resources. + * + * @param name String the token for the resource list + * @return List of <code>PGFDataResource</code> or <b>null</b> + */ +public List<PGFDataResource> getListResource (String name); + +/** + * Invalidates the current mapping of tokens into resources. + * After call to this method, and prior to a reconstruction + * having taken place, all calls to retrieve a resource + * should return <b>null</b>. + * <p>Depending on the implementation this action may include + * physical destruction of external data files. + */ +public void invalidateResources (); + +/** + * If resource mapping of this manager is currently invalid + * (call to <code>invalidateResources()</code> then action + * is taken up to restore validity. This may cause a lengthy operation + * and may involve operations on external media. This method + * blocks until all required operations are completed or a failure + * has occurred. + * + * @return boolean <b>true</b> if and only if the resulting state + * is a valid resource mapping. + */ +public boolean validateResources (); + +/** + * Returns a text which gives a human readable report on the physical + * availability of all resources defined in the mapping. + * + * @return String report text (line breaks according to native setting) + */ +public String reportOnMapping (); + +/** + * Returns a Swing <code>ImageIcon</code> from the data of the (single) + * resource specified by name. If the resource is not defined, not found + * or otherwise not available, <b>null</b> is returned. + * + * @param token String resource name + * @return <code>javax.swing.ImageIcon</code> + * @throws IOException + */ +public ImageIcon getImageIcon (String token) throws IOException; + +} Property changes on: trunk/src/net/petraframe/res/data/PGFResourceManager.java ___________________________________________________________________ Added: svn:mime-type + text/x-java Added: svn:eol-style + native Added: trunk/src/net/petraframe/res/data/PGFResourceManagerImpl.java =================================================================== --- trunk/src/net/petraframe/res/data/PGFResourceManagerImpl.java (rev 0) +++ trunk/src/net/petraframe/res/data/PGFResourceManagerImpl.java 2011-06-11 09:36:50 UTC (rev 3) @@ -0,0 +1,86 @@ +package net.petraframe.res.data; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import javax.swing.ImageIcon; + +public class PGFResourceManagerImpl implements PGFResourceManager { + + private HashMap<String, URL> baseMap = new HashMap<String, URL> (); + private HashMap<String, List<String>> complMap = new HashMap<String, List<String>> (); + + private boolean isValid = false; + + + @Override + public ImageIcon getImageIcon (String token) throws IOException { + PGFDataResource res = getResource(token); + if (res != null) { + byte[] data = res.getContent(); + ImageIcon icon = new ImageIcon(data, token); + return icon; + } + return null; + } + + @Override + public PGFDataResource getResource (String name) { + if (name != null & isValid) { + // lookup resource in basic map + URL url = baseMap.get(name); + if (url != null) { + // create and return a resource object + PGFDataResource res = new PGFDataResourceImpl(url, name); + return res; + } + } + return null; + } + + @Override + public List<PGFDataResource> getListResource(String name) { + if (name != null & isValid) { + // lookup resource list in complex map + List<String> nlist = complMap.get(name); + if (nlist != null) { + // create a resource list + List<PGFDataResource> rlist = new ArrayList<PGFDataResource>(); + for (String rname : nlist) { + PGFDataResource res = getResource(rname); + if (res != null) { + rlist.add(res); + } + } + // return the resource list + return rlist; + } + } + // return null if the list is not defined + return null; + } + + @Override + public synchronized void invalidateResources() { + isValid = false; + baseMap.clear(); + complMap.clear(); + } + + @Override + public synchronized String reportOnMapping() { + // TODO Auto-generated method stub + return null; + } + + @Override + public synchronized boolean validateResources() { + // TODO Auto-generated method stub + return false; + } + +} Property changes on: trunk/src/net/petraframe/res/data/PGFResourceManagerImpl.java ___________________________________________________________________ Added: svn:mime-type + text/x-java Added: svn:eol-style + native Modified: trunk/src/net/petraframe/res/sound/PGFSound.java =================================================================== --- trunk/src/net/petraframe/res/sound/PGFSound.java 2011-06-09 12:51:26 UTC (rev 2) +++ trunk/src/net/petraframe/res/sound/PGFSound.java 2011-06-11 09:36:50 UTC (rev 3) @@ -20,6 +20,17 @@ */ public List <PGFSound> getList (); +/** Returns this sound as a single sound. If this sound is a complex sound + * then this method returns the current random specialisation as a new and + * single sound object. Otherwise <b>this</b> sound is returned. + * <p>It is always true that the returned sound produces the same data stream, + * or the same loading error, as <b>this</b> sound does. If a different object + * is returned, it will hold a different resource name (token). + * + * @return PGFSound this sound as a single sound (may be identical object) + */ +public PGFSound getSingle (); + /** * Whether this sound represents a complex sound. * (Equivalent to <code>getList() == null</code>) @@ -30,10 +41,10 @@ public boolean isComplex (); /** - * This is a convenience method for retrieving a variant of this sound + * Convenience method for retrieving a variant of this sound * if such a variant is defined (i.e. if this sound is a complex sound with - * more than one true element sound). If no variant is defined, the same sound - * is returned. + * more than one true element sound). If no variant is defined, <b>this</b> + * sound is returned. * <p>The contract is that, if this sound is complex and holds more than one * element, the returned sound is a single sound taken at random from the list * of available element sounds and is different from the sound that has been @@ -41,6 +52,27 @@ * * @return <code>PGFSound</code> a single sound */ -public PGFSound getNext (); +public PGFSound getAlternate (); +/** + * Returns the list of element sounds of this sound, if it is complex, + * in a random order. Repeated calls to this method may likely produce + * different sorting orders of the same set of sounds. + * + * @return <code>List of PGFSound</code> + */ +public List <PGFSound> getShuffle (); + +/** + * Returns the list of all reachable single sounds of this sound, if it is complex, + * in a random order. Repeated calls to this method may likely produce + * different sorting orders of the same set of sounds. + * <p>Other than <code>getShuffle()</code> this method performs a full tree scan + * into the elements of this sound and all returned list elements are guaranteed + * to be single sounds. + * + * @return <code>List of PGFSound</code> + */ +public List <PGFSound> getDeepShuffle (); + } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ja...@us...> - 2011-06-09 12:51:32
|
Revision: 2 http://petraframe.svn.sourceforge.net/petraframe/?rev=2&view=rev Author: janet-h Date: 2011-06-09 12:51:26 +0000 (Thu, 09 Jun 2011) Log Message: ----------- added 2 basic resource classes Added Paths: ----------- trunk/.classpath trunk/.project trunk/lib/ trunk/src/ trunk/src/net/ trunk/src/net/petraframe/ trunk/src/net/petraframe/res/ trunk/src/net/petraframe/res/data/ trunk/src/net/petraframe/res/data/PGFDataResource.java trunk/src/net/petraframe/res/sound/ trunk/src/net/petraframe/res/sound/PGFSound.java trunk/src/net/petraframe/res/text/ Added: trunk/.classpath =================================================================== --- trunk/.classpath (rev 0) +++ trunk/.classpath 2011-06-09 12:51:26 UTC (rev 2) @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/> + <classpathentry kind="output" path="classes"/> +</classpath> Property changes on: trunk/.classpath ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:eol-style + native Added: trunk/.project =================================================================== --- trunk/.project (rev 0) +++ trunk/.project 2011-06-09 12:51:26 UTC (rev 2) @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>PetraGameFrame</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> Property changes on: trunk/.project ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:eol-style + native Added: trunk/src/net/petraframe/res/data/PGFDataResource.java =================================================================== --- trunk/src/net/petraframe/res/data/PGFDataResource.java (rev 0) +++ trunk/src/net/petraframe/res/data/PGFDataResource.java 2011-06-09 12:51:26 UTC (rev 2) @@ -0,0 +1,17 @@ +package net.petraframe.res.data; + +import java.io.BufferedInputStream; +import java.net.URL; + +public interface PGFDataResource { + + public BufferedInputStream getDataStream (); + + public URL getResourceURL (); + + public URL getPackageURL (); + + public boolean setCachable (boolean v); + + +} Property changes on: trunk/src/net/petraframe/res/data/PGFDataResource.java ___________________________________________________________________ Added: svn:mime-type + text/x-java Added: svn:eol-style + native Added: trunk/src/net/petraframe/res/sound/PGFSound.java =================================================================== --- trunk/src/net/petraframe/res/sound/PGFSound.java (rev 0) +++ trunk/src/net/petraframe/res/sound/PGFSound.java 2011-06-09 12:51:26 UTC (rev 2) @@ -0,0 +1,46 @@ +package net.petraframe.res.sound; + +import java.util.List; + +import net.petraframe.res.data.PGFDataResource; + +public interface PGFSound extends PGFDataResource { + +/** + * If this sound is a pseudo sound consisting of a complex sound, + * the list of sounds defining this sound is returned. If + * this sound is not a complex sound (hence represents only a single + * sound), <b>null</b> is returned. + * <p>Note that the returned list of sounds may contain + * elements which are again complex sounds. Note also that a return + * value not null does not imply that the returned list contains + * more than one element. + * + * @return <code>List of PGFSound</code> or <b>null</b> if this sound is not a complex + */ +public List <PGFSound> getList (); + +/** + * Whether this sound represents a complex sound. + * (Equivalent to <code>getList() == null</code>) + * @see getList() + * + * @return boolean <b>true</b> if this sound is complex + */ +public boolean isComplex (); + +/** + * This is a convenience method for retrieving a variant of this sound + * if such a variant is defined (i.e. if this sound is a complex sound with + * more than one true element sound). If no variant is defined, the same sound + * is returned. + * <p>The contract is that, if this sound is complex and holds more than one + * element, the returned sound is a single sound taken at random from the list + * of available element sounds and is different from the sound that has been + * returned by this method on its most recent call on this sound object. + * + * @return <code>PGFSound</code> a single sound + */ +public PGFSound getNext (); + +} Property changes on: trunk/src/net/petraframe/res/sound/PGFSound.java ___________________________________________________________________ Added: svn:mime-type + text/x-java Added: svn:eol-style + native This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |