Example usage for java.lang IllegalArgumentException getMessage

List of usage examples for java.lang IllegalArgumentException getMessage

Introduction

In this page you can find the example usage for java.lang IllegalArgumentException getMessage.

Prototype

public String getMessage() 

Source Link

Document

Returns the detail message string of this throwable.

Usage

From source file:com.unboundid.scim2.common.utils.Parser.java

/**
 * Parse a path string./*from ww w  .  ja v  a  2s. c  o  m*/
 *
 * @param pathString   The path string to parse.
 *
 * @return A parsed SCIM path.
 * @throws BadRequestException If the path string could not be parsed.
 */
public static Path parsePath(final String pathString) throws BadRequestException {
    if (pathString == null) {
        return Path.root();
    }

    final String trimmedPathString = pathString.trim();
    if (trimmedPathString.isEmpty()) {
        return Path.root();
    }

    Path path = Path.root();
    StringReader reader = new StringReader(trimmedPathString);
    if (SchemaUtils.isUrn(trimmedPathString)) {
        // The attribute name is prefixed with the schema URN.

        // Find the last ":" before any open brackets. Everything to the left is
        // the schema URN, everything on the right is the attribute name plus a
        // potential value filter.
        int j = trimmedPathString.indexOf('[');
        int i;
        if (j >= 0) {
            i = trimmedPathString.substring(0, j).lastIndexOf(':');
        } else {
            i = trimmedPathString.lastIndexOf(':');
        }
        String schemaUrn = trimmedPathString.substring(0, i++);
        String attributeName = trimmedPathString.substring(i, trimmedPathString.length());
        try {
            path = Path.root(schemaUrn);
        } catch (IllegalArgumentException e) {
            throw BadRequestException.invalidPath(e.getMessage());
        }
        if (attributeName.isEmpty()) {
            // The trailing colon signifies that this is an extension root.
            return path;
        }
        reader = new StringReader(attributeName);
    }

    String token;

    while ((token = readPathToken(reader)) != null) {
        if (token.isEmpty()) {
            // the only time this is allowed to occur is if the previous attribute
            // had a value filter, in which case, consume the token and move on.
            if (path.isRoot() || path.getElement(path.size() - 1).getValueFilter() == null) {
                final String msg = String.format("Attribute name expected at position %d", reader.mark);
                throw BadRequestException.invalidPath(msg);
            }
        } else {
            String attributeName = token;
            Filter valueFilter = null;
            try {
                if (attributeName.endsWith("[")) {
                    // There is a value path.
                    attributeName = attributeName.substring(0, attributeName.length() - 1);
                    valueFilter = readFilter(reader, true);
                }

                path = path.attribute(attributeName, valueFilter);
            } catch (BadRequestException be) {
                Debug.debugException(be);
                final String msg = String.format("Invalid value filter: %s", be.getMessage());
                throw BadRequestException.invalidPath(msg);
            } catch (Exception e) {
                Debug.debugException(e);
                final String msg = String.format("Invalid attribute name starting at position %d: %s",
                        reader.mark, e.getMessage());
                throw BadRequestException.invalidPath(msg);
            }
        }
    }

    return path;
}

From source file:gov.nih.nci.caarray.util.CaArrayUtils.java

/**
 * For each String bean property on o, if o is blank or empty, converts that property to null.
 * /*w w w .java2  s  .com*/
 * @param o object to convert properties on.
 */
public static void blankStringPropsToNull(Object o) {
    if (o == null) {
        return;
    }

    final ReflectionHelper helper = createReflectionHelper(o.getClass());
    for (final PropertyAccessor accessor : helper.getAccessors()) {
        if (accessor.getType().equals(String.class)) {
            try {
                if (StringUtils.isBlank((String) accessor.get(o))) {
                    accessor.set(o, null);
                }
            } catch (final IllegalArgumentException e) {
                LOG.debug(e.getMessage(), e);
            } catch (final IllegalAccessException e) {
                LOG.debug(e.getMessage(), e);
            } catch (final InvocationTargetException e) {
                LOG.debug(e.getMessage(), e);
            }
        }
    }
}

From source file:com.cloudera.flume.conf.FlumeBuilder.java

