You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@manifoldcf.apache.org by kw...@apache.org on 2013/05/31 13:26:22 UTC

svn commit: r1488171 [1/2] - in /manifoldcf/branches/CONNECTORS-694: ./ connectors/ connectors/googledrive/ connectors/googledrive/connector/ connectors/googledrive/connector/src/ connectors/googledrive/connector/src/main/ connectors/googledrive/connec...

Author: kwright
Date: Fri May 31 11:26:21 2013
New Revision: 1488171

URL: http://svn.apache.org/r1488171
Log:
Check in Andrew's first patch.

Added:
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/build.xml
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/java/
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/java/org/
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/java/org/apache/
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/java/org/apache/manifoldcf/
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/java/org/apache/manifoldcf/crawler/
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/googledrive/
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/googledrive/GoogleDriveConfig.java
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/googledrive/GoogleDriveRepositoryConnector.java
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/googledrive/GoogleDriveSession.java
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/googledrive/Messages.java
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/native2ascii/
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/native2ascii/org/
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/native2ascii/org/apache/
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/native2ascii/org/apache/manifoldcf/
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/native2ascii/org/apache/manifoldcf/crawler/
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/native2ascii/org/apache/manifoldcf/crawler/connectors/
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/native2ascii/org/apache/manifoldcf/crawler/connectors/googledrive/
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/native2ascii/org/apache/manifoldcf/crawler/connectors/googledrive/common_en_US.properties
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/resources/
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/resources/org/
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/resources/org/apache/
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/resources/org/apache/manifoldcf/
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/resources/org/apache/manifoldcf/crawler/
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/googledrive/
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/googledrive/common_en_US.properties
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/googledrive/editConfiguration_google_server.html
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/googledrive/editConfiguration_google_server.js
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/googledrive/editSpecification_googledrive.js
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/googledrive/editSpecification_googledriveQuery.html
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/googledrive/viewConfiguration_googledrive.html
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/googledrive/viewSpecification_googledrive.html
    manifoldcf/branches/CONNECTORS-694/connectors/googledrive/pom.xml
Modified:
    manifoldcf/branches/CONNECTORS-694/build.xml
    manifoldcf/branches/CONNECTORS-694/connectors/pom.xml

Modified: manifoldcf/branches/CONNECTORS-694/build.xml
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-694/build.xml?rev=1488171&r1=1488170&r2=1488171&view=diff
==============================================================================
--- manifoldcf/branches/CONNECTORS-694/build.xml (original)
+++ manifoldcf/branches/CONNECTORS-694/build.xml Fri May 31 11:26:21 2013
@@ -59,6 +59,7 @@
         <ant dir="connectors/alfresco" target="clean"/>
         <ant dir="connectors/cmis" target="clean"/>
         <ant dir="connectors/dropbox" target="clean"/>
+        <ant dir="connectors/googledrive" target="clean"/>
         <ant dir="connectors/activedirectory" target="clean"/>
         <ant dir="connectors/ldap" target="clean"/>
         <ant dir="connectors/documentum" target="clean"/>
@@ -110,6 +111,7 @@
         <ant dir="connectors/alfresco" target="clean"/>
         <ant dir="connectors/cmis" target="clean"/>
         <ant dir="connectors/dropbox" target="clean"/>
+        <ant dir="connectors/googledrive" target="clean"/>
         <ant dir="connectors/activedirectory" target="clean"/>
         <ant dir="connectors/ldap" target="clean"/>
         <ant dir="connectors/documentum" target="clean"/>
@@ -281,6 +283,8 @@
     <target name="setup-cmis-connector" depends="build-framework" if="downloaded"/>
     
     <target name="setup-dropbox-connector" depends="build-framework" if="downloaded"/>
+
+    <target name="setup-googledrive-connector" depends="build-framework" if="downloaded"/>
     
     <target name="setup-alfresco-connector-tests" depends="build-tests-framework" if="downloaded"/>
 
@@ -302,10 +306,21 @@
         <ant dir="connectors/dropbox" target="build"/>
     </target>
 
+
+    <target name="build-googledrive-connector" depends="setup-googledrive-connector" if="downloaded">
+        <ant dir="connectors/googledrive" target="build"/>
+    </target>
+
+
     <target name="doc-dropbox-connector" depends="setup-dropbox-connector" if="downloaded">
         <ant dir="connectors/dropbox" target="doc"/>
     </target>
 
+    <target name="doc-googledrive-connector" depends="setup-googledrive-connector" if="downloaded">
+        <ant dir="connectors/googledrive" target="doc"/>
+    </target>
+
+
     <target name="doc-alfresco-connector" depends="setup-alfresco-connector" if="downloaded">
         <ant dir="connectors/alfresco" target="doc"/>
     </target>
@@ -1395,6 +1410,29 @@
         </condition>
     </target>
 
+
+    <target name="calculate-googledrive-condition" depends="build-googledrive-connector">
+        <available file="connectors/googledrive/dist/lib" type="dir" property="googledrive.exists"/>
+        <condition property="googledrive.include">
+            <and>
+                <isset property="googledrive.exists"/>
+                <isset property="downloaded"/>
+            </and>
+        </condition>
+    </target>
+
+    <target name="calculate-googledrive-doc-condition" depends="doc-googledrive-connector">
+        <available file="connectors/googledrive/dist/doc" type="dir" property="googledrive-doc.exists"/>
+        <condition property="googledrive-doc.include">
+            <and>
+                <isset property="googledrive-doc.exists"/>
+                <isset property="downloaded"/>
+            </and>
+        </condition>
+    </target>
+
+
+
     <target name="calculate-cmis-doc-condition" depends="doc-cmis-connector">
         <available file="connectors/cmis/dist/doc" type="dir" property="cmis-doc.exists"/>
         <condition property="cmis-doc.include">
@@ -1437,6 +1475,24 @@
             <param name="connector-name" value="dropbox"/>
         </antcall>
     </target>
+
+    <target name="deliver-googledrive-connector" depends="calculate-googledrive-condition" if="googledrive.include">
+        <antcall target="general-connector-delivery">
+            <param name="connector-name" value="googledrive"/>
+        </antcall>
+        <antcall target="general-add-repository-connector">
+            <param name="connector-name" value="googledrive"/>
+            <param name="connector-label" value="GoogleDrive"/>
+            <param name="connector-class" value="org.apache.manifoldcf.crawler.connectors.googledrive.GoogleDriveRepositoryConnector"/>
+        </antcall>
+    </target>
+
+    <target name="deliver-googledrive-connector-doc" depends="calculate-googledrive-doc-condition" if="googledrive-doc.include">
+        <antcall target="general-connector-doc-delivery">
+            <param name="connector-name" value="googledrive"/>
+        </antcall>
+    </target>
+
     
     <target name="deliver-cmis-connector-doc" depends="calculate-cmis-doc-condition" if="cmis-doc.include">
         <antcall target="general-connector-doc-delivery">
@@ -2590,8 +2646,8 @@
     <target name="end-to-end-loadtests-HSQLDB" depends="run-filesystem-loadtests-HSQLDB,run-rss-loadtests-HSQLDB,run-wiki-loadtests-HSQLDB,run-alfresco-loadtests-HSQLDB,run-cmis-loadtests-HSQLDB,run-sharepoint-loadtests-HSQLDB"/>
 
 
-    <target name="deliver-open-connectors" depends="deliver-dropbox-connector,deliver-nullauthority-connector,deliver-activedirectory-connector,deliver-ldap-connector,deliver-alfresco-connector,deliver-cmis-connector,deliver-filesystem-connector,deliver-rss-connector,deliver-webcrawler-connector,deliver-wiki-connector,deliver-jdbc-connector"/>
-    <target name="deliver-open-connectors-doc" depends="deliver-dropbox-connector-doc,deliver-nullauthority-connector-doc,deliver-activedirectory-connector-doc,deliver-ldap-connector-doc,deliver-alfresco-connector-doc,deliver-cmis-connector-doc,deliver-filesystem-connector-doc,deliver-rss-connector-doc,deliver-webcrawler-connector-doc,deliver-wiki-connector-doc,deliver-jdbc-connector-doc"/>
+    <target name="deliver-open-connectors" depends="deliver-googledrive-connector,deliver-dropbox-connector,deliver-nullauthority-connector,deliver-activedirectory-connector,deliver-ldap-connector,deliver-alfresco-connector,deliver-cmis-connector,deliver-filesystem-connector,deliver-rss-connector,deliver-webcrawler-connector,deliver-wiki-connector,deliver-jdbc-connector"/>
+    <target name="deliver-open-connectors-doc" depends="deliver-googledrive-connector-doc,deliver-dropbox-connector-doc,deliver-nullauthority-connector-doc,deliver-activedirectory-connector-doc,deliver-ldap-connector-doc,deliver-alfresco-connector-doc,deliver-cmis-connector-doc,deliver-filesystem-connector-doc,deliver-rss-connector-doc,deliver-webcrawler-connector-doc,deliver-wiki-connector-doc,deliver-jdbc-connector-doc"/>
     
     <target name="deliver-output-connectors" depends="deliver-gts-connector,deliver-solr-connector,deliver-nulloutput-connector,deliver-opensearchserver-connector,deliver-elasticsearch-connector"/>
     <target name="deliver-output-connectors-doc" depends="deliver-gts-connector-doc,deliver-solr-connector-doc,deliver-nulloutput-connector-doc,deliver-opensearchserver-connector-doc,deliver-elasticsearch-connector-doc"/>
