Merge branch 'master' of github.com:threerings/samskivert

This commit is contained in:
mthomas
2011-06-21 16:24:05 -07:00
14 changed files with 284 additions and 313 deletions
@@ -21,17 +21,14 @@ import com.samskivert.util.ServiceWaiter;
public class HttpPostUtil
{
/**
* Return the results of a form post. Note that the http request takes
* place on another thread, but this thread blocks until the results
* are returned or it times out.
* Return the results of a form post. Note that the http request takes place on another
* thread, but this thread blocks until the results are returned or it times out.
*
* @param url from which to make the request.
* @param submission the entire submission eg "foo=bar&baz=boo&futz=foo".
* @param timeout time to wait for the response, in seconds, or -1
* for forever.
* @param timeout time to wait for the response, in seconds, or -1 for forever.
*/
public static String httpPost (final URL url, final String submission,
int timeout)
public static String httpPost (final URL url, final String submission, int timeout)
throws IOException, ServiceWaiter.TimeoutException
{
final ServiceWaiter<String> waiter = new ServiceWaiter<String>(
@@ -39,16 +36,13 @@ public class HttpPostUtil
Thread tt = new Thread() {
@Override public void run () {
try {
HttpURLConnection conn =
(HttpURLConnection) url.openConnection();
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestProperty(
"Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
DataOutputStream out = new DataOutputStream(
conn.getOutputStream());
DataOutputStream out = new DataOutputStream(conn.getOutputStream());
out.writeBytes(submission);
out.flush();
out.close();
@@ -124,25 +124,26 @@ public class UserManager
}
// register a cron job to prune the session table every hour
_pruner = new Interval() {
@Override public void expired () {
try {
_repository.pruneSessions();
} catch (PersistenceException pe) {
log.warning("Error pruning session table.", pe);
}
}
};
if (pruneQueue != null) {
_pruner.setRunQueue(pruneQueue);
_pruner = new Interval(pruneQueue) {
@Override public void expired () {
try {
_repository.pruneSessions();
} catch (PersistenceException pe) {
log.warning("Error pruning session table.", pe);
}
}
};
_pruner.schedule(SESSION_PRUNE_INTERVAL, true);
}
_pruner.schedule(SESSION_PRUNE_INTERVAL, true);
}
public void shutdown ()
{
// cancel our session table pruning thread
_pruner.cancel();
if (_pruner != null) {
_pruner.cancel();
}
}
/**
@@ -7,7 +7,6 @@ package com.samskivert.util;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Random;
@@ -892,51 +891,6 @@ public class ArrayUtil
return dest;
}
/**
* Return the String representation of the specified Object, which may or may not be an array.
*/
public static String safeToString (Object o)
{
return ((o == null) || !o.getClass().isArray()) ? String.valueOf(o) : toString(o);
}
/**
* Return the String representation of the specified Object, which <em>must</em> be an array.
*
* @throws IllegalArgumentException if array is not actually an array.
*/
public static String toString (Object array)
{
if (array instanceof Object[]) {
return Arrays.deepToString((Object[])array); // go deep, baby
} else if (array instanceof int[]) {
return Arrays.toString((int[])array);
} else if (array instanceof byte[]) {
return Arrays.toString((byte[])array);
} else if (array instanceof char[]) {
return Arrays.toString((char[])array);
} else if (array instanceof short[]) {
return Arrays.toString((short[])array);
} else if (array instanceof long[]) {
return Arrays.toString((long[])array);
} else if (array instanceof float[]) {
return Arrays.toString((float[])array);
} else if (array instanceof double[]) {
return Arrays.toString((double[])array);
} else if (array instanceof boolean[]) {
return Arrays.toString((boolean[])array);
}
throw new IllegalArgumentException("Not an array: " + array);
}
/** The default random object used when shuffling an array. */
protected static final Random _rnd = new Random();
}
@@ -166,7 +166,7 @@ public class AuditLogger
}
/** The interval that rolls over the log file. */
protected Interval _rollover = new Interval() {
protected Interval _rollover = new Interval(Interval.RUN_DIRECT) {
@Override public void expired () {
checkRollOver();
}
+34 -34
View File
@@ -18,6 +18,25 @@ import static com.samskivert.Log.log;
*/
public abstract class Interval
{
/** A marker {@link RunQueue} to supply when you intend for your interval to run directly on
* the interval timer thread, rather than having the interval processed on a separate thread.
* Warning: you must be absolutely sure your interval will complete <em>very quickly</em>,
* otherwise you risk delaying the firing of other intervals. */
public static RunQueue RUN_DIRECT = new RunQueue() {
public void postRunnable (Runnable r) {
throw new UnsupportedOperationException("dummy");
}
public boolean isDispatchThread () {
throw new UnsupportedOperationException("dummy");
}
public boolean isRunning () {
throw new UnsupportedOperationException("dummy");
}
public String toString () {
return "<direct>";
}
};
/**
* An interface for entities that create, and keep track of, intervals. The intended use case
* is for repeating intervals to be created via a factory that tracks all such intervals, and
@@ -54,21 +73,6 @@ public abstract class Interval
public String getIntervalClassName ();
}
/**
* Creates an interval that executes the supplied runnable when it expires.
*/
public static Interval create (final Runnable onExpired)
{
return new Interval() {
@Override public void expired () {
onExpired.run();
}
@Override public String toString () {
return onExpired.toString();
}
};
}
/**
* Creates an interval that executes the supplied runnable on the specified RunQueue when it
* expires.
@@ -88,12 +92,9 @@ public abstract class Interval
};
}
/**
* Create a simple interval that does not use a RunQueue to run the {@link #expired} method.
*/
public Interval ()
{
// _runQueue stays null
/** @deprecated If direct-running is desired, pass {@link #RUN_DIRECT} explicitly. */
@Deprecated public Interval () {
this(RUN_DIRECT);
}
/**
@@ -102,16 +103,14 @@ public abstract class Interval
*/
public Interval (RunQueue runQueue)
{
setRunQueue(runQueue);
if (runQueue == null) {
throw new NullPointerException("RunQueue must be non-null");
}
_runQueue = runQueue;
}
/**
* Configures the run queue to be used by this interval. This <em>must</em> be called before
* the interval is started and a non-null queue must be provided. This exists for situations
* where the caller needs to configure an optional run queue and thus can't easily call the
* appropriate constructor.
*/
public void setRunQueue (RunQueue runQueue)
/** @deprecated Just pass the desired run-queue to the constructor. */
@Deprecated public void setRunQueue (RunQueue runQueue)
{
if (runQueue == null) {
throw new IllegalArgumentException("Supplied RunQueue must be non-null");
@@ -227,7 +226,7 @@ public abstract class Interval
_timer.schedule(_task, initialDelay);
} else if (fixedRate) {
_timer.scheduleAtFixedRate(_task, initialDelay, repeatDelay);
} else if (_runQueue != null) {
} else if (_runQueue != RUN_DIRECT) {
throw new IllegalArgumentException(
"Cannot schedule at a fixed delay when using a RunQueue.");
} else {
@@ -265,7 +264,7 @@ public abstract class Interval
protected void noteRejected ()
{
log.warning("Interval posted to shutdown RunQueue. Cancelling.",
"queue", _runQueue, "interval", this);
"queue", _runQueue, "interval", this);
}
protected static Timer createTimer ()
@@ -297,7 +296,7 @@ public abstract class Interval
if (ival == null) {
return;
}
if (ival._runQueue == null) {
if (ival._runQueue == RUN_DIRECT) {
ival.safelyExpire(this);
return;
}
@@ -328,7 +327,7 @@ public abstract class Interval
ival._runQueue.postRunnable(_runner);
} catch (Exception e) {
log.warning("Failed to execute interval on run-queue",
"queue", ival._runQueue, "interval", ival, e);
"queue", ival._runQueue, "interval", ival, e);
}
} else {
@@ -352,7 +351,8 @@ public abstract class Interval
} // end: static class IntervalTask
/** If non-null, the RunQueue used to run the expired() method for each Interval. */
/** The RunQueue used to run the expired() method for this Interval, or {@link #RUN_DIRECT} to
* indicate that the interval should be executed directly on the Inteval timer thread. */
protected RunQueue _runQueue;
/** The task that actually schedules our execution with the static Timer. */
@@ -48,7 +48,7 @@ public class LogBuilder
}
_log.append(args[ii]).append('=');
try {
_log.append(ArrayUtil.safeToString(args[ii + 1]));
_log.append(StringUtil.toString(args[ii + 1]));
} catch (Throwable t) {
_log.append("<toString() failure: ").append(t).append('>');
}
@@ -142,7 +142,7 @@ public abstract class Logger
}
buf.append(args[ii]).append('=');
try {
buf.append(ArrayUtil.safeToString(args[ii + 1]));
buf.append(StringUtil.toString(args[ii + 1]));
} catch (Throwable t) {
buf.append("<toString() failure: ").append(t).append(">");
}
@@ -135,9 +135,8 @@ public class SerialExecutor
final ExecutorThread thread = new ExecutorThread(task);
thread.start();
// start up a timer that will abort this thread after the specified
// timeout
new Interval() {
// start up a timer that will abort this thread after the specified timeout
new Interval(Interval.RUN_DIRECT) {
@Override public void expired () {
// this will NOOP if the task has already completed
thread.abort();
@@ -6,11 +6,10 @@
package com.samskivert.util;
/**
* A handy base class for issuing server-side service requests and
* awaiting their responses from within a servlet.
* A handy base class for issuing server-side service requests and awaiting their responses from
* within a servlet.
*
* <em>Note:</em> You might think that it would be keen to use this
* anonymously like so:
* <em>Note:</em> You might think that it would be keen to use this anonymously like so:
*
* <pre>
* ServiceWaiter waiter = new ServiceWaiter() {
@@ -21,24 +20,21 @@ package com.samskivert.util;
* };
* </pre>
*
* But that won't work because public methods in anonymous inner classes
* do not have public visibility and so the invocation manager will not be
* able to reflect your response methods when the time comes to deliver
* the response. Unfortunately, there appears to be no manner in which to
* instruct the Java compiler to give public scope to an anonymous inner
* class rather than default scope. Sigh.
* But that won't work because public methods in anonymous inner classes do not have public
* visibility and so the invocation manager will not be able to reflect your response methods
* when the time comes to deliver the response. Unfortunately, there appears to be no manner in
* which to instruct the Java compiler to give public scope to an anonymous inner class rather
* than default scope. Sigh.
*/
public class ServiceWaiter<T>
implements ResultListener<T>
{
/** Timeout to specify when you don't want a timeout. Use at your own
* risk. */
/** Timeout to specify when you don't want a timeout. Use at your own risk. */
public static final int NO_TIMEOUT = -1;
public static class TimeoutException extends Exception
{
public TimeoutException ()
{
public TimeoutException () {
super("Timeout! Pow!");
}
}
@@ -62,8 +58,7 @@ public class ServiceWaiter<T>
}
/**
* Change the timeout being used for this ServiceWaiter after it
* has been constructed.
* Change the timeout being used for this ServiceWaiter after it has been constructed.
*/
public void setTimeout (int timeout)
{
@@ -80,8 +75,8 @@ public class ServiceWaiter<T>
}
/**
* Marks the request as successful and posts the supplied response
* argument for perusal by the caller.
* Marks the request as successful and posts the supplied response argument for perusal by the
* caller.
*/
public synchronized void postSuccess (T arg)
{
@@ -101,8 +96,7 @@ public class ServiceWaiter<T>
}
/**
* Returns the argument posted by the waiter when the response
* arrived.
* Returns the argument posted by the waiter when the response arrived.
*/
public T getArgument ()
{
@@ -120,8 +114,7 @@ public class ServiceWaiter<T>
/**
* Blocks waiting for the response.
*
* @return true if a success response was posted, false if a failure
* repsonse was posted.
* @return true if a success response was posted, false if a failure response was posted.
*/
public boolean waitForResponse ()
throws TimeoutException
@@ -136,8 +129,7 @@ public class ServiceWaiter<T>
} else {
wait(1000L * _timeout);
}
// if we get here without some sort of response, then
// we've timed out
// if we get here without some sort of response, then we've timed out
if (_success == 0) {
throw new TimeoutException();
}
@@ -164,9 +156,8 @@ public class ServiceWaiter<T>
postFailure(cause);
}
/** Whether or not the response succeeded; positive for success,
* negative for failure, zero means we haven't received the response
* yet. */
/** Whether or not the response succeeded; positive for success, negative for failure, zero
* means we haven't received the response yet. */
protected int _success = 0;
/** The argument posted by the waiter upon receipt of the response. */
@@ -178,8 +169,7 @@ public class ServiceWaiter<T>
/** How many seconds to wait before giving up the ghost. */
protected int _timeout;
/** If a response is not received within the specified timeout, an
* exception is thrown which redirects the user to an internal error
* page. */
/** If a response is not received within the specified timeout, an exception is thrown which
* redirects the user to an internal error page. */
protected static final int DEFAULT_WAITER_TIMEOUT = 30;
}
+195 -161
View File
@@ -355,16 +355,8 @@ public class StringUtil
* Converts the supplied object to a string. Normally this is accomplished via the object's
* built in <code>toString()</code> method, but in the case of arrays, <code>toString()</code>
* is called on each element and the contents are listed like so:
*
* <pre>
* (value, value, value)
* </pre>
*
* Arrays of ints, longs, floats and doubles are also handled for convenience.
*
* <p> Additionally, <code>Enumeration</code> or <code>Iterator</code> objects can be passed
* and they will be enumerated and output in a similar manner to arrays. Bear in mind that this
* uses up the enumeration or iterator in question.
* <pre>(value, value, value)</pre>
* Arrays of primitive types are also handled for convenience.
*
* <p> Also note that passing null will result in the string "null" being returned.
*/
@@ -375,10 +367,29 @@ public class StringUtil
return buf.toString();
}
/**
* Converts the supplied value to a string and appends it to the supplied string buffer. See
* {@link #toString()} for more information.
*
* @param buf the string buffer to which we will append the string.
* @param val the value from which to generate the string.
*/
public static void toString (StringBuilder buf, Object val)
{
// these boxes+sep will only be used for arrays
toString(buf, val, "(", ")", ", ", false);
}
/**
* Like the single argument {@link #toString(Object)} with the additional function of
* specifying the characters that are used to box in list and array types. For example, if "["
* and "]" were supplied, an int array might be formatted like so: <code>[1, 3, 5]</code>.
* specifying the characters that are used to box in collection and array types. For example,
* if "[" and "]" were supplied, an int array might be formatted like so: <code>[1, 3,
* 5]</code>.
*
* <p> Note: in this method (unlike {@link #toString()}), <code>Enumeration</code> or
* <code>Iterator</code> objects can be passed and they will be enumerated and output in a
* similar manner to arrays. Bear in mind that this uses up the enumeration or iterator in
* question.
*/
public static String toString (Object val, String openBox, String closeBox)
{
@@ -387,23 +398,16 @@ public class StringUtil
return buf.toString();
}
/**
* Converts the supplied value to a string and appends it to the supplied string buffer. See
* the single argument version for more information.
*
* @param buf the string buffer to which we will append the string.
* @param val the value from which to generate the string.
*/
public static void toString (StringBuilder buf, Object val)
{
toString(buf, val, "(", ")");
}
/**
* Converts the supplied value to a string and appends it to the supplied string buffer. The
* specified boxing characters are used to enclose list and array types. For example, if "["
* and "]" were supplied, an int array might be formatted like so: <code>[1, 3, 5]</code>.
*
* <p> Note: in this method (unlike {@link #toString()}), <code>Enumeration</code> or
* <code>Iterator</code> objects can be passed and they will be enumerated and output in a
* similar manner to arrays. Bear in mind that this uses up the enumeration or iterator in
* question.
*
* @param buf the string buffer to which we will append the string.
* @param val the value from which to generate the string.
* @param openBox the opening box character.
@@ -419,150 +423,21 @@ public class StringUtil
* specified boxing characters are used to enclose list and array types. For example, if "["
* and "]" were supplied, an int array might be formatted like so: <code>[1, 3, 5]</code>.
*
* <p> Note: in this method (unlike {@link #toString()}), <code>Enumeration</code> or
* <code>Iterator</code> objects can be passed and they will be enumerated and output in a
* similar manner to arrays. Bear in mind that this uses up the enumeration or iterator in
* question.
*
* @param buf the string buffer to which we will append the string.
* @param val the value from which to generate the string.
* @param openBox the opening box character.
* @param closeBox the closing box character.
* @param sep the separator string.
*/
public static void toString (
StringBuilder buf, Object val, String openBox, String closeBox, String sep)
public static void toString (StringBuilder buf, Object val, String openBox, String closeBox,
String sep)
{
if (val instanceof byte[]) {
buf.append(openBox);
byte[] v = (byte[])val;
for (int i = 0; i < v.length; i++) {
if (i > 0) {
buf.append(sep);
}
buf.append(v[i]);
}
buf.append(closeBox);
} else if (val instanceof short[]) {
buf.append(openBox);
short[] v = (short[])val;
for (short i = 0; i < v.length; i++) {
if (i > 0) {
buf.append(sep);
}
buf.append(v[i]);
}
buf.append(closeBox);
} else if (val instanceof int[]) {
buf.append(openBox);
int[] v = (int[])val;
for (int i = 0; i < v.length; i++) {
if (i > 0) {
buf.append(sep);
}
buf.append(v[i]);
}
buf.append(closeBox);
} else if (val instanceof long[]) {
buf.append(openBox);
long[] v = (long[])val;
for (int i = 0; i < v.length; i++) {
if (i > 0) {
buf.append(sep);
}
buf.append(v[i]);
}
buf.append(closeBox);
} else if (val instanceof float[]) {
buf.append(openBox);
float[] v = (float[])val;
for (int i = 0; i < v.length; i++) {
if (i > 0) {
buf.append(sep);
}
buf.append(v[i]);
}
buf.append(closeBox);
} else if (val instanceof double[]) {
buf.append(openBox);
double[] v = (double[])val;
for (int i = 0; i < v.length; i++) {
if (i > 0) {
buf.append(sep);
}
buf.append(v[i]);
}
buf.append(closeBox);
} else if (val instanceof Object[]) {
buf.append(openBox);
Object[] v = (Object[])val;
for (int i = 0; i < v.length; i++) {
if (i > 0) {
buf.append(sep);
}
toString(buf, v[i], openBox, closeBox);
}
buf.append(closeBox);
} else if (val instanceof boolean[]) {
buf.append(openBox);
boolean[] v = (boolean[])val;
for (int i = 0; i < v.length; i++) {
if (i > 0) {
buf.append(sep);
}
buf.append(v[i] ? "t" : "f");
}
buf.append(closeBox);
} else if (val instanceof Iterable<?>) {
toString(buf, ((Iterable<?>)val).iterator(), openBox, closeBox);
} else if (val instanceof Iterator<?>) {
buf.append(openBox);
Iterator<?> iter = (Iterator<?>)val;
for (int i = 0; iter.hasNext(); i++) {
if (i > 0) {
buf.append(sep);
}
toString(buf, iter.next(), openBox, closeBox);
}
buf.append(closeBox);
} else if (val instanceof Enumeration<?>) {
buf.append(openBox);
Enumeration<?> enm = (Enumeration<?>)val;
for (int i = 0; enm.hasMoreElements(); i++) {
if (i > 0) {
buf.append(sep);
}
toString(buf, enm.nextElement(), openBox, closeBox);
}
buf.append(closeBox);
} else if (val instanceof Point2D) {
Point2D p = (Point2D)val;
buf.append(openBox);
coordsToString(buf, (int)p.getX(), (int)p.getY());
buf.append(closeBox);
} else if (val instanceof Dimension2D) {
Dimension2D d = (Dimension2D)val;
buf.append(openBox);
buf.append(d.getWidth()).append("x").append(d.getHeight());
buf.append(closeBox);
} else if (val instanceof Rectangle2D) {
Rectangle2D r = (Rectangle2D)val;
buf.append(openBox);
buf.append(r.getWidth()).append("x").append(r.getHeight());
coordsToString(buf, (int)r.getX(), (int)r.getY());
buf.append(closeBox);
} else {
buf.append(val);
}
toString(buf, val, openBox, closeBox, sep, true);
}
/**
@@ -1378,6 +1253,165 @@ public class StringUtil
return buf.toString();
}
/**
* Helper function for the various {@link #toString} methods.
*/
protected static void toString (StringBuilder buf, Object val, String openBox, String closeBox,
String sep, boolean traverseCollections)
{
if (val instanceof byte[]) {
buf.append(openBox);
byte[] v = (byte[])val;
for (int i = 0; i < v.length; i++) {
if (i > 0) {
buf.append(sep);
}
buf.append(v[i]);
}
buf.append(closeBox);
} else if (val instanceof short[]) {
buf.append(openBox);
short[] v = (short[])val;
for (int i = 0; i < v.length; i++) {
if (i > 0) {
buf.append(sep);
}
buf.append(v[i]);
}
buf.append(closeBox);
} else if (val instanceof char[]) {
buf.append(openBox);
char[] v = (char[])val;
for (int i = 0; i < v.length; i++) {
if (i > 0) {
buf.append(sep);
}
buf.append(v[i]);
}
buf.append(closeBox);
} else if (val instanceof int[]) {
buf.append(openBox);
int[] v = (int[])val;
for (int i = 0; i < v.length; i++) {
if (i > 0) {
buf.append(sep);
}
buf.append(v[i]);
}
buf.append(closeBox);
} else if (val instanceof long[]) {
buf.append(openBox);
long[] v = (long[])val;
for (int i = 0; i < v.length; i++) {
if (i > 0) {
buf.append(sep);
}
buf.append(v[i]);
}
buf.append(closeBox);
} else if (val instanceof float[]) {
buf.append(openBox);
float[] v = (float[])val;
for (int i = 0; i < v.length; i++) {
if (i > 0) {
buf.append(sep);
}
buf.append(v[i]);
}
buf.append(closeBox);
} else if (val instanceof double[]) {
buf.append(openBox);
double[] v = (double[])val;
for (int i = 0; i < v.length; i++) {
if (i > 0) {
buf.append(sep);
}
buf.append(v[i]);
}
buf.append(closeBox);
} else if (val instanceof Object[]) {
buf.append(openBox);
Object[] v = (Object[])val;
for (int i = 0; i < v.length; i++) {
if (i > 0) {
buf.append(sep);
}
toString(buf, v[i], openBox, closeBox, sep, traverseCollections);
}
buf.append(closeBox);
} else if (val instanceof boolean[]) {
buf.append(openBox);
boolean[] v = (boolean[])val;
for (int i = 0; i < v.length; i++) {
if (i > 0) {
buf.append(sep);
}
buf.append(v[i] ? "t" : "f");
}
buf.append(closeBox);
} else if (val instanceof Point2D) {
Point2D p = (Point2D)val;
buf.append(openBox);
coordsToString(buf, (int)p.getX(), (int)p.getY());
buf.append(closeBox);
} else if (val instanceof Dimension2D) {
Dimension2D d = (Dimension2D)val;
buf.append(openBox);
buf.append(d.getWidth()).append("x").append(d.getHeight());
buf.append(closeBox);
} else if (val instanceof Rectangle2D) {
Rectangle2D r = (Rectangle2D)val;
buf.append(openBox);
buf.append(r.getWidth()).append("x").append(r.getHeight());
coordsToString(buf, (int)r.getX(), (int)r.getY());
buf.append(closeBox);
} else if (traverseCollections) {
if (val instanceof Iterable<?>) {
toString(buf, ((Iterable<?>)val).iterator(), openBox, closeBox, sep, true);
} else if (val instanceof Iterator<?>) {
buf.append(openBox);
Iterator<?> iter = (Iterator<?>)val;
for (int i = 0; iter.hasNext(); i++) {
if (i > 0) {
buf.append(sep);
}
toString(buf, iter.next(), openBox, closeBox, sep, true);
}
buf.append(closeBox);
} else if (val instanceof Enumeration<?>) {
buf.append(openBox);
Enumeration<?> enm = (Enumeration<?>)val;
for (int i = 0; enm.hasMoreElements(); i++) {
if (i > 0) {
buf.append(sep);
}
toString(buf, enm.nextElement(), openBox, closeBox, sep, true);
}
buf.append(closeBox);
} else {
buf.append(val);
}
} else {
buf.append(val);
}
}
/**
* Helper function for the various <code>join</code> methods.
*/
@@ -36,9 +36,8 @@ public class ValueMarshaller
// look up an argument parser for the field type
Parser parser = _parsers.get(type);
if (parser == null) {
String errmsg = "Don't know how to convert strings into " +
"values of type '" + type + "'.";
throw new Exception(errmsg);
throw new Exception(
"Don't know how to convert strings into values of type '" + type + "'.");
}
return parser.parse(source);
}
@@ -48,7 +47,7 @@ public class ValueMarshaller
public Object parse (String source) throws Exception;
}
protected static Map<Class<?>,Parser> _parsers = new HashMap<Class<?>,Parser>();
protected static Map<Class<?>, Parser> _parsers = new HashMap<Class<?>, Parser>();
static {
Parser p;
// we can parse strings