/**
 * Build a flume source from a flume config specification.
 * /*from   ww  w .  ja  va 2 s  .c  o m*/
 * This should only throw FlumeSpecExceptions (No illegal arg exceptions
 * anymore)
 */
public static EventSource buildSource(Context ctx, String s) throws FlumeSpecException {
    try {
        CommonTree srcTree = parseSource(s);
        return buildEventSource(ctx, srcTree);
    } catch (RecognitionException re) {
        LOG.debug("Failure to parse and instantiate sink: '" + s + "'", re);
        throw new FlumeSpecException(re.toString());
    } catch (NumberFormatException nfe) {
        LOG.debug("Failure to parse and instantiate sink: '" + s + "'", nfe);
        throw new FlumeSpecException(nfe.getMessage());
    } catch (IllegalArgumentException iae) {
        LOG.debug("Failure to parse and instantiate sink: '" + s + "'", iae);
        throw new FlumeSpecException(iae.getMessage());
    } catch (RuntimeRecognitionException re) {
        LOG.debug("Failure to parse and instantiate sink: '" + s + "'", re);
        throw new FlumeSpecException(re.getMessage());
    }
}

From source file:com.cloudera.flume.conf.FlumeBuilder.java

/**
 * Build a flume sink from a flume config specification. Sinks can be much
 * more complicated than sources.//from   w  ww  .j  ava2  s . co  m
 * 
 * This should only throw FlumeSpecExceptions (No illegal arg exceptions
 * anymore)
 */
public static EventSink buildSink(Context context, String s) throws FlumeSpecException {
    try {
        CommonTree snkTree = parseSink(s);
        return buildEventSink(context, snkTree, sinkFactory);
    } catch (RecognitionException re) {
        LOG.debug("Failure to parse and instantiate sink: '" + s + "'", re);
        throw new FlumeSpecException(re.toString());
    } catch (NumberFormatException nfe) {
        LOG.debug("Failure to parse and instantiate sink: '" + s + "'", nfe);
        throw new FlumeSpecException(nfe.getMessage());
    } catch (IllegalArgumentException iae) {
        LOG.debug("Failure to parse and instantiate sink: '" + s + "'", iae);
        throw new FlumeSpecException(iae.getMessage());
    } catch (RuntimeRecognitionException re) {
        LOG.debug("Failure to parse and instantiate sink: '" + s + "'", re);
        throw new FlumeSpecException(re.getMessage());
    }
}

From source file:net.sf.firemox.xml.XmlTools.java

/**
 * Write the TestOn instance corresponding to the given XSD attribute name.
 * //from w ww . jav  a 2 s. co m
 * @param out
 *          the stream this enumeration would be written.
 * @param xsdName
 *          the XSD name of this TestOn.
 * @throws IOException
 *           error while writing.
 */
public static void writeTestOn(OutputStream out, String xsdName) throws IOException {
    if (xsdName != null) {
        try {
            TestOn.serialize(out, xsdName);
        } catch (IllegalArgumentException e) {
            XmlConfiguration.error(e.getMessage());
            TestOn.THIS.serialize(out);
        }
    } else if (defaultOnMeTag)
        TestOn.THIS.serialize(out);
    else
        TestOn.TESTED.serialize(out);
}

From source file:com.impetus.kundera.utils.KunderaCoreUtils.java

private static void prepareLuceneQueryForPartitionKey(LuceneQueryBuilder queryBuilder, Object key,
        MetamodelImpl metaModel, String indexName, Class valueClazz) {
    Field[] fields = key.getClass().getDeclaredFields();
    EmbeddableType embeddable = metaModel.embeddable(key.getClass());
    boolean appendAnd = false;

    try {/*  w ww. j a v  a2 s  .co  m*/
        for (int i = 0; i < fields.length; i++) {
            if (!ReflectUtils.isTransientOrStatic(fields[i])) {
                if (metaModel.isEmbeddable(((AbstractAttribute) embeddable.getAttribute(fields[i].getName()))
                        .getBindableJavaType())) {
                    fields[i].setAccessible(true);
                    prepareLuceneQueryForPartitionKey(queryBuilder, fields[i].get(key), metaModel, indexName,
                            valueClazz);
                } else {
                    if (appendAnd) {
                        queryBuilder.buildQuery("AND", "AND", String.class);
                    }
                    appendAnd = true;
                    String fieldValue = PropertyAccessorHelper.getString(key, fields[i]);
                    fieldValue = fieldValue.replaceAll("[^a-zA-Z0-9]", "_");
                    queryBuilder.appendIndexName(indexName).appendPropertyName(fields[i].getName())
                            .buildQuery("=", fieldValue, valueClazz);
                }
            }
        }
    } catch (IllegalArgumentException e) {
        logger.error("Error during prepare composite key, Caused by {}.", e);
        throw new PersistenceException(e);
    } catch (IllegalAccessException e) {
        logger.error(e.getMessage());
    }
}