@@ -3599,6 +3655,54 @@ Use Apache Forrest version forrest-0.9-d
         </antcall>
     </target>
     
+
+   <target name="download-google-api-client">
+        <mkdir dir="lib"/>
+        <antcall target="download-via-maven">
+            <param name="target" value="lib"/>
+            <param name="project-path" value="com/google/apis"/>
+            <param name="artifact-version" value="v2-rev64-1.14.1-beta"/>
+            <param name="artifact-name" value="google-api-services-drive"/>
+            <param name="artifact-type" value="jar"/>
+        </antcall>
+        <antcall target="download-via-maven">
+            <param name="target" value="lib"/>
+            <param name="project-path" value="com/google/http-client"/>
+            <param name="artifact-version" value="1.14.1-beta"/>
+            <param name="artifact-name" value="google-http-client"/>
+            <param name="artifact-type" value="jar"/>
+        </antcall>
+        <antcall target="download-via-maven">
+            <param name="target" value="lib"/>
+            <param name="project-path" value="com/google/http-client"/>
+            <param name="artifact-version" value="1.14.1-beta"/>
+            <param name="artifact-name" value="google-http-client-jackson2"/>
+            <param name="artifact-type" value="jar"/>
+        </antcall>
+        <antcall target="download-via-maven">
+            <param name="target" value="lib"/>
+            <param name="project-path" value="com/google/oauth-client"/>
+            <param name="artifact-version" value="1.14.1-beta"/>
+            <param name="artifact-name" value="google-oauth-client"/>
+            <param name="artifact-type" value="jar"/>
+        </antcall>
+        <antcall target="download-via-maven">
+            <param name="target" value="lib"/>
+            <param name="project-path" value="com/fasterxml/jackson/core/"/>
+            <param name="artifact-version" value="2.1.3"/>
+            <param name="artifact-name" value="jackson-core"/>
+            <param name="artifact-type" value="jar"/>
+        </antcall> 
+        <antcall target="download-via-maven">
+            <param name="target" value="lib"/>
+            <param name="project-path" value="com/google/api-client"/>
+            <param name="artifact-version" value="1.14.1-beta"/>
+            <param name="artifact-name" value="google-api-client"/>
+            <param name="artifact-type" value="jar"/>
+        </antcall>
+
+    </target>
+
     <target name="download-sharepoint-plugins">
         <mkdir dir="lib/sharepoint-2007"/>
         <!-- Download and unpack binary artifact -->
@@ -3652,7 +3756,7 @@ Use Apache Forrest version forrest-0.9-d
         </antcall>
     </target>
 
-    <target name="make-core-deps" depends="download-dropbox-client,download-solrj,download-httpcomponents,download-json,download-hsqldb,download-xerces,download-commons,download-elasticsearch-plugin,download-solr-plugins,download-sharepoint-plugins,download-jstl,download-xmlgraphics-commons,download-wstx-asl,download-xmlsec,download-xml-apis,download-wss4j,download-velocity,download-streambuffer,download-stax,download-servlet-api,download-xml-resolver,download-osgi,download-opensaml,download-mimepull,download-mail,download-log4j,download-junit,download-jaxws,download-glassfish,download-jaxb,download-tomcat,download-h2,download-h2-support,download-geronimo-specs,download-fop,download-derby,download-postgresql,download-axis,download-saaj,download-wsdl4j,download-castor,download-jetty,download-slf4j,download-xalan,download-activation,download-avalon-framework,download-poi,download-chemistry,download-ecj">
+    <target name="make-core-deps" depends="download-google-api-client,download-dropbox-client,download-solrj,download-httpcomponents,download-json,download-hsqldb,download-xerces,download-commons,download-elasticsearch-plugin,download-solr-plugins,download-sharepoint-plugins,download-jstl,download-xmlgraphics-commons,download-wstx-asl,download-xmlsec,download-xml-apis,download-wss4j,download-velocity,download-streambuffer,download-stax,download-servlet-api,download-xml-resolver,download-osgi,download-opensaml,download-mimepull,download-mail,download-log4j,download-junit,download-jaxws,download-glassfish,download-jaxb,download-tomcat,download-h2,download-h2-support,download-geronimo-specs,download-fop,download-derby,download-postgresql,download-axis,download-saaj,download-wsdl4j,download-castor,download-jetty,download-slf4j,download-xalan,download-activation,download-avalon-framework,download-poi,download-chemistry,download-ecj">
         <copy todir="lib">
             <fileset dir="lib-license" includes="*.txt"/>
         </copy>
@@ -3682,6 +3786,7 @@ Use Apache Forrest version forrest-0.9-d
         <ant dir="connectors/alfresco" target="download-dependencies"/>
         <ant dir="connectors/cmis" target="download-dependencies"/>
         <ant dir="connectors/dropbox" target="download-dependencies"/>
+        <ant dir="connectors/googledrive" target="download-dependencies"/>
         <ant dir="connectors/activedirectory" target="download-dependencies"/>
         <ant dir="connectors/ldap" target="download-dependencies"/>
         <ant dir="connectors/documentum" target="download-dependencies"/>
@@ -3719,6 +3824,7 @@ Use Apache Forrest version forrest-0.9-d
         <ant dir="connectors/alfresco" target="download-cleanup"/>
         <ant dir="connectors/cmis" target="download-cleanup"/>
         <ant dir="connectors/dropbox" target="download-cleanup"/>        
+        <ant dir="connectors/googledrive" target="download-cleanup"/>
         <ant dir="connectors/activedirectory" target="download-cleanup"/>
         <ant dir="connectors/ldap" target="download-cleanup"/>
         <ant dir="connectors/documentum" target="download-cleanup"/>

Added: manifoldcf/branches/CONNECTORS-694/connectors/googledrive/build.xml
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-694/connectors/googledrive/build.xml?rev=1488171&view=auto
==============================================================================
--- manifoldcf/branches/CONNECTORS-694/connectors/googledrive/build.xml (added)
+++ manifoldcf/branches/CONNECTORS-694/connectors/googledrive/build.xml Fri May 31 11:26:21 2013
@@ -0,0 +1,40 @@
+<!--
+ 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 name="googledrive" default="all">
+
+    <import file="../connector-build.xml"/>
+
+    <path id="connector-classpath">
+        <path refid="mcf-connector-build.connector-classpath"/>
+        <fileset dir="../../lib">
+            <include name="google-*.jar"/>
+	    <include name="jackson-core.jar"/>
+        </fileset>
+    </path>
+
+    <target name="lib" depends="mcf-connector-build.lib,precompile-check" if="canBuild">
+        <mkdir dir="dist/lib"/>
+        <copy todir="dist/lib">
+            <fileset dir="../../lib">
+                <include name="google-*.jar"/>
+		<include name="jackson-core.jar"/>
+            </fileset>
+        </copy>
+    </target>
+
+</project>

Added: manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/googledrive/GoogleDriveConfig.java
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/googledrive/GoogleDriveConfig.java?rev=1488171&view=auto
==============================================================================
--- manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/googledrive/GoogleDriveConfig.java (added)
+++ manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/googledrive/GoogleDriveConfig.java Fri May 31 11:26:21 2013
@@ -0,0 +1,19 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.apache.manifoldcf.crawler.connectors.googledrive;
+
+/**
+ *
+ * @author andrew
+ */
+public class GoogleDriveConfig {
+
+    public static final String CLIENT_ID_PARAM = "clientid";
+    public static final String CLIENT_SECRET_PARAM = "clientsecret";
+    public static final String REFRESH_TOKEN_PARAM = "refreshtoken";
+    public static final String REPOSITORY_ID_DEFAULT_VALUE = "googledrive";
+    public static final String GOOGLEDRIVE_QUERY_PARAM = "googledriveQuery";
+    public static final String GOOGLEDRIVE_QUERY_DEFAULT = "mimeType='application/vnd.google-apps.folder' and trashed=false";
+}

