/*
* Copyright 2014 Loic Merckel
* Copyright (c) 2013 Google Inc.
*
* 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.
*/
/*
*
* The original version of this file (i.e., the one that is copyrighted 2013 Google Inc.)
* can be found here:
*
* https://code.google.com/p/google-api-java-client/source/browse/drive-cmdline-sample/src/main/java/com/google/api/services/samples/drive/cmdline/DriveSample.java?repo=samples
*
*/
package io.uploader.drive;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import io.uploader.drive.auth.DriveUploaderAuthorizationCodeInstalledApp;
import io.uploader.drive.auth.webbrowser.Browser;
import io.uploader.drive.auth.webbrowser.SimpleBrowserImpl;
import io.uploader.drive.config.Configuration;
import io.uploader.drive.config.auth.AuthenticationSettingsImpl;
import io.uploader.drive.gui.MainWindow;
import io.uploader.drive.gui.dlg.MessageDialogs;
import io.uploader.drive.gui.dlg.MessageDialogs.Response;
import io.uploader.drive.util.Callback;
import io.uploader.drive.util.ObserverService;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import org.apache.commons.configuration.ConfigurationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.extensions.java6.auth.oauth2.VerificationCodeReceiver;
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
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.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.util.store.DataStoreFactory;
import com.google.api.client.util.store.FileDataStoreFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.DriveScopes;
import com.google.common.base.Preconditions;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.concurrent.WorkerStateEvent;
import javafx.event.EventHandler;
import javafx.scene.image.Image;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
public class DriveUploader extends Application {
private static final Logger logger = LoggerFactory.getLogger(DriveUploader.class);
private static final boolean activateNativeLookAndFeelForMacOs = true ;
public static boolean isMacOsX ()
{
if (!activateNativeLookAndFeelForMacOs) {
return false ;
}
String os = System.getProperty("os.name") ;
return (os != null && os.toLowerCase().contains("mac")) ;
}
/**
* Be sure to specify the name of your application. If the application name
* is {@code null} or blank, the application will log a warning. Suggested
* format is "MyCompany-ProductName/1.0".
*/
private static final String APPLICATION_NAME = Configuration.INSTANCE.getAppName() ;
/** Directory to store user credentials. */
private static final java.io.File DATA_STORE_DIR = new java.io.File(Configuration.INSTANCE.getDataStoreDirectory());
/**
* Global instance of the {@link DataStoreFactory}. The best practice is to
* make it a single globally shared instance across your application.
*/
private static FileDataStoreFactory dataStoreFactory;
/** Global instance of the JSON factory. */
private static final JsonFactory JSON_FACTORY = JacksonFactory
.getDefaultInstance();
/** Global instance of the HTTP transport. */
private static HttpTransport httpTransport;
private static Drive client;
private static final AppEvent appEvent = new AppEvent () ;
public static void main(String[] args) {
if (isMacOsX ())
{
System.setProperty("apple.laf.useScreenMenuBar", "true");
System.setProperty("com.apple.mrj.application.apple.menu.about.name", Configuration.INSTANCE.getAppName());
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) {
logger.error("Error occurred while initializing the UI", e);
}
}
Platform.setImplicitExit(false);
// load the settings
String settingsFile = "driveuploader-settings.xml" ;
if (!new java.io.File (settingsFile).exists())
settingsFile = null ;
try {
Configuration.INSTANCE.load(settingsFile);
} catch (ConfigurationException e) {
logger.error("Error occurred while initializing the configuration", e);
}
try {
// initialize the transport
httpTransport = GoogleNetHttpTransport.newTrustedTransport();
// initialize the data store factory
dataStoreFactory = new FileDataStoreFactory(DATA_STORE_DIR);
} catch (IOException e) {
logger.error("Error occurred while initializing the drive", e);
Platform.exit() ;
} catch (Throwable t) {
logger.error("Error occurred while initializing the drive", t);
Platform.exit() ;
}
launch(args);
}
private static void authorize(final Browser browser, final Callback<Credential> callback) {
try {
// load client secrets
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(
JSON_FACTORY,
new InputStreamReader(AuthenticationSettingsImpl.getClientSecretJson()));
if (clientSecrets.getDetails().getClientId().startsWith("Enter")
|| clientSecrets.getDetails().getClientSecret().startsWith("Enter ")) {
System.out
.println("Overwrite the src/main/resources/client_secrets.json file with the client secrets file "
+ "you downloaded from the Quickstart tool or manually enter your Client ID and Secret "
+ "from https://code.google.com/apis/console/?api=drive#project:94720202188 "
+ "into src/main/resources/client_secrets.json");
System.exit(1);
}
Configuration.INSTANCE.setAuthenticationSettingsImpl(new AuthenticationSettingsImpl (clientSecrets));
// Set up authorization code flow.
Set<String> scopes = new HashSet<String>();
scopes.add(DriveScopes.DRIVE);
// old api for large file support (where upload takes more than one hour)
scopes.add("https://docs.google.com/feeds") ;
final GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
httpTransport, JSON_FACTORY, clientSecrets, scopes)
.setDataStoreFactory(dataStoreFactory)
.setAccessType("offline").setApprovalPrompt("force").build();
// authorize
final VerificationCodeReceiver receiver = new LocalServerReceiver() ;
ObserverService<Credential> service = new ObserverService<Credential>() {
private volatile DriveUploaderAuthorizationCodeInstalledApp driveUploaderAuthorizationCodeInstalledApp = null ;
@Override
protected Task<Credential> createTask() {
Task<Credential> task = new Task<Credential>() {
@Override
protected Credential call() throws Exception {
driveUploaderAuthorizationCodeInstalledApp = new DriveUploaderAuthorizationCodeInstalledApp(
flow, receiver, browser) ;
Credential credential = driveUploaderAuthorizationCodeInstalledApp.authorize("user");
return credential;
}
};
return task ;
}
};
service.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
@Override
public void handle(WorkerStateEvent t) {
logger.info("Login success") ;
Credential ret = (Credential) t.getSource().getValue();
callback.onSuccess(ret);
}
});
appEvent.addObserver(service) ;
service.start();
} catch (Exception e) {
callback.onFailure(e) ;
}
}
@Override
public void stop() throws Exception {
logger.info("Stop!") ;
super.stop();
}
@Override
public void start(final Stage stage) throws Exception {
Preconditions.checkNotNull(stage) ;
try {
stage.onCloseRequestProperty().set(new EventHandler<WindowEvent>() {
public void handle(WindowEvent e) {
logger.info("Close request") ;
if (Response.NO == MessageDialogs.showConfirmDialog(stage, "Are you sure you want to close the application?", "Confirmation")) {
e.consume();
return ;
}
appEvent.exit () ;
Platform.exit ();
// TODO:
// Investigate why when we shutdown the authentication service
// before the end of the process, the app hangs after closing the main window...
// http://stackoverflow.com/questions/4425350/how-to-terminate-a-thread-blocking-on-socket-io-operation-instantly
//if (client == null) {
System.exit(0) ;
//}
}
});
final List<Integer> logoSizeList = Arrays.asList(16, 32, 64, 128, 256, 512) ;
final String logoNameBase = "DriveUploader" ;
final String logoNameExt = ".png" ;
for (Integer size : logoSizeList) {
StringBuilder logoName = new StringBuilder () ;
logoName.append(logoNameBase) ;
logoName.append(size) ;
logoName.append(logoNameExt) ;
Image logo = new Image(getClass().getResourceAsStream("/images/" + logoName)) ;
stage.getIcons().add(logo);
}
//final Browser browser = new SimpleBrowser (new Stage (), null) ;
final Browser browser = new SimpleBrowserImpl (stage, null) ;
authorize (browser, new Callback<Credential> () {
@Override
public void onSuccess(Credential result) {
logger.info("Received credential") ;
client = new Drive.Builder(httpTransport, JSON_FACTORY, result)
.setApplicationName(APPLICATION_NAME).build();
Configuration.INSTANCE.setCredential(result);
//browser.close () ;
try {
MainWindow mainWindow = new MainWindow (client, stage, appEvent, Configuration.INSTANCE) ;
mainWindow.show() ;
} catch (IOException e) {
logger.error("Error occurred while creating the main window", e) ;
Platform.exit() ;
}
}
@Override
public void onFailure(Throwable cause) {
logger.error("Error occurred while authenticating", cause) ;
Platform.exit() ;
}}) ;
}catch (Exception e) {
Platform.exit() ;
throw e ;
}
}
}