From source file:Browser.java

/**
 * Attempts to locate the default web browser on the local system.  
 * Caches results so it only locates the browser once for each use of this 
 * class per JVM instance./*from www .java 2  s.c  om*/
 *
 * @return The browser for the system.  Note that this may not be what you 
 * would consider to be a standard web browser; instead, it's the 
 * application that gets called to open the default web browser.  In some 
 * cases, this will be a non-String object that provides the means of 
 * calling the default browser.
 */
private static Object locateBrowser() {
    if (browser != null) {
        return browser;
    }
    switch (jvm) {
    case MRJ_2_0:
        try {
            Integer finderCreatorCode = (Integer) makeOSType.invoke(null, new Object[] { FINDER_CREATOR });
            Object aeTarget = aeTargetConstructor.newInstance(new Object[] { finderCreatorCode });
            Integer gurlType = (Integer) makeOSType.invoke(null, new Object[] { GURL_EVENT });
            Object appleEvent = appleEventConstructor.newInstance(
                    new Object[] { gurlType, gurlType, aeTarget, kAutoGenerateReturnID, kAnyTransactionID });

            // Don't set browser = appleEvent because then the next time we call
            // locateBrowser(), we'll get the same AppleEvent, to which we'll 
            // already have added the relevant parameter. Instead, regenerate 
            // the AppleEvent every time. There's probably a way to do this 
            // better; if any has any ideas, please let me know.

            return appleEvent;
        } catch (IllegalAccessException iae) {
            browser = null;
            errorMessage = iae.getMessage();
            return browser;
        } catch (InstantiationException ie) {
            browser = null;
            errorMessage = ie.getMessage();
            return browser;
        } catch (InvocationTargetException ite) {
            browser = null;
            errorMessage = ite.getMessage();
            return browser;
        }

    case MRJ_2_1:
        File systemFolder;
        try {
            systemFolder = (File) findFolder.invoke(null, new Object[] { kSystemFolderType });
        } catch (IllegalArgumentException iare) {
            browser = null;
            errorMessage = iare.getMessage();
            return browser;
        } catch (IllegalAccessException iae) {
            browser = null;
            errorMessage = iae.getMessage();
            return browser;
        } catch (InvocationTargetException ite) {
            browser = null;
            errorMessage = ite.getTargetException().getClass() + ": " + ite.getTargetException().getMessage();
            return browser;
        }

        // Avoid a FilenameFilter because that can't be stopped mid-list
        String[] systemFolderFiles = systemFolder.list();

        for (int i = 0; i < systemFolderFiles.length; i++) {
            try {
                File file = new File(systemFolder, systemFolderFiles[i]);
                if (!file.isFile()) {
                    continue;
                }
                // We're looking for a file with a creator code of 'MACS' and
                // a type of 'FNDR'.  Only requiring the type results in non-Finder
                // applications being picked up on certain Mac OS 9 systems,
                // especially German ones, and sending a GURL event to those
                // applications results in a logout under Multiple Users.
                Object fileType = getFileType.invoke(null, new Object[] { file });
                if (FINDER_TYPE.equals(fileType.toString())) {
                    Object fileCreator = getFileCreator.invoke(null, new Object[] { file });
                    if (FINDER_CREATOR.equals(fileCreator.toString())) {
                        // Actually the Finder, but that's OK
                        browser = file.toString();
                        return browser;
                    }
                }
            } catch (IllegalArgumentException iare) {
                browser = browser;
                errorMessage = iare.getMessage();
                return null;
            } catch (IllegalAccessException iae) {
                browser = null;
                errorMessage = iae.getMessage();
                return browser;
            } catch (InvocationTargetException ite) {
                browser = null;
                errorMessage = ite.getTargetException().getClass() + ": "
                        + ite.getTargetException().getMessage();
                return browser;
            }
        }
        browser = null;
        break;

    case MRJ_3_0:
    case MRJ_3_1:
        browser = ""; // Return something non-null
        break;

    case WINDOWS_NT:
        browser = "cmd.exe";
        break;

    case WINDOWS_9x:
        browser = "command.com";
        break;

    case OTHER:
    default:
        browser = "netscape";
        break;
    }

    return browser;
}