Added: manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/googledrive/GoogleDriveRepositoryConnector.java
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/googledrive/GoogleDriveRepositoryConnector.java?rev=1488171&view=auto
==============================================================================
--- manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/googledrive/GoogleDriveRepositoryConnector.java (added)
+++ manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/googledrive/GoogleDriveRepositoryConnector.java Fri May 31 11:26:21 2013
@@ -0,0 +1,1008 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.apache.manifoldcf.crawler.connectors.googledrive;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InterruptedIOException;
+import java.rmi.NotBoundException;
+import java.rmi.RemoteException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import org.apache.manifoldcf.crawler.system.Logging;
+import org.apache.manifoldcf.crawler.connectors.BaseRepositoryConnector;
+import org.apache.manifoldcf.agents.interfaces.ServiceInterruption;
+import org.apache.manifoldcf.core.interfaces.ConfigParams;
+import org.apache.manifoldcf.core.interfaces.ManifoldCFException;
+import org.apache.commons.lang.StringUtils;
+import org.apache.manifoldcf.agents.interfaces.RepositoryDocument;
+import org.apache.manifoldcf.core.interfaces.IHTTPOutput;
+import org.apache.manifoldcf.core.interfaces.IPostParameters;
+import org.apache.manifoldcf.core.interfaces.IThreadContext;
+import org.apache.manifoldcf.core.interfaces.SpecificationNode;
+import org.apache.manifoldcf.crawler.interfaces.DocumentSpecification;
+import org.apache.manifoldcf.crawler.interfaces.IProcessActivity;
+import org.apache.manifoldcf.crawler.interfaces.ISeedingActivity;
+import org.apache.log4j.Logger;
+import com.google.api.services.drive.model.File;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.util.Map.Entry;
+
+/**
+ *
+ * @author andrew
+ */
+public class GoogleDriveRepositoryConnector extends BaseRepositoryConnector {
+
+    protected final static String ACTIVITY_READ = "read document";
+    public final static String ACTIVITY_FETCH = "fetch";
+    protected static final String RELATIONSHIP_CHILD = "child";
+    private static final String JOB_STARTPOINT_NODE_TYPE = "startpoint";
+    private static final String GOOGLEDRIVE_SERVER_TAB_PROPERTY = "GoogleDriveRepositoryConnector.Server";
+    private static final String GOOGLEDRIVE_QUERY_TAB_PROPERTY = "GoogleDriveRepositoryConnector.GoogleDriveQuery";
+    // Template names
+    /**
+     * Forward to the javascript to check the configuration parameters
+     */
+    private static final String EDIT_CONFIG_HEADER_FORWARD = "editConfiguration_google_server.js";
+    /**
+     * Server tab template
+     */
+    private static final String EDIT_CONFIG_FORWARD_SERVER = "editConfiguration_google_server.html";
+    /**
+     * Forward to the javascript to check the specification parameters for the
+     * job
+     */
+    private static final String EDIT_SPEC_HEADER_FORWARD = "editSpecification_googledrive.js";
+    /**
+     * Forward to the template to edit the configuration parameters for the job
+     */
+    private static final String EDIT_SPEC_FORWARD_GOOGLEDRIVEQUERY = "editSpecification_googledriveQuery.html";
+    /**
+     * Forward to the HTML template to view the configuration parameters
+     */
+    private static final String VIEW_CONFIG_FORWARD = "viewConfiguration_googledrive.html";
+    /**
+     * Forward to the template to view the specification parameters for the job
+     */
+    private static final String VIEW_SPEC_FORWARD = "viewSpecification_googledrive.html";
+    /**
+     * Endpoint server name
+     */
+    protected String server = "googledrive";
+    protected GoogleDriveSession session = null;
+    protected long lastSessionFetch = -1L;
+    protected static final long timeToRelease = 300000L;
+    protected String clientid = null;
+    protected String clientsecret = null;
+    protected String refreshtoken = null;
+    protected Map<String, String> parameters = new HashMap<String, String>();
+
+    public GoogleDriveRepositoryConnector() {
+        super();
+    }
+
+    /**
+     * Return the list of activities that this connector supports (i.e. writes
+     * into the log).
+     *
+     * @return the list.
+     */
+    @Override
+    public String[] getActivitiesList() {
+        return new String[]{ACTIVITY_FETCH, ACTIVITY_READ};
+    }
+
+    /**
+     * Get the bin name strings for a document identifier. The bin name
+     * describes the queue to which the document will be assigned for throttling
+     * purposes. Throttling controls the rate at which items in a given queue
+     * are fetched; it does not say anything about the overall fetch rate, which
+     * may operate on multiple queues or bins. For example, if you implement a
+     * web crawler, a good choice of bin name would be the server name, since
+     * that is likely to correspond to a real resource that will need real
+     * throttle protection.
+     *
+     * @param documentIdentifier is the document identifier.
+     * @return the set of bin names. If an empty array is returned, it is
+     * equivalent to there being no request rate throttling available for this
+     * identifier.
+     */
+    @Override
+    public String[] getBinNames(String documentIdentifier) {
+        return new String[]{server};
+    }
+
+    /**
+     * Close the connection. Call this before discarding the connection.
+     */
+    @Override
+    public void disconnect() throws ManifoldCFException {
+        if (session != null) {
+            DestroySessionThread t = new DestroySessionThread();
+            try {
+                t.start();
+                t.join();
+                Throwable thr = t.getException();
+                if (thr != null) {
+                    if (thr instanceof RemoteException) {
+                        throw (RemoteException) thr;
+                    } else {
+                        throw (Error) thr;
+                    }
+                }
+                session = null;
+                lastSessionFetch = -1L;
+            } catch (InterruptedException e) {
+                t.interrupt();
+                throw new ManifoldCFException("Interrupted: " + e.getMessage(), e,
+                        ManifoldCFException.INTERRUPTED);
+            } catch (RemoteException e) {
+                Throwable e2 = e.getCause();
+                if (e2 instanceof InterruptedException
+                        || e2 instanceof InterruptedIOException) {
+
+                    throw new ManifoldCFException(e2.getMessage(), e2,
+                            ManifoldCFException.INTERRUPTED);
+                }
+
+                session = null;
+                lastSessionFetch = -1L;
+
+                // Treat this as a transient problem
+
+                Logging.connectors.warn(
+                        "GOOGLEDRIVE: Transient remote exception closing session: "
+                        + e.getMessage(), e);
+            }
+
+        }
+
+        clientid = null;
+        clientsecret = null;
+        refreshtoken = null;
+    }
+
+    /**
+     * This method create a new GOOGLEDRIVE session for a GOOGLEDRIVE
+     * repository, if the repositoryId is not provided in the configuration, the
+     * connector will retrieve all the repositories exposed for this endpoint
+     * the it will start to use the first one.
+     *
+     * @param configParameters is the set of configuration parameters, which in
+     * this case describe the target appliance, basic auth configuration, etc.
+     * (This formerly came out of the ini file.)
+     */
+    @Override
+    public void connect(ConfigParams configParams) {
+        super.connect(configParams);
+
+        clientid = params.getParameter(GoogleDriveConfig.CLIENT_ID_PARAM);
+        clientsecret = params.getParameter(GoogleDriveConfig.CLIENT_SECRET_PARAM);
+        refreshtoken = params.getParameter(GoogleDriveConfig.REFRESH_TOKEN_PARAM);
+    }
+
+    /**
+     * Test the connection. Returns a string describing the connection
+     * integrity.
+     *
+     * @return the connection's status as a displayable string.
+     */
+    @Override
+    public String check() throws ManifoldCFException {
+        try {
+            checkConnection();
+            return super.check();
+        } catch (ServiceInterruption e) {
+            return "Connection temporarily failed: " + e.getMessage();
+        } catch (ManifoldCFException e) {
+            return "Connection failed: " + e.getMessage();
+        }
+    }
+
+    protected class DestroySessionThread extends Thread {
+
+        protected Throwable exception = null;
+
+        public DestroySessionThread() {
+            super();
+            setDaemon(true);
+        }
+
+        public void run() {
+            try {
+                session = null;
+            } catch (Throwable e) {
+                this.exception = e;
+            }
+        }
+
+        public Throwable getException() {
+            return exception;
+        }
+    }
+
+    protected class CheckConnectionThread extends Thread {
+
+        protected Throwable exception = null;
+
+        public CheckConnectionThread() {
+            super();
+            setDaemon(true);
+        }
+
+        public void run() {
+            try {
+                session.getRepositoryInfo();
+            } catch (Throwable e) {
+                Logging.connectors.warn("GOOGLEDRIVE: Error checking repository: " + e.getMessage(), e);
+                this.exception = e;
+            }
+        }
+
+        public Throwable getException() {
+            return exception;
+        }
+    }
+
+    protected void checkConnection() throws ManifoldCFException,
+            ServiceInterruption {
+        while (true) {
+            boolean noSession = (session == null);
+            getSession();
+            long currentTime;
+            CheckConnectionThread t = new CheckConnectionThread();
+            try {
+                t.start();
+                t.join();
+                Throwable thr = t.getException();
+                if (thr != null) {
+                    if (thr instanceof RemoteException) {
+                        throw (RemoteException) thr;
+                    } else {
+                        throw (Error) thr;
+                    }
+                }
+                return;
+            } catch (InterruptedException e) {
+                t.interrupt();
+                throw new ManifoldCFException("Interrupted: " + e.getMessage(), e,
+                        ManifoldCFException.INTERRUPTED);
+            } catch (RemoteException e) {
+                Throwable e2 = e.getCause();
+                if (e2 instanceof InterruptedException
+                        || e2 instanceof InterruptedIOException) {
+                    throw new ManifoldCFException(e2.getMessage(), e2,
+                            ManifoldCFException.INTERRUPTED);
+                }
+                if (noSession) {
+                    currentTime = System.currentTimeMillis();
+                    throw new ServiceInterruption(
+                            "Transient error connecting to filenet service: "
+                            + e.getMessage(), currentTime + 60000L);
+                }
+                session = null;
+                lastSessionFetch = -1L;
+                continue;
+            }
+        }
+    }
+
+    /**
+     * Set up a session
+     */
+    protected void getSession() throws ManifoldCFException, ServiceInterruption {
+        if (session == null) {
+            // Check for parameter validity
+
+            if (StringUtils.isEmpty(clientid)) {
+                throw new ManifoldCFException("Parameter " + GoogleDriveConfig.CLIENT_ID_PARAM
+                        + " required but not set");
+            }
+
+            if (Logging.connectors.isDebugEnabled()) {
+                Logging.connectors.debug("GOOGLEDRIVE: Clientid = '" + clientid + "'");
+            }
+
+            if (StringUtils.isEmpty(clientsecret)) {
+                throw new ManifoldCFException("Parameter " + GoogleDriveConfig.CLIENT_SECRET_PARAM
+                        + " required but not set");
+            }
+
+            if (Logging.connectors.isDebugEnabled()) {
+                Logging.connectors.debug("GOOGLEDRIVE: Clientsecret = '" + clientsecret + "'");
+            }
+
+            if (StringUtils.isEmpty(refreshtoken)) {
+                throw new ManifoldCFException("Parameter " + GoogleDriveConfig.REFRESH_TOKEN_PARAM
+                        + " required but not set");
+            }
+
+            if (Logging.connectors.isDebugEnabled()) {
+                Logging.connectors.debug("GOOGLEDRIVE: refreshtoken = '" + refreshtoken + "'");
+            }
+
+
+
+            long currentTime;
+            GetSessionThread t = new GetSessionThread();
+            try {
+                t.start();
+                t.join();
+                Throwable thr = t.getException();
+                if (thr != null) {
+                    if (thr instanceof java.net.MalformedURLException) {
+                        throw (java.net.MalformedURLException) thr;
+                    } else if (thr instanceof NotBoundException) {
+                        throw (NotBoundException) thr;
+                    } else if (thr instanceof RemoteException) {
+                        throw (RemoteException) thr;
+                    } else {
+                        throw (Error) thr;
+                    }
+
+                }
+            } catch (InterruptedException e) {
+                t.interrupt();
+                throw new ManifoldCFException("Interrupted: " + e.getMessage(), e,
+                        ManifoldCFException.INTERRUPTED);
+            } catch (java.net.MalformedURLException e) {
+                throw new ManifoldCFException(e.getMessage(), e);
+            } catch (NotBoundException e) {
+                // Transient problem: Server not available at the moment.
+                Logging.connectors.warn(
+                        "GOOGLEDRIVE: Server not up at the moment: " + e.getMessage(), e);
+                currentTime = System.currentTimeMillis();
+                throw new ServiceInterruption(e.getMessage(), currentTime + 60000L);
+            } catch (RemoteException e) {
+                Throwable e2 = e.getCause();
+                if (e2 instanceof InterruptedException
+                        || e2 instanceof InterruptedIOException) {
+                    throw new ManifoldCFException(e2.getMessage(), e2,
+                            ManifoldCFException.INTERRUPTED);
+                }
+                // Treat this as a transient problem
+                Logging.connectors.warn(
+                        "GOOGLEDRIVE: Transient remote exception creating session: "
+                        + e.getMessage(), e);
+                currentTime = System.currentTimeMillis();
+                throw new ServiceInterruption(e.getMessage(), currentTime + 60000L);
+            }
+
+        }
+        lastSessionFetch = System.currentTimeMillis();
+    }
+
+    protected class GetSessionThread extends Thread {
+
+        protected Throwable exception = null;
+
+        public GetSessionThread() {
+            super();
+            setDaemon(true);
+        }
+
+        public void run() {
+            try {
+                // Create a session
+                parameters.clear();
+
+                // user credentials
+                parameters.put(GoogleDriveConfig.CLIENT_ID_PARAM, clientid);
+                parameters.put(GoogleDriveConfig.CLIENT_SECRET_PARAM, clientsecret);
+                parameters.put(GoogleDriveConfig.REFRESH_TOKEN_PARAM, refreshtoken);
+                try {
+                    session = new GoogleDriveSession(parameters);
+                } catch (Exception e) {
+                    Logging.connectors.error("GOOGLEDRIVE: Error during the creation of the new session. Please check the endpoint parameters: " + e.getMessage(), e);
+                    this.exception = e;
+                }
+            } catch (Throwable e) {
+                this.exception = e;
+            }
+        }
+
+        public Throwable getException() {
+            return exception;
+        }
+    }
+
+    @Override
+    public void poll() throws ManifoldCFException {
+        if (lastSessionFetch == -1L) {
+            return;
+        }
+
+        long currentTime = System.currentTimeMillis();
+        if (currentTime >= lastSessionFetch + timeToRelease) {
+            DestroySessionThread t = new DestroySessionThread();
+            try {
+                t.start();
+                t.join();
+                Throwable thr = t.getException();
+                if (thr != null) {
+                    if (thr instanceof RemoteException) {
+                        throw (RemoteException) thr;
+                    } else {
+                        throw (Error) thr;
+                    }
+                }
+                session = null;
+                lastSessionFetch = -1L;
+            } catch (InterruptedException e) {
+                t.interrupt();
+                throw new ManifoldCFException("Interrupted: " + e.getMessage(), e,
+                        ManifoldCFException.INTERRUPTED);
+            } catch (RemoteException e) {
+                Throwable e2 = e.getCause();
+                if (e2 instanceof InterruptedException
+                        || e2 instanceof InterruptedIOException) {
+                    throw new ManifoldCFException(e2.getMessage(), e2,
+                            ManifoldCFException.INTERRUPTED);
+                }
+                session = null;
+                lastSessionFetch = -1L;
+                // Treat this as a transient problem
+                Logging.connectors.warn(
+                        "GOOGLEDRIVE: Transient remote exception closing session: "
+                        + e.getMessage(), e);
+            }
+
+        }
+    }
+
+    /**
+     * Get the maximum number of documents to amalgamate together into one
+     * batch, for this connector.
+     *
+     * @return the maximum number. 0 indicates "unlimited".
+     */
+    @Override
+    public int getMaxDocumentRequest() {
+        return 1;
+    }
+
+    /**
+     * Return the list of relationship types that this connector recognizes.
+     *
+     * @return the list.
+     */
+    @Override
+    public String[] getRelationshipTypes() {
+        return new String[]{RELATIONSHIP_CHILD};
+    }
+
+    /**
+     * Fill in a Server tab configuration parameter map for calling a Velocity
+     * template.
+     *
+     * @param newMap is the map to fill in
+     * @param parameters is the current set of configuration parameters
+     */
+    private static void fillInServerConfigurationMap(Map<String, String> newMap, ConfigParams parameters) {
+        String clientid = parameters.getParameter(GoogleDriveConfig.CLIENT_ID_PARAM);
+        String clientsecret = parameters.getParameter(GoogleDriveConfig.CLIENT_SECRET_PARAM);
+        String refreshtoken = parameters.getParameter(GoogleDriveConfig.REFRESH_TOKEN_PARAM);
+
+        if (clientid == null) {
+            clientid = StringUtils.EMPTY;
+        }
+        if (clientsecret == null) {
+            clientsecret = StringUtils.EMPTY;
+        }
+
+
+        if (refreshtoken == null) {
+            refreshtoken = StringUtils.EMPTY;
+        }
+
+        newMap.put(GoogleDriveConfig.CLIENT_ID_PARAM, clientid);
+        newMap.put(GoogleDriveConfig.CLIENT_SECRET_PARAM, clientsecret);
+        newMap.put(GoogleDriveConfig.REFRESH_TOKEN_PARAM, refreshtoken);
+    }
+
+    /**
+     * View configuration. This method is called in the body section of the
+     * connector's view configuration page. Its purpose is to present the
+     * connection information to the user. The coder can presume that the HTML
+     * that is output from this configuration will be within appropriate <html>
+     * and <body> tags.
+     *
+     * @param threadContext is the local thread context.
+     * @param out is the output to which any HTML should be sent.
+     * @param parameters are the configuration parameters, as they currently
+     * exist, for this connection being configured.
+     */
+    @Override
+    public void viewConfiguration(IThreadContext threadContext, IHTTPOutput out,
+            Locale locale, ConfigParams parameters) throws ManifoldCFException, IOException {
+        Map<String, String> paramMap = new HashMap<String, String>();
+
+        // Fill in map from each tab
+        fillInServerConfigurationMap(paramMap, parameters);
+
+        outputResource(VIEW_CONFIG_FORWARD, out, locale, paramMap);
+    }
+
+    /**
+     * Read the content of a resource, replace the variable ${PARAMNAME} with
+     * the value and copy it to the out.
+     *
+     * @param resName
+     * @param out
+     * @throws ManifoldCFException
+     */
+    private static void outputResource(String resName, IHTTPOutput out,
+            Locale locale, Map<String, String> paramMap) throws ManifoldCFException {
+        Messages.outputResourceWithVelocity(out, locale, resName, paramMap, true);
+    }
+
+    /**
+     *
+     * Output the configuration header section. This method is called in the
+     * head section of the connector's configuration page. Its purpose is to add
+     * the required tabs to the list, and to output any javascript methods that
+     * might be needed by the configuration editing HTML.
+     *
+     * @param threadContext is the local thread context.
+     * @param out is the output to which any HTML should be sent.
+     * @param parameters are the configuration parameters, as they currently
+     * exist, for this connection being configured.
+     * @param tabsArray is an array of tab names. Add to this array any tab
+     * names that are specific to the connector.
+     */
+    @Override
+    public void outputConfigurationHeader(IThreadContext threadContext,
+            IHTTPOutput out, Locale locale, ConfigParams parameters, List<String> tabsArray)
+            throws ManifoldCFException, IOException {
+        // Add the Server tab
+        tabsArray.add(Messages.getString(locale, GOOGLEDRIVE_SERVER_TAB_PROPERTY));
+        // Map the parameters
+        Map<String, String> paramMap = new HashMap<String, String>();
+
+        // Fill in the parameters from each tab
+        fillInServerConfigurationMap(paramMap, parameters);
+
+        // Output the Javascript - only one Velocity template for all tabs
+        outputResource(EDIT_CONFIG_HEADER_FORWARD, out, locale, paramMap);
+    }
+
+    @Override
+    public void outputConfigurationBody(IThreadContext threadContext,
+            IHTTPOutput out, Locale locale, ConfigParams parameters, String tabName)
+            throws ManifoldCFException, IOException {
+
+        // Call the Velocity templates for each tab
+
+        // Server tab
+        Map<String, String> paramMap = new HashMap<String, String>();
+        // Set the tab name
+        paramMap.put("TabName", tabName);
+        // Fill in the parameters
+        fillInServerConfigurationMap(paramMap, parameters);
+        outputResource(EDIT_CONFIG_FORWARD_SERVER, out, locale, paramMap);
+
+    }
+
+    /**
+     * Process a configuration post. This method is called at the start of the
+     * connector's configuration page, whenever there is a possibility that form
+     * data for a connection has been posted. Its purpose is to gather form
+     * information and modify the configuration parameters accordingly. The name
+     * of the posted form is "editconnection".
+     *
+     * @param threadContext is the local thread context.
+     * @param variableContext is the set of variables available from the post,
+     * including binary file post information.
+     * @param parameters are the configuration parameters, as they currently
+     * exist, for this connection being configured.
+     * @return null if all is well, or a string error message if there is an
+     * error that should prevent saving of the connection (and cause a
+     * redirection to an error page).
+     *
+     */
+    @Override
+    public String processConfigurationPost(IThreadContext threadContext,
+            IPostParameters variableContext, ConfigParams parameters)
+            throws ManifoldCFException {
+
+        String clientid = variableContext.getParameter(GoogleDriveConfig.CLIENT_ID_PARAM);
+        if (clientid != null) {
+            parameters.setParameter(GoogleDriveConfig.CLIENT_ID_PARAM, clientid);
+        }
+
+        String clientsecret = variableContext.getParameter(GoogleDriveConfig.CLIENT_SECRET_PARAM);
+        if (clientsecret != null) {
+            parameters.setParameter(GoogleDriveConfig.CLIENT_SECRET_PARAM, clientsecret);
+        }
+
+        String refreshtoken = variableContext.getParameter(GoogleDriveConfig.REFRESH_TOKEN_PARAM);
+        if (refreshtoken != null) {
+            parameters.setParameter(GoogleDriveConfig.REFRESH_TOKEN_PARAM, refreshtoken);
+        }
+
+        return null;
+    }
+
+    /**
+     * Fill in specification Velocity parameter map for GOOGLEDRIVEQuery tab.
+     */
+    private static void fillInGOOGLEDRIVEQuerySpecificationMap(Map<String, String> newMap, DocumentSpecification ds) {
+        int i = 0;
+        String GoogleDriveQuery = GoogleDriveConfig.GOOGLEDRIVE_QUERY_DEFAULT;
+        while (i < ds.getChildCount()) {
+            SpecificationNode sn = ds.getChild(i);
+            if (sn.getType().equals(JOB_STARTPOINT_NODE_TYPE)) {
+                GoogleDriveQuery = sn.getAttributeValue(GoogleDriveConfig.GOOGLEDRIVE_QUERY_PARAM);
+            }
+            i++;
+        }
+        newMap.put(GoogleDriveConfig.GOOGLEDRIVE_QUERY_PARAM, GoogleDriveQuery);
+    }
+
+    /**
+     * View specification. This method is called in the body section of a job's
+     * view page. Its purpose is to present the document specification
+     * information to the user. The coder can presume that the HTML that is
+     * output from this configuration will be within appropriate <html> and
+     * <body> tags.
+     *
+     * @param out is the output to which any HTML should be sent.
+     * @param ds is the current document specification for this job.
+     */
+    @Override
+    public void viewSpecification(IHTTPOutput out, Locale locale, DocumentSpecification ds)
+            throws ManifoldCFException, IOException {
+
+        Map<String, String> paramMap = new HashMap<String, String>();
+
+        // Fill in the map with data from all tabs
+        fillInGOOGLEDRIVEQuerySpecificationMap(paramMap, ds);
+
+        outputResource(VIEW_SPEC_FORWARD, out, locale, paramMap);
+    }
+
+    /**
+     * Process a specification post. This method is called at the start of job's
+     * edit or view page, whenever there is a possibility that form data for a
+     * connection has been posted. Its purpose is to gather form information and
+     * modify the document specification accordingly. The name of the posted
+     * form is "editjob".
+     *
+     * @param variableContext contains the post data, including binary
+     * file-upload information.
+     * @param ds is the current document specification for this job.
+     * @return null if all is well, or a string error message if there is an
+     * error that should prevent saving of the job (and cause a redirection to
+     * an error page).
+     */
+    @Override
+    public String processSpecificationPost(IPostParameters variableContext,
+            DocumentSpecification ds) throws ManifoldCFException {
+        String cmisQuery = variableContext.getParameter(GoogleDriveConfig.GOOGLEDRIVE_QUERY_PARAM);
+        if (cmisQuery != null) {
+            int i = 0;
+            while (i < ds.getChildCount()) {
+                SpecificationNode oldNode = ds.getChild(i);
+                if (oldNode.getType().equals(JOB_STARTPOINT_NODE_TYPE)) {
+                    ds.removeChild(i);
+                    break;
+                }
+                i++;
+            }
+            SpecificationNode node = new SpecificationNode(JOB_STARTPOINT_NODE_TYPE);
+            node.setAttribute(GoogleDriveConfig.GOOGLEDRIVE_QUERY_PARAM, cmisQuery);
+            variableContext.setParameter(GoogleDriveConfig.GOOGLEDRIVE_QUERY_PARAM, cmisQuery);
+            ds.addChild(ds.getChildCount(), node);
+        }
+        return null;
+    }
+
+    /**
+     * Output the specification body section. This method is called in the body
+     * section of a job page which has selected a repository connection of the
+     * current type. Its purpose is to present the required form elements for
+     * editing. The coder can presume that the HTML that is output from this
+     * configuration will be within appropriate <html>, <body>, and <form> tags.
+     * The name of the form is "editjob".
+     *
+     * @param out is the output to which any HTML should be sent.
+     * @param ds is the current document specification for this job.
+     * @param tabName is the current tab name.
+     */
+    @Override
+    public void outputSpecificationBody(IHTTPOutput out,
+            Locale locale, DocumentSpecification ds, String tabName) throws ManifoldCFException,
+            IOException {
+
+        // Output GOOGLEDRIVEQuery tab
+        Map<String, String> paramMap = new HashMap<String, String>();
+        paramMap.put("TabName", tabName);
+        fillInGOOGLEDRIVEQuerySpecificationMap(paramMap, ds);
+        outputResource(EDIT_SPEC_FORWARD_GOOGLEDRIVEQUERY, out, locale, paramMap);
+    }
+
+    /**
+     * Output the specification header section. This method is called in the
+     * head section of a job page which has selected a repository connection of
+     * the current type. Its purpose is to add the required tabs to the list,
+     * and to output any javascript methods that might be needed by the job
+     * editing HTML.
+     *
+     * @param out is the output to which any HTML should be sent.
+     * @param ds is the current document specification for this job.
+     * @param tabsArray is an array of tab names. Add to this array any tab
+     * names that are specific to the connector.
+     */
+    @Override
+    public void outputSpecificationHeader(IHTTPOutput out,
+            Locale locale, DocumentSpecification ds, List<String> tabsArray)
+            throws ManifoldCFException, IOException {
+        tabsArray.add(Messages.getString(locale, GOOGLEDRIVE_QUERY_TAB_PROPERTY));
+
+        Map<String, String> paramMap = new HashMap<String, String>();
+
+        // Fill in the specification header map, using data from all tabs.
+        fillInGOOGLEDRIVEQuerySpecificationMap(paramMap, ds);
+
+        outputResource(EDIT_SPEC_HEADER_FORWARD, out, locale, paramMap);
+    }
+
+    /**
+     * Queue "seed" documents. Seed documents are the starting places for
+     * crawling activity. Documents are seeded when this method calls
+     * appropriate methods in the passed in ISeedingActivity object.
+     *
+     * This method can choose to find repository changes that happen only during
+     * the specified time interval. The seeds recorded by this method will be
+     * viewed by the framework based on what the getConnectorModel() method
+     * returns.
+     *
+     * It is not a big problem if the connector chooses to create more seeds
+     * than are strictly necessary; it is merely a question of overall work
+     * required.
+     *
+     * The times passed to this method may be interpreted for greatest
+     * efficiency. The time ranges any given job uses with this connector will
+     * not overlap, but will proceed starting at 0 and going to the "current
+     * time", each time the job is run. For continuous crawling jobs, this
+     * method will be called once, when the job starts, and at various periodic
+     * intervals as the job executes.
+     *
+     * When a job's specification is changed, the framework automatically resets
+     * the seeding start time to 0. The seeding start time may also be set to 0
+     * on each job run, depending on the connector model returned by
+     * getConnectorModel().
+     *
+     * Note that it is always ok to send MORE documents rather than less to this
+     * method.
+     *
+     * @param activities is the interface this method should use to perform
+     * whatever framework actions are desired.
+     * @param spec is a document specification (that comes from the job).
+     * @param startTime is the beginning of the time range to consider,
+     * inclusive.
+     * @param endTime is the end of the time range to consider, exclusive.
+     * @param jobMode is an integer describing how the job is being run, whether
+     * continuous or once-only.
+     */
+    @Override
+    public void addSeedDocuments(ISeedingActivity activities,
+            DocumentSpecification spec, long startTime, long endTime, int jobMode)
+            throws ManifoldCFException, ServiceInterruption {
+
+        try {
+            getSession();
+            String googleDriveQuery = GoogleDriveConfig.GOOGLEDRIVE_QUERY_DEFAULT;
+            int i = 0;
+            while (i < spec.getChildCount()) {
+                SpecificationNode sn = spec.getChild(i);
+                if (sn.getType().equals(JOB_STARTPOINT_NODE_TYPE)) {
+                    googleDriveQuery = sn.getAttributeValue(GoogleDriveConfig.GOOGLEDRIVE_QUERY_PARAM);
+                    break;
+                }
+                i++;
+            }
+
+            //TODO handle different start directories, and save/retreive the cursor from somewhere..
+            HashSet<String> seeds = session.getSeeds(googleDriveQuery);
+            for (String seed : seeds) {
+                activities.addSeedDocument(seed);
+            }
+        } catch (Exception ex) {
+            Logging.connectors.error("GOOGLEDRIVE: Error adding seed documents: " + ex.getMessage(), ex);
+        }
+    }
+
+    /**
+     * Process a set of documents. This is the method that should cause each
+     * document to be fetched, processed, and the results either added to the
+     * queue of documents for the current job, and/or entered into the
+     * incremental ingestion manager. The document specification allows this
+     * class to filter what is done based on the job.
+     *
+     * @param documentIdentifiers is the set of document identifiers to process.
+     * @param versions is the corresponding document versions to process, as
+     * returned by getDocumentVersions() above. The implementation may choose to
+     * ignore this parameter and always process the current version.
+     * @param activities is the interface this method should use to queue up new
+     * document references and ingest documents.
+     * @param spec is the document specification.
+     * @param scanOnly is an array corresponding to the document identifiers. It
+     * is set to true to indicate when the processing should only find other
+     * references, and should not actually call the ingestion methods.
+     * @param jobMode is an integer describing how the job is being run, whether
+     * continuous or once-only.
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public void processDocuments(String[] documentIdentifiers, String[] versions,
+            IProcessActivity activities, DocumentSpecification spec,
+            boolean[] scanOnly) throws ManifoldCFException, ServiceInterruption {
+        getSession();
+        Logging.connectors.debug("GOOGLEDRIVE: Inside processDocuments");
+        int i = 0;
+
+        while (i < documentIdentifiers.length) {
+            try {
+                long startTime = System.currentTimeMillis();
+                String nodeId = documentIdentifiers[i];
+                if (Logging.connectors.isDebugEnabled()) {
+                    Logging.connectors.debug("GOOGLEDRIVE: Processing document identifier '"
+                            + nodeId + "'");
+                }
+
+                File googleFile = session.getObject(nodeId);
+
+                String errorCode = "OK";
+                String errorDesc = StringUtils.EMPTY;
+                if (googleFile.containsKey("explicitlyTrashed") && googleFile.getExplicitlyTrashed()) { //its deleted, move on
+                    continue;
+                }
+
+
+                if (Logging.connectors.isDebugEnabled()) {
+                    Logging.connectors.debug("GOOGLEDRIVE: have this file:\t" + googleFile.getTitle());
+                }
+
+                if ("application/vnd.google-apps.folder".equals(googleFile.getMimeType())) { //if directory add its children
+
+                    if (Logging.connectors.isDebugEnabled()) {
+                        Logging.connectors.debug("GOOGLEDRIVE: its a directory");
+                    }
+
+                    // adding all the children + subdirs for a folder
+
+                    List<String> children = session.getChildren(nodeId);
+                    for (String child : children) {
+                        activities.addDocumentReference(child, nodeId, RELATIONSHIP_CHILD);
+                    }
+
+                } else { // its a file
+                    InputStream is = null;
+                    long fileLength = 0;
+                    if (Logging.connectors.isDebugEnabled()) {
+                        Logging.connectors.debug("GOOGLEDRIVE: its a file");
+                    }
+                    //otherwise process
+
+                    try {
+                        RepositoryDocument rd = new RepositoryDocument();
+                        ByteArrayOutputStream os;
+                        String documentURI = session.getUrl(googleFile, "application/pdf");
+                        os = session.getGoogleDriveOutputStream(documentURI); // convert it to plain text..many other supported types
+                        byte[] contents = os.toByteArray();
+
+                        is = new ByteArrayInputStream(contents);
+                        fileLength = contents.length;
+                        //binary
+                        rd.setBinary(is, fileLength);
+
+                        for (Entry<String, Object> entry : googleFile.entrySet()) {
+                            rd.addField(entry.getKey(), entry.getValue().toString());
+                        }
+
+                        //ingestion
+
+                        String version = googleFile.getModifiedDate().toStringRfc3339();
+                        if (StringUtils.isEmpty(version)) {
+                            version = StringUtils.EMPTY;
+                        }
+
+                        //documentURI
+
+                        activities.ingestDocument(nodeId, version, documentURI, rd);
+                    } catch (Exception ex) {
+                        Logging.connectors.error("GOOGLEDRIVE: Error processing documents: " + ex.getMessage(), ex);
+                    } finally {
+                        try {
+                            if (is != null) {
+                                is.close();
+                            }
+                        } catch (InterruptedIOException e) {
+                            errorCode = "Interrupted error";
+                            errorDesc = e.getMessage();
+                            throw new ManifoldCFException(e.getMessage(), e,
+                                    ManifoldCFException.INTERRUPTED);
+                        } catch (IOException e) {
+                            errorCode = "IO ERROR";
+                            errorDesc = e.getMessage();
+                            Logging.connectors.warn(
+                                    "GOOGLEDRIVE: IOException closing file input stream: "
+                                    + e.getMessage(), e);
+                        }
+
+                        activities.recordActivity(new Long(startTime), ACTIVITY_READ,
+                                fileLength, nodeId, errorCode, errorDesc, null);
+                    }
+
+
+                }
+            } catch (Exception ex) {
+                Logging.connectors.error("GOOGLEDRIVE: Error processing documents 2: " + ex.getMessage(), ex);
+            }
+            i++;
+        }
+    }
+
+    /**
+     * The short version of getDocumentVersions. Get document versions given an
+     * array of document identifiers. This method is called for EVERY document
+     * that is considered. It is therefore important to perform as little work
+     * as possible here.
+     *
+     * @param documentIdentifiers is the array of local document identifiers, as
+     * understood by this connector.
+     * @param spec is the current document specification for the current job. If
+     * there is a dependency on this specification, then the version string
+     * should include the pertinent data, so that reingestion will occur when
+     * the specification changes. This is primarily useful for metadata.
+     * @return the corresponding version strings, with null in the places where
+     * the document no longer exists. Empty version strings indicate that there
+     * is no versioning ability for the corresponding document, and the document
+     * will always be processed.
+     */
+    @Override
+    public String[] getDocumentVersions(String[] documentIdentifiers,
+            DocumentSpecification spec) throws ManifoldCFException,
+            ServiceInterruption {
+        getSession();
+        String[] rval = new String[documentIdentifiers.length];
+        int i = 0;
+        while (i < rval.length) {
+            try {
+                File googleFile = session.getObject(documentIdentifiers[i]);
+                if (!isDir(googleFile)) {
+                    //we have to check if this CMIS repository support versioning
+                    // or if the versioning is disabled for this content
+                    String rev = googleFile.getModifiedDate().toStringRfc3339();
+                    if (StringUtils.isNotEmpty(rev)) {
+                        rval[i] = rev;
+                    } else {
+                        //a CMIS document that doesn't contain versioning information will always be processed
+                        rval[i] = StringUtils.EMPTY;
+                    }
+                } else {
+                    //a CMIS folder will always be processed
+                    rval[i] = StringUtils.EMPTY;
+                }
+            } catch (Exception ex) {
+                Logging.connectors.error("GOOGLEDRIVE: Error getting document versions: " + ex.getMessage(), ex);
+            }
+            i++;
+        }
+        return rval;
+    }
+
+    private boolean isDir(File f) {
+        return f.getMimeType().compareToIgnoreCase("application/vnd.google-apps.folder") == 0;
+    }
+}

