fr.acxio.tools.agia.google.GoogleDriveServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for fr.acxio.tools.agia.google.GoogleDriveServiceImpl.java

Source

package fr.acxio.tools.agia.google;

/*
 * Copyright 2014 Acxio
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;

import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
import com.google.api.client.extensions.java6.auth.oauth2.FileCredentialStore;
import com.google.api.client.extensions.java6.auth.oauth2.VerificationCodeReceiver;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.googleapis.media.MediaHttpUploader;
import com.google.api.client.http.FileContent;
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 com.google.api.services.drive.Drive.Children;
import com.google.api.services.drive.DriveScopes;
import com.google.api.services.drive.model.About;
import com.google.api.services.drive.model.ChildList;
import com.google.api.services.drive.model.ChildReference;
import com.google.api.services.drive.model.File;
import com.google.api.services.drive.model.ParentReference;
import com.google.api.services.drive.model.Property;
import com.google.api.services.drive.model.PropertyList;

public class GoogleDriveServiceImpl implements GoogleDriveService {

    private static final String FOLDER_MIMETYPE = "application/vnd.google-apps.folder";
    private static final String PATH_SPLIT_REGEX = "/";
    private static final Pattern PATH_EXTRACT_PATTERN = Pattern.compile("^(?:(.*)/)?([^/]*)$");

    private static final Logger LOGGER = LoggerFactory.getLogger(GoogleDriveServiceImpl.class);

    private HttpTransport httpTransport;
    private Drive drive;
    private static final JsonFactory JSON_FACTORY = new JacksonFactory();
    private static final String APPLICATION_NAME = "Acxio-AGIA.2";

    private Resource clientSecretsResource;
    private Resource userCredentialStoreResource;
    private VerificationCodeReceiver verificationCodeReceiver;
    private String user;

    private String rootFolderId = null;

    public Drive getDrive() {
        return drive;
    }

    public void setClientSecretsResource(Resource sClientSecretsResource) {
        clientSecretsResource = sClientSecretsResource;
    }

    public void setUserCredentialStoreResource(Resource sUserCredentialStoreResource) {
        userCredentialStoreResource = sUserCredentialStoreResource;
    }

    public void setVerificationCodeReceiver(VerificationCodeReceiver sVerificationCodeReceiver) {
        verificationCodeReceiver = sVerificationCodeReceiver;
    }

    public void setUser(String sUser) {
        user = sUser;
    }

    protected String getRootFolderID() throws IOException {
        if ((drive != null) && (rootFolderId == null)) {
            About aAbout = drive.about().get().execute();
            rootFolderId = aAbout.get("rootFolderId").toString();
        }
        return rootFolderId;
    }

    protected Credential authorize() throws GoogleException, GeneralSecurityException, IOException {
        // load client secrets
        GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY,
                clientSecretsResource.getInputStream());
        if (clientSecrets.getDetails().getClientId().startsWith("Enter")
                || clientSecrets.getDetails().getClientSecret().startsWith("Enter ")) {
            LOGGER.error("Enter Client ID and Secret from https://code.google.com/apis/console/?api=drive "
                    + "into " + clientSecretsResource.getFile().getAbsolutePath());
            throw new GoogleException("ClientSecrets not configured");
        }
        // set up file credential store
        FileCredentialStore credentialStore = new FileCredentialStore(userCredentialStoreResource.getFile(),
                JSON_FACTORY);
        // set up authorization code flow
        GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(httpTransport, JSON_FACTORY,
                clientSecrets, Collections.singleton(DriveScopes.DRIVE_FILE)).setCredentialStore(credentialStore)
                        .build();
        // authorize
        return new AuthorizationCodeInstalledApp(flow, verificationCodeReceiver).authorize(user);
    }

    @Override
    public void connect() throws GoogleException {
        try {
            httpTransport = GoogleNetHttpTransport.newTrustedTransport();
            Credential credential = authorize();
            drive = new Drive.Builder(httpTransport, JSON_FACTORY, credential).setApplicationName(APPLICATION_NAME)
                    .build();

        } catch (IOException e) {
            throw new GoogleException(e);
        } catch (GeneralSecurityException e) {
            throw new GoogleException(e);
        }
    }

    @Override
    public File createFile(String sName, java.io.File sFile, String sMimeType, Map<String, String> sProperties)
            throws IOException {
        File aResult = null;
        Matcher aPathMatcher = PATH_EXTRACT_PATTERN.matcher(sName);
        if (aPathMatcher.matches()) {
            String aPath = aPathMatcher.group(1);
            String aName = aPathMatcher.group(2);
            if ((aName == null) || aName.isEmpty()) {
                throw new IOException("Name is mandatory.");
            }
            String aParentID = getRootFolderID();
            if ((aPath != null) && !aPath.isEmpty()) {
                aParentID = createPath(aPath).getId();
            }
            aResult = createFile(aParentID, aName, sFile, sMimeType, sProperties);
        } else {
            throw new IOException("Name does not conform to paths syntax.");
        }
        return aResult;
    }

    @Override
    public File createFile(String sParentID, String sName, java.io.File sFile, String sMimeType,
            Map<String, String> sProperties) throws IOException {
        File aResult = null;
        if (drive != null) {
            File fileMetadata = new File();
            fileMetadata.setTitle(sName);
            ParentReference aParentReference = new ParentReference();
            aParentReference.setId(sParentID);
            fileMetadata.setParents(Arrays.asList(aParentReference));

            FileContent mediaContent = new FileContent(sMimeType, sFile);

            Drive.Files.Insert insert = drive.files().insert(fileMetadata, mediaContent);
            MediaHttpUploader uploader = insert.getMediaHttpUploader();
            uploader.setDirectUploadEnabled(false);
            aResult = insert.execute();

            setProperties(aResult.getId(), sProperties);
        }
        return aResult;
    }

    @Override
    public File getFileByPath(String sPath) throws IOException {
        File aResult = null;
        if (drive != null) {
            String[] aSubPaths = sPath.split(PATH_SPLIT_REGEX);
            String aParentID = getRootFolderID();
            if (aSubPaths.length > 0) {
                for (int i = 0; i < (aSubPaths.length - 1); i++) {
                    String aSubPath = aSubPaths[i];
                    if (!aSubPath.isEmpty()) {
                        ArrayList<File> aFiles = getChildrenFolders(aParentID, aSubPath);
                        if (aFiles.isEmpty()) {
                            throw new IOException("Folder '" + aSubPath + "' not found");
                        } else {
                            aResult = aFiles.get(0);
                        }
                        aParentID = aResult.getId();
                    }
                }
                String aSubPath = aSubPaths[aSubPaths.length - 1];
                if (!aSubPath.isEmpty()) {
                    ArrayList<File> aFiles = getChildren(aParentID, aSubPath);
                    if (aFiles.isEmpty()) {
                        throw new IOException("File '" + aSubPath + "' not found");
                    } else {
                        aResult = aFiles.get(0);
                    }
                }
            }
        }
        return aResult;
    }

    @Override
    public File createDirectory(String sName, Map<String, String> sProperties) throws IOException {
        File aResult = null;
        Matcher aPathMatcher = PATH_EXTRACT_PATTERN.matcher(sName);
        if (aPathMatcher.matches()) {
            String aPath = aPathMatcher.group(1);
            String aName = aPathMatcher.group(2);
            if ((aName == null) || aName.isEmpty()) {
                throw new IOException("Name is mandatory.");
            }
            String aParentID = getRootFolderID();
            if ((aPath != null) && !aPath.isEmpty()) {
                aParentID = createPath(aPath).getId();
            }
            aResult = createDirectory(aParentID, aName, sProperties);
        } else {
            throw new IOException("Name does not conform to paths syntax.");
        }

        return aResult;
    }

    @Override
    public File createDirectory(String sParentID, String sName, Map<String, String> sProperties)
            throws IOException {
        File aResult = null;
        if (drive != null) {
            File fileMetadata = new File();
            fileMetadata.setTitle(sName);
            fileMetadata.setMimeType(FOLDER_MIMETYPE);
            ParentReference aParentReference = new ParentReference();
            aParentReference.setId(sParentID);
            fileMetadata.setParents(Arrays.asList(aParentReference));

            Drive.Files.Insert insert = drive.files().insert(fileMetadata);
            aResult = insert.execute();

            setProperties(aResult.getId(), sProperties);
        }
        return aResult;
    }

    @Override
    public File createPath(String sPath) throws IOException {
        File aResult = null;
        if (drive != null) {
            String[] aSubPaths = sPath.split(PATH_SPLIT_REGEX);
            String aParentID = getRootFolderID();
            for (String aSubPath : aSubPaths) {
                if (!aSubPath.isEmpty()) {
                    ArrayList<File> aFiles = getChildrenFolders(aParentID, aSubPath);
                    if (aFiles.isEmpty()) {
                        aResult = createDirectory(aParentID, aSubPath, null);
                    } else {
                        aResult = aFiles.get(0);
                    }
                    aParentID = aResult.getId();
                }
            }
        }
        return aResult;
    }

    @Override
    public String getFolderId(String sPath) throws IOException {
        String aResult = null;
        if (drive != null) {
            String[] aSubPaths = sPath.split(PATH_SPLIT_REGEX);
            int aNbSubPaths = aSubPaths.length;
            int i = 0;
            String aParentID = getRootFolderID();
            while (i < aNbSubPaths) {
                if (!aSubPaths[i].isEmpty()) {
                    ArrayList<File> aFiles = getChildrenFolders(aParentID, aSubPaths[i]);
                    if (!aFiles.isEmpty()) {
                        aParentID = aFiles.get(0).getId();
                    } else {
                        throw new IOException("Folder '" + aSubPaths[i] + "' not found.");
                    }
                }
                i++;
            }
            aResult = (aNbSubPaths > 0) ? aParentID : null;
        }
        return aResult;
    }

    interface ChildrenFilter {
        public boolean isSelected(File sFile);
    }

    protected ArrayList<File> getChildrenFolders(String sFolderId, String sChildName) {
        final String aChildName = sChildName;
        return getChildren(sFolderId, new ChildrenFilter() {
            public boolean isSelected(File sFile) {
                boolean aResult = false;
                if (sFile != null) {
                    String fileExtension = sFile.getFileExtension();
                    String mimeType = sFile.getMimeType();
                    if (mimeType != null && FOLDER_MIMETYPE.equals(mimeType)
                            && (fileExtension == null || fileExtension.isEmpty())) {
                        aResult = ((aChildName == null) || (aChildName.equals(sFile.getTitle())));
                    }
                }
                return aResult;
            }
        });
    }

    protected ArrayList<File> getChildren(String sFolderId, String sChildName) {
        final String aChildName = sChildName;
        return getChildren(sFolderId, new ChildrenFilter() {
            public boolean isSelected(File sFile) {
                boolean aResult = false;
                if (sFile != null) {
                    aResult = ((aChildName == null) || (aChildName.equals(sFile.getTitle())));
                }
                return aResult;
            }
        });
    }

    protected ArrayList<File> getChildren(String sFolderId, ChildrenFilter sFilter) {
        ArrayList<File> aResult = new ArrayList<File>();
        Children.List request = null;
        boolean ok = true;
        do {
            try {
                request = drive.children().list(sFolderId).setMaxResults(200);
                ChildList files = request.execute();
                if (files != null) {
                    List<ChildReference> listChildReference = files.getItems();
                    for (ChildReference childReference : listChildReference) {
                        File file = drive.files().get(childReference.getId()).execute();
                        if (sFilter.isSelected(file)) {
                            aResult.add(file);
                        }
                    }
                    request.setPageToken(files.getNextPageToken());
                }
            } catch (IOException exception) {
                ok = false;
            }
        } while (ok && request.getPageToken() != null && request.getPageToken().length() > 0);

        return aResult;
    }

    protected void setProperties(String sNodeId, Map<String, String> sProperties) throws IOException {
        if ((sNodeId != null) && (!sNodeId.isEmpty()) && (sProperties != null)) {
            for (Entry<String, String> aKeyValue : sProperties.entrySet()) {
                Property newProperty = new Property();
                newProperty.setKey(aKeyValue.getKey());
                newProperty.setValue(aKeyValue.getValue());
                newProperty.setVisibility("PUBLIC");
                drive.properties().insert(sNodeId, newProperty).execute();
            }
        }
    }

    @Override
    public Map<String, String> getProperties(String sFileID) throws IOException {
        Map<String, String> aResult = new HashMap<String, String>(1);
        if ((sFileID != null) && (!sFileID.isEmpty())) {
            PropertyList properties = drive.properties().list(sFileID).execute();
            for (Property aProperty : properties.getItems()) {
                aResult.put(aProperty.getKey(), aProperty.getValue());
            }
        }
        return aResult;
    }
}