From source file:fxts.stations.util.BrowserLauncher.java

/**
 * Attempts to locate the default web browser on the local system.  Caches results so it
 * only locates the browser once for each use of this class per JVM instance.
 *
 * @return The browser for the system.  Note that this may not be what you would consider
 *         to be a standard web browser; instead, it's the application that gets called to
 *         open the default web browser.  In some cases, this will be a non-String object
 *         that provides the means of calling the default browser.
 *//*from   w  w w  .j  av a  2 s .  c o m*/
private static Object locateBrowser() {
    if (browser != null) {
        return browser;
    }
    switch (jvm) {
    case MRJ_2_0:
        try {
            Integer finderCreatorCode = (Integer) makeOSType.invoke(null, new Object[] { FINDER_CREATOR });
            Object aeTarget = aeTargetConstructor.newInstance(new Object[] { finderCreatorCode });
            Integer gurlType = (Integer) makeOSType.invoke(null, new Object[] { GURL_EVENT });
            Object appleEvent = appleEventConstructor.newInstance(
                    new Object[] { gurlType, gurlType, aeTarget, kAutoGenerateReturnID, kAnyTransactionID });
            // Don't set browser = appleEvent because then the next time we call
            // locateBrowser(), we'll get the same AppleEvent, to which we'll already have
            // added the relevant parameter. Instead, regenerate the AppleEvent every time.
            // There's probably a way to do this better; if any has any ideas, please let
            // me know.
            return appleEvent;
        } catch (IllegalAccessException iae) {
            browser = null;
            errorMessage = iae.getMessage();
            return browser;
        } catch (InstantiationException ie) {
            browser = null;
            errorMessage = ie.getMessage();
            return browser;
        } catch (InvocationTargetException ite) {
            browser = null;
            errorMessage = ite.getMessage();
            return browser;
        }
    case MRJ_2_1:
        File systemFolder;
        try {
            systemFolder = (File) findFolder.invoke(null, new Object[] { kSystemFolderType });
        } catch (IllegalArgumentException iare) {
            browser = null;
            errorMessage = iare.getMessage();
            return browser;
        } catch (IllegalAccessException iae) {
            browser = null;
            errorMessage = iae.getMessage();
            return browser;
        } catch (InvocationTargetException ite) {
            browser = null;
            errorMessage = ite.getTargetException().getClass() + ": " + ite.getTargetException().getMessage();
            return browser;
        }
        String[] systemFolderFiles = systemFolder.list();
        // Avoid a FilenameFilter because that can't be stopped mid-list
        for (int i = 0; i < systemFolderFiles.length; i++) {
            try {
                File file = new File(systemFolder, systemFolderFiles[i]);
                if (!file.isFile()) {
                    continue;
                }
                // We're looking for a file with a creator code of 'MACS' and
                // a type of 'FNDR'.  Only requiring the type results in non-Finder
                // applications being picked up on certain Mac OS 9 systems,
                // especially German ones, and sending a GURL event to those
                // applications results in a logout under Multiple Users.
                Object fileType = getFileType.invoke(null, new Object[] { file });
                if (FINDER_TYPE.equals(fileType.toString())) {
                    Object fileCreator = getFileCreator.invoke(null, new Object[] { file });
                    if (FINDER_CREATOR.equals(fileCreator.toString())) {
                        browser = file.toString(); // Actually the Finder, but that's OK
                        return browser;
                    }
                }
            } catch (IllegalArgumentException iare) {
                browser = browser;
                errorMessage = iare.getMessage();
                return null;
            } catch (IllegalAccessException iae) {
                browser = null;
                errorMessage = iae.getMessage();
                return browser;
            } catch (InvocationTargetException ite) {
                browser = null;
                errorMessage = ite.getTargetException().getClass() + ": "
                        + ite.getTargetException().getMessage();
                return browser;
            }
        }
        browser = null;
        break;
    case MRJ_3_0:
    case MRJ_3_1:
        browser = ""; // Return something non-null
        break;
    case WINDOWS_NT:
        browser = "cmd.exe";
        break;
    case WINDOWS_9x:
        browser = "command.com";
        break;
    case OTHER:
    default:
        browser = "netscape";
        break;
    }
    return browser;
}