Added: manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/googledrive/GoogleDriveSession.java
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/googledrive/GoogleDriveSession.java?rev=1488171&view=auto
==============================================================================
--- manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/googledrive/GoogleDriveSession.java (added)
+++ manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/googledrive/GoogleDriveSession.java Fri May 31 11:26:21 2013
@@ -0,0 +1,125 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.apache.manifoldcf.crawler.connectors.googledrive;
+
+import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
+import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
+import com.google.api.client.googleapis.media.MediaHttpDownloader;
+import com.google.api.client.http.GenericUrl;
+import com.google.api.client.http.HttpTransport;
+import com.google.api.client.json.JsonFactory;
+import com.google.api.client.json.jackson2.JacksonFactory;
+import com.google.api.services.drive.Drive;
+import java.util.Map;
+
+
+
+import java.util.HashMap;
+import java.util.HashSet;
+import com.google.api.services.drive.model.File;
+import com.google.api.services.drive.model.FileList;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ *
+ * @author andrew
+ */
+public class GoogleDriveSession {
+
+    private static String APPNAME = "Searchbox Google drive Connector";
+    private Drive drive;
+    private static HttpTransport HTTP_TRANSPORT;
+    private static final JsonFactory JSON_FACTORY = new JacksonFactory();
+
+    GoogleDriveSession(Map<String, String> parameters) {
+        try {
+
+            HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
+            GoogleCredential credentials = new GoogleCredential.Builder().setClientSecrets(parameters.get("clientid"), parameters.get("clientsecret"))
+                    .setJsonFactory(JSON_FACTORY).setTransport(HTTP_TRANSPORT).build().setRefreshToken(parameters.get("refreshtoken"));
+
+            drive = new Drive.Builder(HTTP_TRANSPORT, JSON_FACTORY, credentials).setApplicationName(APPNAME).build();
+        } catch (Exception ex) {
+            Logger.getLogger(GoogleDriveSession.class.getName()).log(Level.SEVERE, null, ex);
+        }
+    }
+
+    public Map<String, String> getRepositoryInfo() throws IOException {
+        Map<String, String> info = new HashMap<String, String>();
+        info.put("Application Name", drive.getApplicationName());
+        info.put("Base URL", drive.getBaseUrl());
+        return info;
+    }
+
+    HashSet<String> getSeeds(String googleDriveQuery) throws IOException {
+        HashSet<String> ids = new HashSet<String>();
+        Drive.Files.List request;
+
+        request = drive.files().list().setQ(googleDriveQuery);
+
+        do {
+            try {
+                FileList files = request.execute();
+                for (File f : files.getItems()) {
+                    ids.add(f.getId());
+                }
+                request.setPageToken(files.getNextPageToken());
+            } catch (IOException e) {
+                System.out.println("An error occurred: " + e);
+                request.setPageToken(null);
+            }
+        } while (request.getPageToken() != null
+                && request.getPageToken().length() > 0);
+        return ids;
+    }
+
+    public File getObject(String id) throws IOException {
+        File file = drive.files().get(id).execute();
+        return file;
+    }
+
+    List<String> getChildren(String nodeId) throws IOException {
+        ArrayList<String> ids = new ArrayList<String>();
+        Drive.Files.List request = drive.files().list().setQ("'" + nodeId + "' in parents");
+
+        do {
+            try {
+                FileList files = request.execute();
+                for (File f : files.getItems()) {
+                    ids.add(f.getId());
+                }
+                request.setPageToken(files.getNextPageToken());
+            } catch (IOException e) {
+
+                request.setPageToken(null);
+            }
+        } while (request.getPageToken() != null
+                && request.getPageToken().length() > 0);
+        return ids;
+    }
+
+    String getUrl(File googleFile, String exportType) {
+        if (googleFile.containsKey("fileSize")) {
+            return googleFile.getDownloadUrl();
+        } else {
+            return googleFile.getExportLinks().get(exportType);
+        }
+    }
+
+    ByteArrayOutputStream getGoogleDriveOutputStream(String documentURI) throws IOException {
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+
+        MediaHttpDownloader downloader =
+                new MediaHttpDownloader(HTTP_TRANSPORT, drive.getRequestFactory().getInitializer());
+        downloader.setDirectDownloadEnabled(false);
+        downloader.download(new GenericUrl(documentURI), outputStream);
+        return outputStream;
+    }
+}

