From fddea490cc94e7a2ef877fae73dfd56dfa57f144 Mon Sep 17 00:00:00 2001
From: Jonathan Hsieh <jon@cloudera.com>
Date: Sat, 21 May 2011 21:00:24 -0700
Subject: [PATCH] FLUME-420: Change Context to accept Objects instead of Strings
 - Backwards compatible version

---
 .../main/java/com/cloudera/flume/conf/Context.java |   33 ++++++++++--
 .../java/com/cloudera/flume/conf/FlumeBuilder.java |   56 ++++++++++----------
 .../com/cloudera/flume/conf/LinkedSinkFactory.java |   19 +++++++
 .../java/com/cloudera/flume/conf/SinkFactory.java  |   54 +++++++++++++++++++
 .../com/cloudera/flume/conf/SinkFactoryImpl.java   |   16 ++++++
 .../com/cloudera/flume/conf/SourceFactory.java     |   12 ++++-
 .../flume/handlers/text/FormatFactory.java         |   26 +++++++++
 .../logical/LogicalConfigurationManager.java       |    2 +-
 .../com/cloudera/flume/conf/TestFactories.java     |   36 ++++++------
 .../com/cloudera/flume/conf/TestPatternMatch.java  |    3 +-
 10 files changed, 204 insertions(+), 53 deletions(-)

