summaryrefslogtreecommitdiff
path: root/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceManager.java
diff options
context:
space:
mode:
authorBenjamin Culkin <scorpress@gmail.com>2024-05-19 17:56:33 -0400
committerBenjamin Culkin <scorpress@gmail.com>2024-05-19 17:56:33 -0400
commitaedc34d55462a75e329bbf342251ff6504cd117e (patch)
treebcc8f1f2352582717b484df302aeea6696b8f000 /projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceManager.java
Initial import from SVN
Diffstat (limited to 'projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceManager.java')
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceManager.java489
1 files changed, 489 insertions, 0 deletions
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceManager.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceManager.java
new file mode 100644
index 0000000..c69c9db
--- /dev/null
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceManager.java
@@ -0,0 +1,489 @@
+/*
+Wotonomy: OpenStep design patterns for pure Java applications.
+Copyright (C) 2000 Blacksmith, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, see http://www.gnu.org
+*/
+
+package net.wotonomy.web;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Map;
+
+import net.wotonomy.foundation.NSArray;
+import net.wotonomy.foundation.NSData;
+import net.wotonomy.foundation.NSKeyValueCoding;
+import net.wotonomy.foundation.NSMutableDictionary;
+import net.wotonomy.foundation.internal.PropertyListParser;
+
+/**
+* Manages all resources vended by the application.
+*
+* @author michael@mpowers.net
+* @author $Author: cgruber $
+* @version $Revision: 905 $
+*/
+public class WOResourceManager
+{
+ private NSMutableDictionary resourceCache;
+ private NSMutableDictionary dynamicDataCache;
+ private NSMutableDictionary stringTableCache;
+ private Map localeCache; // used for wo-style i18n
+ private Locale californiaLocale; // used for wo-style i18n
+
+ /**
+ * Constructor is only accessible to subclasses.
+ */
+ protected WOResourceManager()
+ {
+ resourceCache = new NSMutableDictionary();
+ dynamicDataCache = new NSMutableDictionary();
+ stringTableCache = new NSMutableDictionary();
+ localeCache = new HashMap();
+ californiaLocale = new Locale( "en", "US" );
+ localeCache.put( "en", californiaLocale );
+ }
+
+ /**
+ * Returns the raw data corresponding to the specified resource.
+ * Any data retrieved by this method will be placed in the
+ * resource manager's global cache.
+ */
+ public byte[] bytesForResourceNamed(String aFileName,
+ String aFrameworkName,
+ NSArray aLanguagesList)
+ {
+ String mash = aFileName + aFrameworkName;
+ if ( aLanguagesList != null )
+ {
+ mash = mash + aLanguagesList.componentsJoinedByString(":");
+ }
+
+ byte[] result = (byte[]) resourceCache.objectForKey( mash );
+ if ( result == null )
+ {
+ InputStream input = inputStreamForResourceNamed(
+ aFileName, aFrameworkName, aLanguagesList );
+ if ( input != null )
+ {
+ try
+ {
+ int c;
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ while ( ( c = input.read() ) != -1 )
+ {
+ output.write( c );
+ }
+ output.flush();
+ input.close();
+ output.close();
+ result = output.toByteArray();
+ synchronized ( resourceCache )
+ {
+ resourceCache.setObjectForKey( result, mash );
+ }
+ }
+ catch ( Throwable t )
+ {
+ System.err.println( "WOResourceManager: Error reading bytes: " + aFileName );
+ t.printStackTrace();
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns the content type corresponding to the specified resource.
+ * This implementation recognizes gif, jpg, png, html, and xml extensions.
+ * Otherwise, "text/plain" is returned.
+ */
+ public String contentTypeForResourceNamed(String aResourcePath)
+ {
+ if ( aResourcePath.endsWith( ".gif" ) ) return "image/gif";
+ if ( aResourcePath.endsWith( ".jpg" ) ) return "image/jpeg";
+ if ( aResourcePath.endsWith( ".png" ) ) return "image/png";
+ if ( aResourcePath.endsWith( ".html" ) ) return "text/html";
+ if ( aResourcePath.endsWith( ".xml" ) ) return "text/xml";
+ return "text/plain";
+ }
+
+ /**
+ * Returns a url to be used when errors occur while retrieving a resource.
+ */
+ public String errorMessageUrlForResourceNamed(String aResourceName,
+ String aFrameworkName)
+ {
+ if ( aResourceName == null ) aResourceName = "null";
+ if ( aFrameworkName == null )
+ {
+ return "/ERROR/NOT_FOUND/app=" +
+ WOApplication.application().name() +
+ "/filename=" + aResourceName;
+ }
+ else
+ {
+ return "/ERROR/NOT_FOUND/framework=" +
+ aFrameworkName + "/filename=" + aResourceName;
+ }
+
+ }
+
+ /**
+ * Clears all cached system-wide resource data.
+ */
+ public void flushDataCache()
+ {
+ synchronized ( resourceCache )
+ {
+ resourceCache.removeAllObjects();
+ }
+ synchronized ( dynamicDataCache )
+ {
+ dynamicDataCache.removeAllObjects();
+ }
+ synchronized ( stringTableCache )
+ {
+ stringTableCache.removeAllObjects();
+ }
+ }
+
+ /**
+ * Returns the file-system path for the specified resource.
+ * Deprecated and not implemented.
+ * @deprecated Use inputStreamForResourceNamed instead.
+ */
+ public String pathForResourceNamed(String aResourceName,
+ String aFrameworkName,
+ NSArray aLanguagesList)
+ {
+ throw new RuntimeException( "ResourceManager.pathForResourceNamed: deprecated" );
+ }
+
+ /**
+ * Removes the data from the dynamic data cache for the specified session.
+ * If aSession is null, the data is removed from the application-wide
+ * data cache.
+ */
+ public void removeDataForKey(String aKey,
+ WOSession aSession)
+ {
+ if ( aSession != null )
+ {
+ if ( aSession.dynamicDataCache != null )
+ {
+ aSession.dynamicDataCache.removeObjectForKey( aKey );
+ }
+ }
+ else
+ {
+ synchronized ( dynamicDataCache )
+ {
+ dynamicDataCache.removeObjectForKey( aKey );
+ }
+ }
+ }
+
+ /**
+ * Sets the data in the dynamic data cache for the specified session.
+ * If aSession is null, the data is placed in the application-wide
+ * data cache. If the key is a system-generated key, the data will
+ * be removed by calling removeData() the next time it is requested.
+ */
+ public void setData(NSData someData,
+ String key,
+ String type,
+ WOSession aSession)
+ {
+ if ( aSession != null )
+ {
+ if ( aSession.dynamicDataCache != null )
+ {
+ aSession.dynamicDataCache.setObjectForKey(
+ new TypedData( type, someData ), key );
+ }
+ }
+ else
+ {
+ synchronized ( dynamicDataCache )
+ {
+ dynamicDataCache.setObjectForKey(
+ new TypedData( type, someData ), key );
+ }
+ }
+ }
+
+ /**
+ * Returns a localized string from a property list for
+ * a given key. If the key doesn't exist, aDefaultValue
+ * is returned.
+ */
+ public String stringForKey(String aKey,
+ String aFileName,
+ String aDefaultValue,
+ String aFrameworkName,
+ NSArray aLanguagesList)
+ {
+
+ String mash = aFileName + aFrameworkName;
+ if ( aLanguagesList != null )
+ {
+ mash = mash + aLanguagesList.componentsJoinedByString(":");
+ }
+
+ Object table = stringTableCache.objectForKey( mash );
+ if ( table == null )
+ {
+ try
+ {
+ InputStream input = (InputStream) inputStreamForResourceNamed(
+ aFileName, aFrameworkName, aLanguagesList);
+ if ( input != null )
+ {
+ Reader reader =
+ new BufferedReader(new InputStreamReader(input));
+ table = PropertyListParser.propertyListFromReader( reader );
+ synchronized ( stringTableCache )
+ {
+ stringTableCache.setObjectForKey( table, mash );
+ }
+ }
+ }
+ catch ( IOException ioe )
+ {
+ System.err.println( "WOResourceManager: error reading: " + aFileName );
+ ioe.printStackTrace();
+ }
+ catch ( Throwable t )
+ {
+ // could not parse
+ System.err.println( "WOResourceManager: could not parse: " + aFileName );
+ System.err.println( t );
+ }
+ }
+
+ Object result = null;
+ if ( table != null )
+ {
+ result = NSKeyValueCoding.DefaultImplementation.valueForKey( table, aKey );
+ }
+ if ( result == null )
+ {
+ result = aDefaultValue;
+ }
+ else
+ {
+ result = result.toString();
+ }
+
+ return (String) result;
+ }
+
+ /**
+ * Returns a url that invokes the resource manager for the
+ * specified resource.
+ */
+ public String urlForResourceNamed(String aResourceName,
+ String aFrameworkName,
+ NSArray aLanguagesList,
+ WORequest aRequest)
+ {
+ StringBuffer buffer = new StringBuffer();
+ if ( aFrameworkName == null )
+ {
+ aFrameworkName = "application";
+ }
+ buffer.append( aRequest.applicationName() );
+ buffer.append( '/' );
+ buffer.append( WOApplication.resourceRequestHandlerKey() );
+ if ( !aFrameworkName.startsWith("/") )
+ {
+ buffer.append( '/' );
+ }
+ buffer.append( aFrameworkName );
+ buffer.append( '/' );
+ buffer.append( aResourceName );
+ return buffer.toString();
+ }
+
+ /**
+ * Returns an input for the raw resource. Data returned by
+ * this method will not be put in the resource manager's global cache.
+ */
+ public InputStream inputStreamForResourceNamed(String aResourceName,
+ String aFrameworkName,
+ NSArray aLanguagesList)
+ {
+ if ( aResourceName == null ) return null;
+ InputStream result = null;
+
+ StringBuffer path = new StringBuffer();
+ path.append( '/' );
+ if ( aFrameworkName != null )
+ {
+ path.append( aFrameworkName ).append( '/' );
+ }
+
+ int i = aResourceName.lastIndexOf( "." );
+ if ( i != -1 )
+ path.append( aResourceName.substring( 0, i ) );
+ else
+ path.append( aResourceName );
+
+ String location = path.toString();
+ if ( aLanguagesList != null )
+ {
+ String language;
+ Locale locale;
+ HashSet tried = new HashSet(5);
+ Enumeration e = aLanguagesList.objectEnumerator();
+ while ( e.hasMoreElements() && result == null )
+ {
+ language = e.nextElement().toString();
+
+ // look for java-style localization
+ if ( i != -1 )
+ {
+ result = getStream( location + '_'
+ + language + aResourceName.substring( i ) );
+ }
+ else // no dot extension
+ {
+ result = getStream( location + '_' + language );
+ }
+
+ // look for wo-style localization
+ if ( result == null )
+ {
+ locale = (Locale) localeCache.get( language );
+ if ( locale == null )
+ {
+ if ( language.length() == 5 )
+ {
+ locale = new Locale(
+ language.substring( 0, 2 ),
+ language.substring( 3, 5 ) );
+ }
+ else
+ {
+ locale = new Locale( language, "" );
+ }
+ synchronized ( localeCache )
+ {
+ localeCache.put( language, locale );
+ }
+ }
+
+ language = '/'+locale.getDisplayLanguage( californiaLocale )+".lproj";
+ if ( !tried.contains( language ) )
+ {
+ if ( aFrameworkName != null )
+ {
+ int j = aFrameworkName.length()+1;
+ path.insert( j, language );
+ result = getStream( path.toString() + aResourceName.substring( i ) );
+ path.delete( j, j+language.length() );
+ }
+ else
+ {
+ result = getStream( language + path.toString() + aResourceName.substring( i ) );
+ }
+ tried.add( language );
+ }
+ }
+ }
+ }
+
+ // look for file in package
+ if ( result == null )
+ {
+ if ( i != -1 )
+ {
+ result = getStream( path.append(
+ aResourceName.substring( i ) ).toString() );
+ }
+ else // no dot extension
+ {
+ result = getStream( location );
+ }
+ }
+
+ return result;
+ }
+
+ private static final InputStream getStream( String path )
+ { //System.out.println( "getStream: " + path );
+ InputStream input =
+ WOApplication.application().getClass().getResourceAsStream( path );
+ if ( input == null )
+ {
+ // in case the local class loader doesn't delegate to its parent
+ input = ClassLoader.getSystemResourceAsStream( path );
+ }
+ return input;
+ }
+
+ private static final class TypedData
+ {
+ String type;
+ NSData data;
+
+ public TypedData( String aType, NSData aData )
+ {
+ type = aType;
+ data = aData;
+ }
+ }
+}
+
+/*
+ * $Log$
+ * Revision 1.2 2006/02/19 01:44:02 cgruber
+ * Add xmlrpc files
+ * Remove jclark and replace with dom4j and javax.xml.sax stuff
+ * Re-work dependencies and imports so it all compiles.
+ *
+ * Revision 1.1 2006/02/16 13:22:22 cgruber
+ * Check in all sources in eclipse-friendly maven-enabled packages.
+ *
+ * Revision 1.5 2003/08/07 00:15:15 chochos
+ * general cleanup (mostly removing unused imports)
+ *
+ * Revision 1.4 2003/02/28 22:58:57 mpowers
+ * Added support for wo-style localization (*.lproj).
+ *
+ * Revision 1.3 2003/02/21 16:40:24 mpowers
+ * Now reading port and smtp host from system properties.
+ * Implemented WOApplication.main.
+ *
+ * Revision 1.2 2003/01/28 19:33:52 mpowers
+ * Implemented the rest of WOResourceManager.
+ * Implemented support for java-style i18n.
+ * Components now use the resource manager to load templates.
+ *
+ * Revision 1.1 2003/01/27 15:08:00 mpowers
+ * Implemented WOResourceManager, using java resources for now.
+ *
+ *
+ */
+