org.apache.hadoop.hbase.client.coprocessor.Batch.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.hbase.client.coprocessor.Batch.java

Source

/*
 * Copyright 2010 The Apache Software Foundation
 *
 * 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.hadoop.hbase.client.coprocessor;

import org.apache.commons.lang.reflect.MethodUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.hbase.ipc.CoprocessorProtocol;

import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * A collection of interfaces and utilities used for interacting with custom RPC
 * interfaces exposed by Coprocessors.
 */
public abstract class Batch {
    private static Log LOG = LogFactory.getLog(Batch.class);

    /**
     * Creates a new {@link Batch.Call} instance that invokes a method
     * with the given parameters and returns the result.
     *
     * <p>
     * Note that currently the method is naively looked up using the method name
     * and class types of the passed arguments, which means that
     * <em>none of the arguments can be <code>null</code></em>.
     * For more flexibility, see
     * {@link Batch#forMethod(java.lang.reflect.Method, Object...)}.
     * </p>
     *
     * @param protocol the protocol class being called
     * @param method the method name
     * @param args zero or more arguments to be passed to the method
     * (individual args cannot be <code>null</code>!)
     * @param <T> the class type of the protocol implementation being invoked
     * @param <R> the return type for the method call
     * @return a {@code Callable} instance that will invoke the given method
     * and return the results
     * @throws NoSuchMethodException if the method named, with the given argument
     *     types, cannot be found in the protocol class
     * @see Batch#forMethod(java.lang.reflect.Method, Object...)
     * @see org.apache.hadoop.hbase.client.HTable#coprocessorExec(Class, byte[], byte[], org.apache.hadoop.hbase.client.coprocessor.Batch.Call, org.apache.hadoop.hbase.client.coprocessor.Batch.Callback)
     */
    public static <T extends CoprocessorProtocol, R> Call<T, R> forMethod(final Class<T> protocol,
            final String method, final Object... args) throws NoSuchMethodException {
        Class[] types = new Class[args.length];
        for (int i = 0; i < args.length; i++) {
            if (args[i] == null) {
                throw new NullPointerException("Method argument cannot be null");
            }
            types[i] = args[i].getClass();
        }

        Method m = MethodUtils.getMatchingAccessibleMethod(protocol, method, types);
        if (m == null) {
            throw new NoSuchMethodException("No matching method found for '" + method + "'");
        }

        m.setAccessible(true);
        return forMethod(m, args);
    }

    /**
     * Creates a new {@link Batch.Call} instance that invokes a method
     * with the given parameters and returns the result.
     *
     * @param method the method reference to invoke
     * @param args zero or more arguments to be passed to the method
     * @param <T> the class type of the protocol implementation being invoked
     * @param <R> the return type for the method call
     * @return a {@code Callable} instance that will invoke the given method and
     * return the results
     * @see org.apache.hadoop.hbase.client.HTable#coprocessorExec(Class, byte[], byte[], org.apache.hadoop.hbase.client.coprocessor.Batch.Call, org.apache.hadoop.hbase.client.coprocessor.Batch.Callback)
     */
    public static <T extends CoprocessorProtocol, R> Call<T, R> forMethod(final Method method,
            final Object... args) {
        return new Call<T, R>() {
            public R call(T instance) throws IOException {
                try {
                    if (Proxy.isProxyClass(instance.getClass())) {
                        InvocationHandler invoker = Proxy.getInvocationHandler(instance);
                        return (R) invoker.invoke(instance, method, args);
                    } else {
                        LOG.warn("Non proxied invocation of method '" + method.getName() + "'!");
                        return (R) method.invoke(instance, args);
                    }
                } catch (IllegalAccessException iae) {
                    throw new IOException("Unable to invoke method '" + method.getName() + "'", iae);
                } catch (InvocationTargetException ite) {
                    throw new IOException(ite.toString(), ite);
                } catch (Throwable t) {
                    throw new IOException(t.toString(), t);
                }
            }
        };
    }

    /**
     * Defines a unit of work to be executed.
     *
     * <p>
     * When used with
     * {@link org.apache.hadoop.hbase.client.HTable#coprocessorExec(Class, byte[], byte[], org.apache.hadoop.hbase.client.coprocessor.Batch.Call, org.apache.hadoop.hbase.client.coprocessor.Batch.Callback)}
     * the implementations {@link Batch.Call#call(Object)} method will be invoked
     * with a proxy to the
     * {@link org.apache.hadoop.hbase.ipc.CoprocessorProtocol}
     * sub-type instance.
     * </p>
     * @see org.apache.hadoop.hbase.client.coprocessor
     * @see org.apache.hadoop.hbase.client.HTable#coprocessorExec(Class, byte[], byte[], org.apache.hadoop.hbase.client.coprocessor.Batch.Call)
     * @see org.apache.hadoop.hbase.client.HTable#coprocessorExec(Class, byte[], byte[], org.apache.hadoop.hbase.client.coprocessor.Batch.Call, org.apache.hadoop.hbase.client.coprocessor.Batch.Callback)
     * @param <T> the instance type to be passed to
     * {@link Batch.Call#call(Object)}
     * @param <R> the return type from {@link Batch.Call#call(Object)}
     */
    public static interface Call<T, R> {
        public R call(T instance) throws IOException;
    }

    /**
     * Defines a generic callback to be triggered for each {@link Batch.Call#call(Object)}
     * result.
     *
     * <p>
     * When used with
     * {@link org.apache.hadoop.hbase.client.HTable#coprocessorExec(Class, byte[], byte[], org.apache.hadoop.hbase.client.coprocessor.Batch.Call, org.apache.hadoop.hbase.client.coprocessor.Batch.Callback)},
     * the implementation's {@link Batch.Callback#update(byte[], byte[], Object)}
     * method will be called with the {@link Batch.Call#call(Object)} return value
     * from each region in the selected range.
     * </p>
     * @param <R> the return type from the associated {@link Batch.Call#call(Object)}
     * @see org.apache.hadoop.hbase.client.HTable#coprocessorExec(Class, byte[], byte[], org.apache.hadoop.hbase.client.coprocessor.Batch.Call, org.apache.hadoop.hbase.client.coprocessor.Batch.Callback)
     */
    public static interface Callback<R> {
        public void update(byte[] region, byte[] row, R result);
    }
}