diff --git a/flume-core/src/main/java/com/cloudera/flume/conf/Context.java b/flume-core/src/main/java/com/cloudera/flume/conf/Context.java
index 25829de..1a261ce 100644
--- a/flume-core/src/main/java/com/cloudera/flume/conf/Context.java
+++ b/flume-core/src/main/java/com/cloudera/flume/conf/Context.java
@@ -34,7 +34,7 @@ import java.util.Map;
  * transparently.
  */
 public class Context {
-  Map<String, String> table = new HashMap<String, String>();
+  Map<String, Object> table = new HashMap<String, Object>();
   final Context parent;
 
   final public static Context EMPTY = new Context(null);
@@ -63,14 +63,39 @@ public class Context {
    * try to get the value from there.
    */
   public String getValue(String arg) {
-    String val = table.get(arg);
-    if (val == null && getParent() != null) {
+    Object val = table.get(arg);
+    if (val != null) {
+      return val.toString();
+    }
+
+    if (getParent() != null) {
       return getParent().getValue(arg);
     }
-    return val;
+    return null; // no parent, and was null? return null
   }
 
+  /**
+   * Adds a value to the context assuming it is a string.
+   */
   protected void putValue(String arg, String val) {
     table.put(arg, val);
   }
+
+  /**
+   * Adds an object value to the context.
+   */
+  protected void putObj(String arg, Object val) {
+    table.put(arg, val);
+  }
+
+  /**
+   * Gets an object value from the context.
+   */
+  public Object getObj(String arg) {
+    Object val = table.get(arg);
+    if (val == null && getParent() != null) {
+      return getParent().getObj(arg);
+    }
+    return val;
+  }
 }
diff --git a/flume-core/src/main/java/com/cloudera/flume/conf/FlumeBuilder.java b/flume-core/src/main/java/com/cloudera/flume/conf/FlumeBuilder.java
index e5ced77..3e97884 100644
--- a/flume-core/src/main/java/com/cloudera/flume/conf/FlumeBuilder.java
+++ b/flume-core/src/main/java/com/cloudera/flume/conf/FlumeBuilder.java
@@ -211,8 +211,8 @@ public class FlumeBuilder {
         CommonTree tsrc = (CommonTree) t.getChild(1);
         CommonTree tsnk = (CommonTree) t.getChild(2);
 
-        Pair<String, String> p = new Pair<String, String>(FlumeSpecGen
-            .genEventSource(tsrc), FlumeSpecGen.genEventSink(tsnk));
+        Pair<String, String> p = new Pair<String, String>(
+            FlumeSpecGen.genEventSource(tsrc), FlumeSpecGen.genEventSink(tsnk));
         cfg.put(host, p);
       }
       return cfg;
@@ -331,7 +331,7 @@ public class FlumeBuilder {
    * TODO (jon) move to builders, or allow builders to take Integers/Booleans as
    * well as Strings
    */
-  public static String buildSimpleArg(CommonTree t) throws FlumeSpecException {
+  public static Object buildSimpleArg(CommonTree t) throws FlumeSpecException {
     ASTNODE type = ASTNODE.valueOf(t.getText()); // convert to enum
     switch (type) {
     case HEX:
@@ -385,22 +385,22 @@ public class FlumeBuilder {
    * @throws FlumeSpecException
    */
   @SuppressWarnings("unchecked")
-  static Pair<String, List<String>> handleArgs(CommonTree t, Context ctx)
+  static Pair<String, List<Object>> handleArgs(CommonTree t, Context ctx)
       throws FlumeSpecException {
-    List<CommonTree> children = (List<CommonTree>) new ArrayList<CommonTree>(t
-        .getChildren());
+    List<CommonTree> children = (List<CommonTree>) new ArrayList<CommonTree>(
+        t.getChildren());
     String sinkType = children.remove(0).getText();
-    List<String> args = new ArrayList<String>();
+    List<Object> args = new ArrayList<Object>();
     for (CommonTree tr : children) {
-      String arg = buildSimpleArg(tr);
+      Object arg = buildSimpleArg(tr);
       if (arg != null) {
         args.add(arg);
       } else {
         Pair<String, CommonTree> kwarg = buildKWArg(tr);
-        ctx.putValue(kwarg.getLeft(), buildSimpleArg(kwarg.getRight()));
+        ctx.putObj(kwarg.getLeft(), buildSimpleArg(kwarg.getRight()));
       }
     }
-    return new Pair<String, List<String>>(sinkType, args);
+    return new Pair<String, List<Object>>(sinkType, args);
   }
 
   static EventSource buildEventSource(Context context, CommonTree t)
@@ -409,12 +409,12 @@ public class FlumeBuilder {
     switch (type) {
     case SOURCE: {
       Context ctx = new Context(context);
-      Pair<String, List<String>> idArgs = handleArgs(t, ctx);
+      Pair<String, List<Object>> idArgs = handleArgs(t, ctx);
       String sourceType = idArgs.getLeft();
-      List<String> args = idArgs.getRight();
+      List<Object> args = idArgs.getRight();
 
-      EventSource src = srcFactory.getSource(ctx, sourceType, args
-          .toArray(new String[0]));
+      EventSource src = srcFactory
+          .createSource(ctx, sourceType, args.toArray());
       if (src == null) {
         throw new FlumeIdException("Invalid source: "
             + FlumeSpecGen.genEventSource(t));
@@ -435,12 +435,11 @@ public class FlumeBuilder {
     case SINK: {
 
       Context ctx = new Context(context);
-      Pair<String, List<String>> idargs = handleArgs(t, ctx);
+      Pair<String, List<Object>> idargs = handleArgs(t, ctx);
       String sinkType = idargs.getLeft();
-      List<String> args = idargs.getRight();
+      List<Object> args = idargs.getRight();
 
-      EventSink snk = sinkFactory.getSink(ctx, sinkType, args
-          .toArray(new String[0]));
+      EventSink snk = sinkFactory.createSink(ctx, sinkType, args.toArray());
 
       if (snk == null) {
         throw new FlumeIdException("Invalid sink: "
@@ -575,7 +574,9 @@ public class FlumeBuilder {
         Preconditions.checkArgument(rollArgs.size() == 2, "bad parse tree! "
             + t.toStringTree() + "roll only takes two arguments");
         CommonTree ctbody = rollArgs.get(0);
-        Long period = Long.parseLong(buildSimpleArg(rollArgs.get(1)));
+        // TODO change long args into Long instead of String
+        Long period = Long
+            .parseLong(buildSimpleArg(rollArgs.get(1)).toString());
         String body = FlumeSpecGen.genEventSink(ctbody);
         // TODO (jon) replace the hard coded 250 with a parameterizable value
         RollSink roller = new RollSink(context, body, period, 250);
@@ -600,16 +601,16 @@ public class FlumeBuilder {
         String body = FlumeSpecGen.genEventSink(ctbody);
 
         Context ctx = new Context(context);
-        Pair<String, List<String>> idArgs = handleArgs(t, ctx);
+        Pair<String, List<Object>> idArgs = handleArgs(t, ctx);
         String sourceType = idArgs.getLeft();
-        List<String> args = idArgs.getRight();
+        List<Object> args = idArgs.getRight();
         args.add(0, body);
 
         // TODO replace with Generator Sink lookup
         Preconditions.checkArgument("collector".equals(sourceType));
         SinkBuilder builder = CollectorSink.builder();
 
-        return builder.build(ctx, args.toArray(new String[0]));
+        return builder.create(ctx, args.toArray());
 
       } catch (IllegalArgumentException iae) {
         throw new FlumeSpecException(iae.getMessage());
@@ -631,7 +632,7 @@ public class FlumeBuilder {
           continue;
         }
         // assumes this is a STRING
-        rargs.add(buildSimpleArg(ct));
+        rargs.add(buildSimpleArg(ct).toString());
       }
       String body = FlumeSpecGen.genEventSink(ctbody);
       FlumeConfiguration conf = FlumeConfiguration.get();
@@ -648,15 +649,14 @@ public class FlumeBuilder {
     }
   }
 
-  @SuppressWarnings("unchecked")
   static EventSinkDecorator<EventSink> buildEventSinkDecorator(Context context,
       CommonTree t) throws FlumeSpecException {
     Context ctx = new Context(context);
-    Pair<String, List<String>> idArgs = handleArgs(t, ctx);
+    Pair<String, List<Object>> idArgs = handleArgs(t, ctx);
     String sinkType = idArgs.getLeft();
-    List<String> args = idArgs.getRight();
-    EventSinkDecorator deco = sinkFactory.getDecorator(ctx, sinkType, args
-        .toArray(new String[0]));
+    List<Object> args = idArgs.getRight();
+    EventSinkDecorator<EventSink> deco = sinkFactory.createDecorator(ctx,
+        sinkType, args.toArray());
     if (deco == null) {
       throw new FlumeIdException("Invalid sink decorator: "
           + FlumeSpecGen.genEventSinkDecorator(t));
diff --git a/flume-core/src/main/java/com/cloudera/flume/conf/LinkedSinkFactory.java b/flume-core/src/main/java/com/cloudera/flume/conf/LinkedSinkFactory.java
index 1adc468..11018dd 100644
--- a/flume-core/src/main/java/com/cloudera/flume/conf/LinkedSinkFactory.java
+++ b/flume-core/src/main/java/com/cloudera/flume/conf/LinkedSinkFactory.java
@@ -45,12 +45,31 @@ public class LinkedSinkFactory extends SinkFactory {
   }
 
   @Override
+  public EventSinkDecorator<EventSink> createDecorator(Context context,
+      String name, Object... args) throws FlumeSpecException {
+    return parent.createDecorator(context, name, args);
+  }
+
+  @Override
+  @Deprecated
   public EventSinkDecorator<EventSink> getDecorator(Context context,
       String name, String... args) throws FlumeSpecException {
     return parent.getDecorator(context, name, args);
   }
 
   @Override
+  public EventSink createSink(Context context, String name, Object... args)
+      throws FlumeSpecException {
+    if (sinkname.equals(name)) {
+      // TODO (jon) we are actually close to allowing in sink templates
+      return sink;
+    }
+
+    return parent.createSink(context, name, args);
+  }
+
+  @Override
+  @Deprecated
   public EventSink getSink(Context context, String name, String... args)
       throws FlumeSpecException {
     if (sinkname.equals(name)) {
diff --git a/flume-core/src/main/java/com/cloudera/flume/conf/SinkFactory.java b/flume-core/src/main/java/com/cloudera/flume/conf/SinkFactory.java
index 94308c2..bdbe0dd 100644
--- a/flume-core/src/main/java/com/cloudera/flume/conf/SinkFactory.java
+++ b/flume-core/src/main/java/com/cloudera/flume/conf/SinkFactory.java
@@ -31,6 +31,20 @@ abstract public class SinkFactory {
 
   abstract public static class SinkBuilder {
 
+    /**
+     * The previous default was to build with string arguments. With function
+     * arguments, we take objects instead. Internally this method is called and
+     * to preserve backwards compatibility we translates objects into args.
+     */
+    public EventSink create(Context context, Object... args) {
+      return build(context, toStrings(args));
+    }
+
+    /**
+     * This is required for backwards compatibility and will eventually become
+     * deprecated
+     */
+    @Deprecated
     abstract public EventSink build(Context context, String... argv);
 
     /**
@@ -44,6 +58,20 @@ abstract public class SinkFactory {
   };
 
   abstract public static class SinkDecoBuilder {
+    /**
+     * The previous default was to build with string arguments. With function
+     * arguments, we take objects instead. Internally this method is called and
+     * to preserve backwards compatibility we translates objects into args.
+     */
+    public EventSinkDecorator<EventSink> create(Context context, Object... args) {
+      return build(context, toStrings(args));
+    }
+
+    /**
+     * This is required for backwards compatibility and will eventually become
+     * deprecated
+     */
+    @Deprecated
     abstract public EventSinkDecorator<EventSink> build(Context context,
         String... argv);
 
@@ -57,6 +85,23 @@ abstract public class SinkFactory {
     }
   }
 
+  public static String[] toStrings(Object... args) {
+    String[] sargs = new String[args.length];
+    for (int i = 0; i < args.length; i++) {
+      sargs[i] = args[i].toString();
+    }
+    return sargs;
+  }
+
+  /**
+   * Update to make object arguments instead of string arguments.
+   */
+  public EventSink createSink(Context context, String name, Object... args)
+      throws FlumeSpecException {
+    return getSink(context, name, toStrings(args));
+  }
+
+  @Deprecated
   abstract public EventSink getSink(Context context, String name,
       String... args) throws FlumeSpecException;
 
@@ -70,6 +115,15 @@ abstract public class SinkFactory {
     return getSink(new Context(), name, args);
   }
 
+  /**
+   * Update to make object arguments instead of string arguments.
+   */
+  public EventSinkDecorator<EventSink> createDecorator(Context context,
+      String name, Object... args) throws FlumeSpecException {
+    return getDecorator(context, name, toStrings(args));
+  }
+
+  @Deprecated
   abstract public EventSinkDecorator<EventSink> getDecorator(Context context,
       String name, String... args) throws FlumeSpecException;
 
diff --git a/flume-core/src/main/java/com/cloudera/flume/conf/SinkFactoryImpl.java b/flume-core/src/main/java/com/cloudera/flume/conf/SinkFactoryImpl.java
index cee7513..4882b61 100644
--- a/flume-core/src/main/java/com/cloudera/flume/conf/SinkFactoryImpl.java
+++ b/flume-core/src/main/java/com/cloudera/flume/conf/SinkFactoryImpl.java
@@ -306,6 +306,22 @@ public class SinkFactoryImpl extends SinkFactory {
   }
 
   @Override
+  public EventSink createSink(Context context, String name, Object... args)
+      throws FlumeSpecException {
+    try {
+      SinkBuilder builder = sinks.get(name);
+      if (builder == null)
+        return null;
+      return builder.create(context, args);
+    } catch (NumberFormatException nfe) {
+      throw new FlumeArgException("Illegal number format: " + nfe.getMessage());
+    } catch (IllegalArgumentException iae) {
+      throw new FlumeArgException(iae.getMessage());
+    }
+  }
+
+  
+  @Override
   public EventSink getSink(Context context, String name, String... args)
       throws FlumeSpecException {
     try {
diff --git a/flume-core/src/main/java/com/cloudera/flume/conf/SourceFactory.java b/flume-core/src/main/java/com/cloudera/flume/conf/SourceFactory.java
index 1843248..57238ce 100644
--- a/flume-core/src/main/java/com/cloudera/flume/conf/SourceFactory.java
+++ b/flume-core/src/main/java/com/cloudera/flume/conf/SourceFactory.java
@@ -33,10 +33,20 @@ abstract public class SourceFactory {
       return build(new Context(), argv);
     }
 
+    @Deprecated
     public abstract EventSource build(Context ctx, String... argv);
+
+    public EventSource create(Context ctx, Object... argv) {
+      return build(ctx, SinkFactory.toStrings(argv));
+    }
   };
 
-  
+  public EventSource createSource(Context ctx, String name, Object... args)
+      throws FlumeSpecException {
+    return getSource(ctx, name, SinkFactory.toStrings(args));
+  }
+
+  @Deprecated
   abstract public EventSource getSource(Context ctx, String name,
       String... args) throws FlumeSpecException;
 
diff --git a/flume-core/src/main/java/com/cloudera/flume/handlers/text/FormatFactory.java b/flume-core/src/main/java/com/cloudera/flume/handlers/text/FormatFactory.java
index ad0eb00..6e947e8 100644
--- a/flume-core/src/main/java/com/cloudera/flume/handlers/text/FormatFactory.java
+++ b/flume-core/src/main/java/com/cloudera/flume/handlers/text/FormatFactory.java
@@ -29,6 +29,7 @@ import org.slf4j.LoggerFactory;
 
 import com.cloudera.flume.conf.FlumeConfiguration;
 import com.cloudera.flume.conf.FlumeSpecException;
+import com.cloudera.flume.conf.SinkFactory;
 import com.cloudera.flume.handlers.avro.AvroDataFileOutputFormat;
 import com.cloudera.flume.handlers.avro.AvroJsonOutputFormat;
 import com.cloudera.flume.handlers.avro.AvroNativeFileOutputFormat;
@@ -56,6 +57,10 @@ public class FormatFactory {
 
     public abstract String getName();
 
+    public OutputFormat create(Object... args) {
+      return build(SinkFactory.toStrings(args));
+    }
+
   };
 
   final static OutputFormatBuilder DEFAULT = new OutputFormatBuilder() {
@@ -109,6 +114,27 @@ public class FormatFactory {
     this(CORE_FORMATS);
   }
 
+  public OutputFormat createOutputFormat(String name, Object... args)
+      throws FlumeSpecException {
+    OutputFormatBuilder builder;
+
+    // purposely said no format? return default.
+    if (name == null) {
+      return DEFAULT.build();
+    }
+
+    // specified a format but it was invalid? This is a problem.
+    synchronized (registeredFormats) {
+      builder = registeredFormats.get(name);
+    }
+
+    if (builder == null) {
+      throw new FlumeSpecException("Invalid output format: " + name);
+    }
+
+    return builder.create(args);
+  }
+
   public OutputFormat getOutputFormat(String name, String... args)
       throws FlumeSpecException {
     OutputFormatBuilder builder;
diff --git a/flume-core/src/main/java/com/cloudera/flume/master/logical/LogicalConfigurationManager.java b/flume-core/src/main/java/com/cloudera/flume/master/logical/LogicalConfigurationManager.java
index f14fd19..eb722ea 100644
--- a/flume-core/src/main/java/com/cloudera/flume/master/logical/LogicalConfigurationManager.java
+++ b/flume-core/src/main/java/com/cloudera/flume/master/logical/LogicalConfigurationManager.java
@@ -85,7 +85,7 @@ public class LogicalConfigurationManager extends
         .genEventSink(lsnk));
 
     String tgtLn = FlumeBuilder.buildSimpleArg((CommonTree) lsnk.getChild(0)
-        .getChild(1));
+        .getChild(1)).toString();
 
     PhysicalNodeInfo pni = nameMan.getPhysicalNodeInfo(tgtLn);
 
diff --git a/flume-core/src/test/java/com/cloudera/flume/conf/TestFactories.java b/flume-core/src/test/java/com/cloudera/flume/conf/TestFactories.java
index db4fc61..b11a958 100644
--- a/flume-core/src/test/java/com/cloudera/flume/conf/TestFactories.java
+++ b/flume-core/src/test/java/com/cloudera/flume/conf/TestFactories.java
@@ -55,7 +55,7 @@ public class TestFactories implements ExampleData {
   @Test
   public void testBuildConsole() throws IOException, FlumeSpecException,
       InterruptedException {
-    EventSink snk = fact.getSink(new Context(), "console");
+    EventSink snk = fact.createSink(new Context(), "console", new Object[0]);
     snk.open();
     snk.append(new EventImpl("test".getBytes()));
     snk.close();
@@ -67,7 +67,7 @@ public class TestFactories implements ExampleData {
     Context ctx = LogicalNodeContext.testingContext();
 
     // 25 lines of 100 bytes of ascii
-    EventSource src = srcfact.getSource(ctx, "asciisynth", "25", "100");
+    EventSource src = srcfact.createSource(ctx, "asciisynth", 25, 100);
     src.open();
     Event e = null;
     int cnt = 0;
@@ -84,10 +84,10 @@ public class TestFactories implements ExampleData {
       FlumeSpecException {
     Context ctx = LogicalNodeContext.testingContext();
 
-    EventSink snk = fact.getSink(ctx, "console");
+    EventSink snk = fact.createSink(ctx, "console", new Object[0]);
     snk.open();
 
-    EventSource src = srcfact.getSource(ctx, "asciisynth", "25", "100");
+    EventSource src = srcfact.createSource(ctx, "asciisynth", 25, 100);
     src.open();
 
     DirectDriver conn = new DirectDriver(src, snk);
@@ -103,13 +103,13 @@ public class TestFactories implements ExampleData {
   public void testDecorator() throws IOException, FlumeSpecException,
       InterruptedException {
     Context ctx = LogicalNodeContext.testingContext();
-    EventSource src = srcfact.getSource(ctx, "asciisynth", "25", "100");
+    EventSource src = srcfact.createSource(ctx, "asciisynth", 25, 100);
     src.open();
 
     EventSinkDecorator<EventSink> deco =
 
-    fact.getDecorator(new Context(), "intervalSampler", "5");
-    EventSink snk = fact.getSink(new Context(), "counter", "name");
+    fact.createDecorator(new Context(), "intervalSampler", 5);
+    EventSink snk = fact.createSink(new Context(), "counter", (Object) "name");
 
     snk.open();
 
@@ -127,25 +127,25 @@ public class TestFactories implements ExampleData {
     Context ctx = LogicalNodeContext.testingContext();
 
     // making sure default is Thrift
-    EventSource rpcSrc = srcfact.getSource(ctx, "rpcSource", "31337");
-    EventSink rpcSink = fact.getSink(new Context(), "rpcSink", "0.0.0.0",
-        "31337");
+    EventSource rpcSrc = srcfact.createSource(ctx, "rpcSource", 31337);
+    EventSink rpcSink = fact
+        .createSink(new Context(), "rpcSink", "0.0.0.0", 31337);
     assertEquals(ThriftEventSource.class, rpcSrc.getClass());
     assertEquals(ThriftEventSink.class, rpcSink.getClass());
 
     // make sure initializing to Thrift indeed gives us ThriftEvent sources and
     // sinks.
     FlumeConfiguration.get().set(FlumeConfiguration.EVENT_RPC_TYPE, "THRIFT");
-    rpcSrc = srcfact.getSource(ctx, "rpcSource", "31337");
-    rpcSink = fact.getSink(new Context(), "rpcSink", "0.0.0.0", "31337");
+    rpcSrc = srcfact.createSource(ctx, "rpcSource", 31337);
+    rpcSink = fact.createSink(new Context(), "rpcSink", "0.0.0.0", 31337);
     assertEquals(ThriftEventSource.class, rpcSrc.getClass());
     assertEquals(ThriftEventSink.class, rpcSink.getClass());
 
     // make sure initializing to Avro indeed gives us AvroEvent sources and
     // sinks.
     FlumeConfiguration.get().set(FlumeConfiguration.EVENT_RPC_TYPE, "AVRO");
-    rpcSrc = srcfact.getSource(ctx, "rpcSource", "31337");
-    rpcSink = fact.getSink(new Context(), "rpcSink", "0.0.0.0", "31337");
+    rpcSrc = srcfact.createSource(ctx, "rpcSource", 31337);
+    rpcSink = fact.createSink(new Context(), "rpcSink", "0.0.0.0", 31337);
     assertEquals(AvroEventSource.class, rpcSrc.getClass());
     assertEquals(AvroEventSink.class, rpcSink.getClass());
   }
@@ -172,11 +172,11 @@ public class TestFactories implements ExampleData {
     LOG.info("Testing a more complicated pipeline with a " + rpcType
         + " network connection in the middle");
     Context ctx = LogicalNodeContext.testingContext();
-    EventSource rpcSrc = srcfact.getSource(ctx, "rpcSource", "31337");
-    EventSink rpcSink = fact.getSink(ctx, "rpcSink", "0.0.0.0", "31337");
+    EventSource rpcSrc = srcfact.createSource(ctx, "rpcSource", 31337);
+    EventSink rpcSink = fact.createSink(ctx, "rpcSink", "0.0.0.0", 31337);
 
-    EventSink counter = fact.getSink(ctx, "counter", "count");
-    EventSource txtsrc = srcfact.getSource(ctx, "asciisynth", "25", "100");
+    EventSink counter = fact.createSink(ctx, "counter", (Object) "count");
+    EventSource txtsrc = srcfact.createSource(ctx, "asciisynth", 25, 100);
 
     DirectDriver svrconn = new DirectDriver(rpcSrc, counter);
     svrconn.start();
diff --git a/flume-core/src/test/java/com/cloudera/flume/conf/TestPatternMatch.java b/flume-core/src/test/java/com/cloudera/flume/conf/TestPatternMatch.java
index 3fec59d..5a463c6 100644
--- a/flume-core/src/test/java/com/cloudera/flume/conf/TestPatternMatch.java
+++ b/flume-core/src/test/java/com/cloudera/flume/conf/TestPatternMatch.java
@@ -236,7 +236,8 @@ public class TestPatternMatch {
     CommonTree fix = m.get("logical");
     LOG.info(fix.toStringTree());
 
-    String lname = FlumeBuilder.buildSimpleArg(m.get("LogicalNodeName"));
+    String lname = FlumeBuilder.buildSimpleArg(m.get("LogicalNodeName"))
+        .toString();
     LOG.info("LogicalName " + lname);
 
     CommonTree replace = FlumeBuilder.parseSink("rpcSink(\"foo\",12345)");
-- 
1.7.1

