http://git-wip-us.apache.org/repos/asf/zeppelin/blob/3eea57ab/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/java/org/apache/zeppelin/notebook/repo/zeppelinhub/ZeppelinHubRepo.java
----------------------------------------------------------------------
diff --git 
a/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/java/org/apache/zeppelin/notebook/repo/zeppelinhub/ZeppelinHubRepo.java
 
b/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/java/org/apache/zeppelin/notebook/repo/zeppelinhub/ZeppelinHubRepo.java
new file mode 100644
index 0000000..9dd9fbf
--- /dev/null
+++ 
b/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/java/org/apache/zeppelin/notebook/repo/zeppelinhub/ZeppelinHubRepo.java
@@ -0,0 +1,385 @@
+/*
+ * 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.zeppelin.notebook.repo.zeppelinhub;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.zeppelin.conf.ZeppelinConfiguration;
+import org.apache.zeppelin.notebook.Note;
+import org.apache.zeppelin.notebook.NoteInfo;
+import org.apache.zeppelin.notebook.repo.NotebookRepoWithVersionControl;
+import org.apache.zeppelin.notebook.repo.NotebookRepoSettingsInfo;
+import org.apache.zeppelin.notebook.repo.zeppelinhub.model.Instance;
+import org.apache.zeppelin.notebook.repo.zeppelinhub.model.UserTokenContainer;
+import 
org.apache.zeppelin.notebook.repo.zeppelinhub.model.UserSessionContainer;
+import 
org.apache.zeppelin.notebook.repo.zeppelinhub.rest.ZeppelinhubRestApiHandler;
+import org.apache.zeppelin.notebook.repo.zeppelinhub.websocket.Client;
+import 
org.apache.zeppelin.notebook.repo.zeppelinhub.websocket.utils.ZeppelinhubUtils;
+import org.apache.zeppelin.user.AuthenticationInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+
+/**
+ * ZeppelinHub repo class.
+ */
+public class ZeppelinHubRepo implements NotebookRepoWithVersionControl {
+  private static final Logger LOG = 
LoggerFactory.getLogger(ZeppelinHubRepo.class);
+  private static final String DEFAULT_SERVER = "https://www.zeppelinhub.com";;
+  static final String ZEPPELIN_CONF_PROP_NAME_SERVER = 
"zeppelinhub.api.address";
+  static final String ZEPPELIN_CONF_PROP_NAME_TOKEN = "zeppelinhub.api.token";
+
+  private static final Gson GSON = new Gson();
+  private static final Note EMPTY_NOTE = new Note();
+  private Client websocketClient;
+  private UserTokenContainer tokenManager;
+
+  private String token;
+  private ZeppelinhubRestApiHandler restApiClient;
+  
+  private ZeppelinConfiguration conf;
+
+  public ZeppelinHubRepo() {
+
+  }
+
+  public ZeppelinHubRepo(ZeppelinConfiguration conf) {
+    this();
+    init(conf);
+  }
+
+  public void init(ZeppelinConfiguration conf) {
+    this.conf = conf;
+    String zeppelinHubUrl = getZeppelinHubUrl(conf);
+    LOG.info("Initializing ZeppelinHub integration module");
+
+    token = conf.getString("ZEPPELINHUB_API_TOKEN", 
ZEPPELIN_CONF_PROP_NAME_TOKEN, "");
+    restApiClient = ZeppelinhubRestApiHandler.newInstance(zeppelinHubUrl);
+    //TODO(khalid): check which realm for authentication, pass to token manager
+    tokenManager = UserTokenContainer.init(restApiClient, token);
+
+    websocketClient = Client.initialize(getZeppelinWebsocketUri(conf),
+        getZeppelinhubWebsocketUri(conf), token, conf);
+    websocketClient.start();
+  }
+
+  private String getZeppelinHubWsUri(URI api) throws URISyntaxException {
+    URI apiRoot = api;
+    String scheme = apiRoot.getScheme();
+    int port = apiRoot.getPort();
+    if (port <= 0) {
+      port = (scheme != null && scheme.equals("https")) ? 443 : 80;
+    }
+
+    if (scheme == null) {
+      LOG.info("{} is not a valid zeppelinhub server address. proceed with 
default address {}",
+          apiRoot, DEFAULT_SERVER);
+      apiRoot = new URI(DEFAULT_SERVER);
+      scheme = apiRoot.getScheme();
+      port = apiRoot.getPort();
+      if (port <= 0) {
+        port = (scheme != null && scheme.equals("https")) ? 443 : 80;
+      }
+    }
+    String ws = scheme.equals("https") ? "wss://" : "ws://";
+    return ws + apiRoot.getHost() + ":" + port + "/async";
+  }
+
+  String getZeppelinhubWebsocketUri(ZeppelinConfiguration conf) {
+    String zeppelinHubUri = StringUtils.EMPTY;
+    try {
+      zeppelinHubUri = getZeppelinHubWsUri(new 
URI(conf.getString("ZEPPELINHUB_API_ADDRESS",
+          ZEPPELIN_CONF_PROP_NAME_SERVER, DEFAULT_SERVER)));
+    } catch (URISyntaxException e) {
+      LOG.error("Cannot get ZeppelinHub URI", e);
+    }
+    return zeppelinHubUri;
+  }
+
+  private String getZeppelinWebsocketUri(ZeppelinConfiguration conf) {
+    int port = conf.getServerPort();
+    if (port <= 0) {
+      port = 80;
+    }
+    String ws = conf.useSsl() ? "wss" : "ws";
+    return ws + "://localhost:" + port + "/ws";
+  }
+
+  // Used in tests
+  void setZeppelinhubRestApiHandler(ZeppelinhubRestApiHandler zeppelinhub) {
+    restApiClient = zeppelinhub;
+  }
+
+  String getZeppelinHubUrl(ZeppelinConfiguration conf) {
+    if (conf == null) {
+      LOG.error("Invalid configuration, cannot be null. Using default address 
{}", DEFAULT_SERVER);
+      return DEFAULT_SERVER;
+    }
+    URI apiRoot;
+    String zeppelinhubUrl;
+    try {
+      String url = conf.getString("ZEPPELINHUB_API_ADDRESS",
+                                  ZEPPELIN_CONF_PROP_NAME_SERVER,
+                                  DEFAULT_SERVER);
+      apiRoot = new URI(url);
+    } catch (URISyntaxException e) {
+      LOG.error("Invalid zeppelinhub url, using default address {}", 
DEFAULT_SERVER, e);
+      return DEFAULT_SERVER;
+    }
+
+    String scheme = apiRoot.getScheme();
+    if (scheme == null) {
+      LOG.info("{} is not a valid zeppelinhub server address. proceed with 
default address {}",
+               apiRoot, DEFAULT_SERVER);
+      zeppelinhubUrl = DEFAULT_SERVER;
+    } else {
+      zeppelinhubUrl = scheme + "://" + apiRoot.getHost();
+      if (apiRoot.getPort() > 0) {
+        zeppelinhubUrl += ":" + apiRoot.getPort();
+      }
+    }
+    return zeppelinhubUrl;
+  }
+
+  private boolean isSubjectValid(AuthenticationInfo subject) {
+    if (subject == null) {
+      return false;
+    }
+    return (subject.isAnonymous() && !conf.isAnonymousAllowed()) ? false : 
true;
+  }
+  
+  @Override
+  public List<NoteInfo> list(AuthenticationInfo subject) throws IOException {
+    if (!isSubjectValid(subject)) {
+      return Collections.emptyList();
+    }
+    String token = getUserToken(subject.getUser());
+    String response = restApiClient.get(token, StringUtils.EMPTY);
+    List<NoteInfo> notes = GSON.fromJson(response, new 
TypeToken<List<NoteInfo>>() {}.getType());
+    if (notes == null) {
+      return Collections.emptyList();
+    }
+    LOG.info("ZeppelinHub REST API listing notes ");
+    return notes;
+  }
+
+  @Override
+  public Note get(String noteId, AuthenticationInfo subject) throws 
IOException {
+    if (StringUtils.isBlank(noteId) || !isSubjectValid(subject)) {
+      return EMPTY_NOTE;
+    }
+    String token = getUserToken(subject.getUser());
+    String response = restApiClient.get(token, noteId);
+    Note note = Note.fromJson(response);
+    if (note == null) {
+      return EMPTY_NOTE;
+    }
+    LOG.info("ZeppelinHub REST API get note {} ", noteId);
+    return note;
+  }
+
+  @Override
+  public void save(Note note, AuthenticationInfo subject) throws IOException {
+    if (note == null || !isSubjectValid(subject)) {
+      throw new IOException("Zeppelinhub failed to save note");
+    }
+    String jsonNote = note.toJson();
+    String token = getUserToken(subject.getUser());
+    LOG.info("ZeppelinHub REST API saving note {} ", note.getId());
+    restApiClient.put(token, jsonNote);
+  }
+
+  @Override
+  public void remove(String noteId, AuthenticationInfo subject) throws 
IOException {
+    if (StringUtils.isBlank(noteId) || !isSubjectValid(subject)) {
+      throw new IOException("Zeppelinhub failed to remove note");
+    }
+    String token = getUserToken(subject.getUser());
+    LOG.info("ZeppelinHub REST API removing note {} ", noteId);
+    restApiClient.del(token, noteId);
+  }
+
+  @Override
+  public void close() {
+    websocketClient.stop();
+    restApiClient.close();
+  }
+
+  @Override
+  public Revision checkpoint(String noteId, String checkpointMsg, 
AuthenticationInfo subject)
+      throws IOException {
+    if (StringUtils.isBlank(noteId) || !isSubjectValid(subject)) {
+      return Revision.EMPTY;
+    }
+    String endpoint = Joiner.on("/").join(noteId, "checkpoint");
+    String content = GSON.toJson(ImmutableMap.of("message", checkpointMsg));
+    
+    String token = getUserToken(subject.getUser());
+    String response = restApiClient.putWithResponseBody(token, endpoint, 
content);
+
+    return GSON.fromJson(response, Revision.class);
+  }
+
+  @Override
+  public Note get(String noteId, String revId, AuthenticationInfo subject) 
throws IOException {
+    if (StringUtils.isBlank(noteId) || StringUtils.isBlank(revId) || 
!isSubjectValid(subject)) {
+      return EMPTY_NOTE;
+    }
+    String endpoint = Joiner.on("/").join(noteId, "checkpoint", revId);
+    String token = getUserToken(subject.getUser());
+    String response = restApiClient.get(token, endpoint);
+
+    Note note = Note.fromJson(response);
+    if (note == null) {
+      return EMPTY_NOTE;
+    }
+    LOG.info("ZeppelinHub REST API get note {} revision {}", noteId, revId);
+    return note;
+  }
+
+  @Override
+  public List<Revision> revisionHistory(String noteId, AuthenticationInfo 
subject) {
+    if (StringUtils.isBlank(noteId) || !isSubjectValid(subject)) {
+      return Collections.emptyList();
+    }
+    String endpoint = Joiner.on("/").join(noteId, "checkpoint");
+    List<Revision> history = Collections.emptyList();
+    try {
+      String token = getUserToken(subject.getUser());
+      String response = restApiClient.get(token, endpoint);
+      history = GSON.fromJson(response, new 
TypeToken<List<Revision>>(){}.getType());
+    } catch (IOException e) {
+      LOG.error("Cannot get note history", e);
+    }
+    return history;
+  }
+  
+  private String getUserToken(String user) {
+    return tokenManager.getUserToken(user);
+  }
+
+  @Override
+  public List<NotebookRepoSettingsInfo> getSettings(AuthenticationInfo 
subject) {
+    if (!isSubjectValid(subject)) {
+      return Collections.emptyList();
+    }
+
+    List<NotebookRepoSettingsInfo> settings = Lists.newArrayList();
+    String user = subject.getUser();
+    String zeppelinHubUserSession = 
UserSessionContainer.instance.getSession(user);
+    String userToken = getUserToken(user);
+    List<Instance> instances;
+    List<Map<String, String>> values = Lists.newLinkedList();
+
+    try {
+      instances = tokenManager.getUserInstances(zeppelinHubUserSession);
+    } catch (IOException e) {
+      LOG.warn("Couldnt find instances for the session {}, returning empty 
collection",
+          zeppelinHubUserSession);
+      // user not logged
+      //TODO(xxx): handle this case.
+      instances = Collections.emptyList();
+    }
+    
+    NotebookRepoSettingsInfo repoSetting = 
NotebookRepoSettingsInfo.newInstance();
+    repoSetting.type = NotebookRepoSettingsInfo.Type.DROPDOWN;
+    for (Instance instance : instances) {
+      if (instance.token.equals(userToken)) {
+        repoSetting.selected = Integer.toString(instance.id);
+      }
+      values.add(ImmutableMap.of("name", instance.name, "value", 
Integer.toString(instance.id)));
+    }
+
+    repoSetting.value = values;
+    repoSetting.name = "Instance";
+    settings.add(repoSetting);
+    return settings;
+  }
+
+  private void changeToken(int instanceId, String user) {
+    if (instanceId <= 0) {
+      LOG.error("User {} tried to switch to a non valid instance {}", user, 
instanceId);
+      return;
+    }
+
+    LOG.info("User {} will switch instance", user);
+    String ticket = UserSessionContainer.instance.getSession(user);
+    List<Instance> instances;
+    String currentToken = StringUtils.EMPTY, targetToken = StringUtils.EMPTY;
+    try {
+      instances = tokenManager.getUserInstances(ticket);
+      if (instances.isEmpty()) {
+        return;
+      }
+      currentToken = tokenManager.getExistingUserToken(user);
+      for (Instance instance : instances) {
+        if (instance.id == instanceId) {
+          LOG.info("User {} switched to instance {}", user, instance.name);
+          tokenManager.setUserToken(user, instance.token);
+          targetToken = instance.token;
+          break;
+        }
+      }
+      if (!StringUtils.isBlank(currentToken) && 
!StringUtils.isBlank(targetToken)) {
+        ZeppelinhubUtils.userSwitchTokenRoutine(user, currentToken, 
targetToken);
+      }
+    } catch (IOException e) {
+      LOG.error("Cannot switch instance for user {}", user, e);
+    }
+  }
+
+  @Override
+  public void updateSettings(Map<String, String> settings, AuthenticationInfo 
subject) {
+    if (!isSubjectValid(subject)) {
+      LOG.error("Invalid subject, cannot update Zeppelinhub settings");
+      return;
+    }
+    if (settings == null || settings.isEmpty()) {
+      LOG.error("Cannot update ZeppelinHub repo settings because of invalid 
settings");
+      return;
+    }
+
+    int instanceId = 0;
+    if (settings.containsKey("Instance")) {
+      try {
+        instanceId = Integer.parseInt(settings.get("Instance"));
+      } catch (NumberFormatException e) {
+        LOG.error("ZeppelinHub Instance Id in not a valid integer", e);
+      }
+    }
+    changeToken(instanceId, subject.getUser());
+  }
+
+  @Override
+  public Note setNoteRevision(String noteId, String revId, AuthenticationInfo 
subject)
+      throws IOException {
+    // Auto-generated method stub
+    return null;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/3eea57ab/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/resources/META-INF/services/org.apache.zeppelin.notebook.repo.NotebookRepo
----------------------------------------------------------------------
diff --git 
a/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/resources/META-INF/services/org.apache.zeppelin.notebook.repo.NotebookRepo
 
b/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/resources/META-INF/services/org.apache.zeppelin.notebook.repo.NotebookRepo
new file mode 100644
index 0000000..395d1cd
--- /dev/null
+++ 
b/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/resources/META-INF/services/org.apache.zeppelin.notebook.repo.NotebookRepo
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+org.apache.zeppelin.notebook.repo.zeppelinhub.ZeppelinHubRepo
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/3eea57ab/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/test/org/apache/zeppelin/notebook/repo/zeppelinhub/ZeppelinHubRepoTest.java
----------------------------------------------------------------------
diff --git 
a/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/test/org/apache/zeppelin/notebook/repo/zeppelinhub/ZeppelinHubRepoTest.java
 
b/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/test/org/apache/zeppelin/notebook/repo/zeppelinhub/ZeppelinHubRepoTest.java
new file mode 100644
index 0000000..2fa6d41
--- /dev/null
+++ 
b/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/test/org/apache/zeppelin/notebook/repo/zeppelinhub/ZeppelinHubRepoTest.java
@@ -0,0 +1,155 @@
+package org.apache.zeppelin.notebook.repo.zeppelinhub;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.commons.httpclient.HttpException;
+import org.apache.zeppelin.conf.ZeppelinConfiguration;
+import org.apache.zeppelin.notebook.Note;
+import org.apache.zeppelin.notebook.NoteInfo;
+import 
org.apache.zeppelin.notebook.repo.zeppelinhub.rest.ZeppelinhubRestApiHandler;
+import org.apache.zeppelin.user.AuthenticationInfo;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.io.Files;
+
+
+public class ZeppelinHubRepoTest {
+  final String token = "AAA-BBB-CCC-00";
+  final String testAddr = "http://zeppelinhub.ltd";;
+  final AuthenticationInfo auth = new AuthenticationInfo("anthony");
+
+  private ZeppelinHubRepo repo;
+  private File pathOfNotebooks = new File(System.getProperty("user.dir") + 
"/src/test/resources/list_of_notes");
+  private File pathOfNotebook = new File(System.getProperty("user.dir") + 
"/src/test/resources/note");
+
+  @Before
+  public void setUp() throws Exception {
+    System.setProperty(ZeppelinHubRepo.ZEPPELIN_CONF_PROP_NAME_SERVER, 
testAddr);
+    System.setProperty(ZeppelinHubRepo.ZEPPELIN_CONF_PROP_NAME_TOKEN, token);
+
+    ZeppelinConfiguration conf = new ZeppelinConfiguration();
+    repo = new ZeppelinHubRepo();
+    repo.init(conf);
+    repo.setZeppelinhubRestApiHandler(getMockedZeppelinHandler());
+  }
+
+  private ZeppelinhubRestApiHandler getMockedZeppelinHandler() throws 
HttpException, IOException {
+    ZeppelinhubRestApiHandler mockedZeppelinhubHandler = 
mock(ZeppelinhubRestApiHandler.class);
+
+    byte[] listOfNotesResponse = Files.toByteArray(pathOfNotebooks);
+    when(mockedZeppelinhubHandler.get("AAA-BBB-CCC-00", ""))
+      .thenReturn(new String(listOfNotesResponse));
+
+    byte[] noteResponse =  Files.toByteArray(pathOfNotebook);
+    when(mockedZeppelinhubHandler.get("AAA-BBB-CCC-00", "AAAAA"))
+      .thenReturn(new String(noteResponse));
+
+    return mockedZeppelinhubHandler;
+  }
+
+  @Test
+  public void testGetZeppelinhubUrl() {
+    System.setProperty(ZeppelinHubRepo.ZEPPELIN_CONF_PROP_NAME_SERVER, 
testAddr);
+    
+    ZeppelinConfiguration config = new ZeppelinConfiguration();
+    ZeppelinHubRepo repository = new ZeppelinHubRepo(config);
+    
assertThat(repository.getZeppelinHubUrl(config)).isEqualTo("http://zeppelinhub.ltd";);
+
+    System.setProperty(ZeppelinHubRepo.ZEPPELIN_CONF_PROP_NAME_SERVER, 
"yolow");
+
+    config = new ZeppelinConfiguration();
+    repository = new ZeppelinHubRepo(config);
+    
assertThat(repository.getZeppelinHubUrl(config)).isEqualTo("https://www.zeppelinhub.com";);
+    
+    System.setProperty(ZeppelinHubRepo.ZEPPELIN_CONF_PROP_NAME_SERVER, 
"http://zeppelinhub.ltd:4242";);
+
+    config = new ZeppelinConfiguration();
+    repository = new ZeppelinHubRepo(config);
+    
assertThat(repository.getZeppelinHubUrl(config)).isEqualTo("http://zeppelinhub.ltd:4242";);
+    
+    System.setProperty(ZeppelinHubRepo.ZEPPELIN_CONF_PROP_NAME_SERVER, 
"http://zeppelinhub.ltd:0";);
+
+    config = new ZeppelinConfiguration();
+    repository = new ZeppelinHubRepo(config);
+    
assertThat(repository.getZeppelinHubUrl(config)).isEqualTo("http://zeppelinhub.ltd";);
+  }
+
+  @Test
+  public void testGetZeppelinHubWsEndpoint() {
+    System.setProperty(ZeppelinHubRepo.ZEPPELIN_CONF_PROP_NAME_SERVER, 
testAddr);
+
+    ZeppelinConfiguration config = new ZeppelinConfiguration();
+    ZeppelinHubRepo repository = new ZeppelinHubRepo(config);
+    
assertThat(repository.getZeppelinhubWebsocketUri(config)).isEqualTo("ws://zeppelinhub.ltd:80/async");
+
+    System.setProperty(ZeppelinHubRepo.ZEPPELIN_CONF_PROP_NAME_SERVER, 
"https://zeppelinhub.ltd";);
+
+    config = new ZeppelinConfiguration();
+    repository = new ZeppelinHubRepo(config);
+    
assertThat(repository.getZeppelinhubWebsocketUri(config)).isEqualTo("wss://zeppelinhub.ltd:443/async");
+
+    System.setProperty(ZeppelinHubRepo.ZEPPELIN_CONF_PROP_NAME_SERVER, 
"yolow");
+
+    config = new ZeppelinConfiguration();
+    repository = new ZeppelinHubRepo(config);
+    
assertThat(repository.getZeppelinhubWebsocketUri(config)).isEqualTo("wss://www.zeppelinhub.com:443/async");
+
+    System.setProperty(ZeppelinHubRepo.ZEPPELIN_CONF_PROP_NAME_SERVER, 
"http://zeppelinhub.ltd:4242";);
+
+    config = new ZeppelinConfiguration();
+    repository = new ZeppelinHubRepo(config);
+    
assertThat(repository.getZeppelinhubWebsocketUri(config)).isEqualTo("ws://zeppelinhub.ltd:4242/async");
+
+    System.setProperty(ZeppelinHubRepo.ZEPPELIN_CONF_PROP_NAME_SERVER, 
"https://www.zeppelinhub.com";);
+
+    config = new ZeppelinConfiguration();
+    repository = new ZeppelinHubRepo(config);
+    
assertThat(repository.getZeppelinhubWebsocketUri(config)).isEqualTo("wss://www.zeppelinhub.com:443/async");
+
+    System.setProperty(ZeppelinHubRepo.ZEPPELIN_CONF_PROP_NAME_SERVER, 
"http://www.zeppelinhub.com";);
+
+    config = new ZeppelinConfiguration();
+    repository = new ZeppelinHubRepo(config);
+    
assertThat(repository.getZeppelinhubWebsocketUri(config)).isEqualTo("ws://www.zeppelinhub.com:80/async");
+
+    System.setProperty(ZeppelinHubRepo.ZEPPELIN_CONF_PROP_NAME_SERVER, 
"https://www.zeppelinhub.com:4242";);
+
+    config = new ZeppelinConfiguration();
+    repository = new ZeppelinHubRepo(config);
+    
assertThat(repository.getZeppelinhubWebsocketUri(config)).isEqualTo("wss://www.zeppelinhub.com:4242/async");
+  }
+
+  @Test
+  public void testGetAllNotes() throws IOException {
+    List<NoteInfo> notebooks = repo.list(auth);
+    assertThat(notebooks).isNotEmpty();
+    assertThat(notebooks.size()).isEqualTo(3);
+  }
+  
+  @Test
+  public void testGetNote() throws IOException {
+    Note notebook = repo.get("AAAAA", auth);
+    assertThat(notebook).isNotNull();
+    assertThat(notebook.getId()).isEqualTo("2A94M5J1Z");
+  }
+  
+  @Test
+  public void testRemoveNote() throws IOException {
+    // not suppose to throw
+    repo.remove("AAAAA", auth);
+  }
+  
+  @Test
+  public void testRemoveNoteError() throws IOException {
+    // not suppose to throw
+    repo.remove("BBBBB", auth);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/3eea57ab/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/test/org/apache/zeppelin/notebook/repo/zeppelinhub/websocket/ZeppelinClientTest.java
----------------------------------------------------------------------
diff --git 
a/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/test/org/apache/zeppelin/notebook/repo/zeppelinhub/websocket/ZeppelinClientTest.java
 
b/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/test/org/apache/zeppelin/notebook/repo/zeppelinhub/websocket/ZeppelinClientTest.java
new file mode 100644
index 0000000..b8e52e4
--- /dev/null
+++ 
b/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/test/org/apache/zeppelin/notebook/repo/zeppelinhub/websocket/ZeppelinClientTest.java
@@ -0,0 +1,127 @@
+package org.apache.zeppelin.notebook.repo.zeppelinhub.websocket;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import 
org.apache.zeppelin.notebook.repo.zeppelinhub.websocket.mock.MockEchoWebsocketServer;
+import org.apache.zeppelin.notebook.socket.Message;
+import org.apache.zeppelin.notebook.socket.Message.OP;
+import org.eclipse.jetty.websocket.api.Session;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Maps;
+
+public class ZeppelinClientTest {
+  private Logger LOG = LoggerFactory.getLogger(ZeppelinClientTest.class);
+  private final int zeppelinPort = 8080;
+  private final String validWebsocketUrl = "ws://localhost:" + zeppelinPort + 
"/ws";
+  private ExecutorService executor;
+  private MockEchoWebsocketServer echoServer;
+
+  @Before
+  public void setUp() throws Exception {
+    startWebsocketServer();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    //tear down routine
+    echoServer.stop();
+    executor.shutdown();
+  }
+
+  private void startWebsocketServer() throws InterruptedException {
+    // mock zeppelin websocket server setup
+    executor = Executors.newFixedThreadPool(1);
+    echoServer = new MockEchoWebsocketServer(zeppelinPort);
+    executor.submit(echoServer);
+  }
+
+  @Test
+  public void zeppelinConnectionTest() {
+    try {
+      // Wait for websocket server to start
+      Thread.sleep(2000);
+    } catch (InterruptedException e) {
+      LOG.warn("Cannot wait for websocket server to start, returning");
+      return;
+    }
+    // Initialize and start Zeppelin client
+    ZeppelinClient client = ZeppelinClient.initialize(validWebsocketUrl, 
"dummy token", null);
+    client.start();
+    LOG.info("Zeppelin websocket client started");
+
+    // Connection to note AAAA
+    Session connectionA = client.getZeppelinConnection("AAAA", "anonymous", 
"anonymous");
+    assertNotNull(connectionA);
+    assertTrue(connectionA.isOpen());
+
+    assertEquals(client.countConnectedNotes(), 1);
+    assertEquals(connectionA, client.getZeppelinConnection("AAAA", 
"anonymous", "anonymous"));
+
+    // Connection to note BBBB
+    Session connectionB = client.getZeppelinConnection("BBBB", "anonymous", 
"anonymous");
+    assertNotNull(connectionB);
+    assertTrue(connectionB.isOpen());
+
+    assertEquals(client.countConnectedNotes(), 2);
+    assertEquals(connectionB, client.getZeppelinConnection("BBBB", 
"anonymous", "anonymous"));
+
+    // Remove connection to note AAAA
+    client.removeNoteConnection("AAAA");
+    assertEquals(client.countConnectedNotes(), 1);
+    assertNotEquals(connectionA, client.getZeppelinConnection("AAAA", 
"anonymous", "anonymous"));
+    assertEquals(client.countConnectedNotes(), 2);
+    client.stop();
+  }
+
+  @Test
+  public void zeppelinClientSingletonTest() {
+    ZeppelinClient client1 = ZeppelinClient.getInstance();
+    if (client1 == null) {
+      client1 = ZeppelinClient.initialize(validWebsocketUrl, "TOKEN", null);
+    }
+    assertNotNull(client1);
+    ZeppelinClient client2 = ZeppelinClient.getInstance();
+    assertNotNull(client2);
+    assertEquals(client1, client2);
+  }
+
+  @Test
+  public void zeppelinMessageSerializationTest() {
+    Message msg = new Message(OP.LIST_NOTES);
+    msg.data = Maps.newHashMap();
+    msg.data.put("key", "value");
+    ZeppelinClient client = ZeppelinClient.initialize(validWebsocketUrl, 
"TOKEN", null);
+    String serializedMsg = client.serialize(msg);
+    Message deserializedMsg = client.deserialize(serializedMsg);
+    assertEquals(msg.op, deserializedMsg.op);
+    assertEquals(msg.data.get("key"), deserializedMsg.data.get("key"));
+    
+    String invalidMsg = "random text";
+    deserializedMsg =client.deserialize(invalidMsg);
+    assertNull(deserializedMsg);
+  }
+
+  @Test
+  public void sendToZeppelinTest() {
+    ZeppelinClient client = ZeppelinClient.initialize(validWebsocketUrl, 
"TOKEN", null);
+    client.start();
+    Message msg = new Message(OP.LIST_NOTES);
+    msg.data = Maps.newHashMap();
+    msg.data.put("key", "value");
+    client.send(msg, "DDDD");
+    client.removeNoteConnection("DDDD");
+    client.stop();
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/3eea57ab/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/test/org/apache/zeppelin/notebook/repo/zeppelinhub/websocket/ZeppelinhubClientTest.java
----------------------------------------------------------------------
diff --git 
a/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/test/org/apache/zeppelin/notebook/repo/zeppelinhub/websocket/ZeppelinhubClientTest.java
 
b/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/test/org/apache/zeppelin/notebook/repo/zeppelinhub/websocket/ZeppelinhubClientTest.java
new file mode 100644
index 0000000..384cfe4
--- /dev/null
+++ 
b/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/test/org/apache/zeppelin/notebook/repo/zeppelinhub/websocket/ZeppelinhubClientTest.java
@@ -0,0 +1,72 @@
+package org.apache.zeppelin.notebook.repo.zeppelinhub.websocket;
+
+import static org.junit.Assert.*;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import 
org.apache.zeppelin.notebook.repo.zeppelinhub.websocket.ZeppelinhubClient;
+import 
org.apache.zeppelin.notebook.repo.zeppelinhub.websocket.mock.MockEchoWebsocketServer;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ZeppelinhubClientTest {
+  private Logger LOG = LoggerFactory.getLogger(ZeppelinClientTest.class);
+  private final int zeppelinPort = 8090;
+  private final String validWebsocketUrl = "ws://localhost:" + zeppelinPort + 
"/ws";
+  private ExecutorService executor;
+  private MockEchoWebsocketServer echoServer;
+  private final String runNotebookMsg =
+      "{\"op\":\"RUN_NOTEBOOK\"," +
+      
"\"data\":[{\"id\":\"20150112-172845_1301897143\",\"title\":null,\"config\":{},\"params\":{},\"data\":null},"
 +
+      
"{\"id\":\"20150112-172845_1301897143\",\"title\":null,\"config\":{},\"params\":{},\"data\":null}],"
 +
+      
"\"meta\":{\"owner\":\"author\",\"instance\":\"my-zepp\",\"noteId\":\"2AB7SY361\"}}";
+  private final String invalidRunNotebookMsg = "some random string";
+
+  @Before
+  public void setUp() throws Exception {
+    startWebsocketServer();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    //tear down routine
+    echoServer.stop();
+    executor.shutdown();
+  }
+
+  private void startWebsocketServer() throws InterruptedException {
+    // mock zeppelin websocket server setup
+    executor = Executors.newFixedThreadPool(1);
+    echoServer = new MockEchoWebsocketServer(zeppelinPort);
+    executor.submit(echoServer);
+  }
+
+  @Test
+  public void zeppelinhubClientSingletonTest() {
+    ZeppelinhubClient client1 = ZeppelinhubClient.getInstance();
+    if (client1 == null) {
+      client1 = ZeppelinhubClient.initialize(validWebsocketUrl, "TOKEN");
+    } 
+    assertNotNull(client1);
+    ZeppelinhubClient client2 = ZeppelinhubClient.getInstance();
+    assertNotNull(client2);
+    assertEquals(client1, client2);
+  }
+
+  @Test
+  public void runAllParagraphTest() throws Exception {
+    Client.initialize(validWebsocketUrl, validWebsocketUrl, "TOKEN", null);
+    Client.getInstance().start();
+    ZeppelinhubClient zeppelinhubClient = ZeppelinhubClient.getInstance();
+    boolean runStatus = zeppelinhubClient.runAllParagraph("2AB7SY361", 
runNotebookMsg);
+    assertTrue(runStatus);
+    runStatus = zeppelinhubClient.runAllParagraph("2AB7SY361", 
invalidRunNotebookMsg);
+    assertFalse(runStatus);
+    Client.getInstance().stop();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/3eea57ab/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/test/org/apache/zeppelin/notebook/repo/zeppelinhub/websocket/mock/MockEchoWebsocketServer.java
----------------------------------------------------------------------
diff --git 
a/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/test/org/apache/zeppelin/notebook/repo/zeppelinhub/websocket/mock/MockEchoWebsocketServer.java
 
b/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/test/org/apache/zeppelin/notebook/repo/zeppelinhub/websocket/mock/MockEchoWebsocketServer.java
new file mode 100644
index 0000000..e9959e9
--- /dev/null
+++ 
b/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/test/org/apache/zeppelin/notebook/repo/zeppelinhub/websocket/mock/MockEchoWebsocketServer.java
@@ -0,0 +1,46 @@
+package org.apache.zeppelin.notebook.repo.zeppelinhub.websocket.mock;
+
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.slf4j.LoggerFactory;
+
+public class MockEchoWebsocketServer implements Runnable {
+  private static final org.slf4j.Logger LOG = 
LoggerFactory.getLogger(MockEchoWebsocketServer.class);
+  private Server server;
+
+  public MockEchoWebsocketServer(int port) {
+    server = new Server();
+    ServerConnector connector = new ServerConnector(server);
+    connector.setPort(port);
+    server.addConnector(connector);
+
+    ServletContextHandler context = new 
ServletContextHandler(ServletContextHandler.SESSIONS);
+    context.setContextPath("/");
+    server.setHandler(context);
+
+    //ServletHolder holderEvents = new ServletHolder("ws-events", 
MockEventServlet.class);
+    context.addServlet(MockEventServlet.class, "/ws/*");
+  }
+
+  public void start() throws Exception {
+    LOG.info("Starting mock echo websocket server");
+    server.start();
+    server.join();
+  }
+
+  public void stop() throws Exception {
+    LOG.info("Stopping mock echo websocket server");
+    server.stop();
+  }
+
+  @Override
+  public void run() {
+    try {
+      this.start();
+    } catch (Exception e) {
+      LOG.error("Couldn't start mock echo websocket server", e);
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/3eea57ab/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/test/org/apache/zeppelin/notebook/repo/zeppelinhub/websocket/mock/MockEventServlet.java
----------------------------------------------------------------------
diff --git 
a/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/test/org/apache/zeppelin/notebook/repo/zeppelinhub/websocket/mock/MockEventServlet.java
 
b/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/test/org/apache/zeppelin/notebook/repo/zeppelinhub/websocket/mock/MockEventServlet.java
new file mode 100644
index 0000000..c84f2c3
--- /dev/null
+++ 
b/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/test/org/apache/zeppelin/notebook/repo/zeppelinhub/websocket/mock/MockEventServlet.java
@@ -0,0 +1,14 @@
+package org.apache.zeppelin.notebook.repo.zeppelinhub.websocket.mock;
+
+import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
+import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
+
+@SuppressWarnings("serial")
+public class MockEventServlet extends WebSocketServlet
+{
+    @Override
+    public void configure(WebSocketServletFactory factory)
+    {
+        factory.register(MockEventSocket.class);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/3eea57ab/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/test/org/apache/zeppelin/notebook/repo/zeppelinhub/websocket/mock/MockEventSocket.java
----------------------------------------------------------------------
diff --git 
a/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/test/org/apache/zeppelin/notebook/repo/zeppelinhub/websocket/mock/MockEventSocket.java
 
b/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/test/org/apache/zeppelin/notebook/repo/zeppelinhub/websocket/mock/MockEventSocket.java
new file mode 100644
index 0000000..0f39b01
--- /dev/null
+++ 
b/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/test/org/apache/zeppelin/notebook/repo/zeppelinhub/websocket/mock/MockEventSocket.java
@@ -0,0 +1,38 @@
+package org.apache.zeppelin.notebook.repo.zeppelinhub.websocket.mock;
+
+import org.eclipse.jetty.websocket.api.Session;
+import org.eclipse.jetty.websocket.api.WebSocketAdapter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MockEventSocket extends WebSocketAdapter {
+  private static final Logger LOG = 
LoggerFactory.getLogger(MockEventServlet.class);
+  private Session session;
+
+  @Override
+  public void onWebSocketConnect(Session session) {
+    super.onWebSocketConnect(session);
+    this.session = session;
+    LOG.info("Socket Connected: " + session);
+  }
+
+  @Override
+  public void onWebSocketText(String message) {
+    super.onWebSocketText(message);
+    session.getRemote().sendStringByFuture(message);
+    LOG.info("Received TEXT message: {}", message);
+    
+  }
+
+  @Override
+  public void onWebSocketClose(int statusCode, String reason) {
+    super.onWebSocketClose(statusCode, reason);
+    LOG.info("Socket Closed: [{}] {}", statusCode, reason);
+  }
+
+  @Override
+  public void onWebSocketError(Throwable cause) {
+    super.onWebSocketError(cause);
+    LOG.error("Websocket error: {}", cause);
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/3eea57ab/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/test/org/apache/zeppelin/notebook/repo/zeppelinhub/websocket/protocol/ZeppelinhubMessageTest.java
----------------------------------------------------------------------
diff --git 
a/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/test/org/apache/zeppelin/notebook/repo/zeppelinhub/websocket/protocol/ZeppelinhubMessageTest.java
 
b/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/test/org/apache/zeppelin/notebook/repo/zeppelinhub/websocket/protocol/ZeppelinhubMessageTest.java
new file mode 100644
index 0000000..1f07f4f
--- /dev/null
+++ 
b/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/test/org/apache/zeppelin/notebook/repo/zeppelinhub/websocket/protocol/ZeppelinhubMessageTest.java
@@ -0,0 +1,43 @@
+package org.apache.zeppelin.notebook.repo.zeppelinhub.websocket.protocol;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Map;
+
+import org.apache.zeppelin.notebook.socket.Message.OP;
+import org.junit.Test;
+
+import com.google.common.collect.Maps;
+
+public class ZeppelinhubMessageTest {
+  
+  private String msg = "{\"op\":\"LIST_NOTES\",\"data\":\"my 
data\",\"meta\":{\"key1\":\"val1\"}}";
+
+  @Test
+  public void testThatCanSerializeZeppelinHubMessage() {
+    Map<String,String> meta = Maps.newHashMap();
+    meta.put("key1", "val1");
+    String zeppelinHubMsg = ZeppelinhubMessage.newMessage(OP.LIST_NOTES, "my 
data", meta).toJson();
+
+    assertEquals(msg, zeppelinHubMsg);
+  }
+  
+  @Test
+  public void testThastCanDeserialiseZeppelinhubMessage() {
+    Map<String,String> meta = Maps.newHashMap();
+    meta.put("key1", "val1");
+    ZeppelinhubMessage expected = 
ZeppelinhubMessage.newMessage(OP.LIST_NOTES.toString(), "my data", meta);
+    ZeppelinhubMessage zeppelinHubMsg = ZeppelinhubMessage.fromJson(msg);
+
+    assertEquals(expected.op, zeppelinHubMsg.op);
+    assertEquals(expected.data, zeppelinHubMsg.data);
+    assertEquals(expected.meta, zeppelinHubMsg.meta);
+  }
+  
+  @Test
+  public void testThatInvalidStringReturnEmptyZeppelinhubMessage() {
+    assertEquals(ZeppelinhubMessage.EMPTY, ZeppelinhubMessage.fromJson(""));
+    assertEquals(ZeppelinhubMessage.EMPTY, 
ZeppelinhubMessage.fromJson("dwfewewrewr"));
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/3eea57ab/zeppelin-plugins/pom.xml
----------------------------------------------------------------------
diff --git a/zeppelin-plugins/pom.xml b/zeppelin-plugins/pom.xml
new file mode 100644
index 0000000..f436411
--- /dev/null
+++ b/zeppelin-plugins/pom.xml
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="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
+  ~
+  ~    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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <artifactId>zeppelin</artifactId>
+        <groupId>org.apache.zeppelin</groupId>
+        <version>0.9.0-SNAPSHOT</version>
+        <relativePath>..</relativePath>
+    </parent>
+
+    <groupId>org.apache.zeppelin</groupId>
+    <artifactId>zengine-plugins-parent</artifactId>
+    <packaging>pom</packaging>
+    <version>0.9.0-SNAPSHOT</version>
+    <name>Zeppelin: Plugins Parent</name>
+    <description>Zeppelin Plugins Parent</description>
+
+    <modules>
+        <module>notebookrepo/s3</module>
+        <module>notebookrepo/vfs</module>
+        <module>notebookrepo/git</module>
+        <module>notebookrepo/github</module>
+        <module>notebookrepo/azure</module>
+        <module>notebookrepo/gcs</module>
+        <module>notebookrepo/mongodb</module>
+        <module>notebookrepo/zeppelin-hub</module>
+        <module>notebookrepo/filesystem</module>
+    </modules>
+
+    <dependencies>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>zeppelin-zengine</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.fasterxml.jackson.core</groupId>
+                    <artifactId>jackson-core</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <!-- Test libraries -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>copy-plugin-dependencies</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>copy-dependencies</goal>
+                        </goals>
+                        <configuration>
+                            
<outputDirectory>${project.build.directory}/../../../../plugins/${plugin.name}</outputDirectory>
+                            <overWriteReleases>false</overWriteReleases>
+                            <overWriteSnapshots>false</overWriteSnapshots>
+                            <overWriteIfNewer>true</overWriteIfNewer>
+                            <includeScope>runtime</includeScope>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>copy-plugin-artifact</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>copy</goal>
+                        </goals>
+                        <configuration>
+                            
<outputDirectory>${project.build.directory}/../../../../plugins/${plugin.name}</outputDirectory>
+                            <overWriteReleases>false</overWriteReleases>
+                            <overWriteSnapshots>false</overWriteSnapshots>
+                            <overWriteIfNewer>true</overWriteIfNewer>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>${project.groupId}</groupId>
+                                    
<artifactId>${project.artifactId}</artifactId>
+                                    <version>${project.version}</version>
+                                    <type>${project.packaging}</type>
+                                </artifactItem>
+                            </artifactItems>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+
+        </plugins>
+    </build>
+</project>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/3eea57ab/zeppelin-server/pom.xml
----------------------------------------------------------------------
diff --git a/zeppelin-server/pom.xml b/zeppelin-server/pom.xml
index 3ee83bd..fc6d0dd 100644
--- a/zeppelin-server/pom.xml
+++ b/zeppelin-server/pom.xml
@@ -420,42 +420,6 @@
 
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-antrun-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>start-zeppelin</id>
-            <phase>pre-integration-test</phase>
-            <configuration>
-              <target unless="skipTests">
-                <exec executable="./zeppelin-daemon.sh" 
dir="${zeppelin.daemon.package.base}" spawn="true">
-                  <arg value="start" />
-                </exec>
-              </target>
-            </configuration>
-            <goals>
-              <goal>run</goal>
-            </goals>
-          </execution>
-
-          <execution>
-            <id>stop-zeppelin</id>
-            <phase>post-integration-test</phase>
-            <configuration>
-              <target unless="skipTests">
-                <exec executable="./zeppelin-daemon.sh" 
dir="${zeppelin.daemon.package.base}" spawn="false">
-                  <arg value="stop" />
-                </exec>
-              </target>
-            </configuration>
-            <goals>
-              <goal>run</goal>
-            </goals>
-          </execution>
-        </executions>
-      </plugin>
-
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-dependency-plugin</artifactId>
       </plugin>
 

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/3eea57ab/zeppelin-server/src/main/java/org/apache/zeppelin/realm/PamRealm.java
----------------------------------------------------------------------
diff --git 
a/zeppelin-server/src/main/java/org/apache/zeppelin/realm/PamRealm.java 
b/zeppelin-server/src/main/java/org/apache/zeppelin/realm/PamRealm.java
index 5b3ae10..d7f62ec 100644
--- a/zeppelin-server/src/main/java/org/apache/zeppelin/realm/PamRealm.java
+++ b/zeppelin-server/src/main/java/org/apache/zeppelin/realm/PamRealm.java
@@ -43,7 +43,7 @@ import java.util.Set;
  */
 public class PamRealm extends AuthorizingRealm {
 
-  private static final Logger LOG = 
LoggerFactory.getLogger(ZeppelinHubRealm.class);
+  private static final Logger LOG = LoggerFactory.getLogger(PamRealm.class);
 
   private String service;
 

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/3eea57ab/zeppelin-server/src/main/java/org/apache/zeppelin/realm/ZeppelinHubRealm.java
----------------------------------------------------------------------
diff --git 
a/zeppelin-server/src/main/java/org/apache/zeppelin/realm/ZeppelinHubRealm.java 
b/zeppelin-server/src/main/java/org/apache/zeppelin/realm/ZeppelinHubRealm.java
index 113469f..1d6cdf9 100644
--- 
a/zeppelin-server/src/main/java/org/apache/zeppelin/realm/ZeppelinHubRealm.java
+++ 
b/zeppelin-server/src/main/java/org/apache/zeppelin/realm/ZeppelinHubRealm.java
@@ -88,23 +88,23 @@ public class ZeppelinHubRealm extends AuthorizingRealm {
     LOG.debug("{} successfully login via ZeppelinHub", user.login);
     return new SimpleAuthenticationInfo(user.login, token.getPassword(), name);
   }
-  
+
   @Override
   protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection 
principals) {
     // TODO(xxx): future work will be done here.
     return null;
   }
-  
+
   protected void onInit() {
     super.onInit();
   }
-  
+
   /**
    * Setter of ZeppelinHub URL, this will be called by Shiro based on 
zeppelinhubUrl property
    * in shiro.ini file.</p>
-   * It will also perform a check of ZeppelinHub url {@link 
#isZeppelinHubUrlValid}, 
+   * It will also perform a check of ZeppelinHub url {@link 
#isZeppelinHubUrlValid},
    * if the url is not valid, the default zeppelinhub url will be used.
-   * 
+   *
    * @param url
    */
   public void setZeppelinhubUrl(String url) {
@@ -118,9 +118,9 @@ public class ZeppelinHubRealm extends AuthorizingRealm {
   }
 
   /**
-   * Send to ZeppelinHub a login request based on the request body which is a 
JSON that contains 2 
+   * Send to ZeppelinHub a login request based on the request body which is a 
JSON that contains 2
    * fields "login" and "password".
-   * 
+   *
    * @param requestBody JSON string of ZeppelinHub payload.
    * @return Account object with login, name (if set in ZeppelinHub), and mail.
    * @throws AuthenticationException if fail to login.
@@ -141,12 +141,12 @@ public class ZeppelinHubRealm extends AuthorizingRealm {
       responseBody = put.getResponseBodyAsString();
       userSession = put.getResponseHeader(USER_SESSION_HEADER).getValue();
       put.releaseConnection();
-      
+
     } catch (IOException e) {
       LOG.error("Cannot login user", e);
       throw new AuthenticationException(e.getMessage());
     }
-    
+
     User account = null;
     try {
       account = User.fromJson(responseBody);
@@ -156,7 +156,7 @@ public class ZeppelinHubRealm extends AuthorizingRealm {
     }
 
     onLoginSuccess(account.login, userSession);
-    
+
     return account;
   }
 
@@ -182,7 +182,7 @@ public class ZeppelinHubRealm extends AuthorizingRealm {
    * Perform a Simple URL check by using <code>URI(url).toURL()</code>.
    * If the url is not valid, the try-catch condition will catch the 
exceptions and return false,
    * otherwise true will be returned.
-   * 
+   *
    * @param url
    * @return
    */
@@ -215,7 +215,7 @@ public class ZeppelinHubRealm extends AuthorizingRealm {
       return gson.fromJson(json, User.class);
     }
   }
-  
+
   public void onLoginSuccess(String username, String session) {
     UserSessionContainer.instance.setSession(username, session);
 
@@ -227,7 +227,7 @@ public class ZeppelinHubRealm extends AuthorizingRealm {
 
     ZeppelinhubUtils.userLoginRoutine(username);
   }
-  
+
   @Override
   public void onLogout(PrincipalCollection principals) {
     ZeppelinhubUtils.userLogoutRoutine((String) 
principals.getPrimaryPrincipal());

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/3eea57ab/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java
----------------------------------------------------------------------
diff --git 
a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java 
b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java
index b8f9be9..85fc631 100644
--- 
a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java
+++ 
b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java
@@ -30,7 +30,6 @@ import java.util.regex.Pattern;
 import javax.servlet.http.HttpServletRequest;
 
 import org.apache.commons.lang.StringUtils;
-import org.apache.commons.vfs2.FileSystemException;
 import org.apache.zeppelin.conf.ZeppelinConfiguration;
 import org.apache.zeppelin.conf.ZeppelinConfiguration.ConfVars;
 import org.apache.zeppelin.display.*;
@@ -1052,7 +1051,7 @@ public class NotebookServer extends WebSocketServlet
       note.persist(subject);
       addConnectionToNote(note.getId(), (NotebookSocket) conn);
       conn.send(serializeMessage(new Message(OP.NEW_NOTE).put("note", note)));
-    } catch (FileSystemException e) {
+    } catch (IOException e) {
       LOG.error("Exception from createNote", e);
       conn.send(serializeMessage(new Message(OP.ERROR_INFO).put("info",
           "Oops! There is something wrong with the notebook file system. "
@@ -1840,7 +1839,7 @@ public class NotebookServer extends WebSocketServlet
     try {
       note.persist(p.getAuthenticationInfo());
       return true;
-    } catch (FileSystemException ex) {
+    } catch (IOException ex) {
       LOG.error("Exception from run", ex);
       conn.send(serializeMessage(new Message(OP.ERROR_INFO).put("info",
           "Oops! There is something wrong with the notebook file system. "

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/3eea57ab/zeppelin-server/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/test/resources/log4j.properties 
b/zeppelin-server/src/test/resources/log4j.properties
index aff3b79..ce9bc50 100644
--- a/zeppelin-server/src/test/resources/log4j.properties
+++ b/zeppelin-server/src/test/resources/log4j.properties
@@ -41,5 +41,4 @@ log4j.logger.DataNucleus.Datastore=ERROR
 
 # Log all JDBC parameters
 log4j.logger.org.hibernate.type=ALL
-
-log4j.logger.org.apache.hadoop=WARN
+log4j.logger.org.apache.hadoop=WARN
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/3eea57ab/zeppelin-zengine/pom.xml
----------------------------------------------------------------------
diff --git a/zeppelin-zengine/pom.xml b/zeppelin-zengine/pom.xml
index a7d9d5f..d37f6ea 100644
--- a/zeppelin-zengine/pom.xml
+++ b/zeppelin-zengine/pom.xml
@@ -38,18 +38,13 @@
     <!--library versions-->
     <hadoop.version>2.7.3</hadoop.version>
     <commons.lang3.version>3.4</commons.lang3.version>
-    <commons.vfs2.version>2.0</commons.vfs2.version>
-    <gcs.storage.version>1.14.0</gcs.storage.version>
-    <aws.sdk.s3.version>1.10.62</aws.sdk.s3.version>
-    <adl.sdk.version>2.1.4</adl.sdk.version>
     <jackrabbit.webdav.version>1.5.2</jackrabbit.webdav.version>
     <quartz.scheduler.version>2.2.1</quartz.scheduler.version>
     <lucene.version>5.3.1</lucene.version>
     <org.reflections.version>0.9.8</org.reflections.version>
     <xml.apis.version>1.4.01</xml.apis.version>
-    <eclipse.jgit.version>4.5.4.201711221230-r</eclipse.jgit.version>
     <frontend.maven.plugin.version>1.3</frontend.maven.plugin.version>
-
+    <aws.sdk.s3.version>1.10.62</aws.sdk.s3.version>
     <!--test library versions-->
     <google.truth.version>0.27</google.truth.version>
     <google.testing.nio.version>0.32.0-alpha</google.testing.nio.version>
@@ -83,15 +78,8 @@
     </dependency>
 
     <dependency>
-      <groupId>org.apache.commons</groupId>
-      <artifactId>commons-vfs2</artifactId>
-      <version>${commons.vfs2.version}</version>
-      <exclusions>
-        <exclusion>
-          <groupId>org.codehaus.plexus</groupId>
-          <artifactId>plexus-utils</artifactId>
-        </exclusion>
-      </exclusions>
+      <groupId>joda-time</groupId>
+      <artifactId>joda-time</artifactId>
     </dependency>
 
     <dependency>
@@ -117,86 +105,6 @@
     </dependency>
 
     <dependency>
-      <groupId>com.google.cloud</groupId>
-      <artifactId>google-cloud-storage</artifactId>
-      <version>${gcs.storage.version}</version>
-      <exclusions>
-        <exclusion>
-          <groupId>com.google.code.findbugs</groupId>
-          <artifactId>jsr305</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>com.google.protobuf</groupId>
-          <artifactId>protobuf-java</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>com.google.guava</groupId>
-          <artifactId>guava</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>com.google.api</groupId>
-          <artifactId>api-common</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>com.google.http-client</groupId>
-          <artifactId>google-http-client-jackson2</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>com.google.http-client</groupId>
-          <artifactId>google-http-client</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>org.codehaus.jackson</groupId>
-          <artifactId>jackson-core-asl</artifactId>
-        </exclusion>
-      </exclusions>
-    </dependency>
-
-    <dependency>
-      <groupId>com.google.api</groupId>
-      <artifactId>api-common</artifactId>
-      <version>1.2.0</version>
-      <exclusions>
-        <exclusion>
-          <groupId>com.google.guava</groupId>
-          <artifactId>guava</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>com.google.code.findbugs</groupId>
-          <artifactId>jsr305</artifactId>
-        </exclusion>
-      </exclusions>
-    </dependency>
-
-    <dependency>
-      <groupId>com.google.http-client</groupId>
-      <artifactId>google-http-client-jackson2</artifactId>
-      <version>1.23.0</version>
-      <exclusions>
-        <exclusion>
-          <groupId>com.fasterxml.jackson.core</groupId>
-          <artifactId>jackson-core</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>com.google.code.findbugs</groupId>
-          <artifactId>jsr305</artifactId>
-        </exclusion>
-      </exclusions>
-    </dependency>
-
-    <dependency>
-      <groupId>com.amazonaws</groupId>
-      <artifactId>aws-java-sdk-s3</artifactId>
-      <version>${aws.sdk.s3.version}</version>
-      <exclusions>
-        <exclusion>
-          <groupId>joda-time</groupId>
-          <artifactId>joda-time</artifactId>
-        </exclusion>
-      </exclusions>
-    </dependency>
-
-    <dependency>
       <groupId>org.eclipse.jetty</groupId>
       <artifactId>jetty-client</artifactId>
       <version>${jetty.version}</version>
@@ -250,6 +158,12 @@
     </dependency>
 
     <dependency>
+      <groupId>com.amazonaws</groupId>
+      <artifactId>aws-java-sdk-s3</artifactId>
+      <version>${aws.sdk.s3.version}</version>
+    </dependency>
+
+    <dependency>
       <groupId>org.reflections</groupId>
       <artifactId>reflections</artifactId>
       <version>${org.reflections.version}</version>
@@ -266,12 +180,6 @@
     </dependency>
 
     <dependency>
-      <groupId>org.eclipse.jgit</groupId>
-      <artifactId>org.eclipse.jgit</artifactId>
-      <version>${eclipse.jgit.version}</version>
-    </dependency>
-
-    <dependency>
       <groupId>com.github.eirslett</groupId>
       <artifactId>frontend-maven-plugin</artifactId>
       <version>${frontend.maven.plugin.version}</version>
@@ -304,23 +212,6 @@
     </dependency>
 
     <dependency>
-      <groupId>com.google.cloud</groupId>
-      <artifactId>google-cloud-nio</artifactId>
-      <version>${google.testing.nio.version}</version>
-      <scope>test</scope>
-      <exclusions>
-        <exclusion>
-          <groupId>com.google.code.findbugs</groupId>
-          <artifactId>jsr305</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>com.google.guava</groupId>
-          <artifactId>guava</artifactId>
-        </exclusion>
-      </exclusions>
-    </dependency>
-
-    <dependency>
       <groupId>com.google.truth</groupId>
       <artifactId>truth</artifactId>
       <version>${google.truth.version}</version>
@@ -366,12 +257,6 @@
       <version>1.5</version>
     </dependency>
 
-    <dependency>
-      <groupId>org.mongodb</groupId>
-      <artifactId>mongo-java-driver</artifactId>
-      <version>3.4.1</version>
-    </dependency>
-
   </dependencies>
 
   <build>
@@ -745,73 +630,6 @@
             </exclusion>
           </exclusions>
         </dependency>
-
-        <dependency>
-          <groupId>org.apache.hadoop</groupId>
-          <artifactId>hadoop-azure</artifactId>
-          <version>${hadoop.version}</version>
-          <exclusions>
-            <exclusion>
-              <groupId>com.fasterxml.jackson.core</groupId>
-              <artifactId>jackson-core</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>com.google.guava</groupId>
-              <artifactId>guava</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>org.apache.commons</groupId>
-              <artifactId>commons-lang3</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>com.jcraf</groupId>
-              <artifactId>jsch</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>org.apache.commons</groupId>
-              <artifactId>commons-compress</artifactId>
-            </exclusion>
-          </exclusions>
-        </dependency>
-        <dependency>
-          <groupId>com.microsoft.azure</groupId>
-          <artifactId>azure-data-lake-store-sdk</artifactId>
-          <version>${adl.sdk.version}</version>
-          <exclusions>
-            <exclusion>
-              <groupId>com.fasterxml.jackson.core</groupId>
-              <artifactId>jackson-core</artifactId>
-            </exclusion>
-          </exclusions>
-        </dependency>
-        <dependency>
-          <groupId>org.apache.hadoop</groupId>
-          <artifactId>hadoop-aws</artifactId>
-          <version>${hadoop.version}</version>
-          <exclusions>
-            <exclusion>
-              <groupId>com.amazonaws</groupId>
-              <artifactId>aws-java-sdk</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>com.fasterxml.jackson.core</groupId>
-              <artifactId>jackson-annotations</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>com.fasterxml.jackson.core</groupId>
-              <artifactId>jackson-core</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>com.fasterxml.jackson.core</groupId>
-              <artifactId>jackson-databind</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>joda-time</groupId>
-              <artifactId>joda-time</artifactId>
-            </exclusion>
-          </exclusions>
-        </dependency>
-        
       </dependencies>
     </profile>
 
@@ -837,104 +655,6 @@
           <version>${hadoop.version}</version>
           <scope>test</scope>
         </dependency>
-
-        <dependency>
-          <groupId>org.apache.hadoop</groupId>
-          <artifactId>hadoop-azure</artifactId>
-          <version>${hadoop.version}</version>
-          <exclusions>
-            <exclusion>
-              <groupId>com.fasterxml.jackson.core</groupId>
-              <artifactId>jackson-core</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>com.google.guava</groupId>
-              <artifactId>guava</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>com.jcraft</groupId>
-              <artifactId>jsch</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>org.apache.commons</groupId>
-              <artifactId>commons-compress</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>org.codehaus.jackson</groupId>
-              <artifactId>jackson-mapper-asl</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>com.nimbusds</groupId>
-              <artifactId>nimbus-jose-jwt</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>org.apache.zookeeper</groupId>
-              <artifactId>zookeeper</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>org.eclipse.jetty</groupId>
-              <artifactId>jetty-server</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>org.eclipse.jetty</groupId>
-              <artifactId>jetty-servlet</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>org.codehaus.jackson</groupId>
-              <artifactId>jackson-core-asl</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>com.fasterxml.jackson.core</groupId>
-              <artifactId>jackson-databind</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>org.eclipse.jetty</groupId>
-              <artifactId>jetty-util</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>com.sun.jersey</groupId>
-              <artifactId>jersey-core</artifactId>
-            </exclusion>
-          </exclusions>
-        </dependency>
-        <dependency>
-          <groupId>org.apache.hadoop</groupId>
-          <artifactId>hadoop-azure-datalake</artifactId>
-          <version>${hadoop.version}</version>
-          <exclusions>
-            <exclusion>
-              <groupId>com.fasterxml.jackson.core</groupId>
-              <artifactId>jackson-core</artifactId>
-            </exclusion>
-          </exclusions>
-        </dependency>
-        <dependency>
-          <groupId>org.apache.hadoop</groupId>
-          <artifactId>hadoop-aws</artifactId>
-          <version>${hadoop.version}</version>
-          <exclusions>
-            <exclusion>
-              <groupId>com.amazonaws</groupId>
-              <artifactId>aws-java-sdk</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>com.fasterxml.jackson.core</groupId>
-              <artifactId>jackson-annotations</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>com.fasterxml.jackson.core</groupId>
-              <artifactId>jackson-core</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>com.fasterxml.jackson.core</groupId>
-              <artifactId>jackson-databind</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>joda-time</groupId>
-              <artifactId>joda-time</artifactId>
-            </exclusion>
-          </exclusions>
-        </dependency>
       </dependencies>
     </profile>
   </profiles>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/3eea57ab/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/recovery/FileSystemRecoveryStorage.java
----------------------------------------------------------------------
diff --git 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/recovery/FileSystemRecoveryStorage.java
 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/recovery/FileSystemRecoveryStorage.java
index 9b1b6cb..4fc860d 100644
--- 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/recovery/FileSystemRecoveryStorage.java
+++ 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/recovery/FileSystemRecoveryStorage.java
@@ -18,13 +18,7 @@
 package org.apache.zeppelin.interpreter.recovery;
 
 import org.apache.commons.lang.StringUtils;
-import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.fs.FileStatus;
-import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.fs.Path;
-import org.apache.hadoop.fs.PathFilter;
-import org.apache.hadoop.io.IOUtils;
-import org.apache.hadoop.security.UserGroupInformation;
 import org.apache.zeppelin.conf.ZeppelinConfiguration;
 import org.apache.zeppelin.interpreter.InterpreterSetting;
 import org.apache.zeppelin.interpreter.InterpreterSettingManager;
@@ -34,15 +28,10 @@ import 
org.apache.zeppelin.interpreter.remote.RemoteInterpreterEventPoller;
 import org.apache.zeppelin.interpreter.remote.RemoteInterpreterProcess;
 import org.apache.zeppelin.interpreter.remote.RemoteInterpreterRunningProcess;
 import org.apache.zeppelin.notebook.FileSystemStorage;
-import org.apache.zeppelin.notebook.repo.FileSystemNotebookRepo;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/3eea57ab/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java
----------------------------------------------------------------------
diff --git 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java
index 85a5f1c..3728cd3 100644
--- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java
+++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java
@@ -167,6 +167,11 @@ public class Note implements ParagraphJobListener, 
JsonSerializable {
     return id;
   }
 
+  @VisibleForTesting
+  public void setId(String id) {
+    this.id = id;
+  }
+
   public String getName() {
     if (isNameEmpty()) {
       name = getId();

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/3eea57ab/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java
----------------------------------------------------------------------
diff --git 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java
index ba83449..e9903c7 100644
--- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java
+++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java
@@ -233,7 +233,7 @@ public class Notebook implements NoteEventListener {
    * @throws IOException, CloneNotSupportedException, IllegalArgumentException
    */
   public Note cloneNote(String sourceNoteId, String newNoteName, 
AuthenticationInfo subject)
-      throws IOException, CloneNotSupportedException, IllegalArgumentException 
{
+      throws IOException, IllegalArgumentException {
 
     Note sourceNote = getNote(sourceNoteId);
     if (sourceNote == null) {

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/3eea57ab/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/AzureNotebookRepo.java
----------------------------------------------------------------------
diff --git 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/AzureNotebookRepo.java
 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/AzureNotebookRepo.java
deleted file mode 100644
index 3b01088..0000000
--- 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/AzureNotebookRepo.java
+++ /dev/null
@@ -1,209 +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.zeppelin.notebook.repo;
-
-import com.microsoft.azure.storage.CloudStorageAccount;
-import com.microsoft.azure.storage.StorageException;
-import com.microsoft.azure.storage.file.CloudFile;
-import com.microsoft.azure.storage.file.CloudFileClient;
-import com.microsoft.azure.storage.file.CloudFileDirectory;
-import com.microsoft.azure.storage.file.CloudFileShare;
-import com.microsoft.azure.storage.file.ListFileItem;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-import java.net.URISyntaxException;
-import java.security.InvalidKeyException;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang.StringUtils;
-import org.apache.zeppelin.conf.ZeppelinConfiguration;
-import org.apache.zeppelin.notebook.Note;
-import org.apache.zeppelin.notebook.NoteInfo;
-import org.apache.zeppelin.user.AuthenticationInfo;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Azure storage backend for notebooks
- */
-public class AzureNotebookRepo implements NotebookRepo {
-  private static final Logger LOG = 
LoggerFactory.getLogger(S3NotebookRepo.class);
-
-  private final ZeppelinConfiguration conf;
-  private final String user;
-  private final String shareName;
-  private final CloudFileDirectory rootDir;
-
-  public AzureNotebookRepo(ZeppelinConfiguration conf)
-      throws URISyntaxException, InvalidKeyException, StorageException {
-    this.conf = conf;
-    user = 
conf.getString(ZeppelinConfiguration.ConfVars.ZEPPELIN_NOTEBOOK_AZURE_USER);
-    shareName = 
conf.getString(ZeppelinConfiguration.ConfVars.ZEPPELIN_NOTEBOOK_AZURE_SHARE);
-
-    CloudStorageAccount account = CloudStorageAccount.parse(
-        
conf.getString(ZeppelinConfiguration.ConfVars.ZEPPELIN_NOTEBOOK_AZURE_CONNECTION_STRING));
-    CloudFileClient client = account.createCloudFileClient();
-    CloudFileShare share = client.getShareReference(shareName);
-    share.createIfNotExists();
-
-    CloudFileDirectory userDir = StringUtils.isBlank(user) ?
-        share.getRootDirectoryReference() :
-        share.getRootDirectoryReference().getDirectoryReference(user);
-    userDir.createIfNotExists();
-
-    rootDir = userDir.getDirectoryReference("notebook");
-    rootDir.createIfNotExists();
-  }
-
-  @Override
-  public List<NoteInfo> list(AuthenticationInfo subject) throws IOException {
-    List<NoteInfo> infos = new LinkedList<>();
-    NoteInfo info = null;
-
-    for (ListFileItem item : rootDir.listFilesAndDirectories()) {
-      if (item.getClass() == CloudFileDirectory.class) {
-        CloudFileDirectory dir = (CloudFileDirectory) item;
-
-        try {
-          if (dir.getFileReference("note.json").exists()) {
-            info = new NoteInfo(getNote(dir.getName()));
-
-            if (info != null) {
-              infos.add(info);
-            }
-          }
-        } catch (StorageException | URISyntaxException e) {
-          String msg = "Error enumerating notebooks from Azure storage";
-          LOG.error(msg, e);
-        } catch (Exception e) {
-          LOG.error(e.getMessage(), e);
-        }
-      }
-    }
-
-    return infos;
-  }
-
-  private Note getNote(String noteId) throws IOException {
-    InputStream ins = null;
-
-    try {
-      CloudFileDirectory dir = rootDir.getDirectoryReference(noteId);
-      CloudFile file = dir.getFileReference("note.json");
-
-      ins = file.openRead();
-    } catch (URISyntaxException | StorageException e) {
-      String msg = String.format("Error reading notebook %s from Azure 
storage", noteId);
-
-      LOG.error(msg, e);
-
-      throw new IOException(msg, e);
-    }
-
-    String json = IOUtils.toString(ins,
-        conf.getString(ZeppelinConfiguration.ConfVars.ZEPPELIN_ENCODING));
-    ins.close();
-    return Note.fromJson(json);
-  }
-
-  @Override
-  public Note get(String noteId, AuthenticationInfo subject) throws 
IOException {
-    return getNote(noteId);
-  }
-
-  @Override
-  public void save(Note note, AuthenticationInfo subject) throws IOException {
-    String json = note.toJson();
-
-    ByteArrayOutputStream output = new ByteArrayOutputStream();
-    Writer writer = new OutputStreamWriter(output);
-    writer.write(json);
-    writer.close();
-    output.close();
-
-    byte[] buffer = output.toByteArray();
-
-    try {
-      CloudFileDirectory dir = rootDir.getDirectoryReference(note.getId());
-      dir.createIfNotExists();
-
-      CloudFile cloudFile = dir.getFileReference("note.json");
-      cloudFile.uploadFromByteArray(buffer, 0, buffer.length);
-    } catch (URISyntaxException | StorageException e) {
-      String msg = String.format("Error saving notebook %s to Azure storage", 
note.getId());
-
-      LOG.error(msg, e);
-
-      throw new IOException(msg, e);
-    }
-  }
-
-  // unfortunately, we need to use a recursive delete here
-  private void delete(ListFileItem item) throws StorageException {
-    if (item.getClass() == CloudFileDirectory.class) {
-      CloudFileDirectory dir = (CloudFileDirectory) item;
-
-      for (ListFileItem subItem : dir.listFilesAndDirectories()) {
-        delete(subItem);
-      }
-
-      dir.deleteIfExists();
-    } else if (item.getClass() == CloudFile.class) {
-      CloudFile file = (CloudFile) item;
-
-      file.deleteIfExists();
-    }
-  }
-
-  @Override
-  public void remove(String noteId, AuthenticationInfo subject) throws 
IOException {
-    try {
-      CloudFileDirectory dir = rootDir.getDirectoryReference(noteId);
-
-      delete(dir);
-    } catch (URISyntaxException | StorageException e) {
-      String msg = String.format("Error deleting notebook %s from Azure 
storage", noteId);
-
-      LOG.error(msg, e);
-
-      throw new IOException(msg, e);
-    }
-  }
-
-  @Override
-  public void close() {
-  }
-
-  @Override
-  public List<NotebookRepoSettingsInfo> getSettings(AuthenticationInfo 
subject) {
-    LOG.warn("Method not implemented");
-    return Collections.emptyList();
-  }
-
-  @Override
-  public void updateSettings(Map<String, String> settings, AuthenticationInfo 
subject) {
-    LOG.warn("Method not implemented");
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/3eea57ab/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/FileSystemNotebookRepo.java
----------------------------------------------------------------------
diff --git 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/FileSystemNotebookRepo.java
 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/FileSystemNotebookRepo.java
deleted file mode 100644
index bfc1178..0000000
--- 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/FileSystemNotebookRepo.java
+++ /dev/null
@@ -1,99 +0,0 @@
-package org.apache.zeppelin.notebook.repo;
-
-import org.apache.commons.lang.StringUtils;
-import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.fs.FileStatus;
-import org.apache.hadoop.fs.FileSystem;
-import org.apache.hadoop.fs.Path;
-import org.apache.hadoop.io.IOUtils;
-import org.apache.hadoop.security.UserGroupInformation;
-import org.apache.zeppelin.conf.ZeppelinConfiguration;
-import org.apache.zeppelin.notebook.FileSystemStorage;
-import org.apache.zeppelin.notebook.Note;
-import org.apache.zeppelin.notebook.NoteInfo;
-import org.apache.zeppelin.user.AuthenticationInfo;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.security.PrivilegedExceptionAction;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-/**
- * NotebookRepos for hdfs.
- *
- * Assume the notebook directory structure is as following
- * - notebookdir
- *              - noteId/note.json
- *              - noteId/note.json
- *              - noteId/note.json
- */
-public class FileSystemNotebookRepo implements NotebookRepo {
-  private static final Logger LOGGER = 
LoggerFactory.getLogger(FileSystemNotebookRepo.class);
-
-  private FileSystemStorage fs;
-  private Path notebookDir;
-
-  public FileSystemNotebookRepo(ZeppelinConfiguration zConf) throws 
IOException {
-    this.fs = new FileSystemStorage(zConf, zConf.getNotebookDir());
-    LOGGER.info("Creating FileSystem: " + this.fs.getFs().getClass().getName() 
+
-        " for Zeppelin Notebook.");
-    this.notebookDir = this.fs.makeQualified(new Path(zConf.getNotebookDir()));
-    LOGGER.info("Using folder {} to store notebook", notebookDir);
-    this.fs.tryMkDir(notebookDir);
-  }
-
-  @Override
-  public List<NoteInfo> list(AuthenticationInfo subject) throws IOException {
-    List<Path> notePaths = fs.list(new Path(notebookDir, "*/note.json"));
-    List<NoteInfo> noteInfos = new ArrayList<>();
-    for (Path path : notePaths) {
-      NoteInfo noteInfo = new NoteInfo(path.getParent().getName(), "", null);
-      noteInfos.add(noteInfo);
-    }
-    return noteInfos;
-  }
-
-  @Override
-  public Note get(final String noteId, AuthenticationInfo subject) throws 
IOException {
-    String content = this.fs.readFile(
-        new Path(notebookDir.toString() + "/" + noteId + "/note.json"));
-    return Note.fromJson(content);
-  }
-
-  @Override
-  public void save(final Note note, AuthenticationInfo subject) throws 
IOException {
-    this.fs.writeFile(note.toJson(),
-        new Path(notebookDir.toString() + "/" + note.getId() + "/note.json"),
-        true);
-  }
-
-  @Override
-  public void remove(final String noteId, AuthenticationInfo subject) throws 
IOException {
-    this.fs.delete(new Path(notebookDir.toString() + "/" + noteId));
-  }
-
-  @Override
-  public void close() {
-    LOGGER.warn("close is not implemented for HdfsNotebookRepo");
-  }
-
-  @Override
-  public List<NotebookRepoSettingsInfo> getSettings(AuthenticationInfo 
subject) {
-    LOGGER.warn("getSettings is not implemented for HdfsNotebookRepo");
-    return null;
-  }
-
-  @Override
-  public void updateSettings(Map<String, String> settings, AuthenticationInfo 
subject) {
-    LOGGER.warn("updateSettings is not implemented for HdfsNotebookRepo");
-  }
-
-}

Reply via email to