Added: manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/googledrive/Messages.java
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/googledrive/Messages.java?rev=1488171&view=auto
==============================================================================
--- manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/googledrive/Messages.java (added)
+++ manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/googledrive/Messages.java Fri May 31 11:26:21 2013
@@ -0,0 +1,141 @@
+/* $Id: Messages.java 1295926 2012-03-01 21:56:27Z kwright $ */
+
+/**
+* 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.manifoldcf.crawler.connectors.googledrive;
+
+import java.util.Locale;
+import java.util.Map;
+import org.apache.manifoldcf.core.interfaces.ManifoldCFException;
+import org.apache.manifoldcf.core.interfaces.IHTTPOutput;
+
+public class Messages extends org.apache.manifoldcf.ui.i18n.Messages
+{
+  public static final String DEFAULT_BUNDLE_NAME="org.apache.manifoldcf.crawler.connectors.googledrive.common";
+  public static final String DEFAULT_PATH_NAME="org.apache.manifoldcf.crawler.connectors.googledrive";
+  
+  /** Constructor - do no instantiate
+  */
+  protected Messages()
+  {
+  }
+  
+  public static String getString(Locale locale, String messageKey)
+  {
+    return getString(DEFAULT_BUNDLE_NAME, locale, messageKey, null);
+  }
+
+  public static String getAttributeString(Locale locale, String messageKey)
+  {
+    return getAttributeString(DEFAULT_BUNDLE_NAME, locale, messageKey, null);
+  }
+
+  public static String getBodyString(Locale locale, String messageKey)
+  {
+    return getBodyString(DEFAULT_BUNDLE_NAME, locale, messageKey, null);
+  }
+
+  public static String getAttributeJavascriptString(Locale locale, String messageKey)
+  {
+    return getAttributeJavascriptString(DEFAULT_BUNDLE_NAME, locale, messageKey, null);
+  }
+
+  public static String getBodyJavascriptString(Locale locale, String messageKey)
+  {
+    return getBodyJavascriptString(DEFAULT_BUNDLE_NAME, locale, messageKey, null);
+  }
+
+  public static String getString(Locale locale, String messageKey, Object[] args)
+  {
+    return getString(DEFAULT_BUNDLE_NAME, locale, messageKey, args);
+  }
+
+  public static String getAttributeString(Locale locale, String messageKey, Object[] args)
+  {
+    return getAttributeString(DEFAULT_BUNDLE_NAME, locale, messageKey, args);
+  }
+  
+  public static String getBodyString(Locale locale, String messageKey, Object[] args)
+  {
+    return getBodyString(DEFAULT_BUNDLE_NAME, locale, messageKey, args);
+  }
+
+  public static String getAttributeJavascriptString(Locale locale, String messageKey, Object[] args)
+  {
+    return getAttributeJavascriptString(DEFAULT_BUNDLE_NAME, locale, messageKey, args);
+  }
+
+  public static String getBodyJavascriptString(Locale locale, String messageKey, Object[] args)
+  {
+    return getBodyJavascriptString(DEFAULT_BUNDLE_NAME, locale, messageKey, args);
+  }
+
+  // More general methods which allow bundlenames and class loaders to be specified.
+  
+  public static String getString(String bundleName, Locale locale, String messageKey, Object[] args)
+  {
+    return getString(Messages.class, bundleName, locale, messageKey, args);
+  }
+
+  public static String getAttributeString(String bundleName, Locale locale, String messageKey, Object[] args)
+  {
+    return getAttributeString(Messages.class, bundleName, locale, messageKey, args);
+  }
+
+  public static String getBodyString(String bundleName, Locale locale, String messageKey, Object[] args)
+  {
+    return getBodyString(Messages.class, bundleName, locale, messageKey, args);
+  }
+  
+  public static String getAttributeJavascriptString(String bundleName, Locale locale, String messageKey, Object[] args)
+  {
+    return getAttributeJavascriptString(Messages.class, bundleName, locale, messageKey, args);
+  }
+
+  public static String getBodyJavascriptString(String bundleName, Locale locale, String messageKey, Object[] args)
+  {
+    return getBodyJavascriptString(Messages.class, bundleName, locale, messageKey, args);
+  }
+
+  // Resource output
+  
+  public static void outputResource(IHTTPOutput output, Locale locale, String resourceKey,
+    Map<String,String> substitutionParameters, boolean mapToUpperCase)
+    throws ManifoldCFException
+  {
+    outputResource(output,Messages.class,DEFAULT_PATH_NAME,locale,resourceKey,
+      substitutionParameters,mapToUpperCase);
+  }
+  
+  public static void outputResourceWithVelocity(IHTTPOutput output, Locale locale, String resourceKey,
+    Map<String,String> substitutionParameters, boolean mapToUpperCase)
+    throws ManifoldCFException
+  {
+    outputResourceWithVelocity(output,Messages.class,DEFAULT_BUNDLE_NAME,DEFAULT_PATH_NAME,locale,resourceKey,
+      substitutionParameters,mapToUpperCase);
+  }
+
+  public static void outputResourceWithVelocity(IHTTPOutput output, Locale locale, String resourceKey,
+    Map<String,Object> contextObjects)
+    throws ManifoldCFException
+  {
+    outputResourceWithVelocity(output,Messages.class,DEFAULT_BUNDLE_NAME,DEFAULT_PATH_NAME,locale,resourceKey,
+      contextObjects);
+  }
+  
+}
+

