You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tajo.apache.org by hy...@apache.org on 2014/04/21 13:13:01 UTC

[7/9] git commit: TAJO-737: Change version message when daemon starts up. (hyunsik)

TAJO-737: Change version message when daemon starts up. (hyunsik)


Project: http://git-wip-us.apache.org/repos/asf/tajo/repo
Commit: http://git-wip-us.apache.org/repos/asf/tajo/commit/bbf2461a
Tree: http://git-wip-us.apache.org/repos/asf/tajo/tree/bbf2461a
Diff: http://git-wip-us.apache.org/repos/asf/tajo/diff/bbf2461a

Branch: refs/heads/window_function
Commit: bbf2461a5bddc77b3597030976158e00ee88fe0d
Parents: c367377
Author: Hyunsik Choi <hy...@apache.org>
Authored: Mon Apr 21 16:38:48 2014 +0900
Committer: Hyunsik Choi <hy...@apache.org>
Committed: Mon Apr 21 16:39:15 2014 +0900

----------------------------------------------------------------------
 CHANGES.txt                                     |   2 +
 pom.xml                                         |   1 +
 tajo-common/pom.xml                             |  45 +++
 .../java/org/apache/tajo/util/StringUtils.java  |  68 ++++
 .../java/org/apache/tajo/util/VersionInfo.java  | 177 ++++++++++
 .../main/resources/tajo-version-info.properties |  26 ++
 .../java/org/apache/tajo/master/TajoMaster.java |   2 +-
 .../java/org/apache/tajo/worker/TajoWorker.java |   2 +-
 tajo-maven-plugins/pom.xml                      |  88 +++++
 .../tajo/maven/plugin/protoc/ProtocMojo.java    | 114 ++++++
 .../org/apache/tajo/maven/plugin/util/Exec.java | 117 +++++++
 .../tajo/maven/plugin/util/FileSetUtils.java    |  61 ++++
 .../plugin/versioninfo/VersionInfoMojo.java     | 344 +++++++++++++++++++
 13 files changed, 1045 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tajo/blob/bbf2461a/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 7f22b06..7f1b175 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -153,6 +153,8 @@ Release 0.8.0 - unreleased
 
   IMPROVEMENTS
 
+    TAJO-737: Change version message when daemon starts up. (hyunsik)
+
     TAJO-768: Improve the log4j configuration. (hyoungjunkim via jinho)
 
     TAJO-755: ALTER TABLESPACE LOCATION support. (hyunsilk)

http://git-wip-us.apache.org/repos/asf/tajo/blob/bbf2461a/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 964d984..6eea5c8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -78,6 +78,7 @@
   </properties>
 
   <modules>
+    <module>tajo-maven-plugins</module>
     <module>tajo-project</module>
     <module>tajo-common</module>
     <module>tajo-algebra</module>

http://git-wip-us.apache.org/repos/asf/tajo/blob/bbf2461a/tajo-common/pom.xml
----------------------------------------------------------------------
diff --git a/tajo-common/pom.xml b/tajo-common/pom.xml
index 35ac3e5..f334380 100644
--- a/tajo-common/pom.xml
+++ b/tajo-common/pom.xml
@@ -46,8 +46,53 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xs
   </repositories>
 
   <build>
+    <!--
+  Include all files in src/main/resources.  By default, do not apply property
+  substitution (filtering=false), but do apply property substitution to
+  tajo-version-info.properties (filtering=true).  This will substitute the
+  version information correctly, but prevent Maven from altering other files
+  like tajo-default.xml.
+  -->
+    <resources>
+      <resource>
+        <directory>${basedir}/src/main/resources</directory>
+        <excludes>
+          <exclude>tajo-version-info.properties</exclude>
+        </excludes>
+        <filtering>false</filtering>
+      </resource>
+      <resource>
+        <directory>${basedir}/src/main/resources</directory>
+        <includes>
+          <include>tajo-version-info.properties</include>
+        </includes>
+        <filtering>true</filtering>
+      </resource>
+    </resources>
     <plugins>
       <plugin>
+      <groupId>org.apache.tajo</groupId>
+      <artifactId>tajo-maven-plugins</artifactId>
+        <executions>
+          <execution>
+            <id>version-info</id>
+            <phase>generate-resources</phase>
+            <goals>
+              <goal>version-info</goal>
+            </goals>
+            <configuration>
+              <source>
+                <directory>${basedir}/src/main</directory>
+                <includes>
+                  <include>java/**/*.java</include>
+                  <include>proto/**/*.proto</include>
+                </includes>
+              </source>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-compiler-plugin</artifactId>
         <configuration>