From source file:com.jpeterson.littles3.bo.Acp.java

/**
 * Decode an Acp as XML./*from ww w .  ja v  a 2  s  . co m*/
 * 
 * @param xml
 *            The Acp encoded as XML.
 * @return The Acp decoded from the XML.
 */
public static Acp decode(InputStream xml) throws IOException {
    Acp acp;
    SAXBuilder builder;
    Document document;
    Element accessControlPolicyElement;
    Element ownerElement;
    Element idElement, displayNameElement;
    Element accessControlListElement;
    Element grantElement;
    Element granteeElement, permissionElement;
    Element uriElement;
    Attribute typeAttribute;
    CanonicalUser user;
    Namespace defaultNamespace;

    acp = new Acp();

    builder = new SAXBuilder();

    try {
        document = builder.build(xml);

        accessControlPolicyElement = document.getRootElement();

        if (!(ELEMENT_ACCESS_CONTROL_POLICY.equals(accessControlPolicyElement.getName()))) {
            // TODO: indicate error

            System.out.println("Constant ELEMENT_ACCESS_CONTROL_POLICY: " + ELEMENT_ACCESS_CONTROL_POLICY);
            System.out.println("accessControlPolicyElement.getName(): " + accessControlPolicyElement.getName());

            throw new IOException("Invalid root element: " + accessControlPolicyElement);
        }

        defaultNamespace = accessControlPolicyElement.getNamespace();

        if ((ownerElement = accessControlPolicyElement.getChild(ELEMENT_OWNER, defaultNamespace)) == null) {
            throw new IOException("Invalid XML. Should have 'Owner' element");
        }

        if ((idElement = ownerElement.getChild(ELEMENT_ID, defaultNamespace)) == null) {
            throw new IOException("Invalid XML. Should have 'ID' element");
        }

        user = new CanonicalUser(idElement.getText());

        if ((displayNameElement = ownerElement.getChild(ELEMENT_DISPLAY_NAME, defaultNamespace)) != null) {
            user.setDisplayName(displayNameElement.getText());
        }

        acp.setOwner(user);

        if ((accessControlListElement = accessControlPolicyElement.getChild(ELEMENT_ACCESS_CONTROL_LIST,
                defaultNamespace)) == null) {
            throw new IOException("Invalid XML. Should have 'AccessControlList' element");
        }

        for (Iterator grants = accessControlListElement.getChildren(ELEMENT_GRANT, defaultNamespace)
                .iterator(); grants.hasNext();) {
            Grantee grantee;

            grantElement = (Element) grants.next();
            if ((granteeElement = grantElement.getChild(ELEMENT_GRANTEE, defaultNamespace)) == null) {
                throw new IOException("Invalid XML. Should have 'Grantee' element");
            }
            if ((permissionElement = grantElement.getChild(ELEMENT_PERMISSION, defaultNamespace)) == null) {
                throw new IOException("Invalid XML. Should have 'Permission' element");
            }

            if ((typeAttribute = granteeElement.getAttribute(ATTRIBUTE_TYPE, NAMESPACE_XSI)) == null) {
                throw new IOException("Invalid XML. Should have 'type' attribute");
            }
            String typeValue = typeAttribute.getValue();
            if (ATTRIBUTE_TYPE_VALUE_CANONICAL_USER.equals(typeValue)) {
                if ((idElement = granteeElement.getChild(ELEMENT_ID, defaultNamespace)) == null) {
                    throw new IOException("Invalid XML. Should have 'ID' element");
                }

                user = new CanonicalUser(idElement.getText());

                if ((displayNameElement = granteeElement.getChild(ELEMENT_DISPLAY_NAME,
                        defaultNamespace)) != null) {
                    user.setDisplayName(displayNameElement.getText());
                }

                grantee = user;
            } else if (ATTRIBUTE_TYPE_VALUE_GROUP.equals(typeValue)) {
                if ((uriElement = granteeElement.getChild(ELEMENT_URI, defaultNamespace)) == null) {
                    throw new IOException("Invalid XML. Should have 'URI' element");
                }

                String uriValue = uriElement.getValue();
                if (AllUsersGroup.URI_STRING.equals(uriValue)) {
                    grantee = AllUsersGroup.getInstance();
                } else if (AuthenticatedUsersGroup.URI_STRING.equals(uriValue)) {
                    grantee = AuthenticatedUsersGroup.getInstance();
                } else {
                    throw new IOException("Unknown group uri: " + uriValue);
                }
            } else {
                throw new IOException("Unknown type: " + typeValue);
            }

            try {
                acp.grant(grantee, permissionElement.getValue());
            } catch (IllegalArgumentException e) {
                IOException ex = new IOException("Invalid permission: " + permissionElement.getValue());
                ex.initCause(e);
                throw ex;
            }
        }
    } catch (JDOMException e) {
        IOException ex = new IOException(e.getMessage());
        ex.initCause(e);
        throw ex;
    }

    return acp;
}