Added: manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/native2ascii/org/apache/manifoldcf/crawler/connectors/googledrive/common_en_US.properties
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/native2ascii/org/apache/manifoldcf/crawler/connectors/googledrive/common_en_US.properties?rev=1488171&view=auto
==============================================================================
--- manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/native2ascii/org/apache/manifoldcf/crawler/connectors/googledrive/common_en_US.properties (added)
+++ manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/native2ascii/org/apache/manifoldcf/crawler/connectors/googledrive/common_en_US.properties Fri May 31 11:26:21 2013
@@ -0,0 +1,20 @@
+GoogleDriveRepositoryConnector.Server=Server
+
+
+GoogleDriveRepositoryConnector.RefreshToken=RefreshToken:
+GoogleDriveRepositoryConnector.ClientID=Client ID:
+GoogleDriveRepositoryConnector.ClientSecret=Client Secret ID:
+
+
+GoogleDriveRepositoryConnector.RefreshTokenMustNotBeNull=Refresh Token must not be null
+GoogleDriveRepositoryConnector.ClientSecretMustNotBeNull=Client Secret must not be null
+GoogleDriveRepositoryConnector.ClientMustNotBeNull=Client must not be null
+
+
+GoogleDriveRepositoryConnector.GoogleDriveQuery=Google Drive Seed Query
+GoogleDriveRepositoryConnector.GoogleDriveQueryColon=Google Drive Seed Query:
+
+GoogleDriveRepositoryConnector.ParametersColon=Parameters:
+GoogleDriveRepositoryConnector.UsernameEquals=username=
+GoogleDriveRepositoryConnector.PasswordEquals=password=
+

