Package org.apache.flume.channel

Source Code of org.apache.flume.channel.ChannelUtils

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.flume.channel;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;

import org.apache.flume.Channel;
import org.apache.flume.ChannelException;
import org.apache.flume.Event;
import org.apache.flume.Transaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* <p>
* A collection of utilities for interacting with {@link Channel}
* objects.  Use of these utilities prevents error-prone replication
* of required transaction usage semantics, and allows for more
* concise code.
* </p>
* <p>
* However, as a side-effect of its generality, and in particular of
* its use of {@link Callable}, any checked exceptions thrown by
* user-created transactors will be silently wrapped with {@link
* ChannelException} before being propagated.  Only direct use of
* {@link #transact(Channel,Callable)} suffers from this issue, even
* though all other methods are based upon it, because none of the
* other methods are capable of producing or allowing checked
* exceptions in the first place.
* </p>
*/
public class ChannelUtils {

  private static final Logger logger = LoggerFactory
      .getLogger(ChannelUtils.class);

  /**
   * <p>
   * A convenience method for single-event <code>put</code> transactions.
   * </p>
   * @see #transact(Channel,Callable)
   */
  public static void put(final Channel channel, final Event event)
      throws ChannelException {
    transact(channel, new Runnable() {
        @Override
        public void run() {
          channel.put(event);
        }
      });
  }

  /**
   * <p>
   * A convenience method for multiple-event <code>put</code> transactions.
   * </p>
   * @see #transact(Channel,Callable)
   */
  public static void put(final Channel channel, final Collection<Event> events)
      throws ChannelException {
    transact(channel, new Runnable() {
        @Override
        public void run() {
          for (Event event : events) {
            channel.put(event);
          }
        }
      });
  }

  /**
   * <p>
   * A convenience method for single-event <code>take</code> transactions.
   * </p>
   * @return a single event, or null if the channel has none available
   * @see #transact(Channel,Callable)
   */
  public static Event take(final Channel channel)
      throws ChannelException {
    return transact(channel, new Callable<Event>() {
        @Override
        public Event call() {
          return channel.take();
        }
      });
  }

  /**
   * <p>
   * A convenience method for multiple-event <code>take</code> transactions.
   * </p>
   * @return a list of at most <code>max</code> events
   * @see #transact(Channel,Callable)
   */
  public static List<Event> take(final Channel channel, final int max)
      throws ChannelException {
    return transact(channel, new Callable<List<Event>>() {
        @Override
        public List<Event> call() {
          List<Event> events = new ArrayList<Event>(max);
          while (events.size() < max) {
            Event event = channel.take();
            if (event == null) {
              break;
            }
            events.add(event);
          }
          return events;
        }
      });
  }

  /**
   * <p>
   * A convenience method for transactions that don't require a return
   * value.  Simply wraps the <code>transactor</code> using {@link
   * Executors#callable} and passes that to {@link
   * #transact(Channel,Callable)}.
   * </p>
   * @see #transact(Channel,Callable)
   * @see Executors#callable(Runnable)
   */
  public static void transact(Channel channel, Runnable transactor)
      throws ChannelException {
    transact(channel, Executors.callable(transactor));
  }

  /**
   * <p>
   * A general optimistic implementation of {@link Transaction} client
   * semantics.  It gets a new transaction object from the
   * <code>channel</code>, calls <code>begin()</code> on it, and then
   * invokes the supplied <code>transactor</code> object.  If an
   * exception is thrown, then the transaction is rolled back;
   * otherwise the transaction is committed and the value returned by
   * the <code>transactor</code> is returned.  In either case, the
   * transaction is closed before the function exits.  All secondary
   * exceptions (i.e. those thrown by
   * <code>Transaction.rollback()</code> or
   * <code>Transaction.close()</code> while recovering from an earlier
   * exception) are logged, allowing the original exception to be
   * propagated instead.
   * </p>
   * <p>
   * This implementation is optimistic in that it expects transaction
   * rollback to be infrequent: it will rollback a transaction only
   * when the supplied <code>transactor</code> throws an exception,
   * and exceptions are a fairly heavyweight mechanism for handling
   * frequently-occurring events.
   * </p>
   * @return the value returned by <code>transactor.call()</code>
   */
  public static <T> T transact(Channel channel, Callable<T> transactor)
      throws ChannelException {
    Transaction transaction = channel.getTransaction();
    boolean committed = false;
    boolean interrupted = false;
    try {
      transaction.begin();
      T value = transactor.call();
      transaction.commit();
      committed = true;
      return value;
    } catch (Throwable e) {
      interrupted = Thread.currentThread().isInterrupted();
      try {
        transaction.rollback();
      } catch (Throwable e2) {
        logger.error("Failed to roll back transaction, exception follows:", e2);
      }
      if (e instanceof InterruptedException) {
        interrupted = true;
      } else if (e instanceof Error) {
        throw (Error) e;
      } else if (e instanceof RuntimeException) {
        throw (RuntimeException) e;
      }
      throw new ChannelException(e);
    } finally {
      interrupted = interrupted || Thread.currentThread().isInterrupted();
      try {
        transaction.close();
      } catch (Throwable e) {
        if (committed) {
          if (e instanceof Error) {
            throw (Error) e;
          } else if (e instanceof RuntimeException) {
            throw (RuntimeException) e;
          } else {
            throw new ChannelException(e);
          }
        } else {
          logger.error(
              "Failed to close transaction after error, exception follows:", e);
        }
      } finally {
        if (interrupted) {
          Thread.currentThread().interrupt();
        }
      }
    }
  }

  /** Disallows instantiation */
  private ChannelUtils() {}
}
TOP

Related Classes of org.apache.flume.channel.ChannelUtils

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.