From source file:com.cloudera.flume.conf.FlumeBuilder.java

@SuppressWarnings("unchecked")
static EventSink buildEventSink(Context context, CommonTree t, SinkFactory sinkFactory)
        throws FlumeSpecException {
    ASTNODE type = ASTNODE.valueOf(t.getText()); // convert to enum
    switch (type) {
    case SINK: {/*from  w  w w .j  a va  2s . c  o  m*/

        Context ctx = new Context(context);
        Pair<String, List<String>> idargs = handleArgs(t, ctx);
        String sinkType = idargs.getLeft();
        List<String> args = idargs.getRight();

        EventSink snk = sinkFactory.getSink(ctx, sinkType, args.toArray(new String[0]));

        if (snk == null) {
            throw new FlumeIdException("Invalid sink: " + FlumeSpecGen.genEventSink(t));
        }
        return snk;
    }
    case MULTI: {
        List<CommonTree> elems = (List<CommonTree>) t.getChildren();
        List<EventSink> snks = new ArrayList<EventSink>();
        try {
            for (CommonTree tr : elems) {
                EventSink s = buildEventSink(context, tr, sinkFactory);
                snks.add(s);
            }
            FanOutSink<EventSink> sink = new FanOutSink<EventSink>(snks);
            return sink;
        } catch (FlumeSpecException ife) {
            // TODO (jon) do something if there was an intermediate failure
            throw ife;
        }
    }
    case DECO: {
        List<CommonTree> decoNodes = (List<CommonTree>) t.getChildren();
        Preconditions.checkArgument(decoNodes.size() <= 2, "Only supports one or no decorators per expression");
        // no decorators
        if (decoNodes.size() == 1) {
            CommonTree snkt = decoNodes.get(0);
            try {
                EventSink singleSnk = buildEventSink(context, snkt, sinkFactory);
                return singleSnk;
            } catch (FlumeSpecException ife) {
                throw ife;
            }
        }

        // single decorator
        CommonTree deco = decoNodes.get(0);
        CommonTree decoSnk = decoNodes.get(1);
        EventSinkDecorator<EventSink> decoSink = buildEventSinkDecorator(context, deco);
        try {
            EventSink dsnk = buildEventSink(context, decoSnk, sinkFactory);
            decoSink.setSink(dsnk);
            return decoSink;
        } catch (FlumeSpecException ife) {
            // TODO (jon) need to cleanup after mainsink if this failed.
            throw ife;
        }
    }

    case BACKUP: {
        List<CommonTree> backupNodes = (List<CommonTree>) t.getChildren();
        Preconditions.checkArgument(backupNodes.size() == 2,
                "Only supports two retry nodes per failover expression");
        CommonTree main = backupNodes.get(0);
        CommonTree backup = backupNodes.get(1);
        try {
            EventSink mainSink = buildEventSink(context, main, sinkFactory);
            EventSink backupSink = buildEventSink(context, backup, sinkFactory);
            return new BackOffFailOverSink(mainSink, backupSink);
        } catch (FlumeSpecException ife) {
            LOG.error("Failed to build Failover sink", ife);
            throw ife;
        }
    }

    case LET: {
        List<CommonTree> letNodes = (List<CommonTree>) t.getChildren();
        Preconditions.checkArgument(letNodes.size() == 3);
        String argName = letNodes.get(0).getText();
        CommonTree arg = letNodes.get(1);
        CommonTree body = letNodes.get(2);
        try {
            EventSink argSink = buildEventSink(context, arg, sinkFactory);

            // TODO (jon) This isn't exactly right. 'let' currently does
            // "substitution on parse", which means when there are multiple
            // instances of the let subexpression, it will get opened twice (which
            // is now illegal). This hack makes things work by relaxing open's
            // semantics so that multiple opens are ignored.

            // Another approach is to have "substitution on open". Let would work
            // differently than here. We would have LetDecorator that internally
            // keeps the subexpression and then body. The references to the
            // subexpression in the body would get replaced with a reference. On
            // open, the subexpression would be opened, and the body as well. As the
            // body is traversed, if the reference would not be opened, but would
            // substitute the (already) open subexpression in its place.

            EventSink argSinkRef = new EventSinkDecorator<EventSink>(argSink) {
                boolean open = false;

                @Override
                public void open() throws IOException, InterruptedException {
                    if (open) {
                        return; // Do nothing because already open
                    }
                    open = true;
                    sink.open();
                }

                @Override
                public void append(Event e) throws IOException, InterruptedException {
                    Preconditions.checkState(open);
                    sink.append(e);
                }

                @Override
                public void close() throws IOException, InterruptedException {
                    open = false;
                    sink.close();
                }

            };

            // add arg to context

            LinkedSinkFactory linkedFactory = new LinkedSinkFactory(sinkFactory, argName, argSinkRef);
            EventSink bodySink = buildEventSink(context, body, linkedFactory);
            return bodySink;
        } catch (FlumeSpecException ife) {
            throw ife;
        }
    }

    case ROLL: {
        List<CommonTree> rollArgs = (List<CommonTree>) t.getChildren();
        try {
            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)));
            String body = FlumeSpecGen.genEventSink(ctbody);
            // TODO (jon) replace the hard coded 250 with a parameterizable value
            RollSink roller = new RollSink(context, body, period, 250);
            return roller;
        } catch (IllegalArgumentException iae) {
            throw new FlumeSpecException(iae.getMessage());
        }

    }

    case GEN: {
        List<CommonTree> collArgs = (List<CommonTree>) t.getChildren();
        try {
            Preconditions.checkArgument(collArgs.size() >= 2,
                    "bad parse tree! " + t.toStringTree() + " generator takes at least 2 arguments");
            String genType = collArgs.get(0).getText();
            if (!"collector".equals(genType)) {
                throw new FlumeSpecException("currently only handle 'collector' gen sinks");
            }
            CommonTree ctbody = collArgs.remove(1); // remove subsink.
            String body = FlumeSpecGen.genEventSink(ctbody);

            Context ctx = new Context(context);
            Pair<String, List<String>> idArgs = handleArgs(t, ctx);
            String sourceType = idArgs.getLeft();
            List<String> 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]));

        } catch (IllegalArgumentException iae) {
            throw new FlumeSpecException(iae.getMessage());
        }

    }

    case FAILCHAIN: {
        // TODO (jon) This is no longer necessary with the substitution mechanisms
        // found in the translators
        List<CommonTree> rollArgs = (List<CommonTree>) t.getChildren();
        Preconditions.checkArgument(rollArgs.size() >= 2);
        CommonTree ctbody = rollArgs.get(0);
        List<String> rargs = new ArrayList<String>(rollArgs.size() - 1);
        boolean first = true;
        for (CommonTree ct : rollArgs) {
            if (first) {
                first = false;
                continue;
            }
            // assumes this is a STRING
            rargs.add(buildSimpleArg(ct));
        }
        String body = FlumeSpecGen.genEventSink(ctbody);
        FlumeConfiguration conf = FlumeConfiguration.get();
        FailoverChainSink failchain = new FailoverChainSink(context, body, rargs,
                conf.getFailoverInitialBackoff(), conf.getFailoverMaxSingleBackoff());
        return failchain;
    }
    // TODO (jon) new feature: handle pattern match splitter
    // case MATCH:

    default:
        throw new FlumeSpecException("bad parse tree! expected sink but got " + t.toStringTree());
    }
}