Repository: tajo
Updated Branches:
  refs/heads/master 2056aaa81 -> f868c0e23


TAJO-1735: Implement MetadataProvider and LinkedMetadataManager.

Closes #673


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

Branch: refs/heads/master
Commit: f868c0e237f7523f429d0196e67652e980ca5907
Parents: 2056aaa
Author: Hyunsik Choi <[email protected]>
Authored: Thu Aug 6 16:10:20 2015 +0900
Committer: Hyunsik Choi <[email protected]>
Committed: Thu Aug 6 16:10:20 2015 +0900

----------------------------------------------------------------------
 CHANGES                                         |   2 +
 .../tajo/catalog/AbstractCatalogClient.java     |  18 +-
 .../apache/tajo/catalog/MetadataProvider.java   |  39 ++
 .../InsufficientPrivilegeException.java         |  29 ++
 .../org/apache/tajo/catalog/CatalogServer.java  | 379 ++++++++++++++-----
 .../tajo/catalog/LinkedMetadataManager.java     | 241 ++++++++++++
 .../InfoSchemaMetadataDictionary.java           |   8 +-
 .../org/apache/tajo/catalog/TestCatalog.java    |  12 +-
 .../tajo/catalog/TestLinkedMetadataManager.java | 271 +++++++++++++
 .../java/org/apache/tajo/master/TajoMaster.java |   3 +-
 10 files changed, 890 insertions(+), 112 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tajo/blob/f868c0e2/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index 3757f7f..b478ffb 100644
--- a/CHANGES
+++ b/CHANGES
@@ -459,6 +459,8 @@ Release 0.11.0 - unreleased
 
   SUB TASKS
 
+    TAJO-1735: Implement MetadataProvider and LinkedMetadataManager. (hyunsik)
+
     TAJO-1723: INSERT INTO statement should allow nested fields as 
     target columns. (hyunsik)
 

http://git-wip-us.apache.org/repos/asf/tajo/blob/f868c0e2/tajo-catalog/tajo-catalog-client/src/main/java/org/apache/tajo/catalog/AbstractCatalogClient.java
----------------------------------------------------------------------
diff --git 
a/tajo-catalog/tajo-catalog-client/src/main/java/org/apache/tajo/catalog/AbstractCatalogClient.java
 
b/tajo-catalog/tajo-catalog-client/src/main/java/org/apache/tajo/catalog/AbstractCatalogClient.java
index e239b78..3dca859 100644
--- 
a/tajo-catalog/tajo-catalog-client/src/main/java/org/apache/tajo/catalog/AbstractCatalogClient.java
+++ 
b/tajo-catalog/tajo-catalog-client/src/main/java/org/apache/tajo/catalog/AbstractCatalogClient.java
@@ -95,8 +95,15 @@ public abstract class AbstractCatalogClient implements 
CatalogService, Closeable
 
     try {
       final BlockingInterface stub = getStub();
-      return isSuccess(stub.existTablespace(null, 
ProtoUtil.convertString(tablespaceName)));
 
+      ReturnState state = stub.existTablespace(null, 
ProtoUtil.convertString(tablespaceName));
+
+      if (isThisError(state, ResultCode.UNDEFINED_TABLESPACE)) {
+        return false;
+      }
+
+      ensureOk(state);
+      return true;
     } catch (ServiceException e) {
       throw new RuntimeException(e);
     }
@@ -196,8 +203,15 @@ public abstract class AbstractCatalogClient implements 
CatalogService, Closeable
 
     try {
       final BlockingInterface stub = getStub();
-      return isSuccess(stub.existDatabase(null, 
ProtoUtil.convertString(databaseName)));
 
+      ReturnState state = stub.existDatabase(null, 
ProtoUtil.convertString(databaseName));
+
+      if (isThisError(state, ResultCode.UNDEFINED_DATABASE)) {
+        return false;
+      }
+
+      ensureOk(state);
+      return true;
     } catch (ServiceException e) {
       throw new RuntimeException(e);
     }

http://git-wip-us.apache.org/repos/asf/tajo/blob/f868c0e2/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/MetadataProvider.java
----------------------------------------------------------------------
diff --git 
a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/MetadataProvider.java
 