Added: manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/googledrive/common_en_US.properties
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/googledrive/common_en_US.properties?rev=1488171&view=auto
==============================================================================
--- manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/googledrive/common_en_US.properties (added)
+++ manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/googledrive/common_en_US.properties Fri May 31 11:26:21 2013
@@ -0,0 +1,20 @@
+GoogleDriveRepositoryConnector.Server=Server
+
+
+GoogleDriveRepositoryConnector.RefreshToken=RefreshToken:
+GoogleDriveRepositoryConnector.ClientID=Client ID:
+GoogleDriveRepositoryConnector.ClientSecret=Client Secret ID:
+
+
+GoogleDriveRepositoryConnector.RefreshTokenMustNotBeNull=Refresh Token must not be null
+GoogleDriveRepositoryConnector.ClientSecretMustNotBeNull=Client Secret must not be null
+GoogleDriveRepositoryConnector.ClientMustNotBeNull=Client must not be null
+
+
+GoogleDriveRepositoryConnector.GoogleDriveQuery=Google Drive Seed Query
+GoogleDriveRepositoryConnector.GoogleDriveQueryColon=Google Drive Seed Query:
+
+GoogleDriveRepositoryConnector.ParametersColon=Parameters:
+GoogleDriveRepositoryConnector.UsernameEquals=username=
+GoogleDriveRepositoryConnector.PasswordEquals=password=
+

