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 2013/10/10 14:40:45 UTC

[6/6] git commit: TAJO-239: Improving web UI. (Keuntae Park via hyunsik)

TAJO-239: Improving web UI. (Keuntae Park via hyunsik)


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

Branch: refs/heads/master
Commit: 85b839403fc5b3ccde944b650b23d2977321b852
Parents: 5a257e2
Author: Hyunsik Choi <hy...@apache.org>
Authored: Thu Oct 10 19:48:27 2013 +0900
Committer: Hyunsik Choi <hy...@apache.org>
Committed: Thu Oct 10 21:39:33 2013 +0900

----------------------------------------------------------------------
 CHANGES.txt                                     |     2 +
 pom.xml                                         |     1 +
 .../org/apache/tajo/catalog/CatalogServer.java  |     4 +
 .../java/org/apache/tajo/master/TajoMaster.java |    95 +-
 .../main/java/org/apache/tajo/util/JSPUtil.java |   167 +
 .../tajo/webapp/QueryExecutorServlet.java       |   360 +
 .../java/org/apache/tajo/worker/TajoWorker.java |    52 +-
 .../org/apache/tajo/worker/WorkerJSPUtil.java   |   114 -
 .../resources/webapps/admin/catalogview.jsp     |   211 +-
 .../main/resources/webapps/admin/cluster.jsp    |   122 +
 .../src/main/resources/webapps/admin/conf.jsp   |    37 +
 .../src/main/resources/webapps/admin/env.jsp    |    48 +
 .../src/main/resources/webapps/admin/header.jsp |    13 +
 .../src/main/resources/webapps/admin/index.jsp  |   187 +-
 .../src/main/resources/webapps/admin/query.jsp  |   108 +-
 .../resources/webapps/admin/query_executor.jsp  |   183 +
 .../src/main/resources/webapps/admin/thread.jsp |    26 +
 .../resources/webapps/static/img/logo_tajo.gif  |   Bin 0 -> 3025 bytes
 .../webapps/static/js/jquery-ui.min.js          |     5 +
 .../main/resources/webapps/static/js/jquery.js  |     2 +
 .../static/js/jquery.jsPlumb-1.3.16-all-min.js  |     1 +
 .../static/js/jquery.jsPlumb-1.3.16-all.js      | 10561 +++++++++++++++++
 .../main/resources/webapps/static/queryplan.css |    55 +
 .../src/main/resources/webapps/static/style.css |   321 +-
 .../src/main/resources/webapps/worker/conf.jsp  |    36 +
 .../src/main/resources/webapps/worker/env.jsp   |    50 +
 .../main/resources/webapps/worker/header.jsp    |    18 +
 .../src/main/resources/webapps/worker/index.jsp |   184 +-
 .../resources/webapps/worker/querydetail.jsp    |    98 +-
 .../main/resources/webapps/worker/queryplan.jsp |   220 +
 .../resources/webapps/worker/querytasks.jsp     |    96 +
 .../src/main/resources/webapps/worker/tasks.jsp |    68 +
 .../main/resources/webapps/worker/thread.jsp    |    28 +
 33 files changed, 12707 insertions(+), 766 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 3f01f04..e191aed 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -50,6 +50,8 @@ Release 0.2.0 - unreleased
 
   IMPROVEMENTS
 