b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/MetadataProvider.java
new file mode 100644
index 0000000..216d33c
--- /dev/null
+++ 
b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/MetadataProvider.java
@@ -0,0 +1,39 @@
+/*
+ * 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.catalog;
+
+import org.apache.tajo.catalog.exception.UndefinedTablespaceException;
+
+import javax.annotation.Nullable;
+import java.net.URI;
+import java.util.Collection;
+
+public interface MetadataProvider {
+  String getTablespaceName();
+
+  URI getTablespaceUri();
+
+  String getDatabaseName();
+
+  Collection<String> getCatalogs();
+
+  Collection<String> getTables(@Nullable String catalog);
+
+  TableDesc getTableDescriptor(String catalogName, String tableName) throws 
UndefinedTablespaceException;
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/f868c0e2/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/exception/InsufficientPrivilegeException.java
----------------------------------------------------------------------
diff --git 
a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/exception/InsufficientPrivilegeException.java
 
b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/exception/InsufficientPrivilegeException.java
new file mode 100644
index 0000000..9bcc866
--- /dev/null
+++ 
b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/exception/InsufficientPrivilegeException.java
@@ -0,0 +1,29 @@
+/*
+ * 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.catalog.exception;
+
+import org.apache.tajo.error.Errors.ResultCode;
+import org.apache.tajo.exception.TajoException;
+
+public class InsufficientPrivilegeException extends TajoException {
+
+  public InsufficientPrivilegeException(String towhat) {
+    super(ResultCode.INSUFFICIENT_PRIVILEGE, towhat);
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/f868c0e2/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 e2dcfcd..a7e8348 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
@@ -18,8 +18,11 @@
 
 package org.apache.tajo.catalog;
 
+import com.google.common.base.Function;
 import com.google.common.base.Objects;
+import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
+import com.google.common.collect.Collections2;
 import com.google.common.collect.Lists;
 import com.google.protobuf.RpcController;
 import com.google.protobuf.ServiceException;
@@ -33,6 +36,7 @@ import org.apache.tajo.catalog.CatalogProtocol.*;
 import org.apache.tajo.catalog.dictionary.InfoSchemaMetadataDictionary;
 import org.apache.tajo.catalog.exception.CatalogException;
 import org.apache.tajo.catalog.exception.DuplicateDatabaseException;
+import org.apache.tajo.catalog.exception.UndefinedTableException;
 import org.apache.tajo.catalog.exception.UndefinedTablespaceException;
 import org.apache.tajo.catalog.proto.CatalogProtos.*;
 import org.apache.tajo.catalog.store.CatalogStore;
@@ -50,6 +54,7 @@ import 
org.apache.tajo.rpc.protocolrecords.PrimitiveProtos.ReturnState;
 import org.apache.tajo.rpc.protocolrecords.PrimitiveProtos.StringListResponse;
 import org.apache.tajo.rpc.protocolrecords.PrimitiveProtos.StringProto;
 import org.apache.tajo.util.NetUtils;
+import org.apache.tajo.util.Pair;
 import org.apache.tajo.util.TUtil;
 
 import java.io.IOException;
@@ -84,6 +89,8 @@ public class CatalogServer extends AbstractService {
   private CatalogStore store;
   private Map<String, List<FunctionDescProto>> functions = new 
ConcurrentHashMap<String,
       List<FunctionDescProto>>();
+
+  private final LinkedMetadataManager linkedMetadataManager;
   private final InfoSchemaMetadataDictionary metaDictionary = new 
InfoSchemaMetadataDictionary();
 
   // RPC variables
@@ -97,19 +104,17 @@ public class CatalogServer extends AbstractService {
   public CatalogServer() throws IOException {
     super(CatalogServer.class.getName());
     this.handler = new CatalogProtocolHandler();
+    this.linkedMetadataManager = new 
LinkedMetadataManager(Collections.EMPTY_LIST);
     this.builtingFuncs = new ArrayList<FunctionDesc>();
   }
 
-  public CatalogServer(Collection<FunctionDesc> sqlFuncs) throws IOException {
-    this();
+  public CatalogServer(Set<MetadataProvider> metadataProviders, 
Collection<FunctionDesc> sqlFuncs) throws IOException {
+    super(CatalogServer.class.getName());
+    this.handler = new CatalogProtocolHandler();
+    this.linkedMetadataManager = new LinkedMetadataManager(metadataProviders);
     this.builtingFuncs = sqlFuncs;
   }
 
-  public void reloadBuiltinFunctions(List<FunctionDesc> builtingFuncs) throws 
ServiceException {
-    this.builtingFuncs = builtingFuncs;
-    initBuiltinFunctions(builtingFuncs);
-  }
-
   @Override
   public void serviceInit(Configuration conf) throws Exception {
 
@@ -146,20 +151,6 @@ public class CatalogServer extends AbstractService {
     return store.getClass().getCanonicalName();
   }
 
-  public String getCatalogServerName() {
-    String catalogUri = null;
-    if(conf.get(CatalogConstants.DEPRECATED_CATALOG_URI) != null) {
-      LOG.warn("Configuration parameter " + 
CatalogConstants.DEPRECATED_CATALOG_URI + " " +
-          "is deprecated. Use " + CatalogConstants.CATALOG_URI + " instead.");
-      catalogUri = conf.get(CatalogConstants.DEPRECATED_CATALOG_URI);
-    } else {
-      catalogUri = conf.get(CatalogConstants.CATALOG_URI);
-    }
-
-    return bindAddressStr + ", store=" + this.store.getClass().getSimpleName() 
+ ", catalogUri="
-        + catalogUri;
-  }
-
   private void initBuiltinFunctions(Collection<FunctionDesc> functions)
       throws ServiceException {
     for (FunctionDesc desc : functions) {
@@ -288,6 +279,7 @@ public class CatalogServer extends AbstractService {
       try {
         return StringListResponse.newBuilder()
             .setState(OK)
+            .addAllValues(linkedMetadataManager.getTablespaceNames())
             .addAllValues(store.getAllDatabaseNames())
             .build();
 
@@ -304,9 +296,25 @@ public class CatalogServer extends AbstractService {
         throws ServiceException {
       rlock.lock();
       try {
+
+        // retrieves tablespaces from catalog store
+        final List<TablespaceProto> tableSpaces = 
Lists.newArrayList(store.getTablespaces());
+
+        // retrieves tablespaces from linked meta data
+        
tableSpaces.addAll(Collections2.transform(linkedMetadataManager.getTablespaces(),
+            new Function<Pair<String, URI>, TablespaceProto>() {
+              @Override
+              public TablespaceProto apply(Pair<String, URI> input) {
+                return TablespaceProto.newBuilder()
+                    .setSpaceName(input.getFirst())
+                    .setUri(input.getSecond().toString())
+                    .build();
+              }
+            }));
+
         return GetTablespaceListResponse.newBuilder()
             .setState(OK)
-            .addAllTablespace(store.getTablespaces())
+            .addAllTablespace(tableSpaces)
             .build();
 
       } catch (Throwable t) {
@@ -323,6 +331,19 @@ public class CatalogServer extends AbstractService {
 
       try {
 
+        // if there exists the tablespace in linked meta data
+        Optional<Pair<String, URI>> optional = 
linkedMetadataManager.getTablespace(request.getValue());
+
+        if (optional.isPresent()) {
+          Pair<String, URI> spaceInfo = optional.get();
+          return GetTablespaceResponse.newBuilder()
+              .setState(OK)
+              .setTablespace(TablespaceProto.newBuilder()
+                  .setSpaceName(spaceInfo.getFirst())
+                  .setUri(spaceInfo.getSecond().toString())
+              ).build();
+        }
+
         return GetTablespaceResponse.newBuilder()
             .setState(OK)
             .setTablespace(store.getTablespace(request.getValue()))
@@ -344,8 +365,13 @@ public class CatalogServer extends AbstractService {
     public ReturnState alterTablespace(RpcController controller, 
AlterTablespaceProto request) {
       wlock.lock();
       try {
+
+        if 
(linkedMetadataManager.getTablespace(request.getSpaceName()).isPresent()) {
+          return errInsufficientPrivilege("alter tablespace 
'"+request.getSpaceName()+"'");
+        }
+
         if (!store.existTablespace(request.getSpaceName())) {
-          throw new UndefinedTablespaceException(request.getSpaceName());
+          return errUndefinedTablespace(request.getSpaceName());
         }
 
         if (request.getCommandList().size() > 0) {
@@ -380,6 +406,10 @@ public class CatalogServer extends AbstractService {
       String databaseName = request.getDatabaseName();
       String tablespaceName = request.getTablespaceName();
 
+      if (linkedMetadataManager.existsDatabase(request.getDatabaseName())) {
+        return errDuplicateDatabase(request.getDatabaseName());
+      }
+
       // check virtual database manually because catalog actually does not 
contain them.
       if (metaDictionary.isSystemDatabase(databaseName)) {
         return errDuplicateDatabase(databaseName);
@@ -431,7 +461,11 @@ public class CatalogServer extends AbstractService {
     @Override
     public ReturnState alterTable(RpcController controller, 
AlterTableDescProto proto) {
       String [] split = CatalogUtil.splitTableName(proto.getTableName());
-      
+
+      if (linkedMetadataManager.existsDatabase(split[0])) {
+        return errInsufficientPrivilege("alter a table in database '" + 
split[0] + "'");
+      }
+
       if (metaDictionary.isSystemDatabase(split[0])) {
         return errInsufficientPrivilege("alter a table in database '" + 
split[0] + "'");
       }
@@ -458,7 +492,11 @@ public class CatalogServer extends AbstractService {
     @Override
     public ReturnState dropDatabase(RpcController controller, StringProto 
request) {
       String databaseName = request.getValue();
-      
+
+      if (linkedMetadataManager.existsDatabase(databaseName)) {
+        return errInsufficientPrivilege("alter a table in database '" + 
databaseName + "'");
+      }
+
       if (metaDictionary.isSystemDatabase(databaseName)) {
         return errInsufficientPrivilege("drop a table in database '" + 
databaseName + "'");
       }
@@ -485,6 +523,10 @@ public class CatalogServer extends AbstractService {
     public ReturnState existDatabase(RpcController controller, StringProto 
request) {
       String dbName = request.getValue();
 
+      if (linkedMetadataManager.existsDatabase(dbName)) {
+        return OK;
+      }
+
       if (metaDictionary.isSystemDatabase(dbName)) {
         return OK;
       }
@@ -511,8 +553,9 @@ public class CatalogServer extends AbstractService {
       try {
         return StringListResponse.newBuilder()
             .setState(OK)
-            .addAllValues(store.getAllDatabaseNames())
+            .addAllValues(linkedMetadataManager.getDatabases())
             .addValues(metaDictionary.getSystemDatabaseName())
+            .addAllValues(store.getAllDatabaseNames())
             .build();
 
       } catch (Throwable t) {
@@ -547,41 +590,57 @@ public class CatalogServer extends AbstractService {
 
     @Override
     public TableResponse getTableDesc(RpcController controller,
-                                      TableIdentifierProto request) {
+                                      TableIdentifierProto request) throws 
ServiceException {
       String dbName = request.getDatabaseName();
       String tbName = request.getTableName();
 
-      rlock.lock();
       try {
+        if (linkedMetadataManager.existsDatabase(dbName)) {
+          return TableResponse.newBuilder()
+              .setState(OK)
+              .setTable(linkedMetadataManager.getTable(dbName, "", 
tbName).getProto())
+              .build();
+        }
+      } catch (Throwable t) {
+        printStackTraceIfError(LOG, t);
+        return TableResponse.newBuilder().setState(returnError(t)).build();
+      }
 
-        if (metaDictionary.isSystemDatabase(dbName)) {
-
+      if (metaDictionary.isSystemDatabase(dbName)) {
+        try {
           return TableResponse.newBuilder()
               .setState(OK)
               .setTable(metaDictionary.getTableDesc(tbName))
               .build();
+        } catch (UndefinedTableException e) {
+          return TableResponse.newBuilder()
+              .setState(errUndefinedTable(tbName))
+              .build();
+        }
+      }
 
-        } else {
-          boolean contain;
-          contain = store.existDatabase(dbName);
+      rlock.lock();
+      try {
+        boolean contain;
 
+        contain = store.existDatabase(dbName);
+
+        if (contain) {
+          contain = store.existTable(dbName, tbName);
           if (contain) {
-            contain = store.existTable(dbName, tbName);
-            if (contain) {
-              return TableResponse.newBuilder()
-                  .setState(OK)
-                  .setTable(store.getTable(dbName, tbName))
-                  .build();
-            } else {
-              return TableResponse.newBuilder()
-                  .setState(errUndefinedTable(tbName))
-                  .build();
-            }
+            return TableResponse.newBuilder()
+                .setState(OK)
+                .setTable(store.getTable(dbName, tbName))
+                .build();
           } else {
             return TableResponse.newBuilder()
-                .setState(errUndefinedDatabase(dbName))
+                .setState(errUndefinedTable(tbName))
                 .build();
           }
+        } else {
+          return TableResponse.newBuilder()
+              .setState(errUndefinedDatabase(dbName))
+              .build();
         }
 
       } catch (Throwable t) {
@@ -601,28 +660,35 @@ public class CatalogServer extends AbstractService {
 
       String dbName = request.getValue();
 
-      if (metaDictionary.isSystemDatabase(dbName)) {
+      try {
+        if (linkedMetadataManager.existsDatabase(dbName)) {
+          return returnStringList(linkedMetadataManager.getTableNames(dbName, 
null, null));
+        }
+      } catch (Throwable t) {
+        printStackTraceIfError(LOG, t);
+        return returnFailedStringList(t);
+      }
 
+      if (metaDictionary.isSystemDatabase(dbName)) {
         return returnStringList(metaDictionary.getAllSystemTables());
+      }
 
-      } else {
-        rlock.lock();
-        try {
-          if (store.existDatabase(dbName)) {
-            return returnStringList(store.getAllTableNames(dbName));
-          } else {
-            return StringListResponse.newBuilder()
-                .setState(errUndefinedDatabase(dbName))
-                .build();
-          }
+      rlock.lock();
+      try {
+        if (store.existDatabase(dbName)) {
+          return returnStringList(store.getAllTableNames(dbName));
+        } else {
+          return StringListResponse.newBuilder()
+              .setState(errUndefinedDatabase(dbName))
+              .build();
+        }
 
-        } catch (Throwable t) {
-          printStackTraceIfError(LOG, t);
-          return returnFailedStringList(t);
+      } catch (Throwable t) {
+        printStackTraceIfError(LOG, t);
+        return returnFailedStringList(t);
 
-        } finally {
-          rlock.unlock();
-        }
+      } finally {
+        rlock.unlock();
       }
     }
 
@@ -646,6 +712,10 @@ public class CatalogServer extends AbstractService {
       String dbName = splitted[0];
       String tbName = splitted[1];
 
+      if (linkedMetadataManager.existsDatabase(dbName)) {
+        return errInsufficientPrivilege("drop a table in database '" + dbName 
+ "'");
+      }
+
       if (metaDictionary.isSystemDatabase(dbName)) {
         return errInsufficientPrivilege("create a table in database '" + 
dbName + "'");
       }
@@ -683,7 +753,11 @@ public class CatalogServer extends AbstractService {
 
       String dbName = request.getDatabaseName();
       String tbName = request.getTableName();
-      
+
+      if (linkedMetadataManager.existsDatabase(dbName)) {
+        return errInsufficientPrivilege("drop a table in database '" + dbName 
+ "'");
+      }
+
       if (metaDictionary.isSystemDatabase(dbName)) {
         return errInsufficientPrivilege("drop a table in database '" + dbName 
+ "'");
       }
@@ -720,15 +794,19 @@ public class CatalogServer extends AbstractService {
       String dbName = request.getDatabaseName();
       String tbName = request.getTableName();
 
-      rlock.lock();
-      try {
+      if (linkedMetadataManager.existsDatabase(dbName)) {
+        return linkedMetadataManager.existsTable(dbName, "", tbName) ? OK : 
errUndefinedTable(tbName);
+      }
 
-        if (metaDictionary.isSystemDatabase(dbName)) {
-          return metaDictionary.existTable(tbName) ? OK : 
errUndefinedTable(tbName);
+      if (metaDictionary.isSystemDatabase(dbName)) {
+        return metaDictionary.existTable(tbName) ? OK : 
errUndefinedTable(tbName);
 
-        } else {
+      } else {
+        rlock.lock();
+        try {
 
           boolean contain = store.existDatabase(dbName);
+
           if (contain) {
             if (store.existTable(dbName, tbName)) {
               return OK;
@@ -738,14 +816,14 @@ public class CatalogServer extends AbstractService {
           } else {
             return errUndefinedDatabase(dbName);
           }
-        }
 
-      } catch (Throwable t) {
-        printStackTraceIfError(LOG, t);
-        return returnError(t);
+        } catch (Throwable t) {
+          printStackTraceIfError(LOG, t);
+          return returnError(t);
 
-      } finally {
-        rlock.unlock();
+        } finally {
+          rlock.unlock();
+        }
       }
     }
     
@@ -836,43 +914,55 @@ public class CatalogServer extends AbstractService {
     public GetPartitionMethodResponse 
getPartitionMethodByTableName(RpcController controller,
                                                               
TableIdentifierProto request)
         throws ServiceException {
-      String databaseName = request.getDatabaseName();
-      String tableName = request.getTableName();
+      String dbName = request.getDatabaseName();
+      String tbName = request.getTableName();
 
-      if (metaDictionary.isSystemDatabase(databaseName)) {
-        throw new ServiceException(databaseName + " is a system databsae. It 
does not contain any partitioned tables.");
+      try {
+        // linked meta data do not support partition.
+        // So, the request that wants to get partitions in this db will be 
failed.
+        if (linkedMetadataManager.existsDatabase(dbName)) {
+          return 
GetPartitionMethodResponse.newBuilder().setState(errUndefinedPartitionMethod(tbName))
+              .build();
+        }
+      } catch (Throwable t) {
+        printStackTraceIfError(LOG, t);
+        return 
GetPartitionMethodResponse.newBuilder().setState(returnError(t)).build();
+      }
+
+      if (metaDictionary.isSystemDatabase(dbName)) {
+        throw new ServiceException(dbName + " is a system databsae. It does 
not contain any partitioned tables.");
       }
       
       rlock.lock();
       try {
         boolean contain;
 
-        contain = store.existDatabase(databaseName);
+        contain = store.existDatabase(dbName);
 
         if (contain) {
-          contain = store.existTable(databaseName, tableName);
+          contain = store.existTable(dbName, tbName);
           if (contain) {
 
-            if (store.existPartitionMethod(databaseName, tableName)) {
+            if (store.existPartitionMethod(dbName, tbName)) {
 
               return GetPartitionMethodResponse.newBuilder()
                   .setState(OK)
-                  .setPartition(store.getPartitionMethod(databaseName, 
tableName))
+                  .setPartition(store.getPartitionMethod(dbName, tbName))
                   .build();
 
             } else {
               return GetPartitionMethodResponse.newBuilder()
-                  .setState(errUndefinedPartitionMethod(tableName))
+                  .setState(errUndefinedPartitionMethod(tbName))
                   .build();
             }
           } else {
             return GetPartitionMethodResponse.newBuilder()
-                .setState(errUndefinedTable(tableName))
+                .setState(errUndefinedTable(tbName))
                 .build();
           }
         } else {
           return GetPartitionMethodResponse.newBuilder()
-              .setState(errUndefinedDatabase(tableName))
+              .setState(errUndefinedDatabase(tbName))
               .build();
         }
 
@@ -889,10 +979,21 @@ public class CatalogServer extends AbstractService {
 
     @Override
     public ReturnState existPartitionMethod(RpcController controller, 
TableIdentifierProto request) {
-      String databaseName = request.getDatabaseName();
+      String dbName = request.getDatabaseName();
       String tableName = request.getTableName();
-      
-      if (metaDictionary.isSystemDatabase(databaseName)) {
+
+      try {
+        // linked meta data do not support partition.
+        // So, the request that wants to get partitions in this db will be 
failed.
+        if (linkedMetadataManager.existsDatabase(dbName)) {
+          return errUndefinedPartitionMethod(tableName);
+        }
+      } catch (Throwable t) {
+        printStackTraceIfError(LOG, t);
+        return returnError(t);
+      }
+
+      if (metaDictionary.isSystemDatabase(dbName)) {
         ReturnStateUtil.errFeatureNotSupported("partition feature in virtual 
tables");
       }
 
@@ -900,12 +1001,12 @@ public class CatalogServer extends AbstractService {
       try {
         boolean contain;
 
-        contain = store.existDatabase(databaseName);
+        contain = store.existDatabase(dbName);
 
         if (contain) {
-          contain = store.existTable(databaseName, tableName);
+          contain = store.existTable(dbName, tableName);
           if (contain) {
-            if (store.existPartitionMethod(databaseName, tableName)) {
+            if (store.existPartitionMethod(dbName, tableName)) {
               return OK;
             } else {
               return errUndefinedPartitionMethod(tableName);
@@ -914,7 +1015,7 @@ public class CatalogServer extends AbstractService {
             return errUndefinedTable(tableName);
           }
         } else {
-          return errUndefinedDatabase(databaseName);
+          return errUndefinedDatabase(dbName);
         }
       } catch (Throwable t) {
         printStackTraceIfError(LOG, t);
@@ -937,8 +1038,19 @@ public class CatalogServer extends AbstractService {
       String tbName = request.getTableName();
       String partitionName = request.getPartitionName();
 
+      try {
+        // linked meta data do not support partition.
+        // So, the request that wants to get partitions in this db will be 
failed.
+        if (linkedMetadataManager.existsDatabase(dbName)) {
+          return 
GetPartitionDescResponse.newBuilder().setState(errUndefinedPartitionMethod(tbName)).build();
+        }
+      } catch (Throwable t) {
+        printStackTraceIfError(LOG, t);
+        return 
GetPartitionDescResponse.newBuilder().setState(returnError(t)).build();
+      }
+
       if (metaDictionary.isSystemDatabase(dbName)) {
-        throw new ServiceException(dbName + " is a system databsae. It does 
not contain any partitioned tables.");
+        return 
GetPartitionDescResponse.newBuilder().setState(errUndefinedPartitionMethod(tbName)).build();
       }
 
       rlock.lock();
@@ -995,8 +1107,21 @@ public class CatalogServer extends AbstractService {
       String dbName = request.getDatabaseName();
       String tbName = request.getTableName();
 
+      try {
+        // linked meta data do not support partition.
+        // So, the request that wants to get partitions in this db will be 
failed.
+        if (linkedMetadataManager.existsDatabase(dbName)) {
+          return 
GetPartitionsResponse.newBuilder().setState(errUndefinedPartitionMethod(tbName)).build();
+        }
+      } catch (Throwable t) {
+        printStackTraceIfError(LOG, t);
+        return GetPartitionsResponse.newBuilder()
+            .setState(returnError(t))
+            .build();
+      }
+
       if (metaDictionary.isSystemDatabase(dbName)) {
-        throw new ServiceException(dbName + " is a system databsae. It does 
not contain any partitioned tables.");
+        return 
GetPartitionsResponse.newBuilder().setState(errUndefinedPartitionMethod(tbName)).build();
       }
 
       rlock.lock();
@@ -1107,7 +1232,17 @@ public class CatalogServer extends AbstractService {
     @Override
     public ReturnState createIndex(RpcController controller, IndexDescProto 
indexDesc) {
       String dbName = indexDesc.getTableIdentifier().getDatabaseName();
-      
+
+      try {
+        // linked meta data do not support index. The request will be failed.
+        if (linkedMetadataManager.existsDatabase(dbName)) {
+          return errInsufficientPrivilege("to create index in database '" + 
dbName + "'");
+        }
+      } catch (Throwable t) {
+        printStackTraceIfError(LOG, t);
+        return returnError(t);
+      }
+
       rlock.lock();
       try {
         if (store.existIndexByName(
@@ -1134,6 +1269,16 @@ public class CatalogServer extends AbstractService {
       String dbName = request.getDatabaseName();
       String indexName = request.getIndexName();
 
+      try {
+        // linked meta data do not support index. The request will be failed.
+        if (linkedMetadataManager.existsDatabase(dbName)) {
+          return errUndefinedIndexName(indexName);
+        }
+      } catch (Throwable t) {
+        printStackTraceIfError(LOG, t);
+        return returnError(t);
+      }
+
       rlock.lock();
       try {
 
@@ -1161,6 +1306,16 @@ public class CatalogServer extends AbstractService {
       String tableName = identifier.getTableName();
       List<String> columnNames = request.getColumnNamesList();
 
+      try {
+        // linked meta data do not support index. The request will be failed.
+        if (linkedMetadataManager.existsDatabase(databaseName)) {
+          return errUndefinedIndex(tableName);
+        }
+      } catch (Throwable t) {
+        printStackTraceIfError(LOG, t);
+        return returnError(t);
+      }
+
       rlock.lock();
       try {
 
@@ -1189,6 +1344,16 @@ public class CatalogServer extends AbstractService {
       String databaseName = request.getDatabaseName();
       String tableName = request.getTableName();
 
+      try {
+        // linked meta data do not support index. The request will be failed.
+        if (linkedMetadataManager.existsDatabase(databaseName)) {
+          return errUndefinedIndex(tableName);
+        }
+      } catch (Throwable t) {
+        printStackTraceIfError(LOG, t);
+        return returnError(t);
+      }
+
       rlock.lock();
       try {
 
@@ -1255,6 +1420,7 @@ public class CatalogServer extends AbstractService {
 
       rlock.lock();
       try {
+
         if (!store.existIndexByColumns(databaseName, tableName, columnNames)) {
           return IndexResponse.newBuilder()
               .setState(errUndefinedIndex(tableName, columnNamesList))
@@ -1278,11 +1444,23 @@ public class CatalogServer extends AbstractService {
     @Override
     public IndexListResponse getAllIndexesByTable(RpcController controller, 
TableIdentifierProto request)
         throws ServiceException {
-      String databaseName = request.getDatabaseName();
-      String tableName = request.getTableName();
+      final String databaseName = request.getDatabaseName();
+      final String tableName = request.getTableName();
+
+      try {
+        // linked meta data do not support index.
+        // So, the request that wants to check the index in this db will get 
empty list.
+        if (linkedMetadataManager.existsDatabase(databaseName)) {
+          return IndexListResponse.newBuilder().setState(OK).build();
+        }
+      } catch (Throwable t) {
+        printStackTraceIfError(LOG, t);
+        return IndexListResponse.newBuilder().setState(returnError(t)).build();
+      }
 
       rlock.lock();
       try {
+
         if (!store.existIndexesByTable(databaseName, tableName)) {
           return IndexListResponse.newBuilder()
               .setState(errUndefinedIndex(tableName))
@@ -1631,11 +1809,4 @@ public class CatalogServer extends AbstractService {
     }
 
   }
-
-  public static void main(String[] args) throws Exception {
-    TajoConf conf = new TajoConf();
-    CatalogServer catalog = new CatalogServer(new ArrayList<FunctionDesc>());
-    catalog.init(conf);
-    catalog.start();
-  }
 }

http://git-wip-us.apache.org/repos/asf/tajo/blob/f868c0e2/tajo-catalog/tajo-catalog-server/src/main/java/org/apache/tajo/catalog/LinkedMetadataManager.java
----------------------------------------------------------------------
diff --git 
a/tajo-catalog/tajo-catalog-server/src/main/java/org/apache/tajo/catalog/LinkedMetadataManager.java
 
b/tajo-catalog/tajo-catalog-server/src/main/java/org/apache/tajo/catalog/LinkedMetadataManager.java
new file mode 100644
index 0000000..080c984
--- /dev/null
+++ 
b/tajo-catalog/tajo-catalog-server/src/main/java/org/apache/tajo/catalog/LinkedMetadataManager.java
@@ -0,0 +1,241 @@
+/*
+ * 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.catalog;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import org.apache.tajo.catalog.exception.InsufficientPrivilegeException;
+import org.apache.tajo.catalog.exception.UndefinedDatabaseException;
+import org.apache.tajo.catalog.exception.UndefinedTablespaceException;
+import org.apache.tajo.util.Pair;
+
+import javax.annotation.Nullable;
+import java.net.URI;
+import java.util.Collection;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import static com.google.common.collect.Collections2.filter;
+
+/**
+ * Linked Meta Data Manager which manages all meta data providers and access 
methods for them.
+ */
+public class LinkedMetadataManager {
+  private ImmutableMap<String, MetadataProvider> providerMap;
+
+  /**
+   * Initialize Linked Metadata
+   *
+   * @param providers A collection of Metadata providers.
+   */
+  public LinkedMetadataManager(Collection<MetadataProvider> providers) {
+    Map<String, MetadataProvider> builder = Maps.newHashMap();
+
+    for (MetadataProvider p : providers) {
+      builder.put(p.getDatabaseName(), p);
+    }
+
+    this.providerMap = ImmutableMap.copyOf(builder);
+  }
+
+  /**
+   * Get all tablespace names
+   *
+   * @return A collection of tablespace names
+   */
+  public Collection<String> getTablespaceNames() {
+    ImmutableList.Builder<String> builder = ImmutableList.builder();
+    for (MetadataProvider p : providerMap.values()) {
+      builder.add(p.getTablespaceName());
+    }
+    return builder.build();
+  }
+
+  /**
+   * Get a tablespace by name.
+   *
+   * @param spaceName Tablespace name
+   * @return A pair where the first value is tablespace name and the second 
value is an URI.
+   */
+  public Optional<Pair<String, URI>> getTablespace(final String spaceName) {
+    Collection<MetadataProvider> filtered = filter(providerMap.values(),
+        new Predicate<MetadataProvider>() {
+          @Override
+          public boolean apply(@Nullable MetadataProvider input) {
+            return input.getTablespaceName().equals(spaceName);
+          }
+        });
+
+    if (filtered.isEmpty()) {
+      return Optional.absent();
+    } else {
+      MetadataProvider found = filtered.iterator().next();
+      return Optional.of(new Pair<String, URI>(found.getTablespaceName(), 
found.getTablespaceUri()));
+    }
+  }
+
+  /**
+   * Return all tablespaces.
+   *
+   * @return A list of pairs, each pair represents a tablespace, where the 
first value is tablespace name.
+   *         the second value is an URI.
+   */
+  public Collection<Pair<String, URI>> getTablespaces() {
+    ImmutableList.Builder<Pair<String, URI>> builder = ImmutableList.builder();
+    for (MetadataProvider p : providerMap.values()) {
+      builder.add(new Pair<String, URI>(p.getDatabaseName(), 
p.getTablespaceUri()));
+    }
+    return builder.build();
+  }
+
+  /**
+   * Return all database names
+   *
+   * @return A collection of database names
+   */
+  public Collection<String> getDatabases() {
+    return providerMap.keySet();
+  }
+
+  /**
+   * check if the database exists.
+   *
+   * @param dbName Database name
+   * @return True if the database exists. Otherwise, False.
+   */
+  public boolean existsDatabase(String dbName) {
+    return providerMap.containsKey(dbName);
+  }
+
+  /**
+   * check if the database exists. Otherwise, it throws an exception
+   *
+   * @param dbName Database name
+   * @throws UndefinedDatabaseException
+   */
+  private void ensureIfDBExists(String dbName) throws 
UndefinedDatabaseException {
+    if (!providerMap.containsKey(dbName)) {
+      throw new UndefinedDatabaseException(dbName);
+    }
+  }
+
+  /**
+   * Get schema names
+   *
+   * @param dbName Database name
+   * @return A list of schema names
+   * @throws UndefinedDatabaseException
+   */
+  public Collection<String> getSchemas(@Nullable String dbName) throws 
UndefinedDatabaseException {
+    ensureIfDBExists(dbName);
+
+    return providerMap.get(dbName).getCatalogs();
+  }
+
+  /**
+   * Get all table names matched to a given pattern
+   *
+   * @param dbName Database name
+   * @param schemaPattern a schema name pattern; must match the schema name
+   *        as it is stored in the database; "" retrieves tables without a 
schema;
+   *        <code>null</code> means that the schema name should not be used to 
narrow the search
+   * @param tablePattern a table name pattern: must match the table name as it 
is stored in the meta data provider;
+   *                     "" retrieves tables without a schema; 
<code>null</code> allows all schema names.
+   *
+   * @return
+   */
+  public Collection<String> getTableNames(String dbName,
+                                          @Nullable final String schemaPattern,
+                                          final String tablePattern) throws 
UndefinedDatabaseException {
+    ensureIfDBExists(dbName);
+
+    if (tablePattern == null) { // all tables in this database
+      return providerMap.get(dbName).getTables("null");
+
+    } else {
+      final Pattern pattern = Pattern.compile(tablePattern);
+      return filter(providerMap.get(dbName).getTables(schemaPattern), new 
Predicate<String>() {
+        @Override
+        public boolean apply(@Nullable String input) {
+          return pattern.matcher(tablePattern).matches();
+        }
+      });
+    }
+  }
+
+  /**
+   * Create a table
+   *
+   * @param desc table description
+   * @throws InsufficientPrivilegeException
+   */
+  public void createTable(TableDesc desc) throws 
InsufficientPrivilegeException {
+    // TODO - currently, meta data provider is read only.
+    throw new InsufficientPrivilegeException("create a table in external 
metadata store");
+  }
+
+  /**
+   * Drop table
+   *
+   * @param databaseName Database name
+   * @param schemaName a schema name; "" drops the table without a schema.
+   * @param tableName Table name
+   * @throws InsufficientPrivilegeException
+   */
+  public void dropTable(String databaseName, String schemaName, String 
tableName)
+      throws InsufficientPrivilegeException {
+    // TODO - currently, meta data provider is read only.
+    throw new InsufficientPrivilegeException("drop any table in external 
metadata store");
+  }
+
+  /**
+   * Check if the table exists
+   *
+   * @param dbName Database name
+   * @param schemaName a schema name; "" checks the table without a schema.
+   * @param tableName a table name
+   * @return True if the table exists. Otherwise, False
+   */
+  public boolean existsTable(String dbName, String schemaName, String 
tableName) {
+    if (providerMap.containsKey(dbName)) {
+      return providerMap.get(dbName).getTables(schemaName).contains(tableName);
+    }
+
+    return false;
+  }
+
+  /**
+   * Get Table description
+   *
+   * @param dbName Database name
+   * @param schemaName a schema name; "" checks the table without a schema.
+   * @param tbName Table name
+   * @return Table description
+   */
+  public TableDesc getTable(String dbName, String schemaName, String tbName)
+      throws UndefinedDatabaseException, UndefinedTablespaceException {
+
+    ensureIfDBExists(dbName);
+
+    return providerMap.get(dbName).getTableDescriptor(schemaName, tbName);
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/f868c0e2/tajo-catalog/tajo-catalog-server/src/main/java/org/apache/tajo/catalog/dictionary/InfoSchemaMetadataDictionary.java
----------------------------------------------------------------------
diff --git 
a/tajo-catalog/tajo-catalog-server/src/main/java/org/apache/tajo/catalog/dictionary/InfoSchemaMetadataDictionary.java
 
b/tajo-catalog/tajo-catalog-server/src/main/java/org/apache/tajo/catalog/dictionary/InfoSchemaMetadataDictionary.java
index b59d61c..2fde0e2 100644
--- 
a/tajo-catalog/tajo-catalog-server/src/main/java/org/apache/tajo/catalog/dictionary/InfoSchemaMetadataDictionary.java
+++ 
b/tajo-catalog/tajo-catalog-server/src/main/java/org/apache/tajo/catalog/dictionary/InfoSchemaMetadataDictionary.java
@@ -125,8 +125,12 @@ public class InfoSchemaMetadataDictionary {
     return tableDescriptor.getTableDescription();
   }
   
-  public boolean existTable(String tableName) throws UndefinedTableException {
-    return getTableDescriptor(tableName) != null;
+  public boolean existTable(String tableName) {
+    try {
+      return getTableDescriptor(tableName) != null;
+    } catch (UndefinedTableException e) {
+      return false;
+    }
   }
   
   protected String getTablePath() {

http://git-wip-us.apache.org/repos/asf/tajo/blob/f868c0e2/tajo-catalog/tajo-catalog-server/src/test/java/org/apache/tajo/catalog/TestCatalog.java
----------------------------------------------------------------------
diff --git 
a/tajo-catalog/tajo-catalog-server/src/test/java/org/apache/tajo/catalog/TestCatalog.java
 
b/tajo-catalog/tajo-catalog-server/src/test/java/org/apache/tajo/catalog/TestCatalog.java
index caa85e8..e2a096a 100644
--- 
a/tajo-catalog/tajo-catalog-server/src/test/java/org/apache/tajo/catalog/TestCatalog.java
+++ 
b/tajo-catalog/tajo-catalog-server/src/test/java/org/apache/tajo/catalog/TestCatalog.java
@@ -64,8 +64,7 @@ public class TestCatalog {
        static CatalogServer server;
        static CatalogService catalog;
 
-       @BeforeClass
-       public static void setUp() throws Exception {
+  public static TajoConf newTajoConfForCatalogTest() throws IOException {
     final String HIVE_CATALOG_CLASS_NAME = 
"org.apache.tajo.catalog.store.HiveCatalogStore";
 
     String driverClass = System.getProperty(CatalogConstants.STORE_CLASS);
@@ -98,10 +97,17 @@ public class TestCatalog {
       }
     }
 
+    return conf;
+  }
+
+       @BeforeClass
+       public static void setUp() throws Exception {
+
+
     Path defaultTableSpace = CommonTestingUtil.getTestDir();
 
          server = new CatalogServer();
-    server.init(conf);
+    server.init(newTajoConfForCatalogTest());
     server.start();
     catalog = new LocalCatalogWrapper(server);
     if (!catalog.existTablespace(TajoConstants.DEFAULT_TABLESPACE_NAME)) {

http://git-wip-us.apache.org/repos/asf/tajo/blob/f868c0e2/tajo-catalog/tajo-catalog-server/src/test/java/org/apache/tajo/catalog/TestLinkedMetadataManager.java
----------------------------------------------------------------------
diff --git 
a/tajo-catalog/tajo-catalog-server/src/test/java/org/apache/tajo/catalog/TestLinkedMetadataManager.java
 
b/tajo-catalog/tajo-catalog-server/src/test/java/org/apache/tajo/catalog/TestLinkedMetadataManager.java
new file mode 100644
index 0000000..4ddf7ab
--- /dev/null
+++ 
b/tajo-catalog/tajo-catalog-server/src/test/java/org/apache/tajo/catalog/TestLinkedMetadataManager.java
@@ -0,0 +1,271 @@
+/*
+ * 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.catalog;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import org.apache.hadoop.fs.Path;
+import org.apache.tajo.TajoConstants;
+import org.apache.tajo.catalog.exception.UndefinedTablespaceException;
+import org.apache.tajo.catalog.proto.CatalogProtos;
+import org.apache.tajo.common.TajoDataTypes.Type;
+import org.apache.tajo.conf.TajoConf;
+import org.apache.tajo.error.Errors;
+import org.apache.tajo.exception.TajoInternalError;
+import org.apache.tajo.util.CommonTestingUtil;
+import org.apache.tajo.util.KeyValueSet;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import javax.annotation.Nullable;
+import java.io.IOException;
+import java.net.URI;
+import java.util.Collection;
+import java.util.Collections;
+
+import static org.apache.tajo.TajoConstants.DEFAULT_DATABASE_NAME;
+import static org.junit.Assert.*;
+
+public class TestLinkedMetadataManager {
+
+  static TableDesc TABLE1 = new TableDesc(
+      "table1",
+      new Schema(new Column[]{new Column("c1", Type.INT8)}),
+      "TEXT", new KeyValueSet(), URI.create("http://space1/x/table1";)
+  );
+
+  static TableDesc TABLE2 = new TableDesc(
+      "table2",
+          new Schema(new Column[]{new Column("c1", Type.INT8)}),
+      "TEXT", new KeyValueSet(), URI.create("http://space1/x/table2";)
+  );
+
+  static TableDesc TABLE3 = new TableDesc(
+      "table3",
+      new Schema(new Column[]{new Column("c1", Type.INT8)}),
+      "TEXT", new KeyValueSet(), URI.create("http://space1/x/table3";)
+  );
+
+  static TableDesc TABLE4 = new TableDesc(
+      "table4",
+          new Schema(new Column[]{new Column("c1", Type.INT8)}),
+      "TEXT", new KeyValueSet(), URI.create("http://space1/x/table4";)
+  );
+
+  static class MockupMetadataProvider1 implements MetadataProvider {
+
+    @Override
+    public String getTablespaceName() {
+      return "space1";
+    }
+
+    @Override
+    public URI getTablespaceUri() {
+      return URI.create("http://space1/x";);
+    }
+
+    @Override
+    public String getDatabaseName() {
+      return "space1";
+    }
+
+    @Override
+    public Collection<String> getCatalogs() {
+      return Lists.newArrayList("cat1", "cat2");
+    }
+
+    @Override
+    public Collection<String> getTables(@Nullable String catalog) {
+      return Lists.newArrayList("table1", "table2");
+    }
+
+    @Override
+    public TableDesc getTableDescriptor(String catalogName, String tableName) 
throws UndefinedTablespaceException {
+      if (tableName.equals("table1")) {
+        return TABLE1;
+      } else if (tableName.equals("table2")) {
+        return TABLE2;
+      }
+
+      throw new UndefinedTablespaceException(tableName);
+    }
+  }
+
+  static class MockupMetadataProvider2 implements MetadataProvider {
+
+    @Override
+    public String getTablespaceName() {
+      return "space2";
+    }
+
+    @Override
+    public URI getTablespaceUri() {
+      return URI.create("http://space2/y";);
+    }
+
+    @Override
+    public String getDatabaseName() {
+      return "space2";
+    }
+
+    @Override
+    public Collection<String> getCatalogs() {
+      return Lists.newArrayList("cat3", "cat4");
+    }
+
+    @Override
+    public Collection<String> getTables(@Nullable String catalog) {
+      return Lists.newArrayList("table3", "table4");
+    }
+
+    @Override
+    public TableDesc getTableDescriptor(String catalogName, String tableName) 
throws UndefinedTablespaceException {
+      if (tableName.equals("table3")) {
+        return TABLE3;
+      } else if (tableName.equals("table4")) {
+        return TABLE4;
+      }
+
+      throw new UndefinedTablespaceException(tableName);
+    }
+  }
+
+  static CatalogServer server;
+  static CatalogService catalog;
+
+  @BeforeClass
+  public static void setUp() throws IOException {
+    TajoConf conf = new TajoConf();
+    conf.setVar(TajoConf.ConfVars.CATALOG_ADDRESS, "127.0.0.1:0");
+
+    server = new CatalogServer(
+        Sets.newHashSet(new MockupMetadataProvider1(), new 
MockupMetadataProvider2()), Collections.EMPTY_LIST);
+    server.init(TestCatalog.newTajoConfForCatalogTest());
+    server.start();
+    catalog = new LocalCatalogWrapper(server);
+
+    Path defaultTableSpace = CommonTestingUtil.getTestDir();
+
+    if (!catalog.existTablespace(TajoConstants.DEFAULT_TABLESPACE_NAME)) {
+      catalog.createTablespace(TajoConstants.DEFAULT_TABLESPACE_NAME, 
defaultTableSpace.toUri().toString());
+    }
+    if (!catalog.existDatabase(DEFAULT_DATABASE_NAME)) {
+      catalog.createDatabase(DEFAULT_DATABASE_NAME, 
TajoConstants.DEFAULT_TABLESPACE_NAME);
+    }
+  }
+
+  @AfterClass
+  public static void tearDown() throws IOException {
+    server.stop();
+  }
+
+  @Test
+  public void testGetTablespaceNames() throws Exception {
+    assertEquals(Sets.newHashSet("space1", "space2", "default"), 
Sets.newHashSet(catalog.getAllTablespaceNames()));
+  }
+
+  @Test
+  public void testGetTablespace() throws Exception {
+    CatalogProtos.TablespaceProto space1 = catalog.getTablespace("space1");
+    assertEquals("space1", space1.getSpaceName());
+    assertEquals("http://space1/x";, space1.getUri());
+
+    CatalogProtos.TablespaceProto space2 = catalog.getTablespace("space2");
+    assertEquals("space2", space2.getSpaceName());
+    assertEquals("http://space2/y";, space2.getUri());
+  }
+
+  @Test
+  public void testGetTablespaces() throws Exception {
+    Collection<String> names = 
Collections2.transform(catalog.getAllTablespaces(),
+        new Function<CatalogProtos.TablespaceProto, String>() {
+      @Override
+      public String apply(@Nullable CatalogProtos.TablespaceProto input) {
+        return input.getSpaceName();
+      }
+    });
+
+    assertEquals(Sets.newHashSet("space1", "space2", "default"), 
Sets.newHashSet(names));
+  }
+
+  @Test
+  public void testGetDatabases() throws Exception {
+    assertEquals(Sets.newHashSet("space1", "space2", "default", 
"information_schema"),
+        Sets.newHashSet(catalog.getAllDatabaseNames()));
+  }
+
+  @Test
+  public void testExistsDatabase() throws Exception {
+    assertTrue(catalog.existDatabase("space1"));
+    assertTrue(catalog.existDatabase("space2"));
+    assertTrue(catalog.existDatabase("default"));
+
+    assertFalse(catalog.existDatabase("unknown"));
+  }
+
+  @Test
+  public void testGetTableNames() throws Exception {
+    assertEquals(Sets.newHashSet("table1", "table2"), 
Sets.newHashSet(catalog.getAllTableNames("space1")));
+  }
+
+  @Test
+  public void testCreateTable() throws Exception {
+    TableDesc tb = new TableDesc(
+        "space1.errortable",
+        new Schema(),
+        new TableMeta("x", new KeyValueSet()),
+        URI.create("file:///"));
+
+    try {
+      catalog.createTable(tb);
+      fail();
+    } catch (TajoInternalError e) {
+      assertEquals(Errors.ResultCode.INTERNAL_ERROR, e.getErrorCode());
+    }
+  }
+
+  @Test
+  public void testDropTable() throws Exception {
+    try {
+      catalog.dropTable("space1.table1");
+      fail();
+    } catch (TajoInternalError e) {
+      assertEquals(Errors.ResultCode.INTERNAL_ERROR, e.getErrorCode());
+    }
+  }
+
+  @Test
+  public void testExistsTable() throws Exception {
+    assertTrue(catalog.existsTable("space1", "table1"));
+    assertTrue(catalog.existsTable("space1", "table2"));
+    assertTrue(catalog.existsTable("space2", "table3"));
+    assertTrue(catalog.existsTable("space2", "table4"));
+  }
+
+  @Test
+  public void testGetTable() throws Exception {
+    assertEquals(TABLE1, catalog.getTableDesc("space1", "table1"));
+    assertEquals(TABLE2, catalog.getTableDesc("space1", "table2"));
+    assertEquals(TABLE3, catalog.getTableDesc("space2", "table3"));
+    assertEquals(TABLE4, catalog.getTableDesc("space2", "table4"));
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/f868c0e2/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 d16f7d1..27aabfc 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
@@ -72,6 +72,7 @@ import java.lang.management.ThreadInfo;
 import java.lang.management.ThreadMXBean;
 import java.net.InetSocketAddress;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Map;
 
 import static org.apache.tajo.TajoConstants.DEFAULT_DATABASE_NAME;
@@ -179,7 +180,7 @@ public class TajoMaster extends CompositeService {
       checkAndInitializeSystemDirectories();
       diagnoseTajoMaster();
 
-    catalogServer = new CatalogServer(loadFunctions());
+    catalogServer = new CatalogServer(Collections.EMPTY_SET, loadFunctions());
     addIfService(catalogServer);
     catalog = new LocalCatalogWrapper(catalogServer, systemConf);
 

Reply via email to