http://git-wip-us.apache.org/repos/asf/tajo/blob/bbf2461a/tajo-common/src/main/java/org/apache/tajo/util/StringUtils.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/util/StringUtils.java b/tajo-common/src/main/java/org/apache/tajo/util/StringUtils.java
index 32edc31..ed9014d 100644
--- a/tajo-common/src/main/java/org/apache/tajo/util/StringUtils.java
+++ b/tajo-common/src/main/java/org/apache/tajo/util/StringUtils.java
@@ -18,9 +18,20 @@
 
 package org.apache.tajo.util;
 
+import org.apache.commons.lang.SystemUtils;
+import org.apache.hadoop.util.ShutdownHookManager;
+import org.apache.hadoop.util.SignalLogger;
+
+import java.util.Arrays;
+
 public class StringUtils {
 
   /**
+   * Priority of the StringUtils shutdown hook.
+   */
+  public static final int SHUTDOWN_HOOK_PRIORITY = 0;
+
+  /**
    *
    * Given the time in long milliseconds, returns a
    * String in the format X hrs, Y mins, S sec, M msecs
@@ -97,4 +108,61 @@ public class StringUtils {
   public static String escapeLike(String literal) {
     return literal.replaceAll(LIKE_SPECIAL_CHARACTERS, "\\\\$1");
   }
+
+  /**
+   * Return a message for logging.
+   * @param prefix prefix keyword for the message
+   * @param msg content of the message
+   * @return a message for logging
+   */
+  private static String toStartupShutdownString(String prefix, String [] msg) {
+    StringBuilder b = new StringBuilder(prefix);
+    b.append("\n/************************************************************");
+    for(String s : msg)
+      b.append("\n" + prefix + s);
+    b.append("\n************************************************************/");
+    return b.toString();
+  }
+
+  /**
+   * Print a log message for starting up and shutting down
+   * @param clazz the class of the server
+   * @param args arguments
+   * @param LOG the target log object
+   */
+  public static void startupShutdownMessage(Class<?> clazz, String[] args,
+                                            final org.apache.commons.logging.Log LOG) {
+    final String hostname = org.apache.hadoop.net.NetUtils.getHostname();
+    final String classname = clazz.getSimpleName();
+    LOG.info(
+        toStartupShutdownString("STARTUP_MSG: ", new String[] {
+            "Starting " + classname,
+            "  host = " + hostname,
+            "  args = " + Arrays.asList(args),
+            "  version = " + org.apache.tajo.util.VersionInfo.getVersion(),
+            "  classpath = " + System.getProperty("java.class.path"),
+            "  build = " + org.apache.tajo.util.VersionInfo.getUrl() + " -r "
+                + org.apache.tajo.util.VersionInfo.getRevision()
+                + "; compiled by '" + org.apache.tajo.util.VersionInfo.getUser()
+                + "' on " + org.apache.tajo.util.VersionInfo.getDate(),
+            "  java = " + System.getProperty("java.version") }
+        )
+    );
+
+    if (SystemUtils.IS_OS_UNIX) {
+      try {
+        SignalLogger.INSTANCE.register(LOG);
+      } catch (Throwable t) {
+        LOG.warn("failed to register any UNIX signal loggers: ", t);
+      }
+    }
+    ShutdownHookManager.get().addShutdownHook(
+        new Runnable() {
+          @Override
+          public void run() {
+            LOG.info(toStartupShutdownString("SHUTDOWN_MSG: ", new String[]{
+                "Shutting down " + classname + " at " + hostname}));
+          }
+        }, SHUTDOWN_HOOK_PRIORITY);
+  }
 }

http://git-wip-us.apache.org/repos/asf/tajo/blob/bbf2461a/tajo-common/src/main/java/org/apache/tajo/util/VersionInfo.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/util/VersionInfo.java b/tajo-common/src/main/java/org/apache/tajo/util/VersionInfo.java
new file mode 100644
index 0000000..39e0f54
--- /dev/null
+++ b/tajo-common/src/main/java/org/apache/tajo/util/VersionInfo.java
@@ -0,0 +1,177 @@
+package org.apache.tajo.util;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+import org.apache.hadoop.util.ClassUtil;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+/**
+ * This class returns build information about Hadoop components.
+ */
+@InterfaceAudience.Private
+@InterfaceStability.Unstable
+public class VersionInfo {
+  private static final Log LOG = LogFactory.getLog(VersionInfo.class);
+
+  private Properties info;
+
+  protected VersionInfo(String component) {
+    info = new Properties();
+    String versionInfoFile = component + "-version-info.properties";
+    try {
+      InputStream is = Thread.currentThread().getContextClassLoader()
+          .getResourceAsStream(versionInfoFile);
+      if (is == null) {
+        throw new IOException("Resource not found");
+      }
+      info.load(is);
+    } catch (IOException ex) {
+      LogFactory.getLog(getClass()).warn("Could not read '" +
+          versionInfoFile + "', " + ex.toString(), ex);
+    }
+  }
+
+  protected String _getVersion() {
+    return info.getProperty("version", "Unknown");
+  }
+
+  protected String _getRevision() {
+    return info.getProperty("revision", "Unknown");
+  }
+
+  protected String _getBranch() {
+    return info.getProperty("branch", "Unknown");
+  }
+
+  protected String _getDate() {
+    return info.getProperty("date", "Unknown");
+  }
+
+  protected String _getUser() {
+    return info.getProperty("user", "Unknown");
+  }
+
+  protected String _getUrl() {
+    return info.getProperty("url", "Unknown");
+  }
+
+  protected String _getSrcChecksum() {
+    return info.getProperty("srcChecksum", "Unknown");
+  }
+
+  protected String _getBuildVersion(){
+    return getVersion() +
+        " from " + _getRevision() +
+        " by " + _getUser() +
+        " source checksum " + _getSrcChecksum();
+  }
+
+  protected String _getProtocVersion() {
+    return info.getProperty("protocVersion", "Unknown");
+  }
+
+  private static VersionInfo TAJO_VERSION_INFO = new VersionInfo("tajo");
+  /**
+   * Get the Hadoop version.
+   * @return the Hadoop version string, eg. "0.6.3-dev"
+   */
+  public static String getVersion() {
+    return TAJO_VERSION_INFO._getVersion();
+  }
+
+  /**
+   * Get the subversion revision number for the root directory
+   * @return the revision number, eg. "451451"
+   */
+  public static String getRevision() {
+    return TAJO_VERSION_INFO._getRevision();
+  }
+
+  /**
+   * Get the branch on which this originated.
+   * @return The branch name, e.g. "trunk" or "branches/branch-0.20"
+   */
+  public static String getBranch() {
+    return TAJO_VERSION_INFO._getBranch();
+  }
+
+  /**
+   * The date that Hadoop was compiled.
+   * @return the compilation date in unix date format
+   */
+  public static String getDate() {
+    return TAJO_VERSION_INFO._getDate();
+  }
+
+  /**
+   * The user that compiled Hadoop.
+   * @return the username of the user
+   */
+  public static String getUser() {
+    return TAJO_VERSION_INFO._getUser();
+  }
+
+  /**
+   * Get the subversion URL for the root Hadoop directory.
+   */
+  public static String getUrl() {
+    return TAJO_VERSION_INFO._getUrl();
+  }
+
+  /**
+   * Get the checksum of the source files from which Hadoop was
+   * built.
+   **/
+  public static String getSrcChecksum() {
+    return TAJO_VERSION_INFO._getSrcChecksum();
+  }
+
+  /**
+   * Returns the buildVersion which includes version,
+   * revision, user and date.
+   */
+  public static String getBuildVersion(){
+    return TAJO_VERSION_INFO._getBuildVersion();
+  }
+
+  /**
+   * Returns the protoc version used for the build.
+   */
+  public static String getProtocVersion(){
+    return TAJO_VERSION_INFO._getProtocVersion();
+  }
+
+  public static void main(String[] args) {
+    LOG.debug("version: "+ getVersion());
+    System.out.println("Tajo " + getVersion());
+    System.out.println("Git " + getUrl() + " -r " + getRevision());
+    System.out.println("Compiled by " + getUser() + " on " + getDate());
+    System.out.println("Compiled with protoc " + getProtocVersion());
+    System.out.println("From source with checksum " + getSrcChecksum());
+    System.out.println("This command was run using " + ClassUtil.findContainingJar(VersionInfo.class));
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/tajo/blob/bbf2461a/tajo-common/src/main/resources/tajo-version-info.properties
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/resources/tajo-version-info.properties b/tajo-common/src/main/resources/tajo-version-info.properties
new file mode 100644
index 0000000..ad9a24d
--- /dev/null
+++ b/tajo-common/src/main/resources/tajo-version-info.properties
@@ -0,0 +1,26 @@
+#
+# 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.
+#
+
+version=${pom.version}
+revision=${version-info.scm.commit}
+branch=${version-info.scm.branch}
+user=${user.name}
+date=${version-info.build.time}
+url=${version-info.scm.uri}
+srcChecksum=${version-info.source.md5}
+protocVersion=${protobuf.version}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/bbf2461a/tajo-core/src/main/java/org/apache/tajo/master/TajoMaster.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/master/TajoMaster.java b/tajo-core/src/main/java/org/apache/tajo/master/TajoMaster.java
index 9d54bb5..dfae300 100644
--- a/tajo-core/src/main/java/org/apache/tajo/master/TajoMaster.java
+++ b/tajo-core/src/main/java/org/apache/tajo/master/TajoMaster.java
@@ -30,7 +30,6 @@ import org.apache.hadoop.fs.permission.FsPermission;
 import org.apache.hadoop.io.IOUtils;
 import org.apache.hadoop.service.CompositeService;
 import org.apache.hadoop.util.ShutdownHookManager;
-import org.apache.hadoop.util.StringUtils;
 import org.apache.hadoop.yarn.conf.YarnConfiguration;
 import org.apache.hadoop.yarn.event.AsyncDispatcher;
 import org.apache.hadoop.yarn.event.EventHandler;
@@ -58,6 +57,7 @@ import org.apache.tajo.storage.StorageManagerFactory;
 import org.apache.tajo.util.ClassUtil;
 import org.apache.tajo.util.CommonTestingUtil;
 import org.apache.tajo.util.NetUtils;
+import org.apache.tajo.util.StringUtils;
 import org.apache.tajo.util.metrics.TajoSystemMetrics;
 import org.apache.tajo.webapp.QueryExecutorServlet;
 import org.apache.tajo.webapp.StaticHttpServer;

http://git-wip-us.apache.org/repos/asf/tajo/blob/bbf2461a/tajo-core/src/main/java/org/apache/tajo/worker/TajoWorker.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/worker/TajoWorker.java b/tajo-core/src/main/java/org/apache/tajo/worker/TajoWorker.java
index 0b8d6c2..3768edf 100644
--- a/tajo-core/src/main/java/org/apache/tajo/worker/TajoWorker.java
+++ b/tajo-core/src/main/java/org/apache/tajo/worker/TajoWorker.java
@@ -27,7 +27,6 @@ import org.apache.hadoop.fs.LocalDirAllocator;
 import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.fs.shell.PathData;
 import org.apache.hadoop.service.CompositeService;
-import org.apache.hadoop.util.StringUtils;
 import org.apache.hadoop.yarn.util.RackResolver;
 import org.apache.tajo.QueryId;
 import org.apache.tajo.TajoConstants;
@@ -45,6 +44,7 @@ import org.apache.tajo.rpc.RpcConnectionPool;
 import org.apache.tajo.rpc.protocolrecords.PrimitiveProtos;
 import org.apache.tajo.util.CommonTestingUtil;
 import org.apache.tajo.util.NetUtils;
+import org.apache.tajo.util.StringUtils;
 import org.apache.tajo.util.TajoIdUtils;
 import org.apache.tajo.util.metrics.TajoSystemMetrics;
 import org.apache.tajo.webapp.StaticHttpServer;

http://git-wip-us.apache.org/repos/asf/tajo/blob/bbf2461a/tajo-maven-plugins/pom.xml
----------------------------------------------------------------------
diff --git a/tajo-maven-plugins/pom.xml b/tajo-maven-plugins/pom.xml
new file mode 100644
index 0000000..7de67ef
--- /dev/null
+++ b/tajo-maven-plugins/pom.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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. See accompanying LICENSE file.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.tajo</groupId>
+    <artifactId>tajo-project</artifactId>
+    <version>0.8.0-SNAPSHOT</version>
+    <relativePath>../tajo-project</relativePath>
+  </parent>
+  <groupId>org.apache.tajo</groupId>
+  <artifactId>tajo-maven-plugins</artifactId>
+  <packaging>maven-plugin</packaging>
+  <name>Tajo Maven Plugins</name>
+  <properties>
+    <maven.dependency.version>3.0</maven.dependency.version>
+  </properties>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-plugin-api</artifactId>
+      <version>${maven.dependency.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-core</artifactId>
+      <version>${maven.dependency.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven.plugin-tools</groupId>
+      <artifactId>maven-plugin-annotations</artifactId>
+      <version>${maven.dependency.version}</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>3.8.1</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-plugin-plugin</artifactId>
+        <version>${maven.dependency.version}</version>
+        <configuration>
+          <skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound>
+        </configuration>
+        <executions>
+          <execution>
+            <id>mojo-descriptor</id>
+            <goals>
+              <goal>descriptor</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <!--
+      Skip Clover instrumentation for this module to prevent error finding Clover
+      classes during plugin execution when running a build with Clover enabled.
+      -->
+      <plugin>
+        <groupId>com.atlassian.maven.plugins</groupId>
+        <artifactId>maven-clover2-plugin</artifactId>
+        <version>3.0.5</version>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>

http://git-wip-us.apache.org/repos/asf/tajo/blob/bbf2461a/tajo-maven-plugins/src/main/java/org/apache/tajo/maven/plugin/protoc/ProtocMojo.java
----------------------------------------------------------------------
diff --git a/tajo-maven-plugins/src/main/java/org/apache/tajo/maven/plugin/protoc/ProtocMojo.java b/tajo-maven-plugins/src/main/java/org/apache/tajo/maven/plugin/protoc/ProtocMojo.java
new file mode 100644
index 0000000..498f85d
--- /dev/null
+++ b/tajo-maven-plugins/src/main/java/org/apache/tajo/maven/plugin/protoc/ProtocMojo.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2012 The Apache Software Foundation.
+ *
+ * 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.apache.tajo.maven.plugin.protoc;
+
+import org.apache.tajo.maven.plugin.util.Exec;
+import org.apache.tajo.maven.plugin.util.FileSetUtils;
+import org.apache.maven.model.FileSet;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.project.MavenProject;
+import org.apache.tajo.maven.plugin.util.Exec;
+import org.apache.tajo.maven.plugin.util.FileSetUtils;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+
+@Mojo(name="protoc", defaultPhase = LifecyclePhase.GENERATE_SOURCES)
+public class ProtocMojo extends AbstractMojo {
+
+  @Parameter(defaultValue="${project}")
+  private MavenProject project;
+
+  @Parameter
+  private File[] imports;
+
+  @Parameter(defaultValue="${project.build.directory}/generated-sources/java")
+  private File output;
+
+  @Parameter(required=true)
+  private FileSet source;
+
+  @Parameter
+  private String protocCommand;
+
+  @Parameter(required=true)
+  private String protocVersion;
+
+  public void execute() throws MojoExecutionException {
+    try {
+      if (protocCommand == null || protocCommand.trim().isEmpty()) {
+        protocCommand = "protoc";
+      }
+      List<String> command = new ArrayList<String>();
+      command.add(protocCommand);
+      command.add("--version");
+      Exec exec = new Exec(this);
+      List<String> out = new ArrayList<String>();
+      if (exec.run(command, out) == 127) {
+        getLog().error("protoc, not found at: " + protocCommand);
+        throw new MojoExecutionException("protoc failure");        
+      } else {
+        if (out.isEmpty()) {
+          getLog().error("stdout: " + out);
+          throw new MojoExecutionException(
+              "'protoc --version' did not return a version");
+        } else {
+          if (!out.get(0).endsWith(protocVersion)) {
+            throw new MojoExecutionException(
+                "protoc version is '" + out.get(0) + "', expected version is '" 
+                    + protocVersion + "'");            
+          }
+        }
+      }
+      if (!output.mkdirs()) {
+        if (!output.exists()) {
+          throw new MojoExecutionException("Could not create directory: " + 
+            output);
+        }
+      }
+      command = new ArrayList<String>();
+      command.add(protocCommand);
+      command.add("--java_out=" + output.getCanonicalPath());
+      if (imports != null) {
+        for (File i : imports) {
+          command.add("-I" + i.getCanonicalPath());
+        }
+      }
+      for (File f : FileSetUtils.convertFileSetToFiles(source)) {
+        command.add(f.getCanonicalPath());
+      }
+      exec = new Exec(this);
+      out = new ArrayList<String>();
+      if (exec.run(command, out) != 0) {
+        getLog().error("protoc compiler error");
+        for (String s : out) {
+          getLog().error(s);
+        }
+        throw new MojoExecutionException("protoc failure");
+      }
+    } catch (Throwable ex) {
+      throw new MojoExecutionException(ex.toString(), ex);
+    }
+    project.addCompileSourceRoot(output.getAbsolutePath());
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/bbf2461a/tajo-maven-plugins/src/main/java/org/apache/tajo/maven/plugin/util/Exec.java
----------------------------------------------------------------------
diff --git a/tajo-maven-plugins/src/main/java/org/apache/tajo/maven/plugin/util/Exec.java b/tajo-maven-plugins/src/main/java/org/apache/tajo/maven/plugin/util/Exec.java
new file mode 100644
index 0000000..89ba6fb
--- /dev/null
+++ b/tajo-maven-plugins/src/main/java/org/apache/tajo/maven/plugin/util/Exec.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2012 The Apache Software Foundation.
+ *
+ * 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.apache.tajo.maven.plugin.util;
+
+import org.apache.maven.plugin.Mojo;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Exec is a helper class for executing an external process from a mojo.
+ */
+public class Exec {
+  private Mojo mojo;
+
+  /**
+   * Creates a new Exec instance for executing an external process from the given
+   * mojo.
+   * 
+   * @param mojo Mojo executing external process
+   */
+  public Exec(Mojo mojo) {
+    this.mojo = mojo;
+  }
+
+  /**
+   * Runs the specified command and saves each line of the command's output to
+   * the given list.
+   * 
+   * @param command List<String> containing command and all arguments
+   * @param output List<String> in/out parameter to receive command output
+   * @return int exit code of command
+   */
+  public int run(List<String> command, List<String> output) {
+    int retCode = 1;
+    ProcessBuilder pb = new ProcessBuilder(command);
+    try {
+      Process p = pb.start();
+      OutputBufferThread stdOut = new OutputBufferThread(p.getInputStream());
+      OutputBufferThread stdErr = new OutputBufferThread(p.getErrorStream());
+      stdOut.start();
+      stdErr.start();
+      retCode = p.waitFor();
+      if (retCode != 0) {
+        mojo.getLog().warn(command + " failed with error code " + retCode);
+        for (String s : stdErr.getOutput()) {
+          mojo.getLog().debug(s);
+        }
+      }
+      stdOut.join();
+      stdErr.join();
+      output.addAll(stdOut.getOutput());
+    } catch (Exception ex) {
+      mojo.getLog().warn(command + " failed: " + ex.toString());
+    }
+    return retCode;
+  }
+
+  /**
+   * OutputBufferThread is a background thread for consuming and storing output
+   * of the external process.
+   */
+  private static class OutputBufferThread extends Thread {
+    private List<String> output;
+    private BufferedReader reader;
+
+    /**
+     * Creates a new OutputBufferThread to consume the given InputStream.
+     * 
+     * @param is InputStream to consume
+     */
+    public OutputBufferThread(InputStream is) {
+      this.setDaemon(true);
+      output = new ArrayList<String>();
+      reader = new BufferedReader(new InputStreamReader(is));
+    }
+
+    @Override
+    public void run() {
+      try {
+        String line = reader.readLine();
+        while (line != null) {
+          output.add(line);
+          line = reader.readLine();
+        }
+      } catch (IOException ex) {
+        throw new RuntimeException("make failed with error code " + ex.toString());
+      }
+    }
+
+    /**
+     * Returns every line consumed from the input.
+     * 
+     * @return List<String> every line consumed from the input
+     */
+    public List<String> getOutput() {
+      return output;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/bbf2461a/tajo-maven-plugins/src/main/java/org/apache/tajo/maven/plugin/util/FileSetUtils.java
----------------------------------------------------------------------
diff --git a/tajo-maven-plugins/src/main/java/org/apache/tajo/maven/plugin/util/FileSetUtils.java b/tajo-maven-plugins/src/main/java/org/apache/tajo/maven/plugin/util/FileSetUtils.java
new file mode 100644
index 0000000..f034f44
--- /dev/null
+++ b/tajo-maven-plugins/src/main/java/org/apache/tajo/maven/plugin/util/FileSetUtils.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2012 The Apache Software Foundation.
+ *
+ * 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.apache.tajo.maven.plugin.util;
+
+import org.apache.maven.model.FileSet;
+import org.codehaus.plexus.util.FileUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * FileSetUtils contains helper methods for mojo implementations that need to
+ * work with a Maven FileSet.
+ */
+public class FileSetUtils {
+
+  /**
+   * Returns a string containing every element of the given list, with each
+   * element separated by a comma.
+   * 
+   * @param list List of all elements
+   * @return String containing every element, comma-separated
+   */
+  private static String getCommaSeparatedList(List list) {
+    StringBuilder buffer = new StringBuilder();
+    String separator = "";
+    for (Object e : list) {
+      buffer.append(separator).append(e);
+      separator = ",";
+    }
+    return buffer.toString();
+  }
+
+  /**
+   * Converts a Maven FileSet to a list of File objects.
+   * 
+   * @param source FileSet to convert
+   * @return List<File> containing every element of the FileSet as a File
+   * @throws IOException if an I/O error occurs while trying to find the files
+   */
+  @SuppressWarnings("unchecked")
+  public static List<File> convertFileSetToFiles(FileSet source) throws IOException {
+    String includes = getCommaSeparatedList(source.getIncludes());
+    String excludes = getCommaSeparatedList(source.getExcludes());
+    return FileUtils.getFiles(new File(source.getDirectory()), includes, excludes);
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/bbf2461a/tajo-maven-plugins/src/main/java/org/apache/tajo/maven/plugin/versioninfo/VersionInfoMojo.java
----------------------------------------------------------------------
diff --git a/tajo-maven-plugins/src/main/java/org/apache/tajo/maven/plugin/versioninfo/VersionInfoMojo.java b/tajo-maven-plugins/src/main/java/org/apache/tajo/maven/plugin/versioninfo/VersionInfoMojo.java
new file mode 100644
index 0000000..5347f40
--- /dev/null
+++ b/tajo-maven-plugins/src/main/java/org/apache/tajo/maven/plugin/versioninfo/VersionInfoMojo.java
@@ -0,0 +1,344 @@
+/*
+ * Copyright 2012 The Apache Software Foundation.
+ *
+ * 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.apache.tajo.maven.plugin.versioninfo;
+
+import org.apache.tajo.maven.plugin.util.Exec;
+import org.apache.tajo.maven.plugin.util.FileSetUtils;
+import org.apache.maven.model.FileSet;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.project.MavenProject;
+import org.apache.tajo.maven.plugin.util.Exec;
+import org.apache.tajo.maven.plugin.util.FileSetUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
+import java.util.TimeZone;
+
+/**
+ * VersionInfoMojo calculates information about the current version of the
+ * codebase and exports the information as properties for further use in a Maven
+ * build.  The version information includes build time, SCM URI, SCM branch, SCM
+ * commit, and an MD5 checksum of the contents of the files in the codebase.
+ */
+@Mojo(name="version-info")
+public class VersionInfoMojo extends AbstractMojo {
+
+  @Parameter(defaultValue="${project}")
+  private MavenProject project;
+
+  @Parameter(required=true)
+  private FileSet source;
+
+  @Parameter(defaultValue="version-info.build.time")
+  private String buildTimeProperty;
+
+  @Parameter(defaultValue="version-info.source.md5")
+  private String md5Property;
+
+  @Parameter(defaultValue="version-info.scm.uri")
+  private String scmUriProperty;
+
+  @Parameter(defaultValue="version-info.scm.branch")
+  private String scmBranchProperty;
+
+  @Parameter(defaultValue="version-info.scm.commit")
+  private String scmCommitProperty;
+
+  @Parameter(defaultValue="git")
+  private String gitCommand;
+
+  @Parameter(defaultValue="svn")
+  private String svnCommand;
+
+  private enum SCM {NONE, SVN, GIT}
+
+  @Override
+  public void execute() throws MojoExecutionException {
+    try {
+      SCM scm = determineSCM();
+      project.getProperties().setProperty(buildTimeProperty, getBuildTime());
+      project.getProperties().setProperty(scmUriProperty, getSCMUri(scm));
+      project.getProperties().setProperty(scmBranchProperty, getSCMBranch(scm));
+      project.getProperties().setProperty(scmCommitProperty, getSCMCommit(scm));
+      project.getProperties().setProperty(md5Property, computeMD5());
+    } catch (Throwable ex) {
+      throw new MojoExecutionException(ex.toString(), ex);
+    }
+  }
+
+  /**
+   * Returns a string representing current build time.
+   * 
+   * @return String representing current build time
+   */
+  private String getBuildTime() {
+    DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'");
+    dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+    return dateFormat.format(new Date());
+  }
+  private List<String> scmOut;
+
+  /**
+   * Determines which SCM is in use (Subversion, git, or none) and captures
+   * output of the SCM command for later parsing.
+   * 
+   * @return SCM in use for this build
+   * @throws Exception if any error occurs attempting to determine SCM
+   */
+  private SCM determineSCM() throws Exception {
+    Exec exec = new Exec(this);
+    SCM scm = SCM.NONE;
+    scmOut = new ArrayList<String>();
+    int ret = exec.run(Arrays.asList(svnCommand, "info"), scmOut);
+    if (ret == 0) {
+      scm = SCM.SVN;
+    } else {
+      ret = exec.run(Arrays.asList(gitCommand, "branch"), scmOut);
+      if (ret == 0) {
+        ret = exec.run(Arrays.asList(gitCommand, "remote", "-v"), scmOut);
+        if (ret != 0) {
+          scm = SCM.NONE;
+          scmOut = null;
+        } else {
+          ret = exec.run(Arrays.asList(gitCommand, "log", "-n", "1"), scmOut);
+          if (ret != 0) {
+            scm = SCM.NONE;
+            scmOut = null;
+          } else {
+            scm = SCM.GIT;
+          }
+        }
+      }
+    }
+    if (scmOut != null) {
+      getLog().debug(scmOut.toString());
+    }
+    getLog().info("SCM: " + scm);
+    return scm;
+  }
+
+  /**
+   * Return URI and branch of Subversion repository.
+   * 
+   * @param str String Subversion info output containing URI and branch
+   * @return String[] containing URI and branch
+   */
+  private String[] getSvnUriInfo(String str) {
+    String[] res = new String[]{"Unknown", "Unknown"};
+    try {
+      String path = str;
+      int index = path.indexOf("trunk");
+      if (index > -1) {
+        res[0] = path.substring(0, index - 1);
+        res[1] = "trunk";
+      } else {
+        index = path.indexOf("branches");
+        if (index > -1) {
+          res[0] = path.substring(0, index - 1);
+          int branchIndex = index + "branches".length() + 1;
+          index = path.indexOf("/", branchIndex);
+          if (index > -1) {
+            res[1] = path.substring(branchIndex, index);
+          } else {
+            res[1] = path.substring(branchIndex);
+          }
+        }
+      }
+    } catch (Exception ex) {
+      getLog().warn("Could not determine URI & branch from SVN URI: " + str);
+    }
+    return res;
+  }
+
+  /**
+   * Parses SCM output and returns URI of SCM.
+   * 
+   * @param scm SCM in use for this build
+   * @return String URI of SCM
+   */
+  private String getSCMUri(SCM scm) {
+    String uri = "Unknown";
+    switch (scm) {
+      case SVN:
+        for (String s : scmOut) {
+          if (s.startsWith("URL:")) {
+            uri = s.substring(4).trim();
+            uri = getSvnUriInfo(uri)[0];
+            break;
+          }
+        }
+        break;
+      case GIT:
+        for (String s : scmOut) {
+          if (s.startsWith("origin") && s.endsWith("(fetch)")) {
+            uri = s.substring("origin".length());
+            uri = uri.substring(0, uri.length() - "(fetch)".length());
+            break;
+          }
+        }
+        break;
+    }
+    return uri.trim();
+  }
+
+  /**
+   * Parses SCM output and returns commit of SCM.
+   * 
+   * @param scm SCM in use for this build
+   * @return String commit of SCM
+   */
+  private String getSCMCommit(SCM scm) {
+    String commit = "Unknown";
+    switch (scm) {
+      case SVN:
+        for (String s : scmOut) {
+          if (s.startsWith("Revision:")) {
+            commit = s.substring("Revision:".length());
+            break;
+          }
+        }
+        break;
+      case GIT:
+        for (String s : scmOut) {
+          if (s.startsWith("commit")) {
+            commit = s.substring("commit".length());
+            break;
+          }
+        }
+        break;
+    }
+    return commit.trim();
+  }
+
+  /**
+   * Parses SCM output and returns branch of SCM.
+   * 
+   * @param scm SCM in use for this build
+   * @return String branch of SCM
+   */
+  private String getSCMBranch(SCM scm) {
+    String branch = "Unknown";
+    switch (scm) {
+      case SVN:
+        for (String s : scmOut) {
+          if (s.startsWith("URL:")) {
+            branch = s.substring(4).trim();
+            branch = getSvnUriInfo(branch)[1];
+            break;
+          }
+        }
+        break;
+      case GIT:
+        for (String s : scmOut) {
+          if (s.startsWith("*")) {
+            branch = s.substring("*".length());
+            break;
+          }
+        }
+        break;
+    }
+    return branch.trim();
+  }
+
+  /**
+   * Reads and returns the full contents of the specified file.
+   * 
+   * @param file File to read
+   * @return byte[] containing full contents of file
+   * @throws IOException if there is an I/O error while reading the file
+   */
+  private byte[] readFile(File file) throws IOException {
+    RandomAccessFile raf = new RandomAccessFile(file, "r");
+    byte[] buffer = new byte[(int) raf.length()];
+    raf.readFully(buffer);
+    raf.close();
+    return buffer;
+  }
+
+  /**
+   * Given a list of files, computes and returns an MD5 checksum of the full
+   * contents of all files.
+   * 
+   * @param files List<File> containing every file to input into the MD5 checksum
+   * @return byte[] calculated MD5 checksum
+   * @throws IOException if there is an I/O error while reading a file
+   * @throws NoSuchAlgorithmException if the MD5 algorithm is not supported
+   */
+  private byte[] computeMD5(List<File> files) throws IOException, NoSuchAlgorithmException {
+    MessageDigest md5 = MessageDigest.getInstance("MD5");
+    for (File file : files) {
+      getLog().debug("Computing MD5 for: " + file);
+      md5.update(readFile(file));
+    }
+    return md5.digest();
+  }
+
+  /**
+   * Converts bytes to a hexadecimal string representation and returns it.
+   * 
+   * @param array byte[] to convert
+   * @return String containing hexadecimal representation of bytes
+   */
+  private String byteArrayToString(byte[] array) {
+    StringBuilder sb = new StringBuilder();
+    for (byte b : array) {
+      sb.append(Integer.toHexString(0xff & b));
+    }
+    return sb.toString();
+  }
+
+  /**
+   * Computes and returns an MD5 checksum of the contents of all files in the
+   * input Maven FileSet.
+   * 
+   * @return String containing hexadecimal representation of MD5 checksum
+   * @throws Exception if there is any error while computing the MD5 checksum
+   */
+  private String computeMD5() throws Exception {
+    List<File> files = FileSetUtils.convertFileSetToFiles(source);
+    // File order of MD5 calculation is significant.  Sorting is done on
+    // unix-format names, case-folded, in order to get a platform-independent
+    // sort and calculate the same MD5 on all platforms.
+    Collections.sort(files, new Comparator<File>() {
+      @Override
+      public int compare(File lhs, File rhs) {
+        return normalizePath(lhs).compareTo(normalizePath(rhs));
+      }
+
+      private String normalizePath(File file) {
+        return file.getPath().toUpperCase().replaceAll("\\\\", "/");
+      }
+    });
+    byte[] md5 = computeMD5(files);
+    String md5str = byteArrayToString(md5);
+    getLog().info("Computed MD5: " + md5str);
+    return md5str;
+  }
+}