Added: manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/googledrive/editConfiguration_google_server.html
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/googledrive/editConfiguration_google_server.html?rev=1488171&view=auto
==============================================================================
--- manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/googledrive/editConfiguration_google_server.html (added)
+++ manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/googledrive/editConfiguration_google_server.html Fri May 31 11:26:21 2013
@@ -0,0 +1,64 @@
+<!--
+ 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.
+-->
+
+#if($TABNAME == $ResourceBundle.getString('GoogleDriveRepositoryConnector.Server'))
+
+<table class="displaytable">
+  <tr>
+    <td class="separator" colspan="2">
+      <hr />
+    </td>
+  </tr>
+  <tr>
+    <td class="description">
+      <nobr>
+        $Encoder.bodyEscape($ResourceBundle.getString('GoogleDriveRepositoryConnector.RefreshToken'))
+      </nobr>
+    </td>
+    <td class="value">
+      <input type="text" id="refreshtoken" name="refreshtoken" value="$Encoder.attributeEscape($REFRESHTOKEN)" />
+    </td>
+  </tr>
+  <tr>
+    <td class="description">
+      <nobr>
+        $Encoder.bodyEscape($ResourceBundle.getString('GoogleDriveRepositoryConnector.ClientID'))
+      </nobr>
+    </td>
+    <td class="value">
+      <input type="text" id="clientid" name="clientid" value="$Encoder.attributeEscape($CLIENTID)" />
+    </td>
+  </tr>
+  <tr>
+    <td class="description">
+      <nobr>
+        $Encoder.bodyEscape($ResourceBundle.getString('GoogleDriveRepositoryConnector.ClientSecret'))
+      </nobr>
+    </td>
+    <td class="value">
+      <input type="text" id="clientsecret" name="clientsecret" value="$Encoder.attributeEscape($CLIENTSECRET)" />
+    </td>
+  </tr>
+</table>
+
+#else
+
+<input type="hidden" name="clientid" value="$Encoder.attributeEscape($CLIENTID)" />
+<input type="hidden" name="clientsecret" value="$Encoder.attributeEscape($CLIENTSECRET)" />
+<input type="hidden" name="refreshtoken" value="$Encoder.attributeEscape($REFRESHTOKEN)" />
+
+#end

Added: manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/googledrive/editConfiguration_google_server.js
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/googledrive/editConfiguration_google_server.js?rev=1488171&view=auto
==============================================================================
--- manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/googledrive/editConfiguration_google_server.js (added)
+++ manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/googledrive/editConfiguration_google_server.js Fri May 31 11:26:21 2013
@@ -0,0 +1,52 @@
+<!--
+ 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.
+-->
+
+<script type="text/javascript">
+<!--
+function checkConfig()
+{
+  return true;
+}
+ 
+function checkConfigForSave()
+{
+    
+  if (editconnection.refreshtoken.value == "")
+  {
+    alert("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('GoogleDriveRepositoryConnector.RefreshTokenMustNotBeNull'))");
+    SelectTab("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('GoogleDriveRepositoryConnector.Server'))");
+    editconnection.jsonauth.focus();
+    return false;
+  }
+  if (editconnection.clientid.value == "")
+  {
+    alert("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('GoogleDriveRepositoryConnector.ClientMustNotBeNull'))");
+    SelectTab("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('GoogleDriveRepositoryConnector.Server'))");
+    editconnection.key.focus();
+    return false;
+  }
+  if (editconnection.clientsecret.value == "")
+  {
+    alert("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('GoogleDriveRepositoryConnector.ClientSecretMustNotBeNull'))");
+    SelectTab("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('GoogleDriveRepositoryConnector.Server'))");
+    editconnection.secret.focus();
+    return false;
+  }
+  return true;
+}
+//-->
+</script>
\ No newline at end of file

Added: manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/googledrive/editSpecification_googledrive.js
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/googledrive/editSpecification_googledrive.js?rev=1488171&view=auto
==============================================================================
--- manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/googledrive/editSpecification_googledrive.js (added)
+++ manifoldcf/branches/CONNECTORS-694/connectors/googledrive/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/googledrive/editSpecification_googledrive.js Fri May 31 11:26:21 2013
@@ -0,0 +1,32 @@
+<!--
+ 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.
+-->
+
+<script type="text/javascript">
+<!--
+function checkSpecification()
+{
+  // Does nothing right now.
+  return true;
+}
+ 
+function SpecOp(n, opValue, anchorvalue)
+{
+  eval("editjob."+n+".value = \""+opValue+"\"");
+  postFormSetAnchor(anchorvalue);
+}
+//-->
+</script>
\ No newline at end of file