+    TAJO-239: Improving web UI. (Keuntae Park via hyunsik)
+
     TAJO-232: Rename join operators and add other join operators to
     PhysicalPlanner. (hyunsik)
 

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 1288547..fa247b8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -312,6 +312,7 @@
             <exclude>**/*.schema</exclude>
             <exclude>**/*.tbl</exclude>
             <exclude>**/*.jsp</exclude>
+            <exclude>**/*.js</exclude>
             <exclude>**/web.xml</exclude>
             <exclude>**/*.result</exclude>
             <!-- generated content -->

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/tajo-catalog/tajo-catalog-server/src/main/java/org/apache/tajo/catalog/CatalogServer.java
----------------------------------------------------------------------
diff --git a/tajo-catalog/tajo-catalog-server/src/main/java/org/apache/tajo/catalog/CatalogServer.java b/tajo-catalog/tajo-catalog-server/src/main/java/org/apache/tajo/catalog/CatalogServer.java
index f810431..f15d962 100644
--- a/tajo-catalog/tajo-catalog-server/src/main/java/org/apache/tajo/catalog/CatalogServer.java
+++ b/tajo-catalog/tajo-catalog-server/src/main/java/org/apache/tajo/catalog/CatalogServer.java
@@ -122,6 +122,10 @@ public class CatalogServer extends AbstractService {
     super.init(conf);
   }
 
+  public String getCatalogServerName() {
+    return bindAddressStr + ", class=" + this.store.getClass().getSimpleName() + ", jdbc=" + conf.get(CatalogConstants.JDBC_URI);
+  }
+
   private void initBuiltinFunctions(List<FunctionDesc> functions)
       throws ServiceException {
     for (FunctionDesc desc : functions) {

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/TajoMaster.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/TajoMaster.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/TajoMaster.java
index 2c09dd2..b303ad6 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/TajoMaster.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/TajoMaster.java
@@ -51,9 +51,13 @@ import org.apache.tajo.master.rm.YarnTajoResourceManager;
 import org.apache.tajo.storage.AbstractStorageManager;
 import org.apache.tajo.storage.StorageManagerFactory;
 import org.apache.tajo.util.NetUtils;
+import org.apache.tajo.webapp.QueryExecutorServlet;
 import org.apache.tajo.webapp.StaticHttpServer;
 
-import java.io.IOException;
+import java.io.*;
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
 import java.lang.reflect.Constructor;
 import java.util.ArrayList;
 import java.util.List;
@@ -106,10 +110,24 @@ public class TajoMaster extends CompositeService {
 
   private QueryJobManager queryJobManager;
 
+  private ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
+
   public TajoMaster() throws Exception {
     super(TajoMaster.class.getName());
   }
 
+  public String getMasterName() {
+    return tajoMasterService.getBindAddress().getHostName() + ":" + tajoMasterService.getBindAddress().getPort();
+  }
+
+  public String getVersion() {
+    return "0.2.0";
+  }
+
+  public TajoMasterClientService getTajoMasterClientService() {
+    return  tajoMasterClientService;
+  }
+
   @Override
   public void init(Configuration _conf) {
     this.systemConf = (TajoConf) _conf;
@@ -167,6 +185,7 @@ public class TajoMaster extends CompositeService {
     int httpPort = systemConf.getInt("tajo.master.http.port", 8080);
     webServer = StaticHttpServer.getInstance(this ,"admin", null, httpPort ,
         true, null, context.getConf(), null);
+    webServer.addServlet("queryServlet", "/query_exec", QueryExecutorServlet.class);
     webServer.start();
   }
 
@@ -429,6 +448,10 @@ public class TajoMaster extends CompositeService {
     return this.catalog;
   }
 
+  public CatalogServer getCatalogServer() {
+    return this.catalogServer;
+  }
+
   public AbstractStorageManager getStorageManager() {
     return this.storeManager;
   }
@@ -477,6 +500,76 @@ public class TajoMaster extends CompositeService {
     }
   }
 
+  String getThreadTaskName(long id, String name) {
+    if (name == null) {
+      return Long.toString(id);
+    }
+    return id + " (" + name + ")";
+  }
+
+  public void dumpThread(Writer writer) {
+    PrintWriter stream = new PrintWriter(writer);
+    int STACK_DEPTH = 20;
+    boolean contention = threadBean.isThreadContentionMonitoringEnabled();
+    long[] threadIds = threadBean.getAllThreadIds();
+    stream.println("Process Thread Dump: Tajo Worker");
+    stream.println(threadIds.length + " active threads");
+    for (long tid : threadIds) {
+      ThreadInfo info = threadBean.getThreadInfo(tid, STACK_DEPTH);
+      if (info == null) {
+        stream.println("  Inactive");
+        continue;
+      }
+      stream.println("Thread " + getThreadTaskName(info.getThreadId(), info.getThreadName()) + ":");
+      Thread.State state = info.getThreadState();
+      stream.println("  State: " + state + ", Blocked count: " + info.getBlockedCount() +
+          ", Waited count: " + info.getWaitedCount());
+      if (contention) {
+        stream.println("  Blocked time: " + info.getBlockedTime() + ", Waited time: " + info.getWaitedTime());
+      }
+      if (state == Thread.State.WAITING) {
+        stream.println("  Waiting on " + info.getLockName());
+      } else if (state == Thread.State.BLOCKED) {
+        stream.println("  Blocked on " + info.getLockName() +
+            ", Blocked by " + getThreadTaskName(info.getLockOwnerId(), info.getLockOwnerName()));
+      }
+      stream.println("  Stack:");
+      for (StackTraceElement frame : info.getStackTrace()) {
+        stream.println("    " + frame.toString());
+      }
+      stream.println("");
+    }
+  }
+
+  public static List<File> getMountPath() throws Exception {
+    BufferedReader mountOutput = null;
+    try {
+      Process mountProcess = Runtime.getRuntime ().exec("mount");
+      mountOutput = new BufferedReader(new InputStreamReader(mountProcess.getInputStream()));
+      List<File> mountPaths = new ArrayList<File>();
+      while (true) {
+        String line = mountOutput.readLine();
+        if (line == null) {
+          break;
+        }
+
+        System.out.println(line);
+
+        int indexStart = line.indexOf(" on /");
+        int indexEnd = line.indexOf(" ", indexStart + 4);
+
+        mountPaths.add(new File(line.substring (indexStart + 4, indexEnd)));
+      }
+      return mountPaths;
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    } finally {
+      if(mountOutput != null) {
+        mountOutput.close();
+      }
+    }
+  }
   public static void main(String[] args) throws Exception {
     StringUtils.startupShutdownMessage(TajoMaster.class, args, LOG);
 

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/util/JSPUtil.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/util/JSPUtil.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/util/JSPUtil.java
new file mode 100644
index 0000000..8b2a234
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/util/JSPUtil.java
@@ -0,0 +1,167 @@
+/**
+ * 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.tajo.util;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.tajo.master.querymaster.QueryInProgress;
+import org.apache.tajo.master.querymaster.QueryMasterTask;
+import org.apache.tajo.master.querymaster.QueryUnit;
+import org.apache.tajo.master.querymaster.SubQuery;
+import org.apache.tajo.worker.TaskRunner;
+
+import java.text.DecimalFormat;
+import java.util.*;
+
+public class JSPUtil {
+  static DecimalFormat decimalF = new DecimalFormat("###.0");
+
+  public static void sortQueryUnit(QueryUnit[] queryUnits, String sortField, String sortOrder) {
+    if(sortField == null || sortField.isEmpty()) {
+      sortField = "id";
+    }
+
+    Arrays.sort(queryUnits, new QueryUnitComparator(sortField, "asc".equals(sortOrder)));
+  }
+
+  public static void sortTaskRunner(List<TaskRunner> taskRunners) {
+    Collections.sort(taskRunners, new Comparator<TaskRunner>() {
+      @Override
+      public int compare(TaskRunner taskRunner, TaskRunner taskRunner2) {
+        return taskRunner.getId().compareTo(taskRunner2.getId());
+      }
+    });
+  }
+
+  public static String getElapsedTime(long startTime, long finishTime) {
+    return finishTime == 0 ? decimalF.format((System.currentTimeMillis() - startTime) / 1000) + " sec"
+        : decimalF.format((finishTime - startTime) / 1000) + " sec";
+  }
+
+  public static String getTajoMasterHttpAddr(Configuration config) {
+    try {
+      String[] masterAddr = config.get("tajo.master.manager.addr").split(":");
+
+      return masterAddr[0] + ":" + config.getInt("tajo.master.http.port", 8080);
+    } catch (Exception e) {
+      e.printStackTrace();
+      return e.getMessage();
+    }
+  }
+
+  public static List<QueryMasterTask> sortQueryMasterTask(Collection<QueryMasterTask> queryMasterTasks,
+                                                          final boolean desc) {
+    List<QueryMasterTask> queryMasterTaskList = new ArrayList<QueryMasterTask>(queryMasterTasks);
+
+    Collections.sort(queryMasterTaskList, new Comparator<QueryMasterTask>() {
+
+      @Override
+      public int compare(QueryMasterTask task1, QueryMasterTask task2) {
+        if(desc) {
+          return task2.getQueryId().toString().compareTo(task1.getQueryId().toString());
+        } else {
+          return task1.getQueryId().toString().compareTo(task2.getQueryId().toString());
+        }
+      }
+    });
+
+    return queryMasterTaskList;
+  }
+
+  public static List<QueryInProgress> sortQueryInProgress(Collection<QueryInProgress> queryInProgresses,
+                                                          final boolean desc) {
+    List<QueryInProgress> queryProgressList = new ArrayList<QueryInProgress>(queryInProgresses);
+
+    Collections.sort(queryProgressList, new Comparator<QueryInProgress>() {
+      @Override
+      public int compare(QueryInProgress query1, QueryInProgress query2) {
+        if(desc) {
+          return query2.getQueryId().toString().compareTo(query1.getQueryId().toString());
+        } else {
+          return query1.getQueryId().toString().compareTo(query2.getQueryId().toString());
+        }
+      }
+    });
+
+    return queryProgressList;
+  }
+
+  public static List<SubQuery> sortSubQuery(Collection<SubQuery> subQueries) {
+    List<SubQuery> subQueryList = new ArrayList<SubQuery>(subQueries);
+    Collections.sort(subQueryList, new Comparator<SubQuery>() {
+      @Override
+      public int compare(SubQuery subQuery1, SubQuery subQuery2) {
+        return subQuery1.getId().toString().compareTo(subQuery2.getId().toString());
+      }
+    });
+
+    return subQueryList;
+  }
+
+  static class QueryUnitComparator implements Comparator<QueryUnit> {
+    private String sortField;
+    private boolean asc;
+    public QueryUnitComparator(String sortField, boolean asc) {
+      this.sortField = sortField;
+      this.asc = asc;
+    }
+
+    @Override
+    public int compare(QueryUnit queryUnit, QueryUnit queryUnit2) {
+      if(asc) {
+        if("id".equals(sortField)) {
+          return queryUnit.getId().compareTo(queryUnit2.getId());
+        } else if("host".equals(sortField)) {
+          String host1 = queryUnit.getSucceededHost() == null ? "-" : queryUnit.getSucceededHost();
+          String host2 = queryUnit2.getSucceededHost() == null ? "-" : queryUnit2.getSucceededHost();
+          return host1.compareTo(host2);
+        } else if("runTime".equals(sortField)) {
+          return compareLong(queryUnit.getRunningTime(), queryUnit2.getRunningTime());
+        } else if("startTime".equals(sortField)) {
+          return compareLong(queryUnit.getLaunchTime(), queryUnit2.getLaunchTime());
+        } else {
+          return queryUnit.getId().compareTo(queryUnit2.getId());
+        }
+      } else {
+        if("id".equals(sortField)) {
+          return queryUnit2.getId().compareTo(queryUnit.getId());
+        } else if("host".equals(sortField)) {
+          String host1 = queryUnit.getSucceededHost() == null ? "-" : queryUnit.getSucceededHost();
+          String host2 = queryUnit2.getSucceededHost() == null ? "-" : queryUnit2.getSucceededHost();
+          return host2.compareTo(host1);
+        } else if("runTime".equals(sortField)) {
+          return compareLong(queryUnit2.getRunningTime(), queryUnit.getRunningTime());
+        } else if("startTime".equals(sortField)) {
+          return compareLong(queryUnit2.getLaunchTime(), queryUnit.getLaunchTime());
+        } else {
+          return queryUnit2.getId().compareTo(queryUnit.getId());
+        }
+      }
+    }
+  }
+
+  static int compareLong(long a, long b) {
+    if(a > b) {
+      return 1;
+    } else if(a < b) {
+      return -1;
+    } else {
+      return 0;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/webapp/QueryExecutorServlet.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/webapp/QueryExecutorServlet.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/webapp/QueryExecutorServlet.java
new file mode 100644
index 0000000..2ba563c
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/webapp/QueryExecutorServlet.java
@@ -0,0 +1,360 @@
+package org.apache.tajo.webapp;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.util.StringUtils;
+import org.apache.tajo.QueryId;
+import org.apache.tajo.TajoProtos;
+import org.apache.tajo.catalog.TableDesc;
+import org.apache.tajo.client.QueryStatus;
+import org.apache.tajo.client.TajoClient;
+import org.apache.tajo.conf.TajoConf;
+import org.apache.tajo.ipc.ClientProtos;
+import org.apache.tajo.util.JSPUtil;
+import org.codehaus.jackson.map.DeserializationConfig;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.glassfish.grizzly.threadpool.FixedThreadPool;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * 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.
+ */
+
+public class QueryExecutorServlet extends HttpServlet {
+  private static final Log LOG = LogFactory.getLog(QueryExecutorServlet.class);
+
+  ObjectMapper om = new ObjectMapper();
+
+  //queryRunnerId -> QueryRunner
+  private Map<String, QueryRunner> queryRunners = new HashMap<String, QueryRunner>();
+
+  private TajoClient tajoClient;
+
+  private ExecutorService queryRunnerExecutor = Executors.newFixedThreadPool(5);
+
+  private QueryRunnerCleaner queryRunnerCleaner;
+  @Override
+  public void init(ServletConfig config) throws ServletException {
+    om.getDeserializationConfig().disable(
+        DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES);
+
+    try {
+      tajoClient = new TajoClient(new TajoConf());
+
+      queryRunnerCleaner = new QueryRunnerCleaner();
+      queryRunnerCleaner.start();
+    } catch (IOException e) {
+      LOG.error(e.getMessage());
+    }
+  }
+
+  @Override
+  public void service(HttpServletRequest request,
+                      HttpServletResponse response) throws ServletException, IOException {
+    String action = request.getParameter("action");
+    Map<String, Object> returnValue = new HashMap<String, Object>();
+    try {
+      if(tajoClient == null) {
+        errorResponse(response, "TajoClient not initialized");
+        return;
+      }
+      if(action == null || action.trim().isEmpty()) {
+        errorResponse(response, "no action parameter.");
+        return;
+      }
+
+      if("runQuery".equals(action)) {
+        String query = request.getParameter("query");
+        if(query == null || query.trim().isEmpty()) {
+          errorResponse(response, "No query parameter");
+          return;
+        }
+        String queryRunnerId = null;
+        while(true) {
+          synchronized(queryRunners) {
+            queryRunnerId = "" + System.currentTimeMillis();
+            if(!queryRunners.containsKey(queryRunnerId)) {
+              break;
+            }
+            try {
+              Thread.sleep(100);
+            } catch (InterruptedException e) {
+            }
+          }
+        }
+        QueryRunner queryRunner = new QueryRunner(queryRunnerId, query);
+        synchronized(queryRunners) {
+          queryRunners.put(queryRunnerId, queryRunner);
+        }
+        queryRunnerExecutor.submit(queryRunner);
+        returnValue.put("queryRunnerId", queryRunnerId);
+      } else if("getQueryProgress".equals(action)) {
+        synchronized(queryRunners) {
+          String queryRunnerId = request.getParameter("queryRunnerId");
+          QueryRunner queryRunner = queryRunners.get(queryRunnerId);
+          if(queryRunner == null) {
+            errorResponse(response, "No query info:" + queryRunnerId);
+            return;
+          }
+          if(queryRunner.error != null) {
+            errorResponse(response, queryRunner.error);
+            return;
+          }
+          SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+          returnValue.put("progress", queryRunner.progress);
+          returnValue.put("startTime", df.format(queryRunner.startTime));
+          returnValue.put("finishTime", queryRunner.finishTime == 0 ? "-" : df.format(queryRunner.startTime));
+          returnValue.put("runningTime", JSPUtil.getElapsedTime(queryRunner.startTime, queryRunner.finishTime));
+        }
+      } else if("getQueryResult".equals(action)) {
+        synchronized(queryRunners) {
+          String queryRunnerId = request.getParameter("queryRunnerId");
+          QueryRunner queryRunner = queryRunners.get(queryRunnerId);
+          if(queryRunner == null) {
+            errorResponse(response, "No query info:" + queryRunnerId);
+            return;
+          }
+          if(queryRunner.error != null) {
+            errorResponse(response, queryRunner.error);
+            return;
+          }
+          returnValue.put("resultData", queryRunner.queryResult);
+          returnValue.put("resultColumns", queryRunner.columnNames);
+          returnValue.put("runningTime", JSPUtil.getElapsedTime(queryRunner.startTime, queryRunner.finishTime));
+        }
+      } else if("clearAllQueryRunner".equals(action)) {
+        synchronized(queryRunners) {
+          for(QueryRunner eachQueryRunner: queryRunners.values()) {
+            eachQueryRunner.setStop();
+          }
+          queryRunners.clear();
+        }
+      }
+      returnValue.put("success", "true");
+      writeHttpResponse(response, returnValue);
+    } catch (Exception e) {
+      LOG.error(e.getMessage(), e);
+      errorResponse(response, e);
+    }
+  }
+
+  private void errorResponse(HttpServletResponse response, Exception e) throws IOException {
+    errorResponse(response, e.getMessage() + "\n" + StringUtils.stringifyException(e));
+  }
+
+  private void errorResponse(HttpServletResponse response, String message) throws IOException {
+    Map<String, Object> errorMessage = new HashMap<String, Object>();
+    errorMessage.put("success", "false");
+    errorMessage.put("errorMessage", message);
+    writeHttpResponse(response, errorMessage);
+  }
+
+  private void writeHttpResponse(HttpServletResponse response, Map<String, Object> outputMessage) throws IOException {
+    response.setContentType("text/html");
+
+    OutputStream out = response.getOutputStream();
+    out.write(om.writeValueAsBytes(outputMessage));
+
+    out.flush();
+    out.close();
+  }
+
+  class QueryRunnerCleaner extends Thread {
+    public void run() {
+      List<QueryRunner> queryRunnerList;
+      synchronized(queryRunners) {
+        queryRunnerList = new ArrayList<QueryRunner>(queryRunners.values());
+        for(QueryRunner eachQueryRunner: queryRunnerList) {
+          if(!eachQueryRunner.running.get() &&
+              (System.currentTimeMillis() - eachQueryRunner.finishTime > 180 * 1000)) {
+            queryRunners.remove(eachQueryRunner.queryRunnerId);
+          }
+        }
+      }
+    }
+  }
+
+  class QueryRunner extends Thread {
+    long startTime;
+    long finishTime;
+
+    String queryRunnerId;
+
+    ClientProtos.GetQueryStatusResponse queryRespons;
+    AtomicBoolean running = new AtomicBoolean(true);
+    AtomicBoolean stop = new AtomicBoolean(false);
+    QueryId queryId;
+    String query;
+    Exception error;
+
+    AtomicInteger progress = new AtomicInteger(0);
+
+    List<String> columnNames = new ArrayList<String>();
+
+    List<List<Object>> queryResult;
+
+    public QueryRunner(String queryRunnerId, String query) {
+      this.queryRunnerId = queryRunnerId;
+      this.query = query;
+    }
+
+    public void setStop() {
+      this.stop.set(true);
+      this.interrupt();
+    }
+
+    public void run() {
+      startTime = System.currentTimeMillis();
+      try {
+        queryRespons = tajoClient.executeQuery(query);
+        if (queryRespons.getResultCode() == ClientProtos.ResultCode.OK) {
+          QueryId queryId = null;
+          try {
+            queryId = new QueryId(queryRespons.getQueryId());
+            getQueryResult(queryId);
+          } finally {
+            if (queryId != null) {
+              tajoClient.closeQuery(queryId);
+            }
+          }
+        } else {
+          LOG.error("queryRespons.getResultCode() not OK:" + queryRespons.getResultCode());
+          error = new Exception("queryRespons.getResultCode() not OK:" + queryRespons.getResultCode());
+        }
+      } catch (Exception e) {
+        LOG.error(e.getMessage(), e);
+        error = e;
+      } finally {
+        running.set(false);
+        finishTime = System.currentTimeMillis();
+      }
+    }
+
+    private void getQueryResult(QueryId tajoQueryId) {
+      // query execute
+      try {
+        QueryStatus status = null;
+
+        while (!stop.get()) {
+          try {
+            Thread.sleep(1000);
+          } catch(InterruptedException e) {
+            break;
+          }
+          status = tajoClient.getQueryStatus(tajoQueryId);
+          if (status.getState() == TajoProtos.QueryState.QUERY_MASTER_INIT
+              || status.getState() == TajoProtos.QueryState.QUERY_MASTER_LAUNCHED) {
+            continue;
+          }
+
+          if (status.getState() == TajoProtos.QueryState.QUERY_RUNNING
+              || status.getState() == TajoProtos.QueryState.QUERY_SUCCEEDED) {
+            int progressValue = (int) (status.getProgress() * 100.0f);
+            if(progressValue == 100)  {
+              progressValue = 99;
+            }
+            progress.set(progressValue);
+          }
+          if (status.getState() != TajoProtos.QueryState.QUERY_RUNNING
+              && status.getState() != TajoProtos.QueryState.QUERY_NOT_ASSIGNED) {
+            break;
+          }
+        }
+
+        if(status == null) {
+          LOG.error("Query Status is null");
+          error = new Exception("Query Status is null");
+          return;
+        }
+        if (status.getState() == TajoProtos.QueryState.QUERY_ERROR ||
+            status.getState() == TajoProtos.QueryState.QUERY_FAILED) {
+          error = new Exception(status.getErrorMessage());
+        } else if (status.getState() == TajoProtos.QueryState.QUERY_KILLED) {
+          LOG.info(queryId + " is killed.");
+          error = new Exception(queryId + " is killed.");
+        } else {
+          if (status.getState() == TajoProtos.QueryState.QUERY_SUCCEEDED) {
+            if (status.hasResult()) {
+              ResultSet res = tajoClient.getQueryResult(tajoQueryId);
+              try {
+                ResultSetMetaData rsmd = res.getMetaData();
+                TableDesc desc = tajoClient.getResultDesc(tajoQueryId);
+                LOG.info("Tajo Query Result: " + desc.getPath() + "\n");
+
+                int numOfColumns = rsmd.getColumnCount();
+                for(int i = 0; i < numOfColumns; i++) {
+                  columnNames.add(rsmd.getColumnName(i + 1));
+                }
+                queryResult = new ArrayList<List<Object>>();
+
+                int rowCount = 0;
+                boolean hasMoreData = false;
+                while (res.next()) {
+                  if(rowCount > 1000) {
+                    hasMoreData = true;
+                    break;
+                  }
+                  List<Object> row = new ArrayList<Object>();
+                  for(int i = 0; i < numOfColumns; i++) {
+                    row.add(res.getObject(i + 1).toString());
+                  }
+                  queryResult.add(row);
+                  rowCount++;
+
+                }
+              } finally {
+                if (res != null) {
+                  res.close();
+                }
+                progress.set(100);
+              }
+            } else {
+              error = new Exception(queryId + " no result");
+            }
+          }
+        }
+      } catch (Exception e) {
+        LOG.error(e.getMessage(), e);
+        error = e;
+      }
+    }
+  }
+
+  static class QueryResult {
+    String queryId;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/worker/TajoWorker.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/worker/TajoWorker.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/worker/TajoWorker.java
index 8b115b1..d9984b8 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/worker/TajoWorker.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/worker/TajoWorker.java
@@ -42,10 +42,10 @@ import org.apache.tajo.util.NetUtils;
 import org.apache.tajo.util.TajoIdUtils;
 import org.apache.tajo.webapp.StaticHttpServer;
 
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStreamReader;
+import java.io.*;
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
 import java.net.InetSocketAddress;
 import java.util.ArrayList;
 import java.util.List;
@@ -95,6 +95,8 @@ public class TajoWorker extends CompositeService {
 
   private int httpPort;
 
+  private ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
+
   public TajoWorker(String daemonMode) throws Exception {
     super(TajoWorker.class.getName());
     this.daemonMode = daemonMode;
@@ -468,6 +470,47 @@ public class TajoWorker extends CompositeService {
     setWorkerMode(args);
   }
 
+  String getThreadTaskName(long id, String name) {
+    if (name == null) {
+      return Long.toString(id);
+    }
+    return id + " (" + name + ")";
+  }
+
+  public void dumpThread(Writer writer) {
+    PrintWriter stream = new PrintWriter(writer);
+    int STACK_DEPTH = 20;
+    boolean contention = threadBean.isThreadContentionMonitoringEnabled();
+    long[] threadIds = threadBean.getAllThreadIds();
+    stream.println("Process Thread Dump: Tajo Worker");
+    stream.println(threadIds.length + " active threads");
+    for (long tid : threadIds) {
+      ThreadInfo info = threadBean.getThreadInfo(tid, STACK_DEPTH);
+      if (info == null) {
+        stream.println("  Inactive");
+        continue;
+      }
+      stream.println("Thread " + getThreadTaskName(info.getThreadId(), info.getThreadName()) + ":");
+      Thread.State state = info.getThreadState();
+      stream.println("  State: " + state + ",  Blocked count: " + info.getBlockedCount() +
+          ",  Waited count: " + info.getWaitedCount());
+      if (contention) {
+        stream.println("  Blocked time: " + info.getBlockedTime() + ",  Waited time: " + info.getWaitedTime());
+      }
+      if (state == Thread.State.WAITING) {
+        stream.println("  Waiting on " + info.getLockName());
+      } else if (state == Thread.State.BLOCKED) {
+        stream.println("  Blocked on " + info.getLockName() +
+            ", Blocked by " + getThreadTaskName(info.getLockOwnerId(), info.getLockOwnerName()));
+      }
+      stream.println("  Stack:");
+      for (StackTraceElement frame : info.getStackTrace()) {
+        stream.println("    " + frame.toString());
+      }
+      stream.println("");
+    }
+  }
+
   public static List<File> getMountPath() throws Exception {
     BufferedReader mountOutput = null;
     try {
@@ -507,6 +550,7 @@ public class TajoWorker extends CompositeService {
   }
 
   public static void main(String[] args) throws Exception {
+    args = new String[]{"standby"};
     StringUtils.startupShutdownMessage(TajoWorker.class, args, LOG);
 
     if(args.length < 1) {

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/worker/WorkerJSPUtil.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/worker/WorkerJSPUtil.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/worker/WorkerJSPUtil.java
deleted file mode 100644
index ba49ff6..0000000
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/worker/WorkerJSPUtil.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/**
- * 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.tajo.worker;
-
-import org.apache.hadoop.conf.Configuration;
-import org.apache.tajo.master.querymaster.QueryUnit;
-
-import java.text.DecimalFormat;
-import java.util.*;
-
-public class WorkerJSPUtil {
-  public static void sortQueryUnit(QueryUnit[] queryUnits, String sortField, String sortOrder) {
-    if(sortField == null || sortField.isEmpty()) {
-      sortField = "id";
-    }
-
-    Arrays.sort(queryUnits, new QueryUnitComparator(sortField, "asc".equals(sortOrder)));
-  }
-
-  public static void sortTaskRunner(List<TaskRunner> taskRunners) {
-    Collections.sort(taskRunners, new Comparator<TaskRunner>() {
-      @Override
-      public int compare(TaskRunner taskRunner, TaskRunner taskRunner2) {
-        return taskRunner.getId().compareTo(taskRunner2.getId());
-      }
-    });
-  }
-
-  static DecimalFormat decimalF = new DecimalFormat("###.0");
-
-  public static String getElapsedTime(long startTime, long finishTime) {
-    return finishTime == 0 ? decimalF.format((System.currentTimeMillis() - startTime) / 1000) + " sec"
-        : decimalF.format((finishTime - startTime) / 1000) + " sec";
-  }
-
-  public static String getTajoMasterHttpAddr(Configuration config) {
-    try {
-      String[] masterAddr = config.get("tajo.master.manager.addr").split(":");
-
-      return masterAddr[0] + ":" + config.getInt("tajo.master.http.port", 8080);
-    } catch (Exception e) {
-      e.printStackTrace();
-      return e.getMessage();
-    }
-  }
-
-  static class QueryUnitComparator implements Comparator<QueryUnit> {
-    private String sortField;
-    private boolean asc;
-    public QueryUnitComparator(String sortField, boolean asc) {
-      this.sortField = sortField;
-      this.asc = asc;
-    }
-
-    @Override
-    public int compare(QueryUnit queryUnit, QueryUnit queryUnit2) {
-      if(asc) {
-        if("id".equals(sortField)) {
-          return queryUnit.getId().compareTo(queryUnit2.getId());
-        } else if("host".equals(sortField)) {
-          String host1 = queryUnit.getSucceededHost() == null ? "-" : queryUnit.getSucceededHost();
-          String host2 = queryUnit2.getSucceededHost() == null ? "-" : queryUnit2.getSucceededHost();
-          return host1.compareTo(host2);
-        } else if("runTime".equals(sortField)) {
-          return compareLong(queryUnit.getRunningTime(), queryUnit2.getRunningTime());
-        } else if("startTime".equals(sortField)) {
-          return compareLong(queryUnit.getLaunchTime(), queryUnit2.getLaunchTime());
-        } else {
-          return queryUnit.getId().compareTo(queryUnit2.getId());
-        }
-      } else {
-        if("id".equals(sortField)) {
-          return queryUnit2.getId().compareTo(queryUnit.getId());
-        } else if("host".equals(sortField)) {
-          String host1 = queryUnit.getSucceededHost() == null ? "-" : queryUnit.getSucceededHost();
-          String host2 = queryUnit2.getSucceededHost() == null ? "-" : queryUnit2.getSucceededHost();
-          return host2.compareTo(host1);
-        } else if("runTime".equals(sortField)) {
-          return compareLong(queryUnit2.getRunningTime(), queryUnit.getRunningTime());
-        } else if("startTime".equals(sortField)) {
-          return compareLong(queryUnit2.getLaunchTime(), queryUnit.getLaunchTime());
-        } else {
-          return queryUnit2.getId().compareTo(queryUnit.getId());
-        }
-      }
-    }
-  }
-
-  static int compareLong(long a, long b) {
-    if(a > b) {
-      return 1;
-    } else if(a < b) {
-      return -1;
-    } else {
-      return 0;
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/catalogview.jsp
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/catalogview.jsp b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/catalogview.jsp
index 44c43b3..4b3265b 100644
--- a/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/catalogview.jsp
+++ b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/catalogview.jsp
@@ -1,118 +1,121 @@
-<%@ page language="java" contentType="text/html; charset=UTF-8"
-    pageEncoding="UTF-8"%>
-<%--
-  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
+<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
 
-      http://www.apache.org/licenses/LICENSE-2.0
+<%@ page import="java.util.*" %>
+<%@ page import="org.apache.tajo.webapp.StaticHttpServer" %>
+<%@ page import="org.apache.tajo.master.*" %>
+<%@ page import="org.apache.tajo.catalog.*" %>
+<%@ page import="org.apache.tajo.util.FileUtil" %>
+<%
+  TajoMaster master = (TajoMaster) StaticHttpServer.getInstance().getAttribute("tajo.info.server.object");
+  CatalogService catalog = master.getCatalog();
 
-  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.
--- %>
+  String selectedDatabase = request.getParameter("database");
+  if(selectedDatabase == null || selectedDatabase.trim().isEmpty()) {
+    selectedDatabase = "default";
+  }
 
-<%@ page import="java.util.*" %>
-<%@ page import="nta.engine.cluster.ClusterManager" %>
-<%@ page import="com.google.gson.Gson" %>
-<%@ page import="nta.engine.json.*" %>
-<%@ page import="nta.catalog.*" %>
-<%@ page import="nta.engine.*" %>
+  TableDesc tableDesc = null;
+  String selectedTable = request.getParameter("table");
+  if(selectedTable != null && !selectedTable.trim().isEmpty()) {
+    tableDesc = catalog.getTableDesc(selectedTable);
+  } else {
+    selectedTable = "";
+  }
+
+  //TODO filter with database
+  Collection<String> tableNames = catalog.getAllTableNames();
+%>
 
 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <html>
 <head>
-  <link rel="stylesheet" type = "text/css" href = "./style.css" />
+  <link rel="stylesheet" type = "text/css" href = "/static/style.css" />
   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-  <title>Tajo Catalog</title>
-  <%
-   String masterAddr = (String)application.getAttribute("tajo.master.addr");
-   NtaEngineMaster master = (NtaEngineMaster)application.getAttribute("tajo.master");
-   CatalogService catalog = master.getCatalog();
-   String tableName = request.getParameter("tablename");
-   if(tableName == null) {
-	  if(master.getCatalog().getAllTableNames().iterator().hasNext()) 
-	    tableName = catalog.getAllTableNames().iterator().next();
-	  else
-		tableName = null;
-   }
-   TableDesc desc = null;
-   TableMeta meta = null;
-   Collection<String> tableList = null;
-   if(tableName != null) {
-	 desc = catalog.getTableDesc(tableName);
-     meta = desc.getMeta();
-     tableList = master.getCatalog().getAllTableNames();
-   }
-   %>
+  <title>Tajo</title>
 </head>
 <body>
-  <div class = "container" >
-  <img src="./img/tajochar_catalog_small.jpg" />
-  </div>
-  <br />
-  <div class = "headline_2">
-   <div class = "container">
-    <a href="./index.jsp" class="headline">Tajo Main</a>
-      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-      <a href="./nodeview.jsp" class="headline">Workers</a>
-      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-      <a href="./queryview.jsp" class="headline">Queries</a>
-   </div>
-  </div>
-  <div class = "container">
-    
-    <%
-     if(tableName != null) {
-    	 out.write("<h2 class = \"line\" >Table Info</h2>");
-    	 TableDesc table = catalog.getTableDesc(tableName);
-    	 out.write("<ul>");
-    	 out.write("<li> Table Name : " + table.getId() + "</li>");
-    	 out.write("<li> Table Path : " + table.getPath() + "</li>");
-    	 out.write("<li> Store Type : " + table.getMeta().getStoreType() + "</li>");
-    	 out.write("<li> Schema<ul>");
-    	 Schema schema = table.getMeta().getSchema();
-    	 for(int i = 0 ; i < table.getMeta().getSchema().size() ; i ++) {
-    		 out.write("<li>" + schema.getColumn(i).toString() + "</li>");
-    	 }
-    	 out.write("</ul>");
-    	 out.write("</li>");
-    	 out.write("</ul>");
-     }
-    %>
-    <h2 class = "line">Table List</h2>
-    <table align = "center" class = "new">
-    <tr>
-     <th>TableName</th>
-     <th>TablePath</th>
-     <th>StoreType</th>
-    </tr>
-    <%
-    String[] tableArr = catalog.getAllTableNames().toArray(new String[0]);
-    for(int i = 0 ; i < tableArr.length ; i ++ ) {
-      TableDesc table = catalog.getTableDesc(tableArr[i]);    
-    %>
+<%@ include file="header.jsp"%>
+<div class='contents'>
+  <h2>Tajo Master: <%=master.getMasterName()%></h2>
+  <hr/>
+  <h3>Catalog</h3>
+  <p/>
+  <table width="100%" border='0'>
     <tr>
-      <td><a href = "./catalogview.jsp?tablename=<%=table.getId()%>" class = "tablelink"><%=table.getId()%></a></td>
-      <td><%=table.getPath()%></td>
-      <td><%=table.getMeta().getStoreType()%></td>
-    </tr>	
-    <% 	
+      <!-- left -->
+      <td width="20%" valign="top">
+        <div>
+          <b>Database:</b>
+          <select width="190" style="width: 190px">
+            <option value="default" selected>default</option>
+          </select>
+        </div>
+        <!-- table list -->
+        <div style='margin-top:5px'>
+<%
+  if(tableNames == null || tableNames.isEmpty()) {
+    out.write("No tables");
+  } else {
+%>
+          <table width="100%" border="1" class="border_table">
+            <tr><th>Table Name</th></tr>
+<%
+    for(String eachTableName: tableNames) {
+      String bold = "";
+      if(eachTableName.equals(selectedTable)) {
+        bold = "font-weight:bold";
+      }
+      String detailLink = "catalogview.jsp?database=" + selectedDatabase + "&table=" + eachTableName;
+      out.write("<tr><td><span style='" + bold + "'><a href='" + detailLink + "'>" + eachTableName + "</a></span></td></tr>");
     }
-    %>
-    </table>
-    
-    <h2 class = "line">Function List</h2>
-    <h2 class = "line">Others</h2>
-    
-    
-  </div>
+%>
+          </table>
+<%
+  }
+%>
+        </div>
+      </td>
+      <!-- right -->
+      <td width="80%" valign="top">
+        <div style='margin-left: 15px'>
+          <div style='font-weight:bold'>Table name: <%=selectedTable%></div>
+          <div style='margin-top:5px'>
+<%
+    if(tableDesc != null) {
+      List<Column> columns = tableDesc.getSchema().getColumns();
+      out.write("<table border='1' class='border_table'><tr><th>No</th><th>Column name</th><th>Type</th></tr>");
+      int columnIndex = 1;
+      for(Column eachColumn: columns) {
+        out.write("<tr><td width='30' align='right'>" + columnIndex + "</td><td width='320'>" + eachColumn.getColumnName() + "</td><td width='150'>" + eachColumn.getDataType().getType() + "</td></tr>");
+        columnIndex++;
+      }
+
+      String optionStr = "";
+      String prefix = "";
+      for(Map.Entry<String, String> entry: tableDesc.getMeta().toMap().entrySet()) {
+        optionStr += prefix + "'" + entry.getKey() + "'='" + entry.getValue() + "'";
+        prefix = "<br/>";
+      }
+      out.write("</table>");
+%>
+          </div>
+          <div style='margin-top:10px'>
+            <div style=''>Detail</div>
+            <table border="1" class='border_table'>
+              <tr><td width='100'>Table path</td><td width='410'><%=tableDesc.getPath()%></td></tr>
+              <tr><td>Store type</td><td><%=tableDesc.getMeta().getStoreType()%></td></tr>
+              <tr><td># rows</td><td><%=tableDesc.getMeta().getStat().getNumRows()%></td></tr>
+              <tr><td>Volume</td><td><%=FileUtil.humanReadableByteCount(tableDesc.getMeta().getStat().getNumBytes(),true)%></td></tr>
+              <tr><td>Options</td><td><%=optionStr%></td></tr>
+            </table>
+          </div>
+        </div>
+<%
+    }
+%>
+      </td>
+    </tr>
+  </table>
+</div>
 </body>
 </html>
-

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/cluster.jsp
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/cluster.jsp b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/cluster.jsp
new file mode 100644
index 0000000..20dbc7c
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/cluster.jsp
@@ -0,0 +1,122 @@
+<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
+
+<%@ page import="java.util.*" %>
+<%@ page import="org.apache.tajo.webapp.StaticHttpServer" %>
+<%@ page import="org.apache.tajo.master.*" %>
+<%@ page import="org.apache.tajo.master.rm.*" %>
+
+<%
+  TajoMaster master = (TajoMaster) StaticHttpServer.getInstance().getAttribute("tajo.info.server.object");
+  Map<String, WorkerResource> workers = master.getContext().getResourceManager().getWorkers();
+  List<String> wokerKeys = new ArrayList<String>(workers.keySet());
+  Collections.sort(wokerKeys);
+
+  int totalSlot = 0;
+  int runningSlot = 0;
+  int idleSlot = 0;
+
+  List<WorkerResource> liveWorkers = new ArrayList<WorkerResource>();
+  List<WorkerResource> deadWorkers = new ArrayList<WorkerResource>();
+  List<WorkerResource> decommissionWorkers = new ArrayList<WorkerResource>();
+
+  for(WorkerResource eachWorker: workers.values()) {
+    if(eachWorker.getWorkerStatus() == WorkerStatus.LIVE) {
+      liveWorkers.add(eachWorker);
+      idleSlot += eachWorker.getAvaliableSlots();
+      totalSlot += eachWorker.getSlots();
+      runningSlot += eachWorker.getUsedSlots();
+    } else if(eachWorker.getWorkerStatus() == WorkerStatus.DEAD) {
+      deadWorkers.add(eachWorker);
+    } else if(eachWorker.getWorkerStatus() == WorkerStatus.DECOMMISSION) {
+      decommissionWorkers.add(eachWorker);
+    }
+  }
+%>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+  <link rel="stylesheet" type = "text/css" href = "/static/style.css" />
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  <title>Tajo</title>
+</head>
+<body>
+<%@ include file="header.jsp"%>
+<div class='contents'>
+  <h2>Tajo Master: <%=master.getMasterName()%></h2>
+  <hr/>
+  <div>Live:<%=liveWorkers.size()%>, Dead: <%=deadWorkers.size()%>, Decommission: <%=decommissionWorkers.size()%></div>
+  <hr/>
+  <h3>Live Workers</h3>
+<%
+  if(liveWorkers.isEmpty()) {
+%>
+    No Live Workers
+<%
+  } else {
+%>
+  <table width="100%" class="border_table" border="1">
+    <tr><th>No</th><th>Worker</th><th>Ports</th><th>Running Tasks</th><th>Slot</th></th><th>Heap(free/max)</th><th>Disk</th><th>Cpu</th><th>Status</th></tr>
+<%
+    int no = 1;
+    for(WorkerResource worker: liveWorkers) {
+          String workerHttp = "http://" + worker.getAllocatedHost() + ":" + worker.getHttpPort();
+%>
+    <tr>
+      <td width='30' align='right'><%=no++%></td>
+      <td><a href='<%=workerHttp%>'><%=worker.getAllocatedHost() + ":" + worker.getManagerPort()%></a></td>
+      <td width='100'><%=worker.portsToStr()%></td>
+      <td width='100' align='right'><%=worker.getNumRunningTasks()%></td>
+      <td width='100' align='right'><%=worker.getUsedSlots()%>/<%=worker.getSlots()%></td>
+      <td width='100' align='left'><%=worker.getFreeHeap()/1024/1024%>/<%=worker.getMaxHeap()/1024/1024%> MB</td>
+      <td width='100' align='right'><%=worker.getUsedDiskSlots()%>/<%=worker.getDiskSlots()%></td>
+      <td width='100' align='right'><%=worker.getUsedCpuCoreSlots()%>/<%=worker.getCpuCoreSlots()%></td>
+      <td width='100' align='center'><%=worker.getWorkerStatus()%></td>
+    </tr>
+<%
+    } //end fo for
+%>
+    </table>
+<%
+  } //end of if
+%>
+
+  <p/>
+  <hr/>
+  <p/>
+  <h3>Dead Workers</h3>
+
+<%
+    if(deadWorkers.isEmpty()) {
+%>
+  No Dead Workers
+<%
+  } else {
+%>
+  <table width="100%" class="border_table" border="1">
+    <tr><th>No</th><th>Worker</th><th>Ports</th><th>Running Tasks</th><th>Slot</th></th><th>Heap(free/max)</th><th>Disk</th><th>Cpu</th><th>Status</th></tr>
+<%
+      int no = 1;
+      for(WorkerResource worker: deadWorkers) {
+%>
+    <tr>
+      <td width='30' align='right'><%=no++%></td>
+      <td><%=worker.getAllocatedHost() + ":" + worker.getManagerPort()%></td>
+      <td><%=worker.portsToStr()%></td>
+      <td><%=worker.getNumRunningTasks()%></td>
+      <td><%=worker.getUsedSlots()%>/<%=worker.getSlots()%></td>
+      <td><%=worker.getFreeHeap()/1024/1024%>/<%=worker.getMaxHeap()/1024/1024%> MB</td>
+      <td><%=worker.getUsedDiskSlots()%>/<%=worker.getDiskSlots()%></td>
+      <td><%=worker.getUsedCpuCoreSlots()%>/<%=worker.getCpuCoreSlots()%></td>
+      <td><%=worker.getWorkerStatus()%></td>
+    </tr>
+<%
+      } //end fo for
+%>
+  </table>
+<%
+    } //end of if
+%>
+</div>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/conf.jsp
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/conf.jsp b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/conf.jsp
new file mode 100644
index 0000000..323d6d8
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/conf.jsp
@@ -0,0 +1,37 @@
+<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
+
+<%@ page import="org.apache.tajo.webapp.StaticHttpServer" %>
+<%@ page import="org.apache.tajo.master.*" %>
+<%@ page import="org.apache.tajo.conf.*" %>
+<%@ page import="java.util.Map" %>
+
+<%
+  TajoMaster master = (TajoMaster) StaticHttpServer.getInstance().getAttribute("tajo.info.server.object");
+  TajoMaster.MasterContext context = master.getContext();
+  TajoConf tajoConf = context.getConf();
+%>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+  <link rel="stylesheet" type = "text/css" href = "/static/style.css" />
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  <title>Tajo</title>
+</head>
+<body>
+<%@ include file="header.jsp"%>
+<div class='contents'>
+  <h2>Tajo Master: <%=master.getMasterName()%></h2>
+  <hr/>
+  <table width="100%" border="1" class="border_table">
+<%
+  for(Map.Entry<String,String> entry: tajoConf) {
+%>
+    <tr><td width="200"><%=entry.getKey()%></td><td><%=entry.getValue()%></td>
+<%
+  }
+%>
+  </table>
+</div>
+</body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/env.jsp
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/env.jsp b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/env.jsp
new file mode 100644
index 0000000..122917b
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/env.jsp
@@ -0,0 +1,48 @@
+<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
+
+<%@ page import="org.apache.tajo.webapp.StaticHttpServer" %>
+<%@ page import="org.apache.tajo.master.*" %>
+<%@ page import="java.util.Map" %>
+
+<%
+  TajoMaster master = (TajoMaster) StaticHttpServer.getInstance().getAttribute("tajo.info.server.object");
+%>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+  <link rel="stylesheet" type = "text/css" href = "/static/style.css" />
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  <title>Tajo</title>
+</head>
+<body>
+<%@ include file="header.jsp"%>
+<div class='contents'>
+  <h2>Tajo Master: <%=master.getMasterName()%></h2>
+  <hr/>
+  <h3>System Environment</h3>
+  <table width="100%" class="border_table">
+<%
+  for(Map.Entry<String, String> entry: System.getenv().entrySet()) {
+%>
+    <tr><td width="200"><%=entry.getKey()%></td><td><%=entry.getValue()%></td>
+<%
+  }
+%>
+  </table>
+
+  <h3>Properties</h3>
+  <hr/>
+
+  <table width="100%" class="border_table">
+<%
+  for(Map.Entry<Object, Object> entry: System.getProperties().entrySet()) {
+%>
+    <tr><td width="200"><%=entry.getKey()%></td><td><%=entry.getValue()%></td>
+<%
+  }
+%>
+  </table>
+</div>
+</body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/header.jsp
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/header.jsp b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/header.jsp
new file mode 100644
index 0000000..3f26e20
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/header.jsp
@@ -0,0 +1,13 @@
+<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
+<div class="menu">
+  <div style='float:left; margin-left:12px; margin-top:6px;'><a href='index.jsp'><img src='/static/img/logo_tajo.gif' border='0'/></a></div>
+  <ul>
+    <li><a class='top_menu_item' style='margin-left:10px;' href='index.jsp'>Home</a></li>
+    <li><a class='top_menu_item' href='cluster.jsp'>Cluster</a></li>
+    <li><a class='top_menu_item' href='query.jsp'>Query</a></li>
+    <li><a class='top_menu_item' href='catalogview.jsp'>Catalog</a></li>
+    <li><a class='top_menu_item' href='query_executor.jsp'>Execute Query</a></li>
+  </ul>
+  <br style='clear:left'/>
+</div>
+

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/index.jsp
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/index.jsp b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/index.jsp
index cc262dd..f592c7d 100644
--- a/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/index.jsp
+++ b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/index.jsp
@@ -1,114 +1,117 @@
 <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
 
 <%@ page import="java.util.*" %>
-<%@ page import="java.net.InetSocketAddress" %>
-<%@ page import="java.net.InetAddress"  %>
-<%@ page import="org.apache.hadoop.conf.Configuration" %>
 <%@ page import="org.apache.tajo.webapp.StaticHttpServer" %>
 <%@ page import="org.apache.tajo.master.*" %>
 <%@ page import="org.apache.tajo.master.rm.*" %>
 <%@ page import="org.apache.tajo.catalog.*" %>
 <%@ page import="org.apache.tajo.master.querymaster.QueryInProgress" %>
-<%@ page import="java.text.SimpleDateFormat" %>
+<%@ page import="org.apache.tajo.util.NetUtils" %>
 
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<html>
-<head>
-  <link rel="stylesheet" type = "text/css" href = "/static/style.css" />
-  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-  <title>tajo main</title>
-  <%
-    TajoMaster master = (TajoMaster) StaticHttpServer.getInstance().getAttribute("tajo.info.server.object");
-    CatalogService catalog = master.getCatalog();
-    Map<String, WorkerResource> workers = master.getContext().getResourceManager().getWorkers();
-    List<String> wokerKeys = new ArrayList<String>(workers.keySet());
-    Collections.sort(wokerKeys);
-  %>
-</head>
-<body>
-<img src='/static/img/tajo_logo.png'/>
-<hr/>
+<%
+  TajoMaster master = (TajoMaster) StaticHttpServer.getInstance().getAttribute("tajo.info.server.object");
+  Map<String, WorkerResource> workers = master.getContext().getResourceManager().getWorkers();
 
-<h3>Works</h3>
-<div>Live:<%=wokerKeys.size()%></div>
-<table>
-  <tr><th>Worker</th><th>Ports</th><th>Running Tasks</th><th>Slot</th></th><th>Heap(free/max)</th><th>Disk</th><th>Cpu</th><th>Status</th></tr>
-  <%
-    for(String eachWorker: wokerKeys) {
-      WorkerResource worker = workers.get(eachWorker);
-      String workerHttp = "http://" + worker.getAllocatedHost() + ":" + worker.getHttpPort();
-  %>
+  int numLiveWorkers = 0;
+  int numDeadWorkers = 0;
+  int numDecommissionWorkers = 0;
 
-  <tr>
-    <td><a href='<%=workerHttp%>'><%=eachWorker%></a></td>
-    <td><%=worker.portsToStr()%></td>
-    <td><%=worker.getNumRunningTasks()%></td>
-    <td><%=worker.getUsedSlots()%>/<%=worker.getSlots()%></td>
-    <td><%=worker.getFreeHeap()/1024/1024%>/<%=worker.getMaxHeap()/1024/1024%> MB</td>
-    <td><%=worker.getUsedDiskSlots()%>/<%=worker.getDiskSlots()%></td>
-    <td><%=worker.getUsedCpuCoreSlots()%>/<%=worker.getCpuCoreSlots()%></td>
-    <td><%=worker.getWorkerStatus()%></td>
-  </tr>
-  <%
-    }
+  int totalSlot = 0;
+  int runningSlot = 0;
+  int idleSlot = 0;
 
-    if(workers.isEmpty()) {
-  %>
-  <tr>
-    <td colspan='7'>No Workers</td>
-  </tr>
-  <%
+  for(WorkerResource eachWorker: workers.values()) {
+    if(eachWorker.getWorkerStatus() == WorkerStatus.LIVE) {
+      numLiveWorkers++;
+      idleSlot += eachWorker.getAvaliableSlots();
+      totalSlot += eachWorker.getSlots();
+      runningSlot += eachWorker.getUsedSlots();
+    } else if(eachWorker.getWorkerStatus() == WorkerStatus.DEAD) {
+      numDeadWorkers++;
+    } else if(eachWorker.getWorkerStatus() == WorkerStatus.DECOMMISSION) {
+      numDecommissionWorkers++;
     }
-  %>
-</table>
+  }
 
-<%
   Collection<QueryInProgress> runningQueries = master.getContext().getQueryJobManager().getRunningQueries();
   Collection<QueryInProgress> finishedQueries = master.getContext().getQueryJobManager().getFinishedQueries();
+
+  int avgQueryTime = 0;
+  int minQueryTime = Integer.MAX_VALUE;
+  int maxQueryTime = 0;
+
+  long totalTime = 0;
+  for(QueryInProgress eachQuery: finishedQueries) {
+    int runTime = (int)(eachQuery.getQueryInfo().getFinishTime() == 0 ? -1 :
+            eachQuery.getQueryInfo().getFinishTime() - eachQuery.getQueryInfo().getStartTime());
+    if(runTime > 0) {
+      totalTime += runTime;
+
+      if(runTime < minQueryTime) {
+        minQueryTime = runTime;
+      }
+
+      if(runTime > maxQueryTime) {
+        maxQueryTime = runTime;
+      }
+    }
+  }
+
+  if(minQueryTime == Integer.MAX_VALUE) {
+    minQueryTime = 0;
+  }
+  if(finishedQueries.size() > 0) {
+    avgQueryTime = (int)(totalTime / (long)finishedQueries.size());
+  }
 %>
-<hr/>
-<h3>Running Queries</h3>
-<table>
-  <tr></tr><th>QueryId</th><th>Query Master</th><th>Started</th><th>Progress</th><th>Time</th><th>sql</th></tr>
-<%
-  SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-  for(QueryInProgress eachQuery: runningQueries) {
-    long time = System.currentTimeMillis() - eachQuery.getQueryInfo().getStartTime();
-%>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+  <link rel="stylesheet" type = "text/css" href = "/static/style.css" />
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  <title>Tajo</title>
+</head>
+<body>
+<%@ include file="header.jsp"%>
+<div class='contents'>
+  <h2>Tajo Master: <%=master.getMasterName()%></h2>
+  <hr/>
+  <h3>Master Status</h3>
+  <table border='0'>
+    <tr><td width="100">Version:</td><td><%=master.getVersion()%></td></tr>
+    <tr><td width="100">Started:</td><td><%=new Date(master.getStartTime())%></td></tr>
+    <tr><td width="100">Meta Store:</td><td><%=master.getCatalogServer().getCatalogServerName()%></td></tr>
+    <tr><td width="100">Client Service:</td><td><%=NetUtils.normalizeInetSocketAddress(master.getTajoMasterClientService().getBindAddress())%></td></tr>
+    <tr><td width='100'>MaxHeap: </td><td><%=Runtime.getRuntime().maxMemory()/1024/1024%> MB</td>
+    <tr><td width='100'>TotalHeap: </td><td><%=Runtime.getRuntime().totalMemory()/1024/1024%> MB</td>
+    <tr><td width='100'>FreeHeap: </td><td><%=Runtime.getRuntime().freeMemory()/1024/1024%> MB</td>
+    <tr><td width="100">Configuration:</td><td><a href='conf.jsp'>detail...</a></td></tr>
+    <tr><td width="100">Environment:</td><td><a href='env.jsp'>detail...</a></td></tr>
+    <tr><td width="100">Threads:</td><td><a href='thread.jsp'>thread dump...</a></tr>
+  </table>
+  <hr/>
+
+  <h3>Cluster Summary</h3>
+  <table border='0' width="100%">
     <tr>
-      <td><%=eachQuery.getQueryId()%></td>
-      <td><%=eachQuery.getQueryInfo().getQueryMasterHost()%></td>
-      <td><%=df.format(eachQuery.getQueryInfo().getStartTime())%></td>
-      <td><%=(int)(eachQuery.getQueryInfo().getProgress() * 100.0f)%>%</td>
-      <td><%=(int)(time/1000)%> sec</td>
-      <td><%=eachQuery.getQueryInfo().getSql()%></td>
+      <td width="100"><a href='cluster.jsp'>Workers:</a></td><td>Total: <%=workers.size()%>&nbsp;&nbsp;&nbsp;&nbsp;Live: <%=numLiveWorkers%>&nbsp;&nbsp;&nbsp;&nbsp;Dead: <%=numDeadWorkers%></td>
     </tr>
-<%
-  }
-%>
-</table>
+    <tr>
+      <td width="100">Task Slots</td><td>Total: <%=totalSlot%>&nbsp;&nbsp;&nbsp;&nbsp;Occupied:<%=runningSlot%>&nbsp;&nbsp;&nbsp;&nbsp;Idle: <%=idleSlot%></td>
+    </tr>
+  </table>
+  <hr/>
 
-<hr/>
-<h3>Finished Queries</h3>
-<table>
-  <tr></tr><th>QueryId</th><th>Query Master</th><th>Started</th><th>Finished</th><th>Time</th><th>Status</th><th>sql</th></tr>
-  <%
-    for(QueryInProgress eachQuery: finishedQueries) {
-      long runTime = eachQuery.getQueryInfo().getFinishTime() == 0 ? -1 :
-              eachQuery.getQueryInfo().getFinishTime() - eachQuery.getQueryInfo().getStartTime();
-  %>
-  <tr>
-    <td><%=eachQuery.getQueryId()%></td>
-    <td><%=eachQuery.getQueryInfo().getQueryMasterHost()%></td>
-    <td><%=df.format(eachQuery.getQueryInfo().getStartTime())%></td>
-    <td><%=df.format(eachQuery.getQueryInfo().getFinishTime())%></td>
-    <td><%=runTime%> ms</td>
-    <td><%=eachQuery.getQueryInfo().getQueryState()%></td>
-    <td><%=eachQuery.getQueryInfo().getSql()%></td>
-  </tr>
-  <%
-    }
-  %>
-</table>
+  <h3>Query Summary</h3>
+  <table border='0'>
+    <tr>
+      <td width="100">Queries:</td><td>Running: <%=runningQueries.size()%>&nbsp;&nbsp;&nbsp;&nbsp;Finished: <%=finishedQueries.size()%></td>
+    </tr>
+    <tr>
+      <td width="100">Running time:</td><td>Average: <%=avgQueryTime/1000%>&nbsp;&nbsp;&nbsp;&nbsp;Min: <%=minQueryTime/1000%>&nbsp;&nbsp;&nbsp;&nbsp;Max: <%=maxQueryTime/1000%> ms</td>
+    </tr>
+  </table>
+</div>
 </body>
 </html>

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/query.jsp
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/query.jsp b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/query.jsp
index 10d8e13..7ca6055 100644
--- a/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/query.jsp
+++ b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/query.jsp
@@ -1,38 +1,100 @@
 <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
 
 <%@ page import="java.util.*" %>
-<%@ page import="java.net.InetSocketAddress" %>
-<%@ page import="java.net.InetAddress"  %>
-<%@ page import="org.apache.hadoop.conf.Configuration" %>
 <%@ page import="org.apache.tajo.webapp.StaticHttpServer" %>
 <%@ page import="org.apache.tajo.master.*" %>
-<%@ page import="org.apache.tajo.master.rm.*" %>
-<%@ page import="org.apache.tajo.catalog.*" %>
+<%@ page import="org.apache.tajo.util.*" %>
 <%@ page import="org.apache.tajo.master.querymaster.QueryInProgress" %>
+<%@ page import="java.text.SimpleDateFormat" %>
+
+<%
+  TajoMaster master = (TajoMaster) StaticHttpServer.getInstance().getAttribute("tajo.info.server.object");
+
+  List<QueryInProgress> runningQueries =
+          JSPUtil.sortQueryInProgress(master.getContext().getQueryJobManager().getRunningQueries(), true);
+
+  List<QueryInProgress> finishedQueries =
+          JSPUtil.sortQueryInProgress(master.getContext().getQueryJobManager().getFinishedQueries(), true);
+
+  SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+  int workerHttpPort = master.getConfig().getInt("tajo.worker.http.port", 28080);
+
+%>
 
 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <html>
 <head>
-  <link rel="stylesheet" type = "text/css" href = "./style.css" />
+  <link rel="stylesheet" type = "text/css" href = "/static/style.css" />
   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-  <title>tajo main</title>
-  <%
-    TajoMaster master = (TajoMaster) StaticHttpServer.getInstance().getAttribute("tajo.info.server.object");
-    CatalogService catalog = master.getCatalog();
-    Map<String, WorkerResource> workers = master.getContext().getResourceManager().getWorkers();
-  %>
+  <title>Tajo</title>
 </head>
 <body>
-<img src='img/tajo_logo.png'/>
-<hr/>
-
-<a href="index.jsp">Main</a>
-<a href="query.jsp">Query</a>
-
-<div><h3>Query</h3></div>
-<div>
-  <textarea></textarea>
+<%@ include file="header.jsp"%>
+<div class='contents'>
+  <h2>Tajo Master: <%=master.getMasterName()%></h2>
+  <hr/>
+  <h3>Running Queries</h3>
+<%
+  if(runningQueries.isEmpty()) {
+    out.write("No running queries");
+  } else {
+%>
+  <table width="100%" border="1" class='border_table'>
+    <tr></tr><th>QueryId</th><th>Query Master</th><th>Started</th><th>Progress</th><th>Time</th><th>sql</th></tr>
+    <%
+      for(QueryInProgress eachQuery: runningQueries) {
+        long time = System.currentTimeMillis() - eachQuery.getQueryInfo().getStartTime();
+        String detailView = "http://" + eachQuery.getQueryInfo().getQueryMasterHost() + ":" + workerHttpPort +
+                "/querydetail.jsp?queryId=" + eachQuery.getQueryId();
+    %>
+    <tr>
+      <td><a href='<%=detailView%>'><%=eachQuery.getQueryId()%></a></td>
+      <td><%=eachQuery.getQueryInfo().getQueryMasterHost()%></td>
+      <td><%=df.format(eachQuery.getQueryInfo().getStartTime())%></td>
+      <td><%=(int)(eachQuery.getQueryInfo().getProgress() * 100.0f)%>%</td>
+      <td><%=(int)(time/1000)%> sec</td>
+      <td><%=eachQuery.getQueryInfo().getSql()%></td>
+    </tr>
+    <%
+      }
+    %>
+  </table>
+<%
+  }
+%>
+  <p/>
+  <hr/>
+  <h3>Finished Queries</h3>
+  <%
+    if(finishedQueries.isEmpty()) {
+      out.write("No finished queries");
+    } else {
+  %>
+  <table width="100%" border="1" class='border_table'>
+    <tr></tr><th>QueryId</th><th>Query Master</th><th>Started</th><th>Finished</th><th>Time</th><th>Status</th><th>sql</th></tr>
+    <%
+      for(QueryInProgress eachQuery: finishedQueries) {
+        long runTime = eachQuery.getQueryInfo().getFinishTime() == 0 ? -1 :
+                eachQuery.getQueryInfo().getFinishTime() - eachQuery.getQueryInfo().getStartTime();
+        String detailView = "http://" + eachQuery.getQueryInfo().getQueryMasterHost() + ":" + workerHttpPort +
+                "/querydetail.jsp?queryId=" + eachQuery.getQueryId();
+    %>
+    <tr>
+      <td><a href='<%=detailView%>'><%=eachQuery.getQueryId()%></a></td>
+      <td><%=eachQuery.getQueryInfo().getQueryMasterHost()%></td>
+      <td><%=df.format(eachQuery.getQueryInfo().getStartTime())%></td>
+      <td><%=df.format(eachQuery.getQueryInfo().getFinishTime())%></td>
+      <td><%=runTime%> ms</td>
+      <td><%=eachQuery.getQueryInfo().getQueryState()%></td>
+      <td><%=eachQuery.getQueryInfo().getSql()%></td>
+    </tr>
+    <%
+      }
+    %>
+  </table>
+<%
+  }
+%>
 </div>
-<div>Run Query</div>
 </body>
-</html>
\ No newline at end of file
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/query_executor.jsp
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/query_executor.jsp b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/query_executor.jsp
new file mode 100644
index 0000000..abe955d
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/query_executor.jsp
@@ -0,0 +1,183 @@
+<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
+
+<%@ page import="java.util.*" %>
+<%@ page import="org.apache.tajo.webapp.StaticHttpServer" %>
+<%@ page import="org.apache.tajo.master.*" %>
+<%@ page import="org.apache.tajo.catalog.*" %>
+<%@ page import="org.apache.tajo.util.FileUtil" %>
+
+<%
+  TajoMaster master = (TajoMaster) StaticHttpServer.getInstance().getAttribute("tajo.info.server.object");
+%>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<link rel="stylesheet" type = "text/css" href = "/static/style.css" />
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Tajo</title>
+
+<style type="text/css">
+  #progress_bar {
+    border:1px solid #000000;
+    background:#ffffff;
+    width:400px;
+    height:16px;
+    border-radius: 16px;
+  }
+  #progress_status {background:#fbcb46; width:0%; height:16px; border-radius: 10px; }
+
+</style>
+<script src="/static/js/jquery.js" type="text/javascript"></script>
+<script type="text/javascript">
+var progressInterval = 1000;
+var progressTimer = null;
+var queryRunnerId = null;
+
+$(document).ready(function() {
+  $('#btnSubmit').click(function() {
+    runQuery();
+  });
+});
+
+function init() {
+  $("#progress_status").css("width", "0%");
+  $("#progress_text").text("0%");
+  $("#queryStatus").html("");
+  $("#queryResult").html("");
+  queryRunnerId = null;
+}
+function runQuery() {
+  if(progressTimer != null) {
+    alert("Already query running.");
+    return;
+  }
+  init();
+  var query = $("#query").val();
+
+  $.ajax({
+    type: "POST",
+    url: "query_exec",
+    data: { action: "runQuery", query: query}
+  })
+  .done(function(msg) {
+    var resultJson = $.parseJSON(msg);
+    if(resultJson.success == "false") {
+      clearTimer();
+      alert(resultJson.errorMessage);
+      return;
+    }
+    queryRunnerId = resultJson.queryRunnerId;
+    progressTimer = setInterval(function () {
+      $.ajax({
+        type: "GET",
+        url: "query_exec",
+        data: { action: "getQueryProgress", queryRunnerId: queryRunnerId }
+      })
+      .done(function( msg ) {
+        var resultJson = $.parseJSON(msg);
+        if(resultJson.success == "false") {
+          clearTimer();
+          alert(resultJson.errorMessage);
+          $("#queryStatus").html(getQueryStatusHtml(resultJson));
+          return;
+        }
+        var progress = parseInt(resultJson.progress, 0);
+        $("#progress_status").css("width", progress + "%");
+        $("#progress_text").text(progress + "%");
+        $("#queryStatus").html(getQueryStatusHtml(resultJson));
+        if(progress >= 100) {
+          clearTimer();
+          getResult();
+        }
+      });
+    }, progressInterval);
+  });
+}
+
+function clearTimer() {
+  if(progressTimer != null) {
+    clearInterval(progressTimer);
+  }
+  progressTimer = null;
+}
+
+function getQueryStatusHtml(status) {
+  if(status.success == "false") {
+    return "<div style='color:#ff0000; margin-top: 5px'>" + status.errorMessage + "</div>";
+  } else {
+    var statusHtml = "<div style='margin-top: 5px'>Start: " + status.startTime + "</div>";
+    statusHtml += "<div style='margin-top: 5px'>Finish: " + status.finishTime + "</div>";
+    statusHtml += "<div style='margin-top: 5px'> Running time: " + status.runningTime + "</div>";
+    return statusHtml;
+  }
+}
+
+function getResult() {
+  $.ajax({
+    type: "POST",
+    url: "query_exec",
+    data: { action: "getQueryResult", queryRunnerId: queryRunnerId }
+  })
+  .done(function(msg) {
+    var resultJson = $.parseJSON(msg);
+    if(resultJson.success == "false") {
+      alert(resultJson.errorMessage);
+      $("#queryStatus").html(getQueryStatusHtml(resultJson));
+      return;
+    }
+    console.log(resultJson);
+    $("#queryResult").html("");
+    var resultColumns = resultJson.resultColumns;
+    var resultData = resultJson.resultData;
+
+    var resultTable = "<table width='100%' class='border_table'><tr>";
+    for(var i = 0; i < resultColumns.length; i++) {
+      resultTable += "<th>" + resultColumns[i] + "</th>";
+    }
+    resultTable += "</tr>";
+    for(var i = 0; i < resultData.length; i++) {
+      resultTable += "<tr>";
+      for(var j = 0; j < resultData[i].length; j++) {
+        resultTable += "<td>" + resultData[i][j] + "</td>";
+      }
+      resultTable += "</tr>";
+    }
+    resultTable += "</table>";
+    $("#queryResult").html(resultTable);
+  });
+}
+
+</script>
+</head>
+
+<body>
+<%@ include file="header.jsp"%>
+<div class='contents'>
+  <h2>Tajo Master: <%=master.getMasterName()%></h2>
+  <hr/>
+  <h3>Query</h3>
+  <textarea id="query" style="width:800px; height:250px; font-family:Tahoma; font-size:12px;"></textarea>
+  <p/>
+  <input id="btnSubmit" type="submit" value="Submit">
+  <hr/>
+  <div>
+    <div style="float:left; width:60px">Progress:</div>
+    <div style='float:left; margin-left:10px'>
+      <div id='progress_bar'>
+        <div id='progress_status'></div>
+      </div>
+    </div>
+    <div style='float:left; margin-left:10px;'>
+      <div id="progress_text" style='font-family:Tahoma; font-size:14px; color:#000000; font-weight:bold'>0%</div>
+    </div>
+    <div style='clear:both'></div>
+  </div>
+  <div id="queryStatus">
+  </div>
+  <hr/>
+  <h3>Query Result</h3>
+  <div id="queryResult"></div>
+</div>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/thread.jsp
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/thread.jsp b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/thread.jsp
new file mode 100644
index 0000000..7c7fe5a
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/thread.jsp
@@ -0,0 +1,26 @@
+<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
+
+<%@ page import="org.apache.tajo.webapp.StaticHttpServer" %>
+<%@ page import="org.apache.tajo.master.*" %>
+
+<%
+  TajoMaster master = (TajoMaster) StaticHttpServer.getInstance().getAttribute("tajo.info.server.object");
+%>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+  <link rel="stylesheet" type = "text/css" href = "/static/style.css" />
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  <title>Tajo</title>
+</head>
+<body>
+<%@ include file="header.jsp"%>
+<div class='contents'>
+  <h2>Tajo Master: <%=master.getMasterName()%></h2>
+  <hr/>
+  <h3>Thread Dump</h3>
+  <pre><%master.dumpThread(out);%></pre>
+</div>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/tajo-core/tajo-core-backend/src/main/resources/webapps/static/img/logo_tajo.gif
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/resources/webapps/static/img/logo_tajo.gif b/tajo-core/tajo-core-backend/src/main/resources/webapps/static/img/logo_tajo.gif
new file mode 100644
index 0000000..13674e3
Binary files /dev/null and b/tajo-core/tajo-core-backend/src/main/resources/webapps/static/img/logo_tajo.gif differ