org.kiji.schema.tools.LayoutTool.java Source code

Java tutorial

Introduction

Here is the source code for org.kiji.schema.tools.LayoutTool.java

Source

/**
 * (c) Copyright 2012 WibiData, Inc.
 *
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * Licensed 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.kiji.schema.tools;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;

import com.google.common.base.Preconditions;
import com.odiago.common.flags.Flag;
import org.apache.commons.io.IOUtils;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.client.HBaseAdmin;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.util.ToolRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.kiji.schema.KijiAdmin;
import org.kiji.schema.avro.TableLayoutDesc;
import org.kiji.schema.layout.KijiTableLayout;
import org.kiji.schema.util.ToJson;

/**
 * Command-line tool for interacting with table layouts. Actions include reading a layout,
 * setting a table layout, and viewing a table's layout history.
 */
public class LayoutTool extends VersionValidatedTool {
    private static final Logger LOG = LoggerFactory.getLogger(LayoutTool.class);

    @Flag(name = "do", usage = "Action to perform: dump, set, or history.")
    private String mDo = "dump";

    @Flag(name = "table", usage = "The kiji table to use.")
    private String mTableName = "";

    @Flag(name = "layout", usage = "Path to the file containing the layout update, in JSON.")
    private String mLayout = "";

    @Flag(name = "dry-run", usage = "Prints what actions would be taken, but does not commit changes.")
    private boolean mDryRun = false;

    @Flag(name = "max-versions", usage = "Maximum number of layout versions to retrieve in the layout history.")
    private int mMaxVersions = 1;

    @Flag(name = "write-to", usage = "Write layout(s) to this file(s). " + "Empty means write to console output. "
            + "A '.json' extension is appended to this parameter.")
    private String mWriteTo = "";

    private HBaseAdmin mHBaseAdmin;

    @Override
    protected void validateFlags() throws Exception {
        if (mTableName.isEmpty()) {
            throw new RequiredFlagException("table");
        }
        Preconditions.checkArgument(mMaxVersions >= 1, "--max-versions must be >= 1");
    }

    @Override
    protected void setup() throws Exception {
        super.setup();
        mHBaseAdmin = new HBaseAdmin(getConf());
    }

    @Override
    protected void cleanup() throws IOException {
        IOUtils.closeQuietly(mHBaseAdmin);
        super.cleanup();
    }

    /**
     * Implements the --do=dump operation.
     *
     * @param admin kiji admin interface.
     * @throws Exception on error.
     */
    private void dumpLayout(KijiAdmin admin) throws Exception {
        final KijiTableLayout layout = getKiji().getMetaTable().getTableLayout(mTableName);
        final String json = ToJson.toJsonString(layout.getDesc());
        if (mWriteTo.isEmpty()) {
            System.out.println(json);
        } else {
            final String fileName = String.format("%s.json", mWriteTo);
            final FileOutputStream fos = new FileOutputStream(fileName);
            try {
                fos.write(Bytes.toBytes(json));
            } finally {
                IOUtils.closeQuietly(fos);
            }
        }
    }

    /**
     * Loads a table layout descriptor from a JSON-encoded file.
     *
     * @param filePath Path to a JSON-encoded table layout descriptor.
     * @return the table layout descriptor decoded from the file.
     * @throws Exception on error.
     */
    private TableLayoutDesc loadJsonTableLayoutDesc(String filePath) throws Exception {
        final Path path = new Path(filePath);
        final FileSystem fs = fileSystemSpecified(path) ? path.getFileSystem(getConf())
                : FileSystem.getLocal(getConf());
        final InputStream istream = fs.open(path);
        try {
            return KijiTableLayout.readTableLayoutDescFromJSON(istream);
        } finally {
            IOUtils.closeQuietly(istream);
        }
    }

    /**
     * Implements the --do=set operation.
     *
     * @param admin kiji admin interface.
     * @throws Exception on error.
     */
    private void setLayout(KijiAdmin admin) throws Exception {
        final TableLayoutDesc layoutDesc = loadJsonTableLayoutDesc(mLayout);
        admin.setTableLayout(mTableName, layoutDesc, mDryRun, getPrintStream());
    }

    /**
     * Dumps the history of layouts of a given table.
     *
     * @param admin kiji admin interface.
     * @throws Exception on error.
     */
    private void history(KijiAdmin admin) throws Exception {
        // Gather all of the layouts stored in the metaTable.
        final NavigableMap<Long, KijiTableLayout> timedLayouts = getKiji().getMetaTable()
                .getTimedTableLayoutVersions(mTableName, mMaxVersions);
        if (timedLayouts.isEmpty()) {
            throw new RuntimeException("No such table: " + mTableName);
        }
        for (Map.Entry<Long, KijiTableLayout> entry : timedLayouts.entrySet()) {
            final long timestamp = entry.getKey();
            final KijiTableLayout layout = entry.getValue();
            final String json = ToJson.toJsonString(layout.getDesc());

            if (mWriteTo.isEmpty()) {
                System.out.printf("timestamp: %d:%n%s", timestamp, json);
            } else {
                final String fileName = String.format("%s-%d.json", mWriteTo, timestamp);
                final FileOutputStream fos = new FileOutputStream(fileName);
                try {
                    fos.write(Bytes.toBytes(json));
                } finally {
                    IOUtils.closeQuietly(fos);
                }
            }
        }
    }

    @Override
    protected int run(List<String> nonFlagArgs) throws Exception {
        final KijiAdmin admin = new KijiAdmin(mHBaseAdmin, getKiji());
        if (mDo.equals("dump")) {
            dumpLayout(admin);
        } else if (mDo.equals("set")) {
            Preconditions.checkArgument(!mLayout.isEmpty(), "Specify the layout with --layout=path/to/layout.json");
            setLayout(admin);
        } else if (mDo.equals("history")) {
            history(admin);
        } else {
            System.err.println("Unknown layout action: " + mDo);
            System.err.println("Specify the action to perform with --do=(dump|set|history)");
            return 1;
        }
        return 0;
    }

    /**
     * Determines whether a path has its filesystem explicitly specified.  Did it start
     * with "hdfs://" or "file://"?
     *
     * @param path The path to check.
     * @return Whether a file system was explicitly specified in the path.
     */
    protected static boolean fileSystemSpecified(Path path) {
        return null != path.toUri().getScheme();
    }

    /**
     * Program entry point.
     *
     * @param args The command-line arguments.
     * @throws Exception If there is an error.
     */
    public static void main(String[] args) throws Exception {
        System.exit(ToolRunner.run(new LayoutTool(), args));
    }
}