callback, Object... args) throws IOException {
+ for (NotificationProvider provider : providers) {
+ if (provider.getClass().getName().contains(matcher)) {
+ return provider.getNotification(callback, args);
+ }
+ }
+ throw new NoSuchElementException(matcher);
+ }
+}
+
+/* */
diff --git a/vavi-nio-file-commons/src/main/java/vavi/nio/file/watch/webhook/NotificationProvider.java b/vavi-nio-file-commons/src/main/java/vavi/nio/file/watch/webhook/NotificationProvider.java
new file mode 100644
index 00000000..e4a9aabb
--- /dev/null
+++ b/vavi-nio-file-commons/src/main/java/vavi/nio/file/watch/webhook/NotificationProvider.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.watch.webhook;
+
+import java.io.IOException;
+import java.util.function.Consumer;
+
+
+/**
+ * NotificationProvider.
+ *
+ * for example, ngrok provider.
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/07/07 umjammer initial version
+ */
+public interface NotificationProvider {
+
+ Notification getNotification(Consumer callback, Object... args) throws IOException;
+}
+
+/* */
diff --git a/vavi-nio-file-commons/src/main/java/vavi/nio/file/watch/webhook/WebHookBaseWatchService.java b/vavi-nio-file-commons/src/main/java/vavi/nio/file/watch/webhook/WebHookBaseWatchService.java
new file mode 100644
index 00000000..905a682a
--- /dev/null
+++ b/vavi-nio-file-commons/src/main/java/vavi/nio/file/watch/webhook/WebHookBaseWatchService.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.watch.webhook;
+
+import java.io.IOException;
+import java.nio.file.WatchEvent;
+import java.nio.file.WatchEvent.Kind;
+import java.nio.file.Watchable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.BiConsumer;
+
+import com.github.fge.filesystem.watch.AbstractWatchService;
+
+import vavi.util.Debug;
+
+
+/**
+ * WebHookBaseWatchService.
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/07/06 umjammer initial version
+ */
+public abstract class WebHookBaseWatchService extends AbstractWatchService {
+
+ /** */
+ private static Map> notifications = new HashMap<>();
+
+ static {
+ Runtime.getRuntime().addShutdownHook(new Thread(WebHookBaseWatchService::dispose));
+ }
+
+ /** */
+ protected static void setupNotification(WebHookBaseWatchService o, String matcher, Object... args) throws IOException {
+ if (!notifications.containsKey(matcher)) {
+ Notification notification = Notification.getNotification(matcher, n -> {
+ try {
+ o.onNotifyMessage(n);
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }, args);
+ notifications.put(matcher, notification);
+ }
+ }
+
+ /** call {@link #listener}.accept */
+ protected abstract void onNotifyMessage(T notification) throws IOException;
+
+ /** for the user watch service */
+ protected BiConsumer> listener = this::processNotification;
+
+ /** for the system watch service */
+ public void setNotificationListener(BiConsumer> listener) {
+ this.listener = listener;
+ }
+
+ /** for watchkey */
+ private void processNotification(String id, Kind> kind) {
+ for (BasicWatchKey watchKey : watchKeys) {
+ if (watchKey.subscribesTo(kind)) {
+ watchKey.signal();
+ }
+ }
+ }
+
+ /** TODO */
+ public static void dispose() {
+ notifications.values().forEach(notification -> {
+ try {
+ notification.close();
+Debug.println("NOIFICATION: notification closed: " + notification);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ });
+ notifications.clear();
+ }
+
+ /** */
+ private List watchKeys = new ArrayList<>();
+
+ // design error?
+ @Override
+ public BasicWatchKey register(Watchable watchable,
+ Iterable extends WatchEvent.Kind>> eventTypes,
+ WatchEvent.Modifier... modifiers) throws IOException {
+// if (eventTypes == null) {
+// throw new IllegalArgumentException("no eventTypes");
+// }
+ BasicWatchKey watchKey = super.register(watchable, eventTypes);
+ watchKeys.add(watchKey);
+ return watchKey;
+ }
+
+ @Override
+ public void cancelled(BasicWatchKey watchKey) {
+ watchKeys.remove(watchKey); // TODO ???
+ }
+}
diff --git a/vavi-nio-file-commons/src/main/java/vavi/nio/file/watch/webhook/websocket/BaseWebSocketNotification.java b/vavi-nio-file-commons/src/main/java/vavi/nio/file/watch/webhook/websocket/BaseWebSocketNotification.java
new file mode 100644
index 00000000..4113c268
--- /dev/null
+++ b/vavi-nio-file-commons/src/main/java/vavi/nio/file/watch/webhook/websocket/BaseWebSocketNotification.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.watch.webhook.websocket;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.websocket.ContainerProvider;
+import javax.websocket.DeploymentException;
+import javax.websocket.OnError;
+import javax.websocket.Session;
+import javax.websocket.WebSocketContainer;
+
+import vavi.nio.file.watch.webhook.Notification;
+import vavi.util.Debug;
+
+
+/**
+ * BaseWebSocketNotification.
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/07/26 umjammer initial version
+ */
+public abstract class BaseWebSocketNotification implements Notification {
+
+ /** */
+ private WebSocketContainer container = ContainerProvider.getWebSocketContainer();
+
+ /** websocket uri */
+ private URI uri;
+ /** */
+ protected Session session;
+ /** */
+ private AtomicBoolean reconnect = new AtomicBoolean(true);
+ /** */
+ private Throwable throwable;
+ /** */
+ protected Object[] args;
+
+ /** */
+ protected BaseWebSocketNotification(URI uri, Object... args) throws IOException {
+ this.uri = uri;
+ this.args = args;
+ try {
+ session = container.connectToServer(this, uri);
+ } catch (DeploymentException e) {
+ throw new IOException(e);
+ }
+ }
+
+ /** */
+ protected abstract void onOpenImpl(Session session) throws IOException;
+
+ /** */
+ protected abstract void onNotifyMessageImpl(T notification) throws IOException;
+
+ @OnError
+ public final void onError(Throwable t) {
+Debug.println("WEBSOCKET: onError");
+t.printStackTrace();
+ throwable = t;
+ }
+
+ /** */
+ protected abstract void onCloseImpl(Session session) throws IOException;
+
+ /** */
+ protected final void onCloseInternal(Session session) throws IOException {
+Debug.println("WEBSOCKET: onClose: " + session.getId());
+ onCloseImpl(session);
+
+ if (reconnect.get()) {
+ if (throwable == null) {
+ try {
+Debug.println("WEBSOCKET: reconnect");
+ this.session = container.connectToServer(this, uri);
+ } catch (DeploymentException e) {
+ throw new IOException(e);
+ }
+ } else {
+Debug.println("WEBSOCKET: has error, exit");
+ }
+ }
+ }
+
+ @Override
+ public final void close() throws IOException {
+ if (reconnect.getAndSet(false)) {
+ session.close();
+Debug.println("WEBSOCKET: close: " + session.getId());
+
+ // TODO encapsulate into jsr356
+ // https://stackoverflow.com/a/46472909/6102938
+ if (container != null && container instanceof org.eclipse.jetty.util.component.LifeCycle) {
+ try {
+Debug.println("WEBSOCKET: stopping jetty's websocket client");
+ ((org.eclipse.jetty.util.component.LifeCycle) container).stop();
+Debug.println("WEBSOCKET: jetty's websocket stopped: " + ((org.eclipse.jetty.util.component.LifeCycle) container).isStopped());
+ } catch (Exception e) {
+ throw new IOException(e);
+ }
+ }
+ }
+//Debug.println("close: exit: " + reconnect.get() + ", " + this.hashCode());
+ }
+}
+
+/* */
diff --git a/vavi-nio-file-commons/src/main/java/vavi/nio/file/watch/webhook/websocket/BasicAuthorizationConfigurator.java b/vavi-nio-file-commons/src/main/java/vavi/nio/file/watch/webhook/websocket/BasicAuthorizationConfigurator.java
new file mode 100644
index 00000000..9576017d
--- /dev/null
+++ b/vavi-nio-file-commons/src/main/java/vavi/nio/file/watch/webhook/websocket/BasicAuthorizationConfigurator.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.watch.webhook.websocket;
+
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.List;
+import java.util.Map;
+
+import javax.websocket.ClientEndpointConfig;
+
+
+/**
+ * BasicAuthorizationConfigurator.
+ *
+ * environment variables
+ *
+ * VAVI_APPS_WEBHOOK_USERNAME
+ * VAVI_APPS_WEBHOOK_PASSWORD
+ *
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/07/07 umjammer initial version
+ */
+public class BasicAuthorizationConfigurator extends ClientEndpointConfig.Configurator {
+
+ private static final String username = System.getenv("VAVI_APPS_WEBHOOK_USERNAME");
+ private static final String password = System.getenv("VAVI_APPS_WEBHOOK_PASSWORD");
+
+ @Override
+ public void beforeRequest(Map> headers) {
+ headers.put("Authorization", Arrays.asList("Basic " + Base64.getEncoder().encodeToString((username + ":" + password).getBytes())));
+ }
+}
+
+/* */
diff --git a/vavi-nio-file-commons/src/main/java/vavi/nio/file/watch/webhook/websocket/JsonCodec.java b/vavi-nio-file-commons/src/main/java/vavi/nio/file/watch/webhook/websocket/JsonCodec.java
new file mode 100644
index 00000000..9cf89ab1
--- /dev/null
+++ b/vavi-nio-file-commons/src/main/java/vavi/nio/file/watch/webhook/websocket/JsonCodec.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.watch.webhook.websocket;
+
+import java.io.InputStream;
+
+import javax.websocket.DecodeException;
+import javax.websocket.Decoder;
+import javax.websocket.EncodeException;
+import javax.websocket.Encoder;
+import javax.websocket.EndpointConfig;
+
+import com.google.gson.ExclusionStrategy;
+import com.google.gson.FieldAttributes;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonSyntaxException;
+
+
+/**
+ * JsonCodec.
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/07/02 umjammer initial version
+ */
+public abstract class JsonCodec {
+
+ protected static Gson gson = new GsonBuilder().addSerializationExclusionStrategy(new ExclusionStrategy() {
+ @Override
+ public boolean shouldSkipField(FieldAttributes f) {
+ return false;
+ }
+ @Override
+ public boolean shouldSkipClass(Class> clazz) {
+ return InputStream.class.equals(clazz);
+ }
+ }).create();
+
+ protected static abstract class JsonEncoder implements Encoder.Text {
+ @Override
+ public void init(EndpointConfig config) {
+ }
+
+ @Override
+ public String encode(T notification) throws EncodeException {
+ return gson.toJson(notification);
+ }
+
+ @Override
+ public void destroy() {
+ }
+ }
+
+ protected static abstract class JsonDecoder implements Decoder.Text {
+
+ protected abstract Class getType();
+
+ @Override
+ public void init(EndpointConfig config) {
+ }
+
+ @Override
+ public boolean willDecode(String s) {
+ try {
+ gson.fromJson(s, getType());
+ return true;
+ } catch (JsonSyntaxException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public T decode(String s) throws DecodeException {
+ try {
+ return gson.fromJson(s, getType());
+ } catch (JsonSyntaxException e) {
+ throw new DecodeException(s, e.getMessage(), e);
+ }
+ }
+
+ @Override
+ public void destroy() {
+ }
+ }
+}
+
+/* */
diff --git a/vavi-nio-file-commons/src/main/java/vavi/nio/file/watch/webhook/websocket/StringWebSocketNotification.java b/vavi-nio-file-commons/src/main/java/vavi/nio/file/watch/webhook/websocket/StringWebSocketNotification.java
new file mode 100644
index 00000000..c9c3273a
--- /dev/null
+++ b/vavi-nio-file-commons/src/main/java/vavi/nio/file/watch/webhook/websocket/StringWebSocketNotification.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.watch.webhook.websocket;
+
+import java.io.IOException;
+import java.net.URI;
+
+import javax.websocket.OnMessage;
+import javax.websocket.OnOpen;
+import javax.websocket.Session;
+
+import vavi.util.Debug;
+
+
+/**
+ * StringWebSocketNotification.
+ *
+ * https://stackoverflow.com/a/22090459/6102938
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/07/26 umjammer initial version
+ */
+public abstract class StringWebSocketNotification extends BaseWebSocketNotification {
+
+ /** */
+ protected StringWebSocketNotification(URI uri, Object... args) throws IOException {
+ super(uri, args);
+ }
+
+ @OnOpen
+ public final void onOpen(Session session) throws IOException {
+Debug.println("WEBSOCKET: onOpen: " + session.getId());
+ onOpenImpl(session);
+ }
+
+ @OnMessage
+ public final void onNotifyMessage(String notification, Session session) throws IOException {
+ onNotifyMessageImpl(notification);
+ }
+}
+
+/* */
diff --git a/vavi-nio-file-commons/src/main/java/vavi/nio/file/watch/webhook/websocket/WebSocketNotification.java b/vavi-nio-file-commons/src/main/java/vavi/nio/file/watch/webhook/websocket/WebSocketNotification.java
new file mode 100644
index 00000000..56cc755c
--- /dev/null
+++ b/vavi-nio-file-commons/src/main/java/vavi/nio/file/watch/webhook/websocket/WebSocketNotification.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.watch.webhook.websocket;
+
+import java.io.IOException;
+import java.net.URI;
+
+import javax.websocket.OnClose;
+import javax.websocket.OnMessage;
+import javax.websocket.OnOpen;
+import javax.websocket.Session;
+
+import vavi.util.Debug;
+
+
+/**
+ * WebSocketNotification.
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/07/06 umjammer initial version
+ */
+public abstract class WebSocketNotification extends BaseWebSocketNotification {
+
+ /** */
+ protected WebSocketNotification(URI uri, Object... args) throws IOException {
+ super(uri, args);
+ }
+
+ @OnOpen
+ public final void onOpen(Session session) throws IOException {
+Debug.println("WEBSOCKET: onOpen: " + session.getId());
+ onOpenImpl(session);
+ }
+
+ @OnMessage
+ public final void onNotifyMessage(T notification, Session session) throws IOException {
+ onNotifyMessageImpl(notification);
+ }
+
+ @OnClose
+ public final void onClose(Session session) throws IOException {
+ onCloseInternal(session);
+ }
+}
+
+/* */
diff --git a/vavi-nio-file-commons/src/test/resources/logging.properties b/vavi-nio-file-commons/src/test/resources/logging.properties
new file mode 100644
index 00000000..7d550e01
--- /dev/null
+++ b/vavi-nio-file-commons/src/test/resources/logging.properties
@@ -0,0 +1,14 @@
+handlers=java.util.logging.ConsoleHandler
+.level=INFO
+# Limit the message that are printed on the console to INFO and above.
+java.util.logging.ConsoleHandler.level=INFO
+#java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
+# %1:date/time %2:className and methodName %3logName %4:level %5:message %6:errormessage
+#java.util.logging.SimpleFormatter.format=%1$tY/%1$tm/%1$td %1$tH:%1$tM:%1$tS.%1$tL [%4$s] %5$s %6$s%n
+
+# HttpUrlConnection
+#java.util.logging.ConsoleHandler.level=FINEST
+#sun.net.www.protocol.http.HttpURLConnection.level=ALL
+
+java.util.logging.ConsoleHandler.formatter=vavi.util.logging.VaviFormatter
+#java.util.logging.ConsoleHandler.formatter=vavi.util.logging.BetterFormatter
diff --git a/vavi-nio-file-flickr/pom.xml b/vavi-nio-file-flickr/pom.xml
index ac8daae2..e1a48b79 100644
--- a/vavi-nio-file-flickr/pom.xml
+++ b/vavi-nio-file-flickr/pom.xml
@@ -5,7 +5,7 @@
vavi
vavi-apps-fuse
- 0.1.6
+ 0.1.7
vavi-nio-file-flickr
@@ -32,7 +32,7 @@
- com.github.umjammer.vavi-net-auth
+ ${vavi-net-auth.groupId}
vavi-net-auth-flickr
${vavi-net-auth.version}
diff --git a/vavi-nio-file-flickr/src/main/java/vavi/nio/file/flickr/FlickrBasicFileAttributesProvider.java b/vavi-nio-file-flickr/src/main/java/vavi/nio/file/flickr/FlickrBasicFileAttributesProvider.java
index d4bef1cc..e0ab9977 100644
--- a/vavi-nio-file-flickr/src/main/java/vavi/nio/file/flickr/FlickrBasicFileAttributesProvider.java
+++ b/vavi-nio-file-flickr/src/main/java/vavi/nio/file/flickr/FlickrBasicFileAttributesProvider.java
@@ -86,7 +86,7 @@ public boolean isDirectory() {
public long size() {
// TODO image size
try {
- return entry.getOriginalSize().getWidth() * entry.getOriginalSize().getHeight() * 4;
+ return entry.getOriginalSize().getWidth() * entry.getOriginalSize().getHeight() * 4L;
} catch (Exception e) {
e.printStackTrace();
return 0;
diff --git a/vavi-nio-file-flickr/src/main/java/vavi/nio/file/flickr/FlickrFileAttributesFactory.java b/vavi-nio-file-flickr/src/main/java/vavi/nio/file/flickr/FlickrFileAttributesFactory.java
index 960fabe2..4983c7e4 100644
--- a/vavi-nio-file-flickr/src/main/java/vavi/nio/file/flickr/FlickrFileAttributesFactory.java
+++ b/vavi-nio-file-flickr/src/main/java/vavi/nio/file/flickr/FlickrFileAttributesFactory.java
@@ -7,7 +7,7 @@
package vavi.nio.file.flickr;
import com.flickr4java.flickr.photos.Photo;
-import com.github.fge.filesystem.attributes.FileAttributesFactory;
+import com.github.fge.filesystem.driver.ExtendedFileSystemDriverBase.ExtendsdFileAttributesFactory;
/**
@@ -16,7 +16,7 @@
* @author Naohide Sano (umjammer)
* @version 0.00 2016/03/30 umjammer initial version
*/
-public final class FlickrFileAttributesFactory extends FileAttributesFactory {
+public final class FlickrFileAttributesFactory extends ExtendsdFileAttributesFactory {
public FlickrFileAttributesFactory() {
setMetadataClass(Photo.class);
diff --git a/vavi-nio-file-flickr/src/main/java/vavi/nio/file/flickr/FlickrFileSystemDriver.java b/vavi-nio-file-flickr/src/main/java/vavi/nio/file/flickr/FlickrFileSystemDriver.java
index 43074ee6..792acd67 100644
--- a/vavi-nio-file-flickr/src/main/java/vavi/nio/file/flickr/FlickrFileSystemDriver.java
+++ b/vavi-nio-file-flickr/src/main/java/vavi/nio/file/flickr/FlickrFileSystemDriver.java
@@ -9,36 +9,24 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.nio.file.AccessDeniedException;
-import java.nio.file.AccessMode;
import java.nio.file.CopyOption;
-import java.nio.file.DirectoryStream;
-import java.nio.file.FileAlreadyExistsException;
import java.nio.file.FileStore;
-import java.nio.file.NoSuchFileException;
import java.nio.file.OpenOption;
import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.attribute.FileAttribute;
-import java.nio.file.spi.FileSystemProvider;
-import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import com.flickr4java.flickr.Flickr;
import com.flickr4java.flickr.FlickrException;
import com.flickr4java.flickr.photos.Photo;
-import com.flickr4java.flickr.photos.PhotoList;
import com.flickr4java.flickr.photos.SearchParameters;
-import com.github.fge.filesystem.driver.ExtendedFileSystemDriverBase;
+import com.github.fge.filesystem.driver.CachedFileSystemDriver;
import com.github.fge.filesystem.provider.FileSystemFactoryProvider;
-import vavi.nio.file.Cache;
import vavi.nio.file.Util;
@@ -49,233 +37,137 @@
* @version 0.00 2016/03/30 umjammer initial version
*/
@ParametersAreNonnullByDefault
-public final class FlickrFileSystemDriver extends ExtendedFileSystemDriverBase {
+public final class FlickrFileSystemDriver extends CachedFileSystemDriver {
private final Flickr flickr;
- private boolean ignoreAppleDouble = false;
-
- @SuppressWarnings("unchecked")
public FlickrFileSystemDriver(final FileStore fileStore,
final FileSystemFactoryProvider provider,
final Flickr drive,
final Map env) throws IOException {
super(fileStore, provider);
this.flickr = drive;
- ignoreAppleDouble = (Boolean) ((Map) env).getOrDefault("ignoreAppleDouble", Boolean.FALSE);
+ setEnv(env);
//System.err.println("ignoreAppleDouble: " + ignoreAppleDouble);
}
- /** */
- private Cache cache = new Cache() {
- {
- Photo photo = new Photo();
- photo.setTitle("/");
- photo.setId("root");
- photo.setLastUpdate(new Date(0)); // TODO
- entryCache.put(Paths.get("/"), photo); // TODO filesystem
- }
+ @Override
+ protected String getFilenameString(Photo entry) {
+ return entry.getTitle();
+ }
- /**
- * TODO when the parent is not cached
- * @see #ignoreAppleDouble
- */
- public Photo getEntry(Path path) throws IOException {
- String pathString = Util.toPathString(path);
- if (cache.containsFile(path)) {
-//System.err.println("CACHE: path: " + path + ", id: " + cache.get(pathString).getId());
- return cache.getFile(path);
- } else {
- if (ignoreAppleDouble && path.getFileName() != null && Util.isAppleDouble(path)) {
- throw new NoSuchFileException("ignore apple double file: " + path);
- }
+ @Override
+ protected boolean isFolder(Photo entry) {
+ // flickr doesn't have folder capability
+ return false;
+ }
- try {
- Photo entry = flickr.getPhotosInterface().getInfo(pathString, null); // TODO
+ @Override
+ protected Photo getRootEntry(Path root) throws IOException {
+ Photo photo = new Photo();
+ photo.setTitle("/");
+ photo.setId("root");
+ photo.setLastUpdate(new Date(0)); // TODO
+ return photo;
+ }
+
+ @Override
+ protected Photo getEntry(Photo parentEntry, Path path)throws IOException {
+ try {
+ Photo entry = flickr.getPhotosInterface().getInfo(Util.toPathString(path), null); // TODO
//System.err.println("GOT: path: " + path + ", id: " + entry.getId());
- cache.putFile(path, entry);
- return entry;
- } catch (FlickrException e) {
- if (e.getMessage().startsWith("404")) { // TODO
- throw new NoSuchFileException(path.toString());
- } else {
- throw new IOException(e);
- }
- }
+ return entry;
+ } catch (FlickrException e) {
+ if (e.getMessage().startsWith("404")) { // TODO
+ return null;
+ } else {
+ throw new IOException(e);
}
}
- };
+ }
- @Nonnull
@Override
- public InputStream newInputStream(final Path path, final Set extends OpenOption> options) throws IOException {
- final Photo entry = cache.getEntry(path);
-
+ protected InputStream downloadEntry(Photo entry, Path path, Set extends OpenOption> options) throws IOException {
final java.io.File downloadFile = java.io.File.createTempFile("vavi-apps-fuse-", ".download");
-
return new FlickrInputStream(flickr, entry, downloadFile);
}
- @Nonnull
@Override
- public OutputStream newOutputStream(final Path path, final Set extends OpenOption> options) throws IOException {
- try {
- cache.getEntry(path);
-
- throw new FileAlreadyExistsException("path: " + path);
- } catch (IOException e) {
- System.err.println("newOutputStream: " + e.getMessage());
- }
-
+ protected OutputStream uploadEntry(Photo parentEntry, Path path, Set extends OpenOption> options) throws IOException {
java.io.File temp = java.io.File.createTempFile("vavi-apps-fuse-", ".upload");
-
return new FlickrOutputStream(flickr, temp, Util.toFilenameString(path), newEntry -> {
try {
System.out.println("file: " + newEntry.getTitle() + ", " + newEntry.getDateAdded());
- cache.addEntry(path, newEntry);
+ updateEntry(path, newEntry);
} catch (Exception e) {
throw new IllegalStateException(e);
}
});
}
- @Nonnull
@Override
- public DirectoryStream newDirectoryStream(final Path dir,
- final DirectoryStream.Filter super Path> filter) throws IOException {
+ protected List getDirectoryEntries(Photo dirEntry, Path dir) throws IOException {
try {
- return Util.newDirectoryStream(getDirectoryEntries(dir), filter);
+ SearchParameters params = new SearchParameters();
+ Date now = new Date();
+ params.setMaxTakenDate(now);
+ params.setMinTakenDate(now);
+ return flickr.getPhotosInterface().search(params, 10, 0);
} catch (FlickrException e) {
throw new IOException(e);
}
}
@Override
- public void createDirectory(final Path dir, final FileAttribute>... attrs) throws IOException {
- throw new UnsupportedOperationException("createDirectory");
+ protected Photo createDirectoryEntry(Photo parentEntry, Path dir) throws IOException {
+ throw new UnsupportedOperationException("flickr doesn't have folder capability");
}
@Override
- public void delete(final Path path) throws IOException {
- final Photo entry = cache.getEntry(path);
-
- try {
- flickr.getPhotosInterface().delete(entry.getId());
-
- cache.removeEntry(path);
- } catch (FlickrException e) {
- throw new IOException(e);
- }
+ protected boolean hasChildren(Photo dirEntry, Path dir) throws IOException {
+ // flickr doesn't have folder capability
+ return false;
}
@Override
- public void copy(final Path source, final Path target, final Set options) throws IOException {
- Photo targetEntry;
- String targetFilename;
+ protected void removeEntry(Photo entry, Path path) throws IOException {
try {
- targetEntry = cache.getEntry(target);
- flickr.getPhotosInterface().delete(targetEntry.getId());
-
- cache.removeEntry(target);
-
- targetEntry = cache.getEntry(target.getParent());
- targetFilename = Util.toFilenameString(target);
+ flickr.getPhotosInterface().delete(entry.getId());
} catch (FlickrException e) {
-System.err.println(e);
throw new IOException(e);
}
-
- final Photo sourceEntry = cache.getEntry(source);
- Photo entry = new Photo();
- entry.setTitle(targetFilename);
- // TODO
- Photo newEntry = null; //flickr.getPhotosInterface().copy(sourceEntry.getId(), entry);
-
- cache.addEntry(target, newEntry);
}
@Override
- public void move(final Path source, final Path target, final Set options) throws IOException {
- Photo targetEntry;
- String targetFilename;
- try {
- targetEntry = cache.getEntry(target);
- flickr.getPhotosInterface().delete(targetEntry.getId());
-
- cache.removeEntry(target);
-
- targetEntry = cache.getEntry(target.getParent());
- targetFilename = Util.toFilenameString(target);
- } catch (FlickrException e) {
-System.err.println(e);
- throw new IOException(e);
- }
-
- Photo sourceEntry = cache.getEntry(source);
- sourceEntry.setTitle(targetFilename);
- // TODO
- Photo newEntry = null;//flickr.getPeopleInterface().update(sourceEntry.getId(), sourceEntry);
-
- cache.removeEntry(source);
- cache.addEntry(target, newEntry);
+ protected Photo copyEntry(Photo sourceEntry, Photo targetParentEntry, Path source, Path target, Set options) throws IOException {
+// try {
+ Photo entry = new Photo();
+ entry.setTitle(Util.toFilenameString(target));
+ // TODO
+ return null; //flickr.getPhotosInterface().copy(sourceEntry.getId(), entry);
+// } catch (FlickrException e) {
+// throw new IOException(e);
+// }
}
- /**
- * Check access modes for a path on this filesystem
- *
- * If no modes are provided to check for, this simply checks for the
- * existence of the path.
- *
- *
- * @param path the path to check
- * @param modes the modes to check for, if any
- * @throws IOException filesystem level error, or a plain I/O error
- * if you use this with javafs (jnr-fuse), you should throw {@link NoSuchFileException} when the file not found.
- * @see FileSystemProvider#checkAccess(Path, AccessMode...)
- */
@Override
- protected void checkAccessImpl(final Path path, final AccessMode... modes) throws IOException {
- cache.getEntry(path);
-
- // TODO: assumed; not a file == directory
- for (final AccessMode mode : modes) {
- if (mode == AccessMode.EXECUTE) {
- throw new AccessDeniedException(path.toString());
- }
- }
+ protected Photo moveEntry(Photo sourceEntry, Photo targetParentEntry, Path source, Path target, boolean targetIsParent) throws IOException {
+// try {
+ sourceEntry.setTitle(Util.toFilenameString(target));
+ // TODO
+ return null; //flickr.getPeopleInterface().update(sourceEntry.getId(), sourceEntry);
+// } catch (FlickrException e) {
+// throw new IOException(e);
+// }
}
@Override
- public void close() throws IOException {
- // TODO: what to do here? Flickr does not implement Closeable :(
+ protected Photo moveFolderEntry(Photo sourceEntry, Photo targetParentEntry, Path source, Path target, boolean targetIsParent) throws IOException {
+ throw new UnsupportedOperationException("flickr doesn't have folder capability");
}
- /**
- * @throws IOException if you use this with javafs (jnr-fuse), you should throw {@link NoSuchFileException} when the file not found.
- */
- @Nonnull
@Override
- protected Object getPathMetadataImpl(final Path path) throws IOException {
- return cache.getEntry(path);
- }
-
- /** */
- private List getDirectoryEntries(final Path dir) throws IOException, FlickrException {
- List list = null;
- SearchParameters params = new SearchParameters();
- params.setMaxTakenDate(new Date());
- params.setMinTakenDate(new Date());
- final PhotoList children = flickr.getPhotosInterface().search(params, 10, 0);
- list = new ArrayList<>(children.size());
-
- // TODO nextPageToken
- for (final Photo child : children) {
- Path childPath = dir.resolve(child.getTitle());
- list.add(childPath);
-//System.err.println("child: " + childPath.toRealPath().toString());
- cache.addEntry(childPath, child);
- }
-
- return list;
+ protected Photo renameEntry(Photo sourceEntry, Photo targetParentEntry, Path source, Path target) throws IOException {
+ throw new UnsupportedOperationException("flickr doesn't have folder capability");
}
}
diff --git a/vavi-nio-file-gathered/pom.xml b/vavi-nio-file-gathered/pom.xml
index 42de1a6d..592ba963 100644
--- a/vavi-nio-file-gathered/pom.xml
+++ b/vavi-nio-file-gathered/pom.xml
@@ -5,7 +5,7 @@
vavi
vavi-apps-fuse
- 0.1.6
+ 0.1.7
vavi-nio-file-gathered
@@ -19,6 +19,13 @@
https://github.com/umjammer/vavi-nio-file-gathered/issues
+
+
+ jitpack.io
+ https://jitpack.io
+
+
+
@@ -38,7 +45,7 @@
com.google.guava
guava
- 29.0-jre
+ 31.0.1-jre
@@ -59,7 +66,6 @@
org.junit.jupiter
junit-jupiter-params
- 5.3.0
test
@@ -89,13 +95,13 @@
vavi
vavi-nio-file-googledrive
- 0.1.6
+ 0.1.7
test
vavi
vavi-nio-file-onedrive4
- 0.1.6
+ 0.1.7
test
diff --git a/vavi-nio-file-gathered/src/main/java/vavi/nio/file/gathered/GatheredFileAttributesFactory.java b/vavi-nio-file-gathered/src/main/java/vavi/nio/file/gathered/GatheredFileAttributesFactory.java
index b2ff0b71..dde9857e 100644
--- a/vavi-nio-file-gathered/src/main/java/vavi/nio/file/gathered/GatheredFileAttributesFactory.java
+++ b/vavi-nio-file-gathered/src/main/java/vavi/nio/file/gathered/GatheredFileAttributesFactory.java
@@ -6,7 +6,7 @@
package vavi.nio.file.gathered;
-import com.github.fge.filesystem.attributes.FileAttributesFactory;
+import com.github.fge.filesystem.driver.ExtendedFileSystemDriverBase.ExtendsdFileAttributesFactory;
/**
@@ -15,7 +15,7 @@
* @author Naohide Sano (umjammer)
* @version 0.00 2016/04/06 umjammer initial version
*/
-public final class GatheredFileAttributesFactory extends FileAttributesFactory {
+public final class GatheredFileAttributesFactory extends ExtendsdFileAttributesFactory {
public GatheredFileAttributesFactory() {
setMetadataClass(Object.class);
diff --git a/vavi-nio-file-gathered/src/main/java/vavi/nio/file/gathered/GatheredFileSystemDriver.java b/vavi-nio-file-gathered/src/main/java/vavi/nio/file/gathered/GatheredFileSystemDriver.java
index 8501ced9..3b037abe 100644
--- a/vavi-nio-file-gathered/src/main/java/vavi/nio/file/gathered/GatheredFileSystemDriver.java
+++ b/vavi-nio-file-gathered/src/main/java/vavi/nio/file/gathered/GatheredFileSystemDriver.java
@@ -19,16 +19,12 @@
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.attribute.FileAttribute;
-import java.nio.file.spi.FileSystemProvider;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
-import javax.annotation.Nonnull;
-import javax.annotation.ParametersAreNonnullByDefault;
-
import com.github.fge.filesystem.driver.ExtendedFileSystemDriverBase;
import com.github.fge.filesystem.exceptions.IsDirectoryException;
import com.github.fge.filesystem.provider.FileSystemFactoryProvider;
@@ -44,7 +40,6 @@
* @author Naohide Sano (umjammer)
* @version 0.00 2019/03/30 umjammer initial version
*/
-@ParametersAreNonnullByDefault
public final class GatheredFileSystemDriver extends ExtendedFileSystemDriverBase {
/** should be unaccessible from outer */
@@ -66,7 +61,6 @@ public GatheredFileSystemDriver(final FileStore fileStore,
}
}
- @Nonnull
@Override
public InputStream newInputStream(final Path path, final Set extends OpenOption> options) throws IOException {
final Object entry = getPathMetadata(path);
@@ -79,14 +73,12 @@ public InputStream newInputStream(final Path path, final Set extends OpenOptio
return Files.newInputStream(Path.class.cast(entry));
}
- @Nonnull
@Override
public OutputStream newOutputStream(final Path path, final Set extends OpenOption> options) throws IOException {
// TODO we can implement using Files
throw new UnsupportedOperationException("newOutputStream is not supported by the file system");
}
- @Nonnull
@Override
public DirectoryStream newDirectoryStream(final Path dir,
final DirectoryStream.Filter super Path> filter) throws IOException {
@@ -117,31 +109,14 @@ public void move(final Path source, final Path target, final Set opt
throw new UnsupportedOperationException("move is not supported by the file system");
}
- /**
- * Check access modes for a path on this filesystem
- *
- * If no modes are provided to check for, this simply checks for the
- * existence of the path.
- *
- *
- * @param path the path to check
- * @param modes the modes to check for, if any
- * @see FileSystemProvider#checkAccess(Path, AccessMode...)
- */
@Override
protected void checkAccessImpl(final Path path, final AccessMode... modes) throws IOException {
// TODO currently check read only?
}
- @Override
- public void close() throws IOException {
- // TODO: what to do here? gathered fs does not implement Closeable :(
- }
-
/**
* @throws IOException you should throw {@link NoSuchFileException} when the file not found.
*/
- @Nonnull
@Override
protected Object getPathMetadataImpl(final Path path) throws IOException {
//Debug.println("path: " + path);
@@ -152,6 +127,11 @@ protected Object getPathMetadataImpl(final Path path) throws IOException {
}
}
+ @Override
+ public void close() throws IOException {
+ // TODO: what to do here? gathered fs does not implement Closeable :(
+ }
+
/** */
private List getDirectoryEntries(final Path dir) throws IOException {
if (dir.getNameCount() == 0) {
diff --git a/vavi-nio-file-gathered/src/test/java/vavi/nio/file/gathered/GatheredFileSystemProviderTest.java b/vavi-nio-file-gathered/src/test/java/vavi/nio/file/gathered/GatheredFileSystemProviderTest.java
index 1ffcf2c7..23b39652 100644
--- a/vavi-nio-file-gathered/src/test/java/vavi/nio/file/gathered/GatheredFileSystemProviderTest.java
+++ b/vavi-nio-file-gathered/src/test/java/vavi/nio/file/gathered/GatheredFileSystemProviderTest.java
@@ -26,7 +26,7 @@
import vavi.net.auth.oauth2.OAuth2AppCredential;
import vavi.net.auth.oauth2.box.BoxLocalAppCredential;
import vavi.net.auth.oauth2.dropbox.DropBoxLocalAppCredential;
-import vavi.net.auth.oauth2.google.GoogleLocalAppCredential;
+import vavi.net.auth.oauth2.google.GoogleLocalOAuth2AppCredential;
import vavi.net.auth.oauth2.microsoft.MicrosoftGraphLocalAppCredential;
import vavi.net.fuse.Fuse;
import vavi.nio.file.googledrive.GoogleDriveFileSystemProvider;
@@ -86,7 +86,7 @@ public static void main(String[] args) throws Exception {
/** */
private OAuth2AppCredential microsoftAppCredential = new MicrosoftGraphLocalAppCredential();
/** */
- private OAuth2AppCredential googleAppCredential = new GoogleLocalAppCredential();
+ private OAuth2AppCredential googleAppCredential = new GoogleLocalOAuth2AppCredential("googledrive");
/** */
private OAuth2AppCredential boxAppCredential = new BoxLocalAppCredential();
/** */
diff --git a/vavi-nio-file-gathered/src/test/resources/onedrive.properties b/vavi-nio-file-gathered/src/test/resources/onedrive.properties
new file mode 100644
index 00000000..3f300320
--- /dev/null
+++ b/vavi-nio-file-gathered/src/test/resources/onedrive.properties
@@ -0,0 +1 @@
+authenticatorClassName=vavi.net.auth.oauth2.microsoft.MicrosoftBasicAuthenticator
diff --git a/vavi-nio-file-googledrive/pom.xml b/vavi-nio-file-googledrive/pom.xml
index 2dd2a16d..cdaf00e5 100644
--- a/vavi-nio-file-googledrive/pom.xml
+++ b/vavi-nio-file-googledrive/pom.xml
@@ -5,7 +5,7 @@
vavi
vavi-apps-fuse
- 0.1.6
+ 0.1.7
vavi-nio-file-googledrive
@@ -54,7 +54,6 @@
org.apache.maven.plugins
maven-surefire-plugin
- 2.22.2
${test4.account}
@@ -69,6 +68,27 @@
+
+
+
+ maven-compiler-plugin
+
+ 1.8
+ 1.8
+ utf-8
+ eclipse
+
+
+
+ org.codehaus.plexus
+ plexus-compiler-eclipse
+ 2.7
+
+
+
+
+
+
@@ -82,11 +102,22 @@
- com.github.umjammer.vavi-net-auth
+ vavi
+ vavi-nio-file-commons
+
+
+
+ ${vavi-net-auth.groupId}
vavi-net-auth-google
${vavi-net-auth.version}
+
+ com.google.apis
+ google-api-services-drive
+ v3-rev20211017-1.32.1
+
+
org.junit.jupiter
junit-jupiter-api
@@ -105,7 +136,6 @@
org.junit.jupiter
junit-jupiter-params
- 5.3.0
test
diff --git a/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveBasicFileAttributesProvider.java b/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveBasicFileAttributesProvider.java
index 42ef2ee9..cb593c3e 100644
--- a/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveBasicFileAttributesProvider.java
+++ b/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveBasicFileAttributesProvider.java
@@ -22,6 +22,8 @@
import com.github.fge.filesystem.attributes.provider.BasicFileAttributesProvider;
import com.google.api.services.drive.model.File;
+import vavi.nio.file.googledrive.GoogleDriveFileAttributesFactory.Metadata;
+
/**
* {@link BasicFileAttributes} implementation for GoogleDrive
@@ -35,10 +37,12 @@
*/
public final class GoogleDriveBasicFileAttributesProvider extends BasicFileAttributesProvider implements PosixFileAttributes {
+ private final GoogleDriveFileSystemDriver driver;
private final File entry;
- public GoogleDriveBasicFileAttributesProvider(@Nonnull final File entry) throws IOException {
- this.entry = Objects.requireNonNull(entry);
+ public GoogleDriveBasicFileAttributesProvider(@Nonnull final Metadata entry) throws IOException {
+ this.driver = Objects.requireNonNull(entry).driver;
+ this.entry = Objects.requireNonNull(entry).file;
}
/**
@@ -62,7 +66,7 @@ public FileTime lastModifiedTime() {
*/
@Override
public boolean isRegularFile() {
- return !GoogleDriveFileSystemDriver.isFolder(entry);
+ return !driver.isFolder(entry);
}
/**
@@ -70,7 +74,7 @@ public boolean isRegularFile() {
*/
@Override
public boolean isDirectory() {
- return GoogleDriveFileSystemDriver.isFolder(entry);
+ return driver.isFolder(entry);
}
/**
diff --git a/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveCopyOption.java b/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveCopyOption.java
index cd796a5d..ea41bbe2 100644
--- a/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveCopyOption.java
+++ b/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveCopyOption.java
@@ -17,6 +17,9 @@
*/
public enum GoogleDriveCopyOption implements CopyOption {
+ /**
+ * you can use for OCR image files.
+ */
EXPORT_AS_GDOCS("application/vnd.google-apps.document");
/** */
diff --git a/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveFileAttributesFactory.java b/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveFileAttributesFactory.java
index e7ad527b..77447353 100644
--- a/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveFileAttributesFactory.java
+++ b/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveFileAttributesFactory.java
@@ -6,7 +6,7 @@
package vavi.nio.file.googledrive;
-import com.github.fge.filesystem.attributes.FileAttributesFactory;
+import com.github.fge.filesystem.driver.ExtendedFileSystemDriverBase.ExtendsdFileAttributesFactory;
import com.google.api.services.drive.model.File;
@@ -16,10 +16,20 @@
* @author Naohide Sano (umjammer)
* @version 0.00 2016/03/30 umjammer initial version
*/
-public final class GoogleDriveFileAttributesFactory extends FileAttributesFactory {
+public final class GoogleDriveFileAttributesFactory extends ExtendsdFileAttributesFactory {
+
+ static class Metadata {
+ GoogleDriveFileSystemDriver driver;
+ File file;
+ Metadata(GoogleDriveFileSystemDriver driver, File file) {
+ this.driver = driver;
+ this.file = file;
+ }
+ }
public GoogleDriveFileAttributesFactory() {
- setMetadataClass(File.class);
+ setMetadataClass(Metadata.class);
addImplementation("basic", GoogleDriveBasicFileAttributesProvider.class);
+ addImplementation("user", GoogleDriveUserDefinedFileAttributesProvider.class);
}
}
diff --git a/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveFileSystemDriver.java b/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveFileSystemDriver.java
index 1f99dd93..c501b293 100644
--- a/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveFileSystemDriver.java
+++ b/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveFileSystemDriver.java
@@ -10,45 +10,42 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.nio.file.AccessDeniedException;
-import java.nio.file.AccessMode;
import java.nio.file.CopyOption;
-import java.nio.file.DirectoryNotEmptyException;
-import java.nio.file.DirectoryStream;
-import java.nio.file.FileAlreadyExistsException;
import java.nio.file.FileStore;
-import java.nio.file.NoSuchFileException;
-import java.nio.file.NotDirectoryException;
+import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.nio.file.Path;
-import java.nio.file.StandardCopyOption;
-import java.nio.file.attribute.FileAttribute;
-import java.nio.file.spi.FileSystemProvider;
+import java.nio.file.WatchEvent.Kind;
+import java.nio.file.WatchService;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
+import java.util.NoSuchElementException;
import java.util.Set;
+import java.util.logging.Level;
-import javax.annotation.Nonnull;
-import javax.annotation.ParametersAreNonnullByDefault;
-
-import com.github.fge.filesystem.driver.ExtendedFileSystemDriverBase;
+import com.github.fge.filesystem.driver.CachedFileSystemDriver;
import com.github.fge.filesystem.exceptions.IsDirectoryException;
import com.github.fge.filesystem.provider.FileSystemFactoryProvider;
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
import com.google.api.client.googleapis.media.MediaHttpUploader;
import com.google.api.client.http.AbstractInputStreamContent;
+import com.google.api.client.http.InputStreamContent;
import com.google.api.services.drive.Drive;
-import com.google.api.services.drive.Drive.Files;
import com.google.api.services.drive.model.File;
import com.google.api.services.drive.model.FileList;
+import com.google.api.services.drive.model.Revision;
+import com.google.api.services.drive.model.RevisionList;
-import vavi.nio.file.Cache;
import vavi.nio.file.Util;
+import vavi.nio.file.googledrive.GoogleDriveFileAttributesFactory.Metadata;
import vavi.util.Debug;
+import vavi.util.StringUtil;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
import static vavi.nio.file.Util.toFilenameString;
+import static vavi.nio.file.googledrive.GoogleDriveFileSystemProvider.ENV_USE_SYSTEM_WATCHER;
/**
@@ -57,123 +54,144 @@
* @author Naohide Sano (umjammer)
* @version 0.00 2016/03/30 umjammer initial version
*/
-@ParametersAreNonnullByDefault
-public final class GoogleDriveFileSystemDriver extends ExtendedFileSystemDriverBase {
+public final class GoogleDriveFileSystemDriver extends CachedFileSystemDriver {
- private final Drive drive;
+ private Drive drive;
- private boolean ignoreAppleDouble = false;
+ private GoogleDriveWatchService systemWatcher;
@SuppressWarnings("unchecked")
- public GoogleDriveFileSystemDriver(final FileStore fileStore,
- final FileSystemFactoryProvider provider,
- final Drive drive,
- final Map env) throws IOException {
+ public GoogleDriveFileSystemDriver(FileStore fileStore,
+ FileSystemFactoryProvider provider,
+ Drive drive,
+ Map env) throws IOException {
super(fileStore, provider);
this.drive = drive;
- ignoreAppleDouble = (Boolean) ((Map) env).getOrDefault("ignoreAppleDouble", Boolean.FALSE);
+ setEnv(env);
+ boolean useSystemWatcher = (Boolean) ((Map) env).getOrDefault(ENV_USE_SYSTEM_WATCHER, false);
+
+ if (useSystemWatcher) {
+ systemWatcher = new GoogleDriveWatchService(drive);
+ systemWatcher.setNotificationListener(this::processNotification);
+ }
+ }
+
+ /** for system watcher */
+ private void processNotification(String id, Kind> kind) {
+ if (ENTRY_DELETE == kind) {
+ try {
+ Path path = cache.getEntry(e -> id.equals(e.getId()));
+ cache.removeEntry(path);
+ } catch (NoSuchElementException e) {
+Debug.println("NOTIFICATION: already deleted: " + id);
+ }
+ } else {
+ try {
+ try {
+ Path path = cache.getEntry(e -> id.equals(e.getId()));
+Debug.println("NOTIFICATION: maybe updated: " + path);
+ cache.removeEntry(path);
+ cache.getEntry(path);
+ } catch (NoSuchElementException e) {
+ File entry = drive.files().get(id).execute();
+ Path parent = cache.getEntry(f -> entry.getParents().get(0).equals(f.getId()));
+ Path path = parent.resolve(entry.getName());
+Debug.println("NOTIFICATION: maybe created: " + path);
+ cache.addEntry(path, entry);
+ }
+ } catch (NoSuchElementException e) {
+Debug.println("NOTIFICATION: parent not found: " + e);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
}
/** */
- private static final String ENTRY_FIELDS = "id, parents, name, size, mimeType, createdTime, modifiedTime";
+ private static final String ENTRY_FIELDS = "id, parents, name, size, mimeType, createdTime, modifiedTime, description";
/** */
- private static final String MIME_TYPE_DIR = "application/vnd.google-apps.folder";
+ public static final String MIME_TYPE_DIR = "application/vnd.google-apps.folder";
- /** ugly */
- static boolean isFolder(File file) {
- return file.getMimeType().equals(MIME_TYPE_DIR);
+ @Override
+ protected String getFilenameString(File entry) {
+ try {
+ return Util.toNormalizedString(entry.getName());
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
}
- /** */
- private Cache cache = new Cache() {
- /**
- * @see #ignoreAppleDouble
- */
- public File getEntry(Path path) throws IOException {
- try {
- if (cache.containsFile(path)) {
- return cache.getFile(path);
- } else {
- if (ignoreAppleDouble && path.getFileName() != null && Util.isAppleDouble(path)) {
- throw new NoSuchFileException("ignore apple double file: " + path);
- }
+ @Override
+ protected boolean isFolder(File entry) {
+ return MIME_TYPE_DIR.equals(entry.getMimeType());
+ }
- File entry;
- if (path.getNameCount() == 0) {
- entry = drive.files().get("root").setFields(ENTRY_FIELDS).execute().set("name", "/");
- cache.putFile(path, entry);
- return entry;
- } else {
- List siblings = getDirectoryEntries(path.getParent(), false);
- for (int i = 0; i < siblings.size(); i++) { // avoid ConcurrentModificationException
- Path p = siblings.get(i);
- if (p.getFileName().equals(path.getFileName())) {
- return cache.getEntry(p);
- }
- }
- throw new NoSuchFileException(path.toString());
- }
- }
- } catch (GoogleJsonResponseException e) {
- if (e.getMessage().startsWith("404")) {
- // cache
- if (cache.containsFile(path)) {
- cache.removeEntry(path);
- }
+ @Override
+ protected File getRootEntry(Path root) throws IOException {
+ return drive.files().get("root").setFields(ENTRY_FIELDS).execute().set("name", "/");
+ }
- throw (IOException) new NoSuchFileException("path: " + path).initCause(e);
- } else {
- throw e;
- }
+ @Override
+ protected File getEntry(File parentEntry, Path path) throws IOException {
+ try {
+ String q = "'" + parentEntry.getId() + "' in parents and name = '" + path.getFileName() + "' and trashed=false";
+//System.out.println("q: " + q);
+ FileList files = drive.files().list()
+ .setQ(q)
+ .setSpaces("drive")
+ .setFields("nextPageToken, files(" + ENTRY_FIELDS + ")")
+ .execute();
+ if (files.getFiles().size() > 0) {
+ return files.getFiles().get(0);
+ } else {
+ return null;
+ }
+ } catch (GoogleJsonResponseException e) {
+ if (e.getMessage().startsWith("404")) {
+ return null;
+ } else {
+ throw e;
}
}
- };
+ }
- @Nonnull
@Override
- public InputStream newInputStream(final Path path, final Set extends OpenOption> options) throws IOException {
- final File entry = cache.getEntry(path);
-
- if (isFolder(entry)) {
- throw new IsDirectoryException("path: " + path);
- }
-
- // TODO detect automatically?
- GoogleDriveOpenOption option = Util.getOneOfOptions(GoogleDriveOpenOption.class, options);
- if (option != null) {
+ protected InputStream downloadEntry(File entry, Path path, Set extends OpenOption> options) throws IOException {
+ // TODO detect automatically? (w/o options)
+ if (options != null && options.stream().anyMatch(o -> o.equals(GoogleDriveOpenOption.EXPORT_WITH_GDOCS_DOCX) ||
+ o.equals(GoogleDriveOpenOption.EXPORT_WITH_GDOCS_XLSX))) {
+ GoogleDriveOpenOption option = Util.getOneOfOptions(GoogleDriveOpenOption.class, options);
return drive.files().export(entry.getId(), option.getValue()).executeMediaAsInputStream();
} else {
return drive.files().get(entry.getId()).executeMediaAsInputStream();
}
}
- @Nonnull
@Override
- public OutputStream newOutputStream(final Path path, final Set extends OpenOption> options) throws IOException {
- final File entry;
- try {
- entry = cache.getEntry(path);
-
- if (isFolder(entry)) {
- throw new IsDirectoryException("path: " + path);
- } else {
- throw new FileAlreadyExistsException("path: " + path);
- }
- } catch (NoSuchFileException e) {
-Debug.println("newOutputStream: " + e.getMessage());
+ protected void whenUploadEntryExists(File sourceEntry, Path path, Set extends OpenOption> options) throws IOException {
+ if (options == null || !options.stream().anyMatch(o -> o.equals(GoogleDriveOpenOption.INPORT_AS_NEW_REVISION))) {
+ super.whenUploadEntryExists(sourceEntry, path, options);
}
- // TODO detect automatically?
- @SuppressWarnings("unused")
- GoogleDriveOpenOption option = Util.getOneOfOptions(GoogleDriveOpenOption.class, options);
+ File entry = new File();
- return uploadEntry(path);
+ AbstractInputStreamContent mediaContent = new InputStreamContent(null, Files.newInputStream(path));
+ Drive.Files.Update updator = drive.files().update(sourceEntry.getId(), entry, mediaContent);
+ MediaHttpUploader uploader = updator.getMediaHttpUploader();
+ uploader.setDirectUploadEnabled(true);
+ // MediaHttpUploader#getProgress() cannot use because w/o content length, using #getNumBytesUploaded() instead
+ uploader.setProgressListener(u -> { Debug.println("new revision progress: " + u.getNumBytesUploaded() + ", " + u.getUploadState()); });
+ updator.getMediaHttpUploader();
+ File newEntry = updator.setFields(ENTRY_FIELDS).execute();
+Debug.printf("file: %1$s, %2$tF %2$tT.%2$tL, %3$d\n", newEntry.getName(), newEntry.getCreatedTime().getValue(), newEntry.getSize());
+ updateEntry(path, newEntry);
}
- /** */
- private OutputStream uploadEntry(Path path) throws IOException {
- return new BufferedOutputStream(new Util.StrealingOutputStreamForUploading() {
+ @Override
+ protected OutputStream uploadEntry(File parentEntry, Path path, Set extends OpenOption> options) throws IOException {
+
+ return new BufferedOutputStream(new Util.StealingOutputStreamForUploading() {
@Override
protected File upload() throws IOException {
AbstractInputStreamContent mediaContent = new AbstractInputStreamContent(null) { // implements HttpContent
@@ -195,11 +213,11 @@ public void writeTo(OutputStream os) throws IOException {
}
};
- File fileMetadata = new File();
- fileMetadata.setName(toFilenameString(path));
- fileMetadata.setParents(Arrays.asList(cache.getEntry(path.getParent()).getId()));
+ File entry = new File();
+ entry.setName(toFilenameString(path));
+ entry.setParents(Arrays.asList(parentEntry.getId()));
- Drive.Files.Create creator = drive.files().create(fileMetadata, mediaContent); // why not HttpContent ???
+ Drive.Files.Create creator = drive.files().create(entry, mediaContent); // why not HttpContent ???
MediaHttpUploader uploader = creator.getMediaHttpUploader();
uploader.setDirectUploadEnabled(true);
// MediaHttpUploader#getProgress() cannot use because w/o content length, using #getNumBytesUploaded() instead
@@ -210,246 +228,198 @@ public void writeTo(OutputStream os) throws IOException {
@Override
protected void onClosed(File newEntry) {
Debug.printf("file: %1$s, %2$tF %2$tT.%2$tL, %3$d\n", newEntry.getName(), newEntry.getCreatedTime().getValue(), newEntry.getSize());
- cache.addEntry(path, newEntry);
+ updateEntry(path, newEntry);
}
}, Util.BUFFER_SIZE);
}
- @Nonnull
@Override
- public DirectoryStream newDirectoryStream(final Path dir,
- final DirectoryStream.Filter super Path> filter) throws IOException {
- return Util.newDirectoryStream(getDirectoryEntries(dir, true), filter);
+ protected List getDirectoryEntries(File dirEntry, Path dir) throws IOException {
+ List list = new ArrayList<>();
+ String pageToken = null;
+ do {
+ FileList files = drive.files().list()
+ .setQ("'" + dirEntry.getId() + "' in parents and trashed=false")
+ .setSpaces("drive")
+ .setPageSize(1000)
+ .setFields("nextPageToken, files(" + ENTRY_FIELDS + ")")
+ .setPageToken(pageToken)
+ .setOrderBy("name_natural")
+ .execute();
+
+ for (File child : files.getFiles()) {
+ list.add(child);
+ }
+
+ pageToken = files.getNextPageToken();
+//System.out.println("t: " + (System.currentTimeMillis() - t) + ", " + children.size() + ", " + (pageToken != null));
+ } while (pageToken != null);
+
+ return list;
}
@Override
- public void createDirectory(final Path dir, final FileAttribute>... attrs) throws IOException {
+ protected File createDirectoryEntry(File parentEntry, Path dir) throws IOException {
File dirEntry = new File();
dirEntry.setName(toFilenameString(dir));
dirEntry.setMimeType(MIME_TYPE_DIR);
- if (dir.getParent().getFileName() != null) {
- dirEntry.setParents(Arrays.asList(cache.getEntry(dir.getParent()).getId()));
+ if (dir.toAbsolutePath().getParent().getNameCount() != 0) {
+ dirEntry.setParents(Arrays.asList(parentEntry.getId()));
}
- File newEntry = drive.files().create(dirEntry).setFields(ENTRY_FIELDS).execute();
- cache.addEntry(dir, newEntry);
+ return drive.files().create(dirEntry).setFields(ENTRY_FIELDS).execute();
}
@Override
- public void delete(final Path path) throws IOException {
- removeEntry(path);
+ protected boolean hasChildren(File dirEntry, Path dir) throws IOException {
+ // TODO use cache ???
+ List files = drive.files().list()
+ .setQ("'" + dirEntry.getId() + "' in parents and trashed=false")
+ .execute().getFiles();
+ return files != null && files.size() > 0;
}
@Override
- public void copy(final Path source, final Path target, final Set options) throws IOException {
- if (cache.existsEntry(target)) {
- if (options != null && options.stream().anyMatch(o -> o.equals(StandardCopyOption.REPLACE_EXISTING))) {
- removeEntry(target);
- } else {
- throw new FileAlreadyExistsException(target.toString());
- }
- }
-
- copyEntry(source, target, options);
+ protected void removeEntry(File entry, Path path) throws IOException {
+ drive.files().delete(entry.getId()).execute();
}
@Override
- public void move(final Path source, final Path target, final Set options) throws IOException {
- if (cache.existsEntry(target)) {
- if (isFolder(cache.getEntry(target))) {
- if (options != null && options.stream().anyMatch(o -> o.equals(StandardCopyOption.REPLACE_EXISTING))) {
- // replace the target
- if (cache.getChildCount(target) > 0) {
- throw new DirectoryNotEmptyException(target.toString());
- } else {
- removeEntry(target);
- moveEntry(source, target, false);
- }
- } else {
- // move into the target
- // TODO SPEC is FileAlreadyExistsException ?
- moveEntry(source, target, true);
- }
- } else {
- if (options != null && options.stream().anyMatch(o -> o.equals(StandardCopyOption.REPLACE_EXISTING))) {
- removeEntry(target);
- moveEntry(source, target, false);
- } else {
- throw new FileAlreadyExistsException(target.toString());
- }
- }
- } else {
- if (source.getParent().equals(target.getParent())) {
- // rename
- renameEntry(source, target);
- } else {
- moveEntry(source, target, false);
- }
+ protected File copyEntry(File sourceEntry, File targetParentEntry, Path source, Path target, Set options) throws IOException {
+ File entry = new File();
+ entry.setName(toFilenameString(target));
+ entry.setParents(Arrays.asList(targetParentEntry.getId()));
+ if (options != null && options.stream().anyMatch(o -> o.equals(GoogleDriveCopyOption.EXPORT_AS_GDOCS))) {
+ entry.setMimeType(GoogleDriveCopyOption.EXPORT_AS_GDOCS.getValue());
}
+ return drive.files().copy(sourceEntry.getId(), entry).setFields(ENTRY_FIELDS).execute();
}
- /**
- * Check access modes for a path on this filesystem
- *
- * If no modes are provided to check for, this simply checks for the
- * existence of the path.
- *
- *
- * @param path the path to check
- * @param modes the modes to check for, if any
- * @throws IOException filesystem level error, or a plain I/O error
- * if you use this with fuse, you should throw {@link NoSuchFileException} when the file not found.
- * @see FileSystemProvider#checkAccess(Path, AccessMode...)
- */
@Override
- protected void checkAccessImpl(final Path path, final AccessMode... modes) throws IOException {
- final File entry = cache.getEntry(path);
-
- if (isFolder(entry)) {
- return;
+ protected File moveEntry(File sourceEntry, File targetParentEntry, Path source, Path target, boolean targetIsParent) throws IOException {
+ File entry = new File();
+ entry.setName(toFilenameString(target));
+ String previousParents = null;
+ if (sourceEntry.getParents() != null) {
+ previousParents = String.join(",", sourceEntry.getParents());
}
+ return drive.files().update(sourceEntry.getId(), entry)
+ .setAddParents(targetParentEntry.getId())
+ .setRemoveParents(previousParents)
+ .setFields(ENTRY_FIELDS).execute();
+ }
- // TODO: assumed; not a file == directory
- for (final AccessMode mode : modes) {
- if (mode == AccessMode.EXECUTE) {
- throw new AccessDeniedException(path.toString());
- }
+ @Override
+ protected File moveFolderEntry(File sourceEntry, File targetParentEntry, Path source, Path target, boolean targetIsParent) throws IOException {
+ File dirEntry = new File();
+ dirEntry.setName(toFilenameString(target));
+ dirEntry.setMimeType(MIME_TYPE_DIR);
+ String previousParents = null;
+ if (sourceEntry.getParents() != null) {
+ previousParents = String.join(",", sourceEntry.getParents());
}
+ return drive.files().update(sourceEntry.getId(), dirEntry)
+ .setAddParents(targetParentEntry.getId())
+ .setRemoveParents(previousParents)
+ .setFields(ENTRY_FIELDS).execute();
}
@Override
- public void close() throws IOException {
- // GoogleDrive does not implement Closeable :(
+ protected File renameEntry(File sourceEntry, File targetParentEntry, Path source, Path target) throws IOException {
+ File entry = new File();
+ entry.setName(toFilenameString(target));
+ return drive.files().update(sourceEntry.getId(), entry).setFields(ENTRY_FIELDS).execute();
}
- /**
- * @throws IOException if you use this with fuse, you should throw {@link NoSuchFileException} when the file not found.
- */
- @Nonnull
@Override
- protected Object getPathMetadataImpl(final Path path) throws IOException {
- return cache.getEntry(path);
+ protected Object getPathMetadata(File entry) throws IOException {
+ return new Metadata(this, entry);
}
- /** */
- private List getDirectoryEntries(Path dir, boolean useCache) throws IOException {
- final File entry = cache.getEntry(dir);
-
- if (!isFolder(entry)) {
- throw new NotDirectoryException("dir: " + dir);
+ @Override
+ public WatchService newWatchService() {
+ try {
+ return new GoogleDriveWatchService(drive);
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
}
+ }
- List list = new ArrayList<>();
- if (useCache && cache.containsFolder(dir)) {
- list = cache.getFolder(dir);
- } else {
- Files.List request = drive.files().list();
- do {
- FileList files = request
- .setQ("'" + entry.getId() + "' in parents and trashed=false")
- .setFields("nextPageToken, files(" + ENTRY_FIELDS + ")").execute();
- final List children = files.getFiles();
- request.setPageToken(files.getNextPageToken());
-
- for (final File child : children) {
- Path childPath = dir.resolve(child.getName());
- list.add(childPath);
-
- cache.putFile(childPath, child);
- }
- } while (request.getPageToken() != null && request.getPageToken().length() > 0);
-
- cache.putFolder(dir, list);
- }
+ //
+ // user:attributes
+ //
- return list;
+ /** attributes user:description */
+ void patchEntryDescription(File sourceEntry, String description) throws IOException {
+ File entry = new File();
+ entry.setDescription(description);
+ File newEntry = drive.files().update(sourceEntry.getId(), entry).setFields(ENTRY_FIELDS).execute();
+ Path path = cache.getEntry(sourceEntry);
+ cache.removeEntry(path);
+ cache.addEntry(path, newEntry);
}
- /** */
- private void removeEntry(Path path) throws IOException {
- final File entry = cache.getEntry(path);
+ /** attributes user:revisions */
+ List getRevisions(File entry) throws IOException {
if (isFolder(entry)) {
- // TODO use cache ???
- List list = drive.files().list()
- .setQ("'" + entry.getId() + "' in parents and trashed=false")
- .execute().getFiles();
+ throw new IsDirectoryException("dir: " + entry.getName());
+ }
- if (list != null && list.size() > 0) {
- throw new DirectoryNotEmptyException(path.toString());
+ List list = new ArrayList<>();
+ String pageToken = null;
+ do {
+ RevisionList revisions = drive.revisions().list(entry.getId())
+ .setPageSize(1000)
+ .setFields("nextPageToken, revisions(id, mimeType, modifiedTime, size)")
+ .setPageToken(pageToken)
+ .execute();
+
+ if (revisions.getRevisions() != null) {
+Debug.println(Level.FINE, "revisions: " + revisions.getRevisions().size() + ", " + revisions.getNextPageToken());
+ revisions.getRevisions().forEach(r -> list.add(r));
}
- }
- drive.files().delete(entry.getId()).execute();
+ pageToken = revisions.getNextPageToken();
+ } while (pageToken != null);
- cache.removeEntry(path);
+ return list;
}
- /** */
- private void copyEntry(final Path source, final Path target, Set options) throws IOException {
- final File sourceEntry = cache.getEntry(source);
- File targetParentEntry = cache.getEntry(target.getParent());
- if (!isFolder(sourceEntry)) {
- File entry = new File();
- entry.setName(toFilenameString(target));
- entry.setParents(Arrays.asList(targetParentEntry.getId()));
- if (options != null && options.stream().anyMatch(o -> o.equals(GoogleDriveCopyOption.EXPORT_AS_GDOCS))) {
- entry.setMimeType(GoogleDriveCopyOption.EXPORT_AS_GDOCS.getValue());
- }
- File newEntry = drive.files().copy(sourceEntry.getId(), entry).setFields(ENTRY_FIELDS).execute();
-
- cache.addEntry(target, newEntry);
- } else {
- // TODO java spec. allows empty folder
- throw new UnsupportedOperationException("source can not be a folder");
- }
+ /** attributes user:revisions */
+ void removeRevision(File entry, String revisionId) throws IOException {
+Debug.println(Level.INFO, "delete revision: " + entry.getName() + ", revision: " + revisionId);
+ drive.revisions().delete(entry.getId(), revisionId).execute();
}
/**
- * @param targetIsParent if the target is folder
+ * attributes user:thumbnail
+ * @param image currently only jpeg is available.
*/
- private void moveEntry(final Path source, final Path target, boolean targetIsParent) throws IOException {
- File sourceEntry = cache.getEntry(source);
- File targetParentEntry = cache.getEntry(targetIsParent ? target : target.getParent());
- if (!isFolder(sourceEntry)) {
- File entry = new File();
- entry.setName(targetIsParent ? toFilenameString(source) : toFilenameString(target));
- String previousParents = null;
- if (sourceEntry.getParents() != null) {
- previousParents = String.join(",", sourceEntry.getParents());
- }
- File newEntry = drive.files().update(sourceEntry.getId(), entry)
- .setAddParents(targetParentEntry.getId())
- .setRemoveParents(previousParents)
- .setFields(ENTRY_FIELDS).execute();
- cache.removeEntry(source);
- if (targetIsParent) {
- cache.addEntry(target.resolve(source.getFileName()), newEntry);
- } else {
- cache.addEntry(target, newEntry);
- }
- } else if (isFolder(sourceEntry)) {
- File dirEntry = new File();
- dirEntry.setName(toFilenameString(target));
- dirEntry.setMimeType(MIME_TYPE_DIR);
- String previousParents = null;
- if (sourceEntry.getParents() != null) {
- previousParents = String.join(",", sourceEntry.getParents());
- }
- File newEntry = drive.files().update(sourceEntry.getId(), dirEntry)
- .setAddParents(targetParentEntry.getId())
- .setRemoveParents(previousParents)
- .setFields(ENTRY_FIELDS).execute();
- cache.moveEntry(source, target, newEntry);
- }
+ void setThumbnail(File sourceEntry, byte[] image) throws IOException {
+ File.ContentHints.Thumbnail thumbnail = new File.ContentHints.Thumbnail();
+ thumbnail.setMimeType("image/jpg");
+ thumbnail.encodeImage(image);
+
+ File.ContentHints contentHints = new File.ContentHints();
+ contentHints.setThumbnail(thumbnail);
+
+ File entry = new File();
+ entry.setContentHints(contentHints);
+
+ File newEntry = drive.files().update(sourceEntry.getId(), entry).setFields("thumbnailLink").execute();
+Debug.println(Level.INFO, "thumbnail updated: " + sourceEntry.getName() + ", size: " + image.length + ", " + StringUtil.paramString(newEntry));
}
- /** */
- private void renameEntry(final Path source, final Path target) throws IOException {
- File sourceEntry = cache.getEntry(source);
+ /**
+ * attributes user:thumbnail
+ * @return url
+ * @see "https://stackoverflow.com/a/45027853"
+ */
+ String getThumbnail(File sourceEntry) throws IOException {
File entry = new File();
- entry.setName(toFilenameString(target));
- File newEntry = drive.files().update(sourceEntry.getId(), entry).setFields(ENTRY_FIELDS).execute();
- cache.removeEntry(source);
- cache.addEntry(target, newEntry);
+
+ File newEntry = drive.files().update(sourceEntry.getId(), entry).setFields("thumbnailLink").execute();
+Debug.println(Level.INFO, "thumbnail url: " + sourceEntry.getName() + ", url: " + newEntry.getThumbnailLink());
+ return newEntry.getThumbnailLink();
}
}
diff --git a/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveFileSystemOptionsFactory.java b/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveFileSystemOptionsFactory.java
index 9b429cfc..4d96f21d 100644
--- a/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveFileSystemOptionsFactory.java
+++ b/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveFileSystemOptionsFactory.java
@@ -23,6 +23,8 @@ public GoogleDriveFileSystemOptionsFactory() {
addLinkOption(LinkOption.NOFOLLOW_LINKS);
addCopyOption(GoogleDriveCopyOption.EXPORT_AS_GDOCS);
addReadOpenOption(GoogleDriveOpenOption.EXPORT_WITH_GDOCS_DOCX);
+ addReadOpenOption(GoogleDriveOpenOption.EXPORT_WITH_GDOCS_XLSX);
+ addWriteOpenOption(GoogleDriveOpenOption.INPORT_AS_NEW_REVISION);
}
}
diff --git a/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveFileSystemProvider.java b/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveFileSystemProvider.java
index f40aeb46..fffd1ac2 100644
--- a/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveFileSystemProvider.java
+++ b/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveFileSystemProvider.java
@@ -23,6 +23,8 @@ public final class GoogleDriveFileSystemProvider extends FileSystemProviderBase
public static final String ENV_APP_CREDENTIAL = "app_credential";
+ public static final String ENV_USE_SYSTEM_WATCHER = "use_system_watcher";
+
public GoogleDriveFileSystemProvider() {
super(new GoogleDriveFileSystemRepository());
}
diff --git a/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveFileSystemRepository.java b/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveFileSystemRepository.java
index 7b652c13..fc7be447 100644
--- a/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveFileSystemRepository.java
+++ b/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveFileSystemRepository.java
@@ -16,11 +16,12 @@
import com.github.fge.filesystem.driver.FileSystemDriver;
import com.github.fge.filesystem.provider.FileSystemRepositoryBase;
+import com.google.api.client.auth.oauth2.Credential;
import com.google.api.services.drive.Drive;
import vavi.net.auth.WithTotpUserCredential;
-import vavi.net.auth.oauth2.google.GoogleAppCredential;
-import vavi.net.auth.oauth2.google.GoogleLocalAppCredential;
+import vavi.net.auth.oauth2.google.GoogleOAuth2AppCredential;
+import vavi.net.auth.oauth2.google.GoogleLocalOAuth2AppCredential;
import vavi.net.auth.oauth2.google.GoogleOAuth2;
import vavi.net.auth.web.google.GoogleLocalUserCredential;
@@ -64,18 +65,26 @@ public FileSystemDriver createDriver(final URI uri, final Map env) th
}
// 2. app credential
- GoogleAppCredential appCredential = null;
+ GoogleOAuth2AppCredential appCredential = null;
if (env.containsKey(GoogleDriveFileSystemProvider.ENV_APP_CREDENTIAL)) {
- appCredential = GoogleAppCredential.class.cast(env.get(GoogleDriveFileSystemProvider.ENV_APP_CREDENTIAL));
+ appCredential = GoogleOAuth2AppCredential.class.cast(env.get(GoogleDriveFileSystemProvider.ENV_APP_CREDENTIAL));
}
if (appCredential == null) {
- appCredential = new GoogleLocalAppCredential(); // TODO use props
+ appCredential = new GoogleLocalOAuth2AppCredential("googledrive"); // TODO use props
}
// 3. process
- Drive drive = new GoogleOAuth2(appCredential).authorize(userCredential);
+ Credential credential = new GoogleOAuth2(appCredential).authorize(userCredential);
+ Drive drive = new Drive.Builder(GoogleOAuth2.getHttpTransport(), GoogleOAuth2.getJsonFactory(), credential)
+ .setHttpRequestInitializer(httpRequest -> {
+ credential.initialize(httpRequest);
+ httpRequest.setConnectTimeout(30 * 1000);
+ httpRequest.setReadTimeout(30 * 1000);
+ })
+ .setApplicationName(appCredential.getClientId())
+ .build();
GoogleDriveFileStore fileStore = new GoogleDriveFileStore(drive, factoryProvider.getAttributesFactory());
return new GoogleDriveFileSystemDriver(fileStore, factoryProvider, drive, env);
}
diff --git a/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveOpenOption.java b/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveOpenOption.java
index 9c58c25d..4021c9f4 100644
--- a/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveOpenOption.java
+++ b/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveOpenOption.java
@@ -12,15 +12,27 @@
/**
* GoogleDriveOpenOption.
*
+ * TODO direct ocr
+ *
* @author Naohide Sano (umjammer)
* @version 0.00 2017/03/01 umjammer initial version
*/
public enum GoogleDriveOpenOption implements OpenOption {
+ /**
+ * download a file as docx.
+ */
EXPORT_WITH_GDOCS_DOCX("application/vnd.openxmlformats-officedocument.wordprocessingml.document"),
- EXPORT_WITH_GDOCS_XLSX("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
-
- /** */
+ /**
+ * download a file as xlsx.
+ */
+ EXPORT_WITH_GDOCS_XLSX("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"),
+ /**
+ * upload a file as new revision.
+ */
+ INPORT_AS_NEW_REVISION(null);
+
+ /** depends on enum stuff */
private String value;
/** */
diff --git a/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveUserDefinedFileAttributesProvider.java b/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveUserDefinedFileAttributesProvider.java
new file mode 100644
index 00000000..cb731e28
--- /dev/null
+++ b/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveUserDefinedFileAttributesProvider.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.googledrive;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.nio.ByteBuffer;
+import java.time.OffsetDateTime;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Level;
+import java.util.stream.Collectors;
+
+import com.github.fge.filesystem.attributes.provider.UserDefinedFileAttributesProvider;
+import com.google.api.services.drive.model.File;
+import com.google.api.services.drive.model.Revision;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+import vavi.nio.file.googledrive.GoogleDriveFileAttributesFactory.Metadata;
+import vavi.util.Debug;
+
+
+/**
+ * GoogleDriveUserDefinedFileAttributesProvider.
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/09/08 umjammer initial version
+ */
+public class GoogleDriveUserDefinedFileAttributesProvider extends UserDefinedFileAttributesProvider {
+
+ /** driver & file entry */
+ private final Metadata entry;
+
+ /** */
+ public GoogleDriveUserDefinedFileAttributesProvider(Metadata entry) throws IOException {
+ this.entry = entry;
+ }
+
+ /** pre-listed */
+ private static final List list = Arrays.stream(UserAttributes.values()).map(e -> e.name()).collect(Collectors.toList());
+
+ @Override
+ public List list() throws IOException {
+ return list;
+ }
+
+ @Override
+ public int size(String name) throws IOException {
+ return UserAttributes.valueOf(name).size(entry);
+ }
+
+ @Override
+ public int read(String name, ByteBuffer dst) throws IOException {
+ return UserAttributes.valueOf(name).read(entry, dst);
+ }
+
+ @Override
+ public int write(final String name, final ByteBuffer src) throws IOException {
+ return UserAttributes.valueOf(name).write(entry, src);
+ }
+
+ /** */
+ private interface UserAttribute {
+ int size(T entry) throws IOException;
+ int read(T entry, ByteBuffer dst) throws IOException;
+ int write(T entry, ByteBuffer src) throws IOException;
+ }
+
+ /** user:foo */
+ private enum UserAttributes implements UserAttribute {
+ /** {@link String} */
+ description {
+ /** */
+ Map descriptionCache = new ConcurrentHashMap<>(); // TODO LRU
+
+ /** */
+ private String getDescription(File file) {
+ if (descriptionCache.containsKey(file)) {
+ return descriptionCache.get(file);
+ } else {
+ String description = file.getDescription();
+ descriptionCache.put(file, description);
+ return description;
+ }
+ }
+
+ @Override
+ public int size(Metadata entry) throws IOException {
+ String description = getDescription(entry.file);
+if (description != null) {
+ Debug.println(Level.FINE, "size " + name() + ": " + description);
+}
+ return description == null ? 0 : description.getBytes().length;
+ }
+
+ @Override
+ public int read(Metadata entry, ByteBuffer dst) throws IOException {
+ String description = getDescription(entry.file);
+if (description != null) {
+ Debug.println(Level.FINE, "read " + name() + ": " + description);
+}
+ if (description != null) {
+ dst.put(description.getBytes());
+ }
+ return dst.array().length;
+ }
+
+ @Override
+ public int write(Metadata entry, ByteBuffer src) throws IOException {
+ String description = new String(src.array());
+Debug.println(Level.FINE, "write " + name() + ": " + description);
+ entry.driver.patchEntryDescription(entry.file, description);
+ return description.getBytes().length;
+ }
+ },
+ /** {@link String}, "\n" separated */
+ revisions {
+ /** */
+ Map> revisionsCache = new ConcurrentHashMap<>(); // TODO LRU
+
+ /** */
+ private List getRevisions(Metadata entry) throws IOException {
+ if (revisionsCache.containsKey(entry.file)) {
+ return revisionsCache.get(entry.file);
+ } else {
+ List revisions = entry.driver.getRevisions(entry.file);
+ List results = revisions.stream().map(r -> r.toString()).collect(Collectors.toList());
+ revisionsCache.put(entry.file, results);
+ return results;
+ }
+ }
+
+ @Override
+ public int size(Metadata entry) throws IOException {
+ // joined by '\n'
+ int len = getRevisions(entry).stream().mapToInt(r -> r.toString().getBytes().length + 1).sum() - 1;
+if (len > 0) {
+ Debug.println(Level.FINE, "size " + name() + ": " + len);
+}
+ return len;
+ }
+
+ @Override
+ public int read(Metadata entry, ByteBuffer dst) throws IOException {
+Debug.println(Level.FINE, "read " + name() + ":\n" + String.join("\n", getRevisions(entry)));
+ dst.put(String.join("\n", getRevisions(entry)).getBytes());
+ return dst.array().length;
+ }
+
+ @Override
+ public int write(Metadata entry, ByteBuffer src) throws IOException {
+ String[] revisions = RevisionsUtil.split(src.array());
+Arrays.stream(revisions).forEach(r -> {
+ Debug.println(Level.INFO, "write " + name() + ": " + r);
+});
+ // to be deleted
+ List toDeleted = new ArrayList<>();
+ Arrays.stream(revisions)
+ .map(y -> (String) gson.fromJson(y, Map.class).get("id"))
+ .forEach(b -> {
+ try {
+ toDeleted.addAll(getRevisions(entry).stream()
+ .map(x -> (String) gson.fromJson(x, Map.class).get("id"))
+ .filter(a -> !a.equals(b))
+ .collect(Collectors.toList()));
+ } catch (IOException e) {
+Debug.printStackTrace(Level.WARNING, e);
+ }
+ });
+
+ toDeleted.forEach(id -> {
+ try {
+ entry.driver.removeRevision(entry.file, id);
+ } catch (IOException e) {
+Debug.printStackTrace(Level.WARNING, e);
+ }
+ });
+
+ revisionsCache.remove(entry.file);
+
+ // TODO to be added?
+
+ return src.array().length;
+ }
+ },
+ /** whole image file */
+ thumbnail {
+ /** */
+ Map thumbnailCache = new ConcurrentHashMap<>(); // TODO LRU
+
+ /** */
+ private String getUrl(Metadata entry) throws IOException {
+ String url = thumbnailCache.get(entry.file);
+ if (url != null) {
+ return url;
+ } else {
+ url = entry.driver.getThumbnail(entry.file);
+ if (url != null) {
+ thumbnailCache.put(entry.file, url);
+ }
+ return url;
+ }
+ }
+
+ /** */
+ private byte[] getThumbnail(Metadata entry) throws IOException {
+try {
+ String url = getUrl(entry);
+ InputStream is = new BufferedInputStream(new URL(url).openStream());
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ byte[] buffer = new byte[8024];
+ int l = 0;
+ while ((l = is.read(buffer)) != -1) {
+ baos.write(buffer, 0, l);
+ }
+ return baos.toByteArray();
+} catch (java.io.FileNotFoundException e) {
+ Debug.println(Level.WARNING, e.toString());
+ return null;
+}
+ }
+
+ @Override
+ public int size(Metadata entry) throws IOException {
+ String url = getUrl(entry);
+ if (url != null) {
+ byte[] thumbnail = getThumbnail(entry);
+ if (thumbnail != null) {
+ return thumbnail.length;
+ }
+ }
+ return 0;
+ }
+
+ @Override
+ public int read(Metadata entry, ByteBuffer dst) throws IOException {
+ String url = getUrl(entry);
+ if (url != null) {
+ byte[] thumbnail = getThumbnail(entry);
+ if (thumbnail != null) {
+ dst.put(thumbnail);
+ return thumbnail.length;
+ }
+ }
+ return 0;
+ }
+
+ @Override
+ public int write(Metadata entry, ByteBuffer src) throws IOException {
+ byte[] thumbnail = src.array();
+ entry.driver.setThumbnail(entry.file, thumbnail);
+ return thumbnail.length;
+ }
+ };
+ }
+
+ /** */
+ private static Gson gson = new GsonBuilder().create();
+
+ /** utility */
+ public static class RevisionsUtil {
+ /** sort by "modifiedTime" desc */
+ public static byte[] getLatestOnly(byte[] revisions) {
+ List> revisionList = Arrays.stream(split(revisions))
+ .map(r -> gson.fromJson(r, Map.class))
+ .sorted((o1, o2) -> {
+ OffsetDateTime odt1 = OffsetDateTime.parse((String) o1.get("modifiedTime"));
+ OffsetDateTime odt2 = OffsetDateTime.parse((String) o2.get("modifiedTime"));
+ return odt2.compareTo(odt1);
+ })
+ .collect(Collectors.toList());
+//revisionList.forEach(System.err::println);
+ return gson.toJson(revisionList.get(0)).getBytes();
+ }
+ public static String[] split(byte[] revisions) {
+ return new String((byte[]) revisions).split("\n");
+ }
+ public static int size(Object revisions) {
+ return split((byte[]) revisions).length;
+ }
+ }
+}
+
+/* */
diff --git a/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveWatchService.java b/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveWatchService.java
new file mode 100644
index 00000000..3e7a8c5d
--- /dev/null
+++ b/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/GoogleDriveWatchService.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.googledrive;
+
+import java.io.IOException;
+import java.util.UUID;
+
+import com.google.api.client.googleapis.notifications.UnparsedNotification;
+import com.google.api.services.drive.Drive;
+import com.google.api.services.drive.model.Change;
+import com.google.api.services.drive.model.ChangeList;
+import com.google.api.services.drive.model.Channel;
+import com.google.api.services.drive.model.File;
+import com.google.api.services.drive.model.StartPageToken;
+
+import vavi.nio.file.watch.webhook.WebHookBaseWatchService;
+import vavi.util.Debug;
+
+import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
+
+
+/**
+ * GoogleDriveWatchService.
+ *
+ * notification source is {@link #channel}.
+ *
+ * system properties
+ *
+ * vavi.nio.file.watch.webhook.NotificationProvider.googledrive
+ *
+ *
+ *
+ * environment variables
+ *
+ * VAVI_APPS_WEBHOOK_SECRET
+ * VAVI_APPS_WEBHOOK_WEBHOOK_GOOGLE_URL
+ *
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/07/06 umjammer initial version
+ */
+public class GoogleDriveWatchService extends WebHookBaseWatchService {
+
+ private static final String WEBHOOK_NOTIFICATION_PROVIDER =
+ System.getProperty("vavi.nio.file.watch.webhook.NotificationProvider.googledrive", ".googledrive.webhook.websocket");
+
+ private static final String VAVI_APPS_WEBHOOK_SECRET = System.getenv("VAVI_APPS_WEBHOOK_SECRET");
+ private static final String webhooktUrl = System.getenv("VAVI_APPS_WEBHOOK_WEBHOOK_GOOGLE_URL");
+
+ private Drive drive;
+ private Channel channel = null;
+
+ private String savedStartPageToken;
+
+ /** */
+ public GoogleDriveWatchService(Drive drive) throws IOException {
+ this.drive = drive;
+
+ UUID uuid = UUID.randomUUID();
+
+ setupNotification(this, WEBHOOK_NOTIFICATION_PROVIDER, uuid);
+
+ StartPageToken response = drive.changes().getStartPageToken().execute();
+ savedStartPageToken = response.getStartPageToken();
+Debug.println("GOOGLE: start token: " + savedStartPageToken);
+
+ Channel content = new Channel()
+ .setId(uuid.toString())
+ .setType("web_hook")
+ .setToken(VAVI_APPS_WEBHOOK_SECRET)
+ .setAddress(webhooktUrl);
+
+ channel = drive.changes().watch(savedStartPageToken, content).execute();
+Debug.println("GOOGLE: channel: " + channel);
+ }
+
+ /**
+ UnparsedNotification{
+ messageNumber=9727,
+ resourceState=change,
+ resourceId=r7_j-XM_WRzwHe8Lns_ECZzzXS8,
+ resourceUri=https://www.googleapis.com/drive/v3/changes?includeCorpusRemovals=false&includeItemsFromAllDrives=false&includeRemoved=true&includeTeamDriveItems=false&pageSize=100&pageToken=905064&restrictToMyDrive=false&spaces=drive&supportsAllDrives=false&supportsTeamDrives=false&alt=json,
+ channelId=$uuid,
+ channelExpiration=Mon, 06 Jul 2020 16:44:43 GMT,
+ channelToken=$VAVI_APPS_WEBHOOK_SECRET,
+ changed=null,
+ contentType=null
+ }
+ */
+ protected void onNotifyMessage(UnparsedNotification notification) throws IOException {
+Debug.println(">> notification: " + notification.getResourceState());
+
+ if (!channel.getId().equals(notification.getChannelId())) {
+Debug.println(">> notification is not for this channel: " + notification.getChannelId());
+
+//try { // *** STOP ANOTHER CHANNEL ***
+// Channel c = new Channel();
+// c.setId(notification.getChannelId());
+// c.setResourceId(notification.getResourceId());
+// drive.channels().stop(c).execute();
+// Debug.println(">> notification: stop another channel: " + c.getId());
+//} catch (IOException e) {
+// e.printStackTrace();
+//}
+
+ return;
+ }
+
+ switch (notification.getResourceState()) {
+ case "sync":
+Debug.println(">> synched");
+ break;
+ case "change":
+ // Begin with our last saved start token for this user or the
+ // current token from getStartPageToken()
+ String pageToken = savedStartPageToken;
+ while (pageToken != null) {
+ ChangeList changes = drive.changes().list(pageToken).execute();
+ for (Change change : changes.getChanges()) {
+ // Process change
+Debug.println(">> " + (change.getFile() == null ? "id" : isFolder(change.getFile()) ? "folder" : "file") +
+ "[" + (change.getFile() != null ? change.getFile().getName() : change.getFileId()) + "] " + (change.getRemoved() ? "deleted" : "updated?"));
+
+ listener.accept(change.getFileId(), change.getRemoved() ? ENTRY_DELETE : ENTRY_MODIFY);
+ }
+ if (changes.getNewStartPageToken() != null) {
+ // Last page, save this token for the next polling interval
+ savedStartPageToken = changes.getNewStartPageToken();
+ }
+ pageToken = changes.getNextPageToken();
+ }
+ break;
+ default:
+Debug.println(">> unhandled state: " + notification.getResourceState());
+ break;
+ }
+
+Debug.println(">> notification: done");
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (isOpen()) {
+ super.close();
+
+ drive.channels().stop(channel).execute();
+Debug.println("GOOGLE: channel deleted: " + channel);
+ }
+ }
+
+ /** TODO duplicated */
+ private static boolean isFolder(File file) {
+ return GoogleDriveFileSystemDriver.MIME_TYPE_DIR.equals(file.getMimeType());
+ }
+}
diff --git a/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/webhook/websocket/GoogleJsonCodec.java b/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/webhook/websocket/GoogleJsonCodec.java
new file mode 100644
index 00000000..a453536d
--- /dev/null
+++ b/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/webhook/websocket/GoogleJsonCodec.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.googledrive.webhook.websocket;
+
+import com.google.api.client.googleapis.notifications.UnparsedNotification;
+import com.google.gson.Gson;
+
+import vavi.nio.file.watch.webhook.websocket.JsonCodec;
+
+
+/**
+ * GoogleJsonCodec.
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/07/02 umjammer initial version
+ */
+public class GoogleJsonCodec extends JsonCodec {
+
+ public static Gson gsonForGoogleJsonCodec = gson;
+
+ public static class GoogleJsonEncoder extends JsonEncoder {
+ }
+
+ public static class GoogleJsonDecoder extends JsonDecoder {
+ @Override
+ protected Class getType() {
+ return UnparsedNotification.class;
+ }
+ }
+}
+
+/* */
diff --git a/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/webhook/websocket/GoogleWebSocketNotification.java b/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/webhook/websocket/GoogleWebSocketNotification.java
new file mode 100644
index 00000000..3bd523f5
--- /dev/null
+++ b/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/webhook/websocket/GoogleWebSocketNotification.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.googledrive.webhook.websocket;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.function.Consumer;
+
+import javax.websocket.ClientEndpoint;
+import javax.websocket.Session;
+
+import com.google.api.client.googleapis.notifications.UnparsedNotification;
+
+import vavi.nio.file.googledrive.webhook.websocket.GoogleJsonCodec.GoogleJsonDecoder;
+import vavi.nio.file.googledrive.webhook.websocket.GoogleJsonCodec.GoogleJsonEncoder;
+import vavi.nio.file.watch.webhook.websocket.BasicAuthorizationConfigurator;
+import vavi.nio.file.watch.webhook.websocket.WebSocketNotification;
+
+
+/**
+ * GoogleWebSocketNotification.
+ *
+ * environment variables
+ *
+ * VAVI_APPS_WEBHOOK_WEBSOCKET_BASE_URL
+ * VAVI_APPS_WEBHOOK_WEBSOCKET_GOOGLE_PATH
+ *
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/07/06 umjammer initial version
+ */
+@ClientEndpoint(decoders = GoogleJsonDecoder.class,
+ encoders = GoogleJsonEncoder.class,
+ configurator = BasicAuthorizationConfigurator.class)
+public class GoogleWebSocketNotification extends WebSocketNotification {
+
+ private static final String websocketBaseUrl = System.getenv("VAVI_APPS_WEBHOOK_WEBSOCKET_BASE_URL");
+ private static final String websocketPath = System.getenv("VAVI_APPS_WEBHOOK_WEBSOCKET_GOOGLE_PATH");
+
+ private static final URI uri = URI.create(websocketBaseUrl + websocketPath);
+
+ private Consumer callback;
+
+ /**
+ * @param args 0: uuid for channel id
+ */
+ public GoogleWebSocketNotification(Consumer callback, Object... args) throws IOException {
+ super(uri, args);
+ this.callback = callback;
+ }
+
+ @Override
+ public void onOpenImpl(Session session) throws IOException {
+ session.getBasicRemote().sendText(String.join(" ", "GOOGLE_DRIVE_CHANGE", args[0].toString()));
+ }
+
+ @Override
+ protected void onNotifyMessageImpl(UnparsedNotification notification) throws IOException {
+ callback.accept(notification);
+ }
+
+ @Override
+ protected void onCloseImpl(Session session) throws IOException {
+ }
+}
+
+/* */
diff --git a/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/webhook/websocket/GoogleWebSocketNotificationProvider.java b/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/webhook/websocket/GoogleWebSocketNotificationProvider.java
new file mode 100644
index 00000000..efaf4e6c
--- /dev/null
+++ b/vavi-nio-file-googledrive/src/main/java/vavi/nio/file/googledrive/webhook/websocket/GoogleWebSocketNotificationProvider.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.googledrive.webhook.websocket;
+
+import java.io.IOException;
+import java.util.function.Consumer;
+
+import vavi.nio.file.watch.webhook.Notification;
+import vavi.nio.file.watch.webhook.NotificationProvider;
+
+
+/**
+ * GoogleWebSocketNotificationProvider.
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/07/07 umjammer initial version
+ */
+public class GoogleWebSocketNotificationProvider implements NotificationProvider {
+
+ @Override
+ public Notification getNotification(Consumer callback, Object... args) throws IOException {
+ return Notification.class.cast(new GoogleWebSocketNotification(Consumer.class.cast(callback), args));
+ }
+}
+
+/* */
diff --git a/vavi-nio-file-googledrive/src/main/resources/META-INF/services/vavi.nio.file.watch.webhook.NotificationProvider b/vavi-nio-file-googledrive/src/main/resources/META-INF/services/vavi.nio.file.watch.webhook.NotificationProvider
new file mode 100644
index 00000000..451d5380
--- /dev/null
+++ b/vavi-nio-file-googledrive/src/main/resources/META-INF/services/vavi.nio.file.watch.webhook.NotificationProvider
@@ -0,0 +1 @@
+vavi.nio.file.googledrive.webhook.websocket.GoogleWebSocketNotificationProvider
diff --git a/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/GoogleDriveFS.java b/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/GoogleDriveFS.java
deleted file mode 100644
index 6dcb5c56..00000000
--- a/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/GoogleDriveFS.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2016 by Naohide Sano, All rights reserved.
- *
- * Programmed by Naohide Sano
- */
-
-package vavi.nio.file.googledrive;
-
-import java.net.URI;
-import java.nio.file.FileSystem;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-import vavi.net.fuse.Fuse;
-
-
-/**
- * GoogleDriveFS.
- *
- * @depends "file://${HOME}.vavifuse/googledrive/?"
- *
- * @author Naohide Sano (umjammer)
- * @version 0.00 2016/02/29 umjammer initial version
- */
-public class GoogleDriveFS {
- /**
- * @param args 0: mount point, 1: email
- */
- public static void main(String[] args) throws Exception {
- if (args.length != 2) {
- System.err.println("Usage: GoogleDriveFS ");
- System.exit(1);
- }
-
- String email = args[1];
-
- URI uri = URI.create("googledrive:///?id=" + email);
-
- Map env = new HashMap<>();
- env.put("ignoreAppleDouble", true);
-
- FileSystem fs = new GoogleDriveFileSystemProvider().newFileSystem(uri, env);
-
-// System.setProperty("vavi.net.fuse.FuseProvider.class", "vavi.net.fuse.javafs.JavaFSFuseProvider");
-// System.setProperty("vavi.net.fuse.FuseProvider.class", "vavi.net.fuse.jnrfuse.JnrFuseFuseProvider");
-
- Fuse.getFuse().mount(fs, args[0], Collections.EMPTY_MAP);
- }
-}
diff --git a/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/Main.java b/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/Main.java
index a1059f16..7cc3308b 100644
--- a/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/Main.java
+++ b/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/Main.java
@@ -11,7 +11,6 @@
import java.nio.file.Files;
import java.util.Collections;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import static vavi.nio.file.Base.testAll;
@@ -35,17 +34,16 @@ void test01() throws Exception {
URI uri = URI.create("googledrive:///?id=" + email);
- testAll(new GoogleDriveFileSystemProvider().newFileSystem(uri, Collections.EMPTY_MAP));
+ testAll(new GoogleDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap()));
}
- @Test
- @Disabled
- void test02() throws Exception {
- String email = System.getenv("GOOGLE_TEST_ACCOUNT2");
+ /** */
+ public static void main(String[] args) throws Exception {
+ String email = System.getenv("GOOGLE_TEST_ACCOUNT");
URI uri = URI.create("googledrive:///?id=" + email);
- FileSystem fs = new GoogleDriveFileSystemProvider().newFileSystem(uri, Collections.EMPTY_MAP);
+ FileSystem fs = new GoogleDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap());
Files.list(fs.getPath("/")).forEach(System.out::println);
}
}
\ No newline at end of file
diff --git a/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/Main2.java b/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/Main2.java
index b39ad608..fa80ee48 100644
--- a/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/Main2.java
+++ b/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/Main2.java
@@ -11,6 +11,7 @@
import java.util.Collections;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable;
import static vavi.nio.file.Base.testLargeFile;
@@ -27,11 +28,12 @@ public class Main2 {
* caution! google drive api quota is small for repeating tests.
*/
@Test
+ @DisabledIfEnvironmentVariable(named = "GITHUB_WORKFLOW", matches = ".*")
void test01() throws Exception {
String email = System.getenv("GOOGLE_TEST_ACCOUNT");
URI uri = URI.create("googledrive:///?id=" + email);
- FileSystem fs = new GoogleDriveFileSystemProvider().newFileSystem(uri, Collections.EMPTY_MAP);
+ FileSystem fs = new GoogleDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap());
testLargeFile(fs, null);
}
diff --git a/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/Main3.java b/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/Main3.java
index ea43f868..36552127 100644
--- a/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/Main3.java
+++ b/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/Main3.java
@@ -31,7 +31,7 @@ void test01() throws Exception {
String email = System.getenv("GOOGLE_TEST_ACCOUNT");
URI uri = URI.create("googledrive:///?id=" + email);
- FileSystem fs = new GoogleDriveFileSystemProvider().newFileSystem(uri, Collections.EMPTY_MAP);
+ FileSystem fs = new GoogleDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap());
testMoveFolder(fs);
}
diff --git a/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/Main4.java b/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/Main4.java
index 7bb6ca19..6c0425c7 100644
--- a/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/Main4.java
+++ b/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/Main4.java
@@ -10,7 +10,6 @@
import java.net.URI;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
-import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@@ -74,7 +73,7 @@ public void test01(String providerClassName) throws Exception {
//
- public static void main(final String... args) throws IOException {
+ public static void main(String[] args) throws IOException {
String email = args[1];
Map env = new HashMap<>();
@@ -84,17 +83,17 @@ public static void main(final String... args) throws IOException {
FileSystem fs = new GoogleDriveFileSystemProvider().newFileSystem(uri, env);
-// System.setProperty("vavi.net.fuse.FuseProvider.class", "vavi.net.fuse.javafs.JavaFSFuseProvider");
+ System.setProperty("vavi.net.fuse.FuseProvider.class", "vavi.net.fuse.javafs.JavaFSFuseProvider");
// System.setProperty("vavi.net.fuse.FuseProvider.class", "vavi.net.fuse.jnrfuse.JnrFuseFuseProvider");
Map options = new HashMap<>();
options.put("fsname", "googledrive_fs" + "@" + System.currentTimeMillis());
- options.put(vavi.net.fuse.javafs.JavaFSFuse.ENV_DEBUG, true);
+ options.put(vavi.net.fuse.javafs.JavaFSFuse.ENV_DEBUG, false);
options.put(vavi.net.fuse.javafs.JavaFSFuse.ENV_READ_ONLY, false);
options.put("noappledouble", null);
// options.put("noapplexattr", null);
- Fuse.getFuse().mount(fs, args[0], Collections.EMPTY_MAP);
+ Fuse.getFuse().mount(fs, args[0], options);
}
}
diff --git a/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/Main6.java b/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/Main6.java
new file mode 100644
index 00000000..b6a41740
--- /dev/null
+++ b/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/Main6.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.googledrive;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.Files;
+import java.util.Collections;
+
+import org.junit.jupiter.api.Test;
+
+import static vavi.nio.file.Base.testDescription;
+
+
+/**
+ * GoogleDrive user:description.
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/05/31 umjammer initial version
+ */
+public class Main6 {
+
+ @Test
+ void test01() throws Exception {
+ String email = System.getenv("GOOGLE_TEST_ACCOUNT");
+
+ URI uri = URI.create("googledrive:///?id=" + email);
+ FileSystem fs = new GoogleDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap());
+
+ testDescription(fs);
+ }
+
+ //
+
+ public static void main(String[] args) throws IOException {
+ String email = System.getenv("GOOGLE_TEST_ACCOUNT");
+
+ URI uri = URI.create("googledrive:///?id=" + email);
+ FileSystem fs = new GoogleDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap());
+
+ String description = "čĒŦæããšã " + System.currentTimeMillis() + "\n\n" + "ããŧã ããŧã ";
+ Files.setAttribute(fs.getPath("tmp/amazon_parchase_history.txt"), "user:description", description.getBytes());
+
+ fs.close();
+ }
+}
\ No newline at end of file
diff --git a/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/Main7.java b/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/Main7.java
new file mode 100644
index 00000000..4f894652
--- /dev/null
+++ b/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/Main7.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2021 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.googledrive;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.junit.jupiter.api.Test;
+
+import vavi.nio.file.googledrive.GoogleDriveUserDefinedFileAttributesProvider.RevisionsUtil;
+import vavi.util.Debug;
+
+import static java.nio.file.FileVisitResult.CONTINUE;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+
+/**
+ * GoogleDrive attribute user:revision.
+ *
+ * TODO upload a file as new revision
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2021/10/30 umjammer initial version
+ */
+public class Main7 {
+
+ @Test
+ void test01() throws Exception {
+ String email = System.getenv("GOOGLE_TEST_ACCOUNT");
+
+ URI uri = URI.create("googledrive:///?id=" + email);
+ FileSystem fs = new GoogleDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap());
+
+ Path src = Paths.get(Main7.class.getResource("/Hello.java").toURI());
+ Path dst = fs.getPath("/tmp/vavi.nio.file.googledrive.Main7-" + System.currentTimeMillis());
+
+ // revision 1
+ Files.copy(src, dst);
+
+ Thread.sleep(100);
+
+ // revision 2
+ // copy options don't be passed to the upload method of file system driver...
+ Files.copy(src, Files.newOutputStream(dst, GoogleDriveOpenOption.INPORT_AS_NEW_REVISION));
+
+ byte[] in = (byte[]) Files.getAttribute(dst, "user:revisions");
+ String[] revisions = RevisionsUtil.split(in);
+ assertEquals(2, revisions.length);
+System.err.println(dst);
+Arrays.stream(revisions).forEach(System.err::println);
+
+ // revision latest
+ byte[] out = RevisionsUtil.getLatestOnly(in);
+ Files.setAttribute(dst, "user:revisions", out);
+
+ in = (byte[]) Files.getAttribute(dst, "user:revisions");
+ revisions = RevisionsUtil.split(in);
+ assertEquals(1, revisions.length);
+System.err.println("---- latest ---");
+Arrays.stream(revisions).forEach(System.err::println);
+
+ // clean up
+ Files.delete(dst);
+
+ fs.close();
+ }
+
+ //
+
+ public static void main(String[] args) throws IOException {
+ t1(args);
+ }
+
+ /** list */
+ static void t2(String[] args) throws IOException {
+ String email = System.getenv("GOOGLE_TEST_ACCOUNT");
+
+ URI uri = URI.create("googledrive:///?id=" + email);
+ FileSystem fs = new GoogleDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap());
+
+ Files.list(fs.getPath("/tmp")).forEach(p -> {
+ try {
+ if (!Files.isDirectory(p)) {
+ System.err.println(p + "\n" + new String((byte[]) Files.getAttribute(p, "user:revisions")));
+ }
+ } catch (IOException e) {
+ System.err.println(e);
+ }
+ });
+
+ fs.close();
+ }
+
+ /** remove all remaining latest */
+ static void t3(String[] args) throws IOException {
+ String email = System.getenv("GOOGLE_TEST_ACCOUNT");
+
+ URI uri = URI.create("googledrive:///?id=" + email);
+ FileSystem fs = new GoogleDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap());
+ Path path = fs.getPath("/tmp/heroku-blog-duke.png");
+
+System.err.println("--- before ---");
+ byte[] in = (byte[]) Files.getAttribute(path, "user:revisions");
+ byte[] out = RevisionsUtil.getLatestOnly(in);
+System.err.println("--- write ---");
+System.err.println(new String(out));
+ Files.setAttribute(path, "user:revisions", out);
+
+System.err.println("--- after ---");
+ in = (byte[]) Files.getAttribute(path, "user:revisions");
+ String[] as = RevisionsUtil.split(in);
+Arrays.stream(as).forEach(System.err::println);
+
+ fs.close();
+ }
+
+ static class MyFileVisitor extends SimpleFileVisitor {
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attr) {
+ if (attr.isRegularFile()) {
+ try {
+ int size = RevisionsUtil.size(Files.getAttribute(file, "user:revisions"));
+ if (size > 1) {
+ System.err.println(file + ": " + size);
+
+System.err.println("--- before ---");
+ byte[] in = (byte[]) Files.getAttribute(file, "user:revisions");
+ byte[] out = RevisionsUtil.getLatestOnly(in);
+System.err.println("--- write ---");
+System.err.println(new String(out));
+ Files.setAttribute(file, "user:revisions", out);
+
+System.err.println("--- after ---");
+ in = (byte[]) Files.getAttribute(file, "user:revisions");
+ String[] as = RevisionsUtil.split(in);
+Arrays.stream(as).forEach(System.err::println);
+System.err.println("\n");
+ }
+ } catch (IOException e) {
+ System.err.println(e);
+ }
+ }
+ return CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
+ return CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFileFailed(Path file, IOException exc) {
+ System.err.println(exc);
+ return CONTINUE;
+ }
+ }
+
+ /** remove all remaining latest, tree */
+ static void t1(String[] args) throws IOException {
+ String email = System.getenv("GOOGLE_TEST_ACCOUNT");
+
+ URI uri = URI.create("googledrive:///?id=" + email);
+ FileSystem fs = new GoogleDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap());
+
+ Files.walkFileTree(fs.getPath("/Books/Comics/"), new MyFileVisitor());
+
+ fs.close();
+Debug.println("Done");
+ }
+}
\ No newline at end of file
diff --git a/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/Main9.java b/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/Main9.java
new file mode 100644
index 00000000..446bba06
--- /dev/null
+++ b/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/Main9.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2022 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.googledrive;
+
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collections;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+
+
+/**
+ * GoogleDrive attribute user:thumbnail
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2022/01/26 umjammer initial version
+ */
+class Main9 {
+
+ @Test
+ void test01() throws Exception {
+ String email = System.getenv("GOOGLE_TEST_ACCOUNT");
+
+ URI uri = URI.create("googledrive:///?id=" + email);
+ FileSystem fs = new GoogleDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap());
+
+ // write
+ byte[] bytes = Files.readAllBytes(Paths.get(Main9.class.getResource("/duke.jpg").toURI()));
+
+ Path sourcePath = Paths.get(Main9.class.getResource("/test.zip").toURI());
+
+// String name = "/tmp/test.zip";
+ String name = "/tmp/test" + System.currentTimeMillis() + ".zip";
+ Path targetPath = fs.getPath(name);
+
+ Files.copy(sourcePath, targetPath);
+
+ Thread.sleep(10000);
+
+ Files.setAttribute(targetPath, "user:thumbnail", bytes);
+
+ int retry = 3;
+ while (retry > 0) {
+ bytes = (byte[]) Files.getAttribute(targetPath, "user:thumbnail");
+ if (bytes.length == 0) {
+ fs.close();
+
+ fs = new GoogleDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap());
+
+ targetPath = fs.getPath(name);
+
+ Thread.sleep(10000);
+
+ Files.setAttribute(targetPath, "user:thumbnail", bytes);
+
+ retry--;
+ } else {
+ break;
+ }
+ }
+
+ fs.close();
+
+ Thread.sleep(1000);
+
+ // read
+ fs = new GoogleDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap());
+
+ targetPath = fs.getPath(name);
+
+ bytes = (byte[]) Files.getAttribute(targetPath, "user:thumbnail");
+
+ Files.delete(targetPath);
+ fs.close();
+
+ assertNotEquals(0, bytes.length);
+ Files.write(Paths.get("tmp/thumbnail.jpg"), bytes);
+ }
+}
+
+/* */
diff --git a/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/WatchDirectoryTest.java b/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/WatchDirectoryTest.java
new file mode 100644
index 00000000..27c963ee
--- /dev/null
+++ b/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/WatchDirectoryTest.java
@@ -0,0 +1,164 @@
+/*
+ * https://github.com/bbejeck/Java-7/blob/cf0256be2122d9063e21743fb01bd19f07feef69/src/test/java/bbejeck/nio/files/watch/WatchDirectoryTest.java
+ */
+
+package vavi.nio.file.googledrive;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.URI;
+import java.nio.charset.Charset;
+import java.nio.file.FileSystem;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardWatchEventKinds;
+import java.nio.file.WatchEvent;
+import java.nio.file.WatchKey;
+import java.nio.file.WatchService;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
+import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static vavi.nio.file.Base.removeTree;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: bbejeck
+ * Date: 2/13/12
+ * Time: 9:47 PM
+ */
+@Disabled
+public class WatchDirectoryTest {
+
+ static Path dir1Path;
+
+ private WatchService watchService;
+ private WatchKey basePathWatchKey;
+
+ static FileSystem fs;
+
+ static Path basePath;
+
+ @BeforeAll
+ static void before() throws IOException {
+ String email = System.getenv("GOOGLE_TEST_ACCOUNT");
+
+ URI uri = URI.create("googledrive:///?id=" + email);
+ fs = new GoogleDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap());
+
+ basePath = Files.createTempDirectory(fs.getRootDirectories().iterator().next(), "VAVIFUSE-TEST-WATCHSERVICE-");
+ dir1Path = basePath.resolve("dir1");
+ }
+
+ @AfterAll
+ static void afterAll() throws Exception {
+ Files.delete(basePath);
+ }
+
+ @BeforeEach
+ public void setUo() throws Exception {
+ watchService = fs.newWatchService();
+ basePathWatchKey = basePath.register(watchService,ENTRY_CREATE);
+ }
+
+ @AfterEach
+ public void after() throws Exception {
+ watchService.close();
+ removeTree(basePath, false);
+ }
+
+ @Test
+ public void testEventForDirectory() throws Exception {
+ generateFile(basePath.resolve("newTextFile.txt"), 10);
+ generateFile(basePath.resolve("newTextFileII.txt"), 10);
+ generateFile(basePath.resolve("newTextFileIII.txt"), 10);
+ WatchKey watchKey = watchService.poll(20, TimeUnit.SECONDS);
+ assertNotNull(watchKey);
+ assertEquals(basePathWatchKey, watchKey);
+ List> eventList = watchKey.pollEvents();
+ assertEquals(3, eventList.size());
+ for (WatchEvent> event : eventList) {
+ assertTrue(event.kind() == StandardWatchEventKinds.ENTRY_CREATE);
+ assertEquals(1, event.count());
+ }
+ Path eventPath = (Path) eventList.get(0).context();
+ assertTrue(Files.isSameFile(eventPath, Paths.get("newTextFile.txt")));
+ Path watchedPath = (Path) watchKey.watchable();
+ assertTrue(Files.isSameFile(watchedPath, basePath));
+ }
+
+ @Test
+ public void testEventForDirectoryWatchKey() throws Exception {
+ generateFile(basePath.resolve("newTextFile.txt"), 10);
+ List> eventList = basePathWatchKey.pollEvents();
+ while (eventList.size() == 0 ){
+ eventList = basePathWatchKey.pollEvents();
+ Thread.sleep(10000);
+ }
+ assertEquals(1, eventList.size());
+ for (WatchEvent> event : eventList) {
+ assertTrue(event.kind() == StandardWatchEventKinds.ENTRY_CREATE);
+ }
+ basePathWatchKey.reset();
+ generateFile(basePath.resolve("newTextFileII.txt"), 10);
+ generateFile(basePath.resolve("newTextFileIII.txt"), 10);
+ while (eventList.size() == 0 ){
+ eventList = basePathWatchKey.pollEvents();
+ Thread.sleep(10000);
+ }
+ Path eventPath = (Path) eventList.get(0).context();
+ assertTrue(Files.isSameFile(eventPath, Paths.get("newTextFile.txt")));
+ Path watchedPath = (Path) basePathWatchKey.watchable();
+ assertTrue(Files.isSameFile(watchedPath, basePath));
+ }
+
+
+
+ @Test
+ public void testEventForSubDirectory() throws Exception {
+ dir1Path.register(watchService, StandardWatchEventKinds.ENTRY_CREATE);
+ generateFile(basePath.resolve("newTextFile.txt"), 10);
+ generateFile(dir1Path.resolve("newTextFile.txt"), 10);
+ int count = 0;
+ while (count < 2) {
+ WatchKey watchKey = watchService.poll(20, TimeUnit.SECONDS);
+ @SuppressWarnings("unused")
+ Path watchedPath = (Path) watchKey.watchable();
+ assertNotNull(watchKey);
+ List> eventList = watchKey.pollEvents();
+ WatchEvent> event = eventList.get(0);
+ assertEquals(1, event.count());
+ assertTrue(event.kind() == StandardWatchEventKinds.ENTRY_CREATE);
+ assertTrue(Files.isSameFile((Path) event.context(), Paths.get("newTextFile.txt")));
+ count++;
+ }
+ }
+
+ private static final String LINE_OF_TEXT = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do " +
+ "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad " +
+ "minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea " +
+ "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit" +
+ " esse cillum dolore eu fugiat nulla pariatur. " +
+ "Excepteur sint occaecat cupidatat non proident, sunt " +
+ "in culpa qui officia deserunt mollit anim id est laborum.";
+
+ public static void generateFile(Path path, int lines) throws Exception {
+ try(PrintWriter printWriter = new PrintWriter(Files.newBufferedWriter(path, Charset.defaultCharset()))){
+ for(int i = 0; i< lines; i++){
+ printWriter.println(LINE_OF_TEXT);
+ }
+ }
+ }
+}
diff --git a/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/WatchServiceTest.java b/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/WatchServiceTest.java
new file mode 100644
index 00000000..9a18510e
--- /dev/null
+++ b/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/WatchServiceTest.java
@@ -0,0 +1,266 @@
+/*
+ * Copyright 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.
+ */
+
+package vavi.nio.file.googledrive;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.NotDirectoryException;
+import java.nio.file.Path;
+import java.nio.file.WatchEvent;
+import java.nio.file.WatchEvent.Kind;
+import java.nio.file.WatchKey;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.UUID;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.Timeout;
+
+import com.github.fge.filesystem.watch.AbstractWatchService;
+import com.google.common.collect.ImmutableList;
+import com.google.common.util.concurrent.Uninterruptibles;
+
+import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertIterableEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+
+/**
+ * Tests for {@link GoogleDriveWatchService}.
+ *
+ * @author Colin Decker
+ */
+@Disabled
+public class WatchServiceTest {
+
+ private FileSystem fs;
+
+ private AbstractWatchService watcher;
+
+ @BeforeEach
+ public void setUp() throws IOException {
+ String email = System.getenv("GOOGLE_TEST_ACCOUNT");
+
+ URI uri = URI.create("googledrive:///?id=" + email);
+ fs = new GoogleDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap());
+
+ watcher = (AbstractWatchService) fs.newWatchService();
+ }
+
+ @AfterEach
+ public void tearDown() throws IOException {
+ watcher.close();
+ fs.close();
+ watcher = null;
+ fs = null;
+ }
+
+ @Test
+ public void testNewWatcher() {
+// assertTrue(watcher.isOpen());
+// assertFalse(watcher.isPolling());
+ }
+
+ @Test
+ public void testRegister() throws IOException {
+ WatchKey key = watcher.register(createDirectory(), ImmutableList.of(ENTRY_CREATE));
+ assertTrue(key.isValid());
+
+// assertTrue(watcher.isPolling());
+ }
+
+ @Test
+ public void testRegister_fileDoesNotExist() throws IOException {
+ try {
+ watcher.register(fs.getPath("/a/b/c"), ImmutableList.of(ENTRY_CREATE));
+ fail();
+ } catch (NoSuchFileException expected) {
+ }
+ }
+
+ @Test
+ public void testRegister_fileIsNotDirectory() throws IOException {
+ Path path = fs.getPath("/a.txt");
+ Files.createFile(path);
+ try {
+ watcher.register(path, ImmutableList.of(ENTRY_CREATE));
+ fail();
+ } catch (NotDirectoryException expected) {
+ }
+ }
+
+ @Test
+ public void testCancellingLastKeyStopsPolling() throws IOException {
+ WatchKey key = watcher.register(createDirectory(), ImmutableList.of(ENTRY_CREATE));
+ key.cancel();
+ assertFalse(key.isValid());
+
+// assertFalse(watcher.isPolling());
+
+ WatchKey key2 = watcher.register(createDirectory(), ImmutableList.of(ENTRY_CREATE));
+ WatchKey key3 = watcher.register(createDirectory(), ImmutableList.of(ENTRY_DELETE));
+
+// assertTrue(watcher.isPolling());
+
+ key2.cancel();
+
+// assertTrue(watcher.isPolling());
+
+ key3.cancel();
+
+// assertFalse(watcher.isPolling());
+ }
+
+ @Test
+ public void testCloseCancelsAllKeysAndStopsPolling() throws IOException {
+ WatchKey key1 = watcher.register(createDirectory(), ImmutableList.of(ENTRY_CREATE));
+ WatchKey key2 = watcher.register(createDirectory(), ImmutableList.of(ENTRY_DELETE));
+
+ assertTrue(key1.isValid());
+ assertTrue(key2.isValid());
+// assertTrue(watcher.isPolling());
+
+ watcher.close();
+
+ assertFalse(key1.isValid());
+ assertFalse(key2.isValid());
+// assertFalse(watcher.isPolling());
+ }
+
+ @Test
+ @Timeout(30000)
+ public void testWatchForOneEventType() throws IOException, InterruptedException {
+ Path path = createDirectory();
+ watcher.register(path, ImmutableList.of(ENTRY_CREATE));
+
+ Files.createFile(path.resolve("foo"));
+
+ assertWatcherHasEvents(HackedAbstractWatchService.createWatchEvent(ENTRY_CREATE, 1, fs.getPath("foo")));
+
+ Files.createFile(path.resolve("bar"));
+ Files.createFile(path.resolve("baz"));
+
+ assertWatcherHasEvents(HackedAbstractWatchService.createWatchEvent(ENTRY_CREATE, 1, fs.getPath("bar")),
+ HackedAbstractWatchService.createWatchEvent(ENTRY_CREATE, 1, fs.getPath("baz")));
+ }
+
+ @Test
+ @Timeout(30000)
+ public void testWatchForMultipleEventTypes() throws IOException, InterruptedException {
+ Path path = createDirectory();
+ watcher.register(path, ImmutableList.of(ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY));
+
+ Files.createDirectory(path.resolve("foo"));
+ Files.createFile(path.resolve("bar"));
+
+ assertWatcherHasEvents(HackedAbstractWatchService.createWatchEvent(ENTRY_CREATE, 1, fs.getPath("bar")),
+ HackedAbstractWatchService.createWatchEvent(ENTRY_CREATE, 1, fs.getPath("foo")));
+
+ Files.createFile(path.resolve("baz"));
+ Files.delete(path.resolve("bar"));
+ Files.createFile(path.resolve("foo/bar"));
+
+ assertWatcherHasEvents(HackedAbstractWatchService.createWatchEvent(ENTRY_CREATE, 1, fs.getPath("baz")),
+ HackedAbstractWatchService.createWatchEvent(ENTRY_DELETE, 1, fs.getPath("bar")),
+ HackedAbstractWatchService.createWatchEvent(ENTRY_MODIFY, 1, fs.getPath("foo")));
+
+ Files.delete(path.resolve("foo/bar"));
+ ensureTimeToPoll(); // watcher polls, seeing modification, then polls
+ // again, seeing delete
+ Files.delete(path.resolve("foo"));
+
+ assertWatcherHasEvents(HackedAbstractWatchService.createWatchEvent(ENTRY_MODIFY, 1, fs.getPath("foo")),
+ HackedAbstractWatchService.createWatchEvent(ENTRY_DELETE, 1, fs.getPath("foo")));
+
+ Files.createDirectories(path.resolve("foo/bar"));
+
+ // polling here may either see just the creation of foo, or may first
+ // see the creation of foo
+ // and then the creation of foo/bar (modification of foo) since those
+ // don't happen atomically
+ assertWatcherHasEvents(ImmutableList
+ .> of(HackedAbstractWatchService.createWatchEvent(ENTRY_CREATE, 1, fs.getPath("foo"))),
+ // or
+ ImmutableList.> of(
+ HackedAbstractWatchService
+ .createWatchEvent(ENTRY_CREATE, 1, fs.getPath("foo")),
+ HackedAbstractWatchService
+ .createWatchEvent(ENTRY_MODIFY, 1, fs.getPath("foo"))));
+
+ Files.delete(path.resolve("foo/bar"));
+ Files.delete(path.resolve("foo"));
+
+ // polling here may either just see the deletion of foo, or may first
+ // see the deletion of bar
+ // (modification of foo) and then the deletion of foo
+ assertWatcherHasEvents(ImmutableList
+ .> of(HackedAbstractWatchService.createWatchEvent(ENTRY_DELETE, 1, fs.getPath("foo"))),
+ // or
+ ImmutableList.> of(
+ HackedAbstractWatchService
+ .createWatchEvent(ENTRY_MODIFY, 1, fs.getPath("foo")),
+ HackedAbstractWatchService
+ .createWatchEvent(ENTRY_DELETE, 1, fs.getPath("foo"))));
+ }
+
+ private void assertWatcherHasEvents(WatchEvent>... events) throws InterruptedException {
+ assertWatcherHasEvents(Arrays.asList(events), ImmutableList.> of());
+ }
+
+ private void assertWatcherHasEvents(List> expected,
+ List> alternate) throws InterruptedException {
+ ensureTimeToPoll(); // otherwise we could read 1 event but not all the
+ // events we're expecting
+ WatchKey key = watcher.take();
+ List> keyEvents = key.pollEvents();
+
+ if (keyEvents.size() == expected.size() || alternate.isEmpty()) {
+ assertIterableEquals(expected, keyEvents);
+ } else {
+ assertIterableEquals(alternate, keyEvents);
+ }
+ key.reset();
+ }
+
+ private static void ensureTimeToPoll() {
+ Uninterruptibles.sleepUninterruptibly(40, MILLISECONDS);
+ }
+
+ private Path createDirectory() throws IOException {
+ Path path = fs.getPath("/" + UUID.randomUUID().toString());
+ Files.createDirectory(path);
+ return path;
+ }
+
+ static class HackedAbstractWatchService extends AbstractWatchService {
+ public static WatchEvent createWatchEvent(Kind kind, int count, T context) {
+ return new BasicWatchEvent<>(kind, count, context);
+ }
+ }
+}
diff --git a/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/WebHookTest.java b/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/WebHookTest.java
new file mode 100644
index 00000000..0a798335
--- /dev/null
+++ b/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/WebHookTest.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.googledrive;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.websocket.ClientEndpoint;
+import javax.websocket.ClientEndpointConfig;
+import javax.websocket.ContainerProvider;
+import javax.websocket.DeploymentException;
+import javax.websocket.OnClose;
+import javax.websocket.OnError;
+import javax.websocket.OnMessage;
+import javax.websocket.OnOpen;
+import javax.websocket.Session;
+import javax.websocket.WebSocketContainer;
+
+import com.google.api.client.auth.oauth2.Credential;
+import com.google.api.client.googleapis.notifications.UnparsedNotification;
+import com.google.api.client.http.HttpRequest;
+import com.google.api.client.http.HttpRequestInitializer;
+import com.google.api.services.drive.Drive;
+import com.google.api.services.drive.model.Change;
+import com.google.api.services.drive.model.ChangeList;
+import com.google.api.services.drive.model.Channel;
+import com.google.api.services.drive.model.StartPageToken;
+
+import vavi.net.auth.WithTotpUserCredential;
+import vavi.net.auth.oauth2.google.GoogleOAuth2AppCredential;
+import vavi.net.auth.oauth2.google.GoogleLocalOAuth2AppCredential;
+import vavi.net.auth.oauth2.google.GoogleOAuth2;
+import vavi.net.auth.web.google.GoogleLocalUserCredential;
+import vavi.nio.file.googledrive.webhook.websocket.GoogleJsonCodec.GoogleJsonDecoder;
+import vavi.nio.file.googledrive.webhook.websocket.GoogleJsonCodec.GoogleJsonEncoder;
+import vavi.util.Debug;
+
+
+/**
+ * WebHookTest. google drive
+ *
+ * @depends "file://${HOME}.vavifuse/googledrive/?"
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2016/02/29 umjammer initial version
+ */
+public class WebHookTest {
+
+ static final String VAVI_APPS_WEBHOOK_SECRET = System.getenv("VAVI_APPS_WEBHOOK_SECRET");
+
+ @ClientEndpoint(decoders = GoogleJsonDecoder.class,
+ encoders = GoogleJsonEncoder.class,
+ configurator = AuthorizationConfigurator.class)
+ public static class NotificationClient {
+ Service service;
+ NotificationClient(Service service) {
+ this.service = service;
+ }
+ @OnOpen
+ public void onOpen(Session session) throws IOException {
+Debug.println("OPEN: " + session);
+ session.getBasicRemote().sendText(String.join(" ", "GOOGLE_DRIVE_CHANGE", service.uuid.toString()));
+ }
+
+ @OnMessage
+ public void onMessage(UnparsedNotification notification) throws IOException {
+Debug.println(notification);
+ service.process(notification);
+ }
+
+ @OnError
+ public void onError(Throwable t) {
+t.printStackTrace();
+ }
+
+ @OnClose
+ public void onClose(Session session) throws IOException {
+Debug.println("CLOSE");
+ service.stop();
+ }
+ }
+
+ static String websocketBaseUrl = System.getenv("VAVI_APPS_WEBHOOK_WEBSOCKET_BASE_URL");
+ static String websocketPath = System.getenv("VAVI_APPS_WEBHOOK_WEBSOCKET_GOOGLE_PATH");
+ static String webhooktUrl = System.getenv("VAVI_APPS_WEBHOOK_WEBHOOK_GOOGLE_URL");
+ static String username = System.getenv("VAVI_APPS_WEBHOOK_USERNAME");
+ static String password = System.getenv("VAVI_APPS_WEBHOOK_PASSWORD");
+
+ public static class AuthorizationConfigurator extends ClientEndpointConfig.Configurator {
+ @Override
+ public void beforeRequest(Map> headers) {
+ headers.put("Authorization", Arrays.asList("Basic " + Base64.getEncoder().encodeToString((username + ":" + password).getBytes())));
+ }
+ };
+
+ static class Service {
+ Drive driveService;
+ String savedStartPageToken;
+ Channel channel = null;
+ Session session;
+ UUID uuid;
+
+ Service() throws IOException {
+ WithTotpUserCredential userCredential = new GoogleLocalUserCredential(email);
+ GoogleOAuth2AppCredential appCredential = new GoogleLocalOAuth2AppCredential("googledrive");
+
+ Credential credential = new GoogleOAuth2(appCredential).authorize(userCredential);
+ driveService = new Drive.Builder(GoogleOAuth2.getHttpTransport(), GoogleOAuth2.getJsonFactory(), credential)
+ .setHttpRequestInitializer(new HttpRequestInitializer() {
+ @Override
+ public void initialize(HttpRequest httpRequest) throws IOException {
+ credential.initialize(httpRequest);
+ httpRequest.setConnectTimeout(30 * 1000);
+ httpRequest.setReadTimeout(30 * 1000);
+ }
+ })
+ .setApplicationName(appCredential.getClientId())
+ .build();
+ }
+
+ void start() throws IOException {
+ uuid = UUID.randomUUID();
+
+ try {
+ WebSocketContainer container = ContainerProvider.getWebSocketContainer();
+ URI uri = URI.create(websocketBaseUrl + websocketPath);
+ // TODO using client ssl is so annoying
+ // https://github.com/eclipse/jetty.project/issues/155
+// URI uri = URI.create(String.format("ws://localhost:5000" + websocketPath));
+ session = container.connectToServer(new NotificationClient(this), uri);
+// session.setMaxIdleTimeout(0);
+ } catch (DeploymentException e) {
+ throw new IOException(e);
+ }
+
+ StartPageToken response = driveService.changes().getStartPageToken().execute();
+ savedStartPageToken = response.getStartPageToken();
+Debug.println("Start token: " + savedStartPageToken);
+
+ Channel content = new Channel()
+ .setId(uuid.toString())
+ .setType("web_hook")
+ .setToken(VAVI_APPS_WEBHOOK_SECRET)
+ .setAddress(webhooktUrl);
+
+ channel = driveService.changes().watch(savedStartPageToken, content).execute();
+Debug.println("channel: " + channel);
+ }
+
+ void stop() throws IOException {
+ if (channel != null) {
+ driveService.channels().stop(channel).execute();
+Debug.println("channel deleted: " + channel);
+ channel = null;
+ }
+
+ if (session != null) {
+ session.close();
+ session = null;
+ }
+ }
+
+ void process(UnparsedNotification notification) throws IOException {
+Debug.println("notification: " + notification.getResourceState());
+ // Begin with our last saved start token for this user or the
+ // current token from getStartPageToken()
+ String pageToken = savedStartPageToken;
+ while (pageToken != null) {
+ ChangeList changes = driveService.changes().list(pageToken).execute();
+ for (Change change : changes.getChanges()) {
+ // Process change
+Debug.println("Change found for file: " + change);
+ }
+ if (changes.getNewStartPageToken() != null) {
+ // Last page, save this token for the next polling interval
+ savedStartPageToken = changes.getNewStartPageToken();
+ }
+ pageToken = changes.getNextPageToken();
+ }
+ }
+ }
+
+ static String email = System.getenv("GOOGLE_TEST_ACCOUNT");
+
+ /**
+ * @param args 0: email
+ *
+ * https://developers.google.com/drive/api/v3/reference/changes/watch
+ * https://stackoverflow.com/a/43793313/6102938
+ * TODO needs domain authorize
+ */
+ public static void main(String[] args) throws Exception {
+ WebHookTest app = new WebHookTest();
+ app.test();
+ }
+
+ void test() throws Exception {
+Debug.println("Start");
+ Service service = new Service();
+ try {
+ service.start();
+
+ URI uri = URI.create("googledrive:///?id=" + email);
+ FileSystem fs = FileSystems.newFileSystem(uri, Collections.emptyMap());
+
+ Path tmpDir = fs.getPath("tmp");
+ if (!Files.exists(tmpDir)) {
+System.out.println("rmdir " + tmpDir);
+ Files.createDirectory(tmpDir);
+ }
+ Path remote = tmpDir.resolve("Test+Watch");
+ if (Files.exists(remote)) {
+System.out.println("rm " + remote);
+ Files.delete(remote);
+ }
+ Path source = Paths.get("src/test/resources", "Hello.java");
+System.out.println("cp " + source + " " + remote);
+ Files.copy(source, remote);
+
+System.out.println("rm " + remote);
+ Files.delete(remote);
+
+ Thread.sleep(5000);
+ } finally {
+ service.stop();
+ }
+Debug.println("Done");
+ }
+}
diff --git a/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/WebHookTest2.java b/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/WebHookTest2.java
new file mode 100644
index 00000000..0ad8822d
--- /dev/null
+++ b/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/WebHookTest2.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.googledrive;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.UUID;
+import java.util.concurrent.CountDownLatch;
+
+import com.google.api.client.auth.oauth2.Credential;
+import com.google.api.client.googleapis.notifications.UnparsedNotification;
+import com.google.api.client.http.HttpRequest;
+import com.google.api.client.http.HttpRequestInitializer;
+import com.google.api.services.drive.Drive;
+import com.google.api.services.drive.model.Change;
+import com.google.api.services.drive.model.ChangeList;
+import com.google.api.services.drive.model.Channel;
+import com.google.api.services.drive.model.StartPageToken;
+
+import vavi.net.auth.WithTotpUserCredential;
+import vavi.net.auth.oauth2.google.GoogleOAuth2AppCredential;
+import vavi.net.auth.oauth2.google.GoogleLocalOAuth2AppCredential;
+import vavi.net.auth.oauth2.google.GoogleOAuth2;
+import vavi.net.auth.web.google.GoogleLocalUserCredential;
+import vavi.nio.file.watch.webhook.Notification;
+import vavi.util.Debug;
+
+
+/**
+ * WebHookTest2. google drive, using now construction libraries.
+ *
+ * @depends "file://${HOME}.vavifuse/googledrive/?"
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2016/02/29 umjammer initial version
+ */
+public class WebHookTest2 {
+
+ static final String VAVI_APPS_WEBHOOK_SECRET = System.getenv("VAVI_APPS_WEBHOOK_SECRET");
+ static String webhooktUrl = System.getenv("VAVI_APPS_WEBHOOK_WEBHOOK_GOOGLE_URL");
+
+ static CountDownLatch countDownLatch = new CountDownLatch(1);
+
+ static class Service {
+ Drive driveService;
+ String savedStartPageToken;
+ Channel channel = null;
+ Notification notification;
+
+ Service() throws IOException {
+ WithTotpUserCredential userCredential = new GoogleLocalUserCredential(email);
+ GoogleOAuth2AppCredential appCredential = new GoogleLocalOAuth2AppCredential("googledrive");
+
+ Credential credential = new GoogleOAuth2(appCredential).authorize(userCredential);
+ driveService = new Drive.Builder(GoogleOAuth2.getHttpTransport(), GoogleOAuth2.getJsonFactory(), credential)
+ .setHttpRequestInitializer(new HttpRequestInitializer() {
+ @Override
+ public void initialize(HttpRequest httpRequest) throws IOException {
+ credential.initialize(httpRequest);
+ httpRequest.setConnectTimeout(30 * 1000);
+ httpRequest.setReadTimeout(30 * 1000);
+ }
+ })
+ .setApplicationName(appCredential.getClientId())
+ .build();
+ }
+
+ void start() throws IOException {
+ UUID uuid = UUID.randomUUID();
+
+ notification = Notification.getNotification("googledrive.webhook.websocket", notification -> {
+ try {
+ process(notification);
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }, uuid);
+Debug.println("notification: " + notification);
+
+ StartPageToken response = driveService.changes().getStartPageToken().execute();
+ savedStartPageToken = response.getStartPageToken();
+Debug.println("Start token: " + savedStartPageToken);
+
+ Channel content = new Channel()
+ .setId(uuid.toString())
+ .setType("web_hook")
+ .setToken(VAVI_APPS_WEBHOOK_SECRET)
+ .setAddress(webhooktUrl);
+
+ channel = driveService.changes().watch(savedStartPageToken, content).execute();
+Debug.println("channel: " + channel);
+ }
+
+ void stop() throws IOException {
+ if (channel != null) {
+ driveService.channels().stop(channel).execute();
+Debug.println("channel deleted: " + channel);
+ channel = null;
+ }
+ notification.close();
+ }
+
+ private void process(UnparsedNotification notification) throws IOException {
+Debug.println(">> notification: " + notification.getResourceState());
+ if (notification.getResourceState().equals("sync")) {
+ countDownLatch.countDown();
+Debug.println(">> synched");
+ } else {
+ // Begin with our last saved start token for this user or the
+ // current token from getStartPageToken()
+ String pageToken = savedStartPageToken;
+ while (pageToken != null) {
+ ChangeList changes = driveService.changes().list(pageToken).execute();
+ for (Change change : changes.getChanges()) {
+ // Process change
+Debug.println(">> change: " + change);
+ }
+ if (changes.getNewStartPageToken() != null) {
+ // Last page, save this token for the next polling interval
+ savedStartPageToken = changes.getNewStartPageToken();
+ }
+ pageToken = changes.getNextPageToken();
+ }
+ }
+ }
+ }
+
+ static String email = System.getenv("GOOGLE_TEST_ACCOUNT");
+
+ /**
+ * @param args 0: email
+ *
+ * https://developers.google.com/drive/api/v3/reference/changes/watch
+ * https://stackoverflow.com/a/43793313/6102938
+ * TODO needs domain authorize
+ */
+ public static void main(String[] args) throws Exception {
+ WebHookTest2 app = new WebHookTest2();
+ app.test();
+ }
+
+ void test() throws Exception {
+Debug.println("Start");
+ Service service = new Service();
+ try {
+ service.start();
+
+ URI uri = URI.create("googledrive:///?id=" + email);
+ FileSystem fs = FileSystems.newFileSystem(uri, Collections.emptyMap());
+
+ countDownLatch.await();
+
+ Path tmpDir = fs.getPath("tmp");
+ if (!Files.exists(tmpDir)) {
+System.out.println("rmdir " + tmpDir);
+ Files.createDirectory(tmpDir);
+ }
+ Path remote = tmpDir.resolve("Test+Watch");
+ if (Files.exists(remote)) {
+System.out.println("rm " + remote);
+ Files.delete(remote);
+ }
+ Path source = Paths.get("src/test/resources", "Hello.java");
+System.out.println("cp " + source + " " + remote);
+ Files.copy(source, remote);
+
+System.out.println("rm " + remote);
+ Files.delete(remote);
+
+ Thread.sleep(10000);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ service.stop();
+ }
+Debug.println("Done");
+//Thread.getAllStackTraces().keySet().forEach(System.err::println);
+ }
+}
diff --git a/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/WebHookTest3.java b/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/WebHookTest3.java
new file mode 100644
index 00000000..850608cb
--- /dev/null
+++ b/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/WebHookTest3.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.googledrive;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collections;
+
+import com.google.api.client.auth.oauth2.Credential;
+import com.google.api.client.http.HttpRequest;
+import com.google.api.client.http.HttpRequestInitializer;
+import com.google.api.services.drive.Drive;
+
+import vavi.net.auth.WithTotpUserCredential;
+import vavi.net.auth.oauth2.google.GoogleOAuth2AppCredential;
+import vavi.net.auth.oauth2.google.GoogleLocalOAuth2AppCredential;
+import vavi.net.auth.oauth2.google.GoogleOAuth2;
+import vavi.net.auth.web.google.GoogleLocalUserCredential;
+import vavi.util.Debug;
+
+
+/**
+ * WebHookTest3. google drive, using libraries now construction.
+ *
+ * @depends "file://${HOME}.vavifuse/googledrive/?"
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2016/02/29 umjammer initial version
+ */
+public class WebHookTest3 {
+
+ static String email = System.getenv("GOOGLE_TEST_ACCOUNT");
+
+ /**
+ * @param args 0: email
+ *
+ * https://developers.google.com/drive/api/v3/reference/changes/watch
+ * https://stackoverflow.com/a/43793313/6102938
+ * TODO needs domain authorize
+ */
+ public static void main(String[] args) throws Exception {
+ WebHookTest3 app = new WebHookTest3();
+ app.test();
+ }
+
+ void test() throws Exception {
+ WithTotpUserCredential userCredential = new GoogleLocalUserCredential(email);
+ GoogleOAuth2AppCredential appCredential = new GoogleLocalOAuth2AppCredential("googledrive");
+
+ Credential credential = new GoogleOAuth2(appCredential).authorize(userCredential);
+ Drive driveService = new Drive.Builder(GoogleOAuth2.getHttpTransport(), GoogleOAuth2.getJsonFactory(), credential)
+ .setHttpRequestInitializer(new HttpRequestInitializer() {
+ @Override
+ public void initialize(HttpRequest httpRequest) throws IOException {
+ credential.initialize(httpRequest);
+ httpRequest.setConnectTimeout(30 * 1000);
+ httpRequest.setReadTimeout(30 * 1000);
+ }
+ })
+ .setApplicationName(appCredential.getClientId())
+ .build();
+
+ GoogleDriveWatchService service = new GoogleDriveWatchService(driveService);
+Debug.println("WEBSOCKET: start: " + service);
+ try {
+ URI uri = URI.create("googledrive:///?id=" + email);
+ FileSystem fs = FileSystems.newFileSystem(uri, Collections.emptyMap());
+
+ Path tmpDir = fs.getPath("tmp");
+ if (!Files.exists(tmpDir)) {
+System.out.println("rmdir " + tmpDir);
+ Files.createDirectory(tmpDir);
+ }
+ Path remote = tmpDir.resolve("Test+Watch");
+ if (Files.exists(remote)) {
+System.out.println("rm " + remote);
+ Files.delete(remote);
+ }
+ Path source = Paths.get("src/test/resources", "Hello.java");
+System.out.println("cp " + source + " " + remote);
+ Files.copy(source, remote);
+
+System.out.println("rm " + remote);
+ Files.delete(remote);
+
+ Thread.sleep(10000);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ service.close();
+ }
+Debug.println("APP: done");
+ GoogleDriveWatchService.dispose();
+//Thread.getAllStackTraces().keySet().forEach(System.err::println);
+ }
+}
diff --git a/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/WebSocketTest.java b/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/WebSocketTest.java
new file mode 100644
index 00000000..999d800d
--- /dev/null
+++ b/vavi-nio-file-googledrive/src/test/java/vavi/nio/file/googledrive/WebSocketTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.googledrive;
+
+import java.net.URI;
+import java.util.concurrent.CountDownLatch;
+
+import javax.websocket.ClientEndpoint;
+import javax.websocket.ContainerProvider;
+import javax.websocket.OnClose;
+import javax.websocket.OnError;
+import javax.websocket.OnMessage;
+import javax.websocket.OnOpen;
+import javax.websocket.Session;
+import javax.websocket.WebSocketContainer;
+
+import com.google.api.client.googleapis.notifications.UnparsedNotification;
+
+import vavi.nio.file.googledrive.WebHookTest.AuthorizationConfigurator;
+import vavi.nio.file.googledrive.webhook.websocket.GoogleJsonCodec.GoogleJsonDecoder;
+import vavi.nio.file.googledrive.webhook.websocket.GoogleJsonCodec.GoogleJsonEncoder;
+import vavi.util.Debug;
+
+
+/**
+ * WebSocketTest.
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/07/01 umjammer initial version
+ */
+public class WebSocketTest {
+
+ static String websocketBaseUrl = System.getenv("VAVI_APPS_WEBHOOK_WEBSOCKET_BASE_URL");
+ static String websocketPath = System.getenv("VAVI_APPS_WEBHOOK_WEBSOCKET_GOOGLE_PATH");
+
+ static CountDownLatch cdl = new CountDownLatch(1);
+
+ @ClientEndpoint(decoders = GoogleJsonDecoder.class,
+ encoders = GoogleJsonEncoder.class,
+ configurator = AuthorizationConfigurator.class)
+ public static class NotificationClient {
+
+ @OnOpen
+ public void onOpen(Session session) {
+Debug.println("OPEN: " + session);
+ }
+
+ @OnMessage
+ public void onMessage(UnparsedNotification notification) {
+Debug.println(notification);
+ }
+
+ @OnError
+ public void onError(Throwable t) {
+t.printStackTrace();
+ }
+
+ @OnClose
+ public void onClose(Session session) {
+Debug.println("CLOSE");
+ cdl.countDown();
+ }
+ }
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args) throws Exception {
+ WebSocketContainer container = ContainerProvider.getWebSocketContainer();
+// URI uri = URI.create("ws://localhost:5000" + websocketPath);
+ URI uri = URI.create(websocketBaseUrl + websocketPath);
+ Session session = container.connectToServer(new NotificationClient(), uri);
+
+Debug.println("Stop");
+ cdl.await();
+
+ session.close();
+Debug.println("Done");
+
+// TODO https://stackoverflow.com/a/46472909/6102938
+if(container != null && container instanceof org.eclipse.jetty.util.component.LifeCycle) {
+ try {
+Debug.println("Stopping Jetty's WebSocket Client");
+ ((org.eclipse.jetty.util.component.LifeCycle) container).stop();
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+}
+ }
+}
+
+/* */
diff --git a/vavi-nio-file-googledrive/src/test/resources/duke.jpg b/vavi-nio-file-googledrive/src/test/resources/duke.jpg
new file mode 100644
index 00000000..3402f12e
Binary files /dev/null and b/vavi-nio-file-googledrive/src/test/resources/duke.jpg differ
diff --git a/vavi-nio-file-googledrive/src/test/resources/googledrive.properties b/vavi-nio-file-googledrive/src/test/resources/googledrive.properties
index d8d319de..39b70f03 100644
--- a/vavi-nio-file-googledrive/src/test/resources/googledrive.properties
+++ b/vavi-nio-file-googledrive/src/test/resources/googledrive.properties
@@ -1 +1 @@
-authenticatorClassName=vavi.net.auth.oauth2.google.GoogleLocalAuthenticator
+authenticatorClassName=vavi.net.auth.oauth2.google.GoogleBasicOAuth2Authenticator
diff --git a/vavi-nio-file-googledrive/src/test/resources/test.zip b/vavi-nio-file-googledrive/src/test/resources/test.zip
new file mode 100644
index 00000000..8fcb7600
Binary files /dev/null and b/vavi-nio-file-googledrive/src/test/resources/test.zip differ
diff --git a/vavi-nio-file-hfs/pom.xml b/vavi-nio-file-hfs/pom.xml
index b70cfc95..f3228395 100644
--- a/vavi-nio-file-hfs/pom.xml
+++ b/vavi-nio-file-hfs/pom.xml
@@ -5,7 +5,7 @@
vavi
vavi-apps-fuse
- 0.1.6
+ 0.1.7
vavi-nio-file-hfs
@@ -32,16 +32,10 @@
-
+
com.github.umjammer
hfsexplorer
- 0.23.0
-
-
- org.netbeans.external
- swing-layout-1.0.4
-
-
+ 0.23.2
@@ -64,5 +58,22 @@
junit-platform-commons
test
+
+ org.junit.jupiter
+ junit-jupiter-params
+ test
+
+
+
+ vavi
+ vavi-net-fuse
+ test
+
+
+ vavi
+ vavi-net-fuse
+ test-jar
+ test
+
diff --git a/vavi-nio-file-hfs/src/main/java/vavi/nio/file/hfs/HfsFileAttributesFactory.java b/vavi-nio-file-hfs/src/main/java/vavi/nio/file/hfs/HfsFileAttributesFactory.java
index 93b006d3..1bf1b06d 100644
--- a/vavi-nio-file-hfs/src/main/java/vavi/nio/file/hfs/HfsFileAttributesFactory.java
+++ b/vavi-nio-file-hfs/src/main/java/vavi/nio/file/hfs/HfsFileAttributesFactory.java
@@ -8,7 +8,7 @@
import org.catacombae.storage.fs.FSEntry;
-import com.github.fge.filesystem.attributes.FileAttributesFactory;
+import com.github.fge.filesystem.driver.ExtendedFileSystemDriverBase.ExtendsdFileAttributesFactory;
/**
@@ -17,7 +17,7 @@
* @author Naohide Sano (umjammer)
* @version 0.00 2016/04/06 umjammer initial version
*/
-public final class HfsFileAttributesFactory extends FileAttributesFactory {
+public final class HfsFileAttributesFactory extends ExtendsdFileAttributesFactory {
public HfsFileAttributesFactory() {
setMetadataClass(FSEntry.class);
diff --git a/vavi-nio-file-hfs/src/main/java/vavi/nio/file/hfs/HfsFileStore.java b/vavi-nio-file-hfs/src/main/java/vavi/nio/file/hfs/HfsFileStore.java
index e0e48885..3809958b 100644
--- a/vavi-nio-file-hfs/src/main/java/vavi/nio/file/hfs/HfsFileStore.java
+++ b/vavi-nio-file-hfs/src/main/java/vavi/nio/file/hfs/HfsFileStore.java
@@ -8,6 +8,7 @@
import java.io.IOException;
import java.nio.file.FileStore;
+import java.util.logging.Level;
import org.catacombae.storage.fs.FSFolder;
import org.catacombae.storage.fs.FSForkType;
@@ -16,6 +17,9 @@
import com.github.fge.filesystem.attributes.FileAttributesFactory;
import com.github.fge.filesystem.filestore.FileStoreBase;
+import vavi.util.Debug;
+import vavi.util.StringUtil;
+
/**
* A simple HFS {@link FileStore}
@@ -35,6 +39,9 @@ public final class HfsFileStore extends FileStoreBase {
public HfsFileStore(HFSCommonFileSystemHandler handler, final FileAttributesFactory factory) {
super("hfs", factory, false);
this.root = handler.getRoot();
+Debug.println(Level.FINE, StringUtil.paramString(root));
+Debug.println(Level.FINE, StringUtil.paramString(root.getAllForks()));
+Debug.println(Level.FINE, StringUtil.paramString(root.getAttributes()));
}
/**
@@ -46,7 +53,7 @@ public HfsFileStore(HFSCommonFileSystemHandler handler, final FileAttributesFact
*/
@Override
public long getTotalSpace() throws IOException {
- return root.getForkByType(FSForkType.DATA).getLength();
+ return 100000000;
}
/**
@@ -67,7 +74,7 @@ public long getTotalSpace() throws IOException {
*/
@Override
public long getUsableSpace() throws IOException {
- return root.getForkByType(FSForkType.DATA).getLength();
+ return 100000000;
}
/**
@@ -86,6 +93,6 @@ public long getUsableSpace() throws IOException {
*/
@Override
public long getUnallocatedSpace() throws IOException {
- return root.getForkByType(FSForkType.DATA).getLength();
+ return 100000000;
}
}
diff --git a/vavi-nio-file-hfs/src/main/java/vavi/nio/file/hfs/HfsFileSystemDriver.java b/vavi-nio-file-hfs/src/main/java/vavi/nio/file/hfs/HfsFileSystemDriver.java
index d6543adc..f6f36288 100644
--- a/vavi-nio-file-hfs/src/main/java/vavi/nio/file/hfs/HfsFileSystemDriver.java
+++ b/vavi-nio-file-hfs/src/main/java/vavi/nio/file/hfs/HfsFileSystemDriver.java
@@ -19,7 +19,6 @@
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.attribute.FileAttribute;
-import java.nio.file.spi.FileSystemProvider;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -54,19 +53,16 @@ public final class HfsFileSystemDriver extends ExtendedFileSystemDriverBase {
private final HFSCommonFileSystemHandler handler;
- private boolean ignoreAppleDouble = false;
-
/**
* @param env
*/
- @SuppressWarnings("unchecked")
public HfsFileSystemDriver(final FileStore fileStore,
final FileSystemFactoryProvider provider,
final HFSCommonFileSystemHandler handler,
final Map env) throws IOException {
super(fileStore, provider);
+ setEnv(env);
this.handler = handler;
- ignoreAppleDouble = (Boolean) ((Map) env).getOrDefault("ignoreAppleDouble", Boolean.FALSE);
}
/** */
@@ -88,8 +84,10 @@ private FSEntry getEntry(Path path) throws IOException {
if (path.getNameCount() == 0) {
return handler.getRoot();
} else {
- FSEntry entry = handler.getEntry(toPathString(path));
+//Debug.println(Arrays.toString(toPathString(path).replaceFirst("^/", "").split("/", -1)));
+ FSEntry entry = handler.getEntry(toPathString(path).replaceFirst("^/", "").split("/", -1));
if (entry != null) {
+//Debug.println("entry: " + entry.getName() + ", " + isFolder(entry));
return entry;
} else {
throw new NoSuchFileException(path.toString());
@@ -142,17 +140,6 @@ public void move(final Path source, final Path target, final Set opt
throw new UnsupportedOperationException("this file system is read only");
}
- /**
- * Check access modes for a path on this filesystem
- *
- * If no modes are provided to check for, this simply checks for the
- * existence of the path.
- *
- *
- * @param path the path to check
- * @param modes the modes to check for, if any
- * @see FileSystemProvider#checkAccess(Path, AccessMode...)
- */
@Override
protected void checkAccessImpl(final Path path, final AccessMode... modes) throws IOException {
final FSEntry entry = getEntry(path);
@@ -169,20 +156,17 @@ protected void checkAccessImpl(final Path path, final AccessMode... modes) throw
}
}
- @Override
- public void close() throws IOException {
- handler.close();
- }
-
- /**
- * @throws IOException if you use this with javafs (jnr-fuse), you should throw {@link NoSuchFileException} when the file not found.
- */
@Nonnull
@Override
protected Object getPathMetadataImpl(final Path path) throws IOException {
return getEntry(path);
}
+ @Override
+ public void close() throws IOException {
+ handler.close();
+ }
+
/** */
private List getDirectoryEntries(final Path dir) throws IOException {
final FSEntry dirEntry = getEntry(dir);
diff --git a/vavi-nio-file-hfs/src/test/java/vavi/nio/file/hfs/HfsFileSystemProviderTest.java b/vavi-nio-file-hfs/src/test/java/vavi/nio/file/hfs/HfsFileSystemProviderTest.java
index 4862fb15..f33e0cd4 100644
--- a/vavi-nio-file-hfs/src/test/java/vavi/nio/file/hfs/HfsFileSystemProviderTest.java
+++ b/vavi-nio-file-hfs/src/test/java/vavi/nio/file/hfs/HfsFileSystemProviderTest.java
@@ -6,13 +6,23 @@
package vavi.nio.file.hfs;
+import java.io.IOException;
import java.net.URI;
+import java.net.URL;
import java.nio.file.FileSystem;
import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.Collections;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable;
+import org.junit.jupiter.api.condition.EnabledIf;
+
+import vavi.util.Debug;
+import vavi.util.properties.annotation.Property;
+import vavi.util.properties.annotation.PropsEntity;
/**
@@ -21,13 +31,52 @@
* @author Naohide Sano (umjammer)
* @version 0.00 2019/06/23 umjammer initial version
*/
+@PropsEntity(url = "file://${user.dir}/local.properties")
class HfsFileSystemProviderTest {
+ static boolean localPropertiesExists() {
+ return Files.exists(Paths.get("local.properties"));
+ }
+
@Test
- @DisabledIfEnvironmentVariable(named = "GITHUB_WORKFLOW", matches = ".*")
void test3() throws Exception {
- URI uri = URI.create("hfs:file:/Users/nsano/Downloads/googlechrome-80.dmg");
- FileSystem fs = new HfsFileSystemProvider().newFileSystem(uri, Collections.EMPTY_MAP);
+ URL url = HfsFileSystemProviderTest.class.getResource("/test.dmg");
+Debug.println("file: " + url.getPath());
+ URI uri = URI.create("hfs:file:" + url.getPath());
+ FileSystem fs = new HfsFileSystemProvider().newFileSystem(uri, Collections.emptyMap());
+ Files.list(fs.getRootDirectories().iterator().next()).forEach(System.err::println);
+ }
+
+ @Test
+ @EnabledIf("localPropertiesExists")
+ @Disabled("doesn't work")
+ void test() throws Exception {
+ Path path = Paths.get("/Users/nsano/src/vavi/vavi-nio-file-apfs/src/test/resources/apfs.dmg");
+Debug.println("file: " + path);
+ URI uri = URI.create("hfs:file:" + path);
+ FileSystem fs = new HfsFileSystemProvider().newFileSystem(uri, Collections.emptyMap());
+ Files.list(fs.getRootDirectories().iterator().next()).forEach(System.err::println);
+ }
+
+ //----
+
+ @Property(name = "test.dmg")
+ String file;
+
+ @BeforeEach
+ void setup() throws IOException {
+ if (localPropertiesExists()) {
+ PropsEntity.Util.bind(this);
+ }
+ }
+
+ /** */
+ public static void main(String[] args) throws Exception {
+ HfsFileSystemProviderTest app = new HfsFileSystemProviderTest();
+ app.setup();
+Debug.println("file: " + app.file);
+ URI uri = URI.create("hfs:file:" + app.file);
+ FileSystem fs = new HfsFileSystemProvider().newFileSystem(uri, Collections.emptyMap());
Files.list(fs.getRootDirectories().iterator().next()).forEach(System.err::println);
}
}
diff --git a/vavi-nio-file-hfs/src/test/java/vavi/nio/file/hfs/Main4.java b/vavi-nio-file-hfs/src/test/java/vavi/nio/file/hfs/Main4.java
new file mode 100644
index 00000000..3ad5748c
--- /dev/null
+++ b/vavi-nio-file-hfs/src/test/java/vavi/nio/file/hfs/Main4.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2021 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.hfs;
+
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.condition.EnabledIf;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import com.github.fge.filesystem.driver.CachedFileSystemDriver;
+
+import vavi.net.fuse.Base;
+import vavi.net.fuse.Fuse;
+import vavi.util.properties.annotation.Property;
+import vavi.util.properties.annotation.PropsEntity;
+
+
+/**
+ * Main4. (fuse)
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2021/11/23 umjammer initial version
+ */
+@EnabledIf("localPropertiesExists")
+@PropsEntity(url = "file://${user.dir}/local.properties")
+public class Main4 {
+
+ static {
+ System.setProperty("vavi.util.logging.VaviFormatter.extraClassMethod", "co\\.paralleluniverse\\.fuse\\.LoggedFuseFilesystem#log");
+ }
+
+ static boolean localPropertiesExists() {
+ return Files.exists(Paths.get("local.properties"));
+ }
+
+ @Property
+ String diskImage;
+ @Property
+ String mountPoint;
+
+ FileSystem fs;
+ Map options;
+
+ @BeforeEach
+ public void before() throws Exception {
+ PropsEntity.Util.bind(this);
+
+ URI uri = URI.create("hfs:file:" + diskImage);
+
+ Map env = new HashMap<>();
+ env.put(CachedFileSystemDriver.ENV_IGNORE_APPLE_DOUBLE, true); // mandatory
+
+ fs = FileSystems.newFileSystem(uri, env);
+//Files.list(fs.getRootDirectories().iterator().next()).forEach(System.err::println);
+
+ options = new HashMap<>();
+ options.put("fsname", "hfs_fs" + "@" + System.currentTimeMillis());
+ options.put("noappledouble", null);
+// options.put("noapplexattr", null);
+ options.put(vavi.net.fuse.javafs.JavaFSFuse.ENV_DEBUG, false);
+ options.put(vavi.net.fuse.javafs.JavaFSFuse.ENV_READ_ONLY, false);
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {
+ "vavi.net.fuse.javafs.JavaFSFuseProvider",
+ "vavi.net.fuse.jnrfuse.JnrFuseFuseProvider",
+ "vavi.net.fuse.fusejna.FuseJnaFuseProvider",
+ })
+ public void test01(String providerClassName) throws Exception {
+ System.setProperty("vavi.net.fuse.FuseProvider.class", providerClassName);
+
+ Base.testFuse(fs, mountPoint, options);
+
+ fs.close();
+ }
+
+ //
+
+ public static void main(String[] args) throws Exception {
+// System.setProperty("vavi.net.fuse.FuseProvider.class", "vavi.net.fuse.javafs.JavaFSFuseProvider");
+// System.setProperty("vavi.net.fuse.FuseProvider.class", "vavi.net.fuse.jnrfuse.JnrFuseFuseProvider");
+ System.setProperty("vavi.net.fuse.FuseProvider.class", "vavi.net.fuse.fusejna.FuseJnaFuseProvider");
+
+ Main4 app = new Main4();
+ app.before();
+
+ try (Fuse fuse = Fuse.getFuse()) {
+ fuse.mount(app.fs, app.mountPoint, app.options);
+while (true) { // for jnrfuse
+ Thread.yield();
+}
+ }
+ }
+}
+
+/* */
diff --git a/vavi-nio-file-hfs/src/test/resources/test.dmg b/vavi-nio-file-hfs/src/test/resources/test.dmg
new file mode 100644
index 00000000..84c9ca09
Binary files /dev/null and b/vavi-nio-file-hfs/src/test/resources/test.dmg differ
diff --git a/vavi-nio-file-onedrive/pom.xml b/vavi-nio-file-onedrive/pom.xml
index 4ca45e36..87f119b4 100644
--- a/vavi-nio-file-onedrive/pom.xml
+++ b/vavi-nio-file-onedrive/pom.xml
@@ -5,7 +5,7 @@
vavi
vavi-apps-fuse
- 0.1.6
+ 0.1.7
vavi-nio-file-onedrive
@@ -19,6 +19,13 @@
https://github.com/umjammer/vavi-nio-file-onedrive/issues
+
+
+ jitpack.io
+ https://jitpack.io
+
+
+
@@ -32,7 +39,7 @@
- com.github.umjammer.vavi-net-auth
+ ${vavi-net-auth.groupId}
vavi-net-auth-microsoft
${vavi-net-auth.version}
@@ -41,7 +48,12 @@
com.github.umjammer
OneDriveJavaSDK
- 0.0.7v
+ 0.0.8v
+
+
+
+ vavi
+ vavi-nio-file-commons
@@ -62,7 +74,6 @@
org.junit.jupiter
junit-jupiter-params
- 5.3.0
test
@@ -88,5 +99,11 @@
test-jar
test
+
+ com.github.budhash
+ cliche
+ 153113a
+ test
+
diff --git a/vavi-nio-file-onedrive/src/main/java/vavi/nio/file/onedrive/OneDriveFileAttributesFactory.java b/vavi-nio-file-onedrive/src/main/java/vavi/nio/file/onedrive/OneDriveFileAttributesFactory.java
index a1e866dc..1b4a20ad 100644
--- a/vavi-nio-file-onedrive/src/main/java/vavi/nio/file/onedrive/OneDriveFileAttributesFactory.java
+++ b/vavi-nio-file-onedrive/src/main/java/vavi/nio/file/onedrive/OneDriveFileAttributesFactory.java
@@ -6,7 +6,7 @@
package vavi.nio.file.onedrive;
-import com.github.fge.filesystem.attributes.FileAttributesFactory;
+import com.github.fge.filesystem.driver.ExtendedFileSystemDriverBase.ExtendsdFileAttributesFactory;
import de.tuberlin.onedrivesdk.common.OneItem;
@@ -17,7 +17,7 @@
* @author Naohide Sano (umjammer)
* @version 0.00 2016/03/11 umjammer initial version
*/
-public final class OneDriveFileAttributesFactory extends FileAttributesFactory {
+public final class OneDriveFileAttributesFactory extends ExtendsdFileAttributesFactory {
public OneDriveFileAttributesFactory() {
setMetadataClass(OneItem.class);
diff --git a/vavi-nio-file-onedrive/src/main/java/vavi/nio/file/onedrive/OneDriveFileSystemDriver.java b/vavi-nio-file-onedrive/src/main/java/vavi/nio/file/onedrive/OneDriveFileSystemDriver.java
index 83c7b1ae..0f0b5b01 100644
--- a/vavi-nio-file-onedrive/src/main/java/vavi/nio/file/onedrive/OneDriveFileSystemDriver.java
+++ b/vavi-nio-file-onedrive/src/main/java/vavi/nio/file/onedrive/OneDriveFileSystemDriver.java
@@ -10,46 +10,35 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.nio.file.AccessDeniedException;
-import java.nio.file.AccessMode;
import java.nio.file.CopyOption;
-import java.nio.file.DirectoryNotEmptyException;
-import java.nio.file.DirectoryStream;
-import java.nio.file.FileAlreadyExistsException;
import java.nio.file.FileStore;
import java.nio.file.Files;
-import java.nio.file.NoSuchFileException;
-import java.nio.file.NotDirectoryException;
import java.nio.file.OpenOption;
import java.nio.file.Path;
-import java.nio.file.StandardCopyOption;
-import java.nio.file.attribute.FileAttribute;
-import java.nio.file.spi.FileSystemProvider;
-import java.util.ArrayList;
+import java.nio.file.WatchEvent.Kind;
+import java.nio.file.WatchService;
import java.util.List;
import java.util.Map;
+import java.util.NoSuchElementException;
import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
-import org.json.simple.parser.ParseException;
-
-import com.github.fge.filesystem.driver.ExtendedFileSystemDriverBase;
-import com.github.fge.filesystem.exceptions.IsDirectoryException;
+import com.github.fge.filesystem.driver.CachedFileSystemDriver;
import com.github.fge.filesystem.provider.FileSystemFactoryProvider;
-import vavi.nio.file.Cache;
import vavi.nio.file.Util;
import vavi.util.Debug;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
import static vavi.nio.file.Util.toFilenameString;
import static vavi.nio.file.Util.toPathString;
+import static vavi.nio.file.onedrive.OneDriveFileSystemProvider.ENV_USE_SYSTEM_WATCHER;
import de.tuberlin.onedrivesdk.OneDriveException;
import de.tuberlin.onedrivesdk.OneDriveSDK;
import de.tuberlin.onedrivesdk.common.OneItem;
-import de.tuberlin.onedrivesdk.downloadFile.OneDownload;
import de.tuberlin.onedrivesdk.file.OneFile;
import de.tuberlin.onedrivesdk.folder.OneFolder;
import de.tuberlin.onedrivesdk.uploadFile.OneUpload;
@@ -62,98 +51,109 @@
* @version 0.00 2016/03/11 umjammer initial version
*/
@ParametersAreNonnullByDefault
-public final class OneDriveFileSystemDriver extends ExtendedFileSystemDriverBase {
+public final class OneDriveFileSystemDriver extends CachedFileSystemDriver {
private final OneDriveSDK client;
- private boolean ignoreAppleDouble = false;
+ private OneDriveWatchService systemWatcher;
@SuppressWarnings("unchecked")
public OneDriveFileSystemDriver(final FileStore fileStore,
final FileSystemFactoryProvider provider,
final OneDriveSDK client,
- final Map env) {
+ final Map env) throws IOException {
super(fileStore, provider);
this.client = client;
- ignoreAppleDouble = (Boolean) ((Map) env).getOrDefault("ignoreAppleDouble", Boolean.FALSE);
-//System.err.println("ignoreAppleDouble: " + ignoreAppleDouble);
+ setEnv(env);
+ boolean useSystemWatcher = (Boolean) ((Map) env).getOrDefault(ENV_USE_SYSTEM_WATCHER, false);
+
+ if (useSystemWatcher) {
+ systemWatcher = new OneDriveWatchService(client);
+ systemWatcher.setNotificationListener(this::processNotification);
+ }
}
- /** */
- private Cache cache = new Cache() {
- /**
- * TODO when the parent is not cached
- * @see #ignoreAppleDouble
- * @throws NoSuchFileException must be thrown when the path is not found in this cache
- */
- public OneItem getEntry(Path path) throws IOException {
+ /** for system watcher */
+ private void processNotification(String id, Kind> kind) {
+ if (ENTRY_DELETE == kind) {
try {
- if (cache.containsFile(path)) {
- return cache.getFile(path);
- } else {
- if (ignoreAppleDouble && path.getFileName() != null && Util.isAppleDouble(path)) {
- throw new NoSuchFileException("ignore apple double file: " + path);
- }
-
- OneItem entry = client.getItemByPath(toPathString(path));
- cache.putFile(path, entry);
- return entry;
- }
- } catch (OneDriveException e) {
- // TODO focus only file not found
- // cache
- if (cache.containsFile(path)) {
+ Path path = cache.getEntry(e -> id.equals(e.getId()));
+ cache.removeEntry(path);
+ } catch (NoSuchElementException e) {
+Debug.println("NOTIFICATION: already deleted: " + id);
+ }
+ } else {
+ try {
+ try {
+ Path path = cache.getEntry(e -> id.equals(e.getId()));
+Debug.println("NOTIFICATION: maybe updated: " + path);
cache.removeEntry(path);
+ cache.getEntry(path);
+ } catch (NoSuchElementException e) {
+ OneFile entry = client.getFileById(id);
+ Path parent = cache.getEntry(f -> { try { return entry.getParentFolder().getId().equals(f.getId()); } catch (IOException g) { g.printStackTrace(); return false; }});
+ Path path = parent.resolve(entry.getName());
+Debug.println("NOTIFICATION: maybe created: " + path);
+ cache.addEntry(path, OneItem.class.cast(entry));
}
-
- throw (IOException) new NoSuchFileException("path: " + path).initCause(e);
+ } catch (NoSuchElementException e) {
+Debug.println("NOTIFICATION: parent not found: " + e);
+ } catch (IOException e) {
+ e.printStackTrace();
}
}
- };
+ }
+
+ /** */
+ private static OneFile asFile(OneItem entry) {
+ return OneFile.class.cast(entry);
+ }
+
+ /** */
+ private static OneFolder asFolder(OneItem entry) {
+ return OneFolder.class.cast(entry);
+ }
- @Nonnull
@Override
- public InputStream newInputStream(final Path path, final Set extends OpenOption> options) throws IOException {
- try {
- final OneItem entry = cache.getEntry(path);
- // TODO: metadata driver
- if (entry.isFolder()) {
- throw new IsDirectoryException("path: " + path);
- }
+ protected String getFilenameString(OneItem entry) {
+ return entry.getName();
+ }
- final OneDownload downloader = OneFile.class.cast(entry).download();
- return downloader.getDownloadedInputStream();
- } catch (OneDriveException e) {
- throw new IOException("path: " + path, e);
- }
+ @Override
+ protected boolean isFolder(OneItem entry) {
+ return entry.isFolder();
}
- @Nonnull
@Override
- public OutputStream newOutputStream(final Path path, final Set extends OpenOption> options) throws IOException {
- final OneItem entry;
- try {
- entry = cache.getEntry(path);
+ protected OneItem getRootEntry(Path root) throws IOException {
+ return client.getItemByPath(toPathString(root));
+ }
- if (entry.isFolder()) {
- throw new IsDirectoryException("path: " + path);
- } else {
- throw new FileAlreadyExistsException("path: " + path);
- }
- } catch (NoSuchFileException e) {
-System.out.println("newOutputStream: " + e.getMessage());
-//new Exception("*** DUMMY ***").printStackTrace();
+ @Override
+ protected OneItem getEntry(OneItem parentEntry, Path path)throws IOException {
+ try {
+ return client.getItemByPath(toPathString(path));
+ } catch (OneDriveException e) {
+ return null;
}
+ }
+
+ @Override
+ protected InputStream downloadEntry(OneItem entry, Path path, Set extends OpenOption> options) throws IOException {
+ return asFile(entry).download().getDownloadedInputStream();
+ }
+ @Override
+ protected OutputStream uploadEntry(OneItem parentEntry, Path path, Set extends OpenOption> options) throws IOException {
OneDriveUploadOption uploadOption = Util.getOneOfOptions(OneDriveUploadOption.class, options);
if (uploadOption != null) {
// java.nio.file is highly abstracted, so here source information is lost.
// but onedrive graph api requires content length for upload.
- // so reluctantly we provide {@link OneDriveUploadOpenOption} for {@link java.nio.file.Files#copy} options.
+ // so reluctantly we provide {@link OneDriveUploadOption} for {@link java.nio.file.Files#copy} options.
Path source = uploadOption.getSource();
Debug.println("upload w/ option: " + source);
- return uploadEntry(path, (int) Files.size(source));
+ return uploadEntry(parentEntry, path, (int) Files.size(source));
} else {
Debug.println("upload w/o option");
return new Util.OutputStreamForUploading() { // TODO used for getting file length
@@ -161,7 +161,7 @@ public OutputStream newOutputStream(final Path path, final Set extends OpenOpt
protected void onClosed() throws IOException {
InputStream is = getInputStream();
Debug.println("upload w/o option: " + is.available());
- OutputStream os = uploadEntry(path, is.available());
+ OutputStream os = uploadEntry(parentEntry, path, is.available());
Util.transfer(is, os);
is.close();
os.close();
@@ -171,253 +171,72 @@ protected void onClosed() throws IOException {
}
/** OneDriveUploadOption */
- private OutputStream uploadEntry(Path path, int size) throws IOException {
- try {
- OneFolder dirEntry = (OneFolder) cache.getEntry(path.getParent());
- final OneUpload uploader = dirEntry.upload(toFilenameString(path), size, newEntry -> {
- cache.addEntry(path, newEntry);
- });
- return new BufferedOutputStream(uploader.upload(), Util.BUFFER_SIZE);
- } catch (OneDriveException e) {
- throw new IOException(e);
- }
+ private OutputStream uploadEntry(OneItem parentEntry, Path path, int size) throws IOException {
+ OneUpload uploader = asFolder(parentEntry).upload(toFilenameString(path), size, newEntry -> {
+ updateEntry(path, newEntry);
+ });
+ return new BufferedOutputStream(uploader.upload(), Util.BUFFER_SIZE);
}
- @Nonnull
@Override
- public DirectoryStream newDirectoryStream(final Path dir,
- final DirectoryStream.Filter super Path> filter) throws IOException {
- try {
- return Util.newDirectoryStream(getDirectoryEntries(dir), filter);
- } catch (OneDriveException e) {
- throw new IOException("dir: " + dir, e);
- }
+ protected List getDirectoryEntries(OneItem dirEntry, Path dir) throws IOException {
+ return asFolder(dirEntry).getChildren();
}
@Override
- public void createDirectory(final Path dir, final FileAttribute>... attrs) throws IOException {
- try {
- OneItem parentEntry = cache.getEntry(dir.getParent());
-
- // TODO: how to diagnose?
- OneFolder dirEntry = OneFolder.class.cast(parentEntry).createFolder(toFilenameString(dir));
-
- cache.addEntry(dir, OneItem.class.cast(dirEntry));
- } catch (OneDriveException e) {
- throw new IOException("dir: "+ dir, e);
- }
+ protected OneItem createDirectoryEntry(OneItem parentEntry, Path dir) throws IOException {
+ // TODO: how to diagnose?
+ return OneItem.class.cast(asFolder(parentEntry).createFolder(toFilenameString(dir)));
}
@Override
- public void delete(final Path path) throws IOException {
- try {
- removeEntry(path);
- } catch (OneDriveException e) {
- throw new IOException("path: " + path, e);
- }
+ protected boolean hasChildren(OneItem dirEntry, Path dir) throws IOException {
+ return client.getFolderByPath(toPathString(dir)).getChildren().size() > 0;
}
@Override
- public void copy(final Path source, final Path target, final Set options) throws IOException {
- try {
- if (cache.existsEntry(target)) {
- if (options != null && options.stream().anyMatch(o -> o.equals(StandardCopyOption.REPLACE_EXISTING))) {
- removeEntry(target);
- } else {
- throw new FileAlreadyExistsException(target.toString());
- }
- }
- copyEntry(source, target);
- } catch (OneDriveException e) {
-e.printStackTrace();
- throw new IOException("source: "+ source + ", target: " + target, e);
- }
+ protected void removeEntry(OneItem entry, Path path) throws IOException {
+ // TODO: unknown what happens when a move operation is performed
+ // and the target already exists
+ entry.delete();
}
@Override
- public void move(final Path source, final Path target, final Set options) throws IOException {
- try {
- if (cache.existsEntry(target)) {
- if (cache.getEntry(target).isFolder()) {
- if (options != null && options.stream().anyMatch(o -> o.equals(StandardCopyOption.REPLACE_EXISTING))) {
- // replace the target
- if (cache.getChildCount(target) > 0) {
- throw new DirectoryNotEmptyException(target.toString());
- } else {
- removeEntry(target);
- moveEntry(source, target, false);
- }
- } else {
- // move into the target
- // TODO SPEC is FileAlreadyExistsException ?
- moveEntry(source, target, true);
- }
- } else {
- if (options != null && options.stream().anyMatch(o -> o.equals(StandardCopyOption.REPLACE_EXISTING))) {
- removeEntry(target);
- moveEntry(source, target, false);
- } else {
- throw new FileAlreadyExistsException(target.toString());
- }
- }
- } else {
- if (source.getParent().equals(target.getParent())) {
- // rename
- renameEntry(source, target);
- } else {
- moveEntry(source, target, false);
- }
- }
- } catch (OneDriveException e) {
-e.printStackTrace();
- throw new IOException("source: " + source + ", target: " + target, e);
- }
- }
- /**
- * Check access modes for a path on this filesystem
- *
- * If no modes are provided to check for, this simply checks for the
- * existence of the path.
- *
- *
- * @param path the path to check
- * @param modes the modes to check for, if any
- * @throws IOException filesystem level error, or a plain I/O error
- * if you use this with javafs (jnr-fuse), you should throw {@link NoSuchFileException} when the file not found.
- * @see FileSystemProvider#checkAccess(Path, AccessMode...)
- */
- @Override
- protected void checkAccessImpl(final Path path, final AccessMode... modes) throws IOException {
- final OneItem entry = cache.getEntry(path);
-
- if (!entry.isFile()) {
- return;
- }
-
- // TODO: assumed; not a file == directory
- for (final AccessMode mode : modes) {
- if (mode == AccessMode.EXECUTE) {
- throw new AccessDeniedException(path.toString());
- }
- }
+ protected OneItem copyEntry(OneItem sourceEntry, OneItem targetParentEntry, Path source, Path target, Set options) throws IOException {
+ OneFile newEntry = asFile(sourceEntry).copy(asFolder(targetParentEntry), toFilenameString(target));
+Debug.println(newEntry.getParentFolder().getName() + "/" + newEntry.getName());
+ return OneItem.class.cast(newEntry);
}
@Override
- public void close() throws IOException {
- // TODO: what to do here? OneDriveClient does not implement Closeable :(
+ protected OneItem moveEntry(OneItem sourceEntry, OneItem targetParentEntry, Path source, Path target, boolean targetIsParent) throws IOException {
+ return asFile(sourceEntry).move(asFolder(targetParentEntry));
}
- /**
- * @throws IOException if you use this with javafs (jnr-fuse), you should throw {@link NoSuchFileException} when the file not found.
- */
- @Nonnull
@Override
- protected Object getPathMetadataImpl(final Path path) throws IOException {
- return cache.getEntry(path);
- }
-
- /** */
- private List getDirectoryEntries(Path dir) throws IOException, OneDriveException {
- final OneItem entry = cache.getEntry(dir);
-
- if (!entry.isFolder()) {
- throw new NotDirectoryException(dir.toString());
- }
-
- List list = null;
- if (cache.containsFolder(dir)) {
- list = cache.getFolder(dir);
- } else {
- final List children = OneFolder.class.cast(entry).getChildren();
- list = new ArrayList<>(children.size());
-
- for (final OneItem child : children) {
- Path childPath = dir.resolve(child.getName());
- list.add(childPath);
-//System.err.println("child: " + childPath.toRealPath().toString());
-
- cache.putFile(childPath, child);
- }
-
- cache.putFolder(dir, list);
- }
-
- return list;
- }
-
- /** */
- private void removeEntry(Path path) throws IOException, OneDriveException {
- OneItem entry = cache.getEntry(path);
- if (entry.isFolder()) {
- // TODO use cache ???
- final List children = client.getFolderByPath(toPathString(path)).getChildren();
-
- if (children.size() > 0) {
- throw new DirectoryNotEmptyException(path.toString());
- }
- }
-
- // TODO: unknown what happens when a move operation is performed
- // and the target already exists
- entry.delete();
-
- cache.removeEntry(path);
+ protected OneItem moveFolderEntry(OneItem sourceEntry, OneItem targetParentEntry, Path source, Path target, boolean targetIsParent) throws IOException {
+ OneItem newEntry = asFolder(sourceEntry).move(asFolder(targetParentEntry));
+Debug.println(newEntry.getParentFolder().getName() + "/" + newEntry.getName());
+ return newEntry;
}
- /** */
- private void copyEntry(final Path source, final Path target) throws IOException, OneDriveException {
- try {
- OneItem sourceEntry = cache.getEntry(source);
- OneItem targetParentEntry = cache.getEntry(target.getParent());
- if (sourceEntry.isFile()) {
- OneFile newEntry = OneFile.class.cast(sourceEntry).copy(OneFolder.class.cast(targetParentEntry), toFilenameString(target));
-Debug.println(newEntry.getParentFolder().getName() + "/" + newEntry.getName());
- cache.addEntry(target, OneItem.class.cast(newEntry));
- } else if (sourceEntry.isFolder()) {
- throw new IsDirectoryException("source can not be a folder: " + source);
- }
- } catch (ParseException | InterruptedException e) {
- throw new IOException(e);
- }
+ @Override
+ protected OneItem renameEntry(OneItem sourceEntry, OneItem targetParentEntry, Path source, Path target) throws IOException {
+ return sourceEntry.rename(asFolder(targetParentEntry), toFilenameString(target));
}
- /**
- * @param targetIsParent if the target is folder
- */
- private void moveEntry(final Path source, final Path target, boolean targetIsParent) throws IOException, OneDriveException {
- try {
- OneItem sourceEntry = cache.getEntry(source);
- OneItem targetParentEntry = cache.getEntry(targetIsParent ? target : target.getParent());
- if (sourceEntry.isFile()) {
- OneItem newEntry = OneFile.class.cast(sourceEntry).move(OneFolder.class.cast(targetParentEntry));
- cache.removeEntry(source);
- if (targetIsParent) {
- cache.addEntry(target.resolve(source.getFileName()), newEntry);
- } else {
- cache.addEntry(target, newEntry);
- }
- } else if (sourceEntry.isFolder()) {
- OneItem newEntry = OneFolder.class.cast(sourceEntry).move(OneFolder.class.cast(targetParentEntry));
-Debug.println(newEntry.getParentFolder().getName() + "/" + newEntry.getName());
- cache.moveEntry(source, target, newEntry);
- }
- } catch (ParseException | InterruptedException e) {
- throw new IOException(e);
- }
+ @Override
+ public void close() throws IOException {
+ client.disconnect();
}
- /** */
- private void renameEntry(final Path source, final Path target) throws IOException, OneDriveException {
+ @Nonnull
+ @Override
+ public WatchService newWatchService() {
try {
- OneItem sourceEntry = cache.getEntry(source);
- OneItem targetEntry = cache.getEntry(target.getParent());
-
- OneItem newEntry = sourceEntry.rename(OneFolder.class.cast(targetEntry), toFilenameString(target));
-
- cache.removeEntry(source);
- cache.addEntry(target, newEntry);
- } catch (ParseException | InterruptedException e) {
- throw new IOException(e);
+ return new OneDriveWatchService(client);
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
}
}
}
diff --git a/vavi-nio-file-onedrive/src/main/java/vavi/nio/file/onedrive/OneDriveFileSystemProvider.java b/vavi-nio-file-onedrive/src/main/java/vavi/nio/file/onedrive/OneDriveFileSystemProvider.java
index 40f42689..c8fd37fb 100644
--- a/vavi-nio-file-onedrive/src/main/java/vavi/nio/file/onedrive/OneDriveFileSystemProvider.java
+++ b/vavi-nio-file-onedrive/src/main/java/vavi/nio/file/onedrive/OneDriveFileSystemProvider.java
@@ -26,6 +26,8 @@ public final class OneDriveFileSystemProvider extends FileSystemProviderBase {
public static final String ENV_APP_CREDENTIAL = "app_credential";
+ public static final String ENV_USE_SYSTEM_WATCHER = "use_system_watcher";
+
public OneDriveFileSystemProvider() {
super(new OneDriveFileSystemRepository());
}
diff --git a/vavi-nio-file-onedrive/src/main/java/vavi/nio/file/onedrive/OneDriveFileSystemRepository.java b/vavi-nio-file-onedrive/src/main/java/vavi/nio/file/onedrive/OneDriveFileSystemRepository.java
index 8c8db68a..084db41c 100644
--- a/vavi-nio-file-onedrive/src/main/java/vavi/nio/file/onedrive/OneDriveFileSystemRepository.java
+++ b/vavi-nio-file-onedrive/src/main/java/vavi/nio/file/onedrive/OneDriveFileSystemRepository.java
@@ -44,7 +44,7 @@
public final class OneDriveFileSystemRepository extends FileSystemRepositoryBase {
public OneDriveFileSystemRepository() {
- super("onedrive", new OneDriveFileSystemFactoryProvider());
+ super("onedrive1", new OneDriveFileSystemFactoryProvider());
}
/**
@@ -88,7 +88,7 @@ public FileSystemDriver createDriver(final URI uri, final Map env) th
OneDriveSDK client = OneDriveFactory.createOneDriveSDK(appCredential.getClientId(),
appCredential.getClientSecret(),
appCredential.getRedirectUrl(),
- OneDriveScope.OFFLINE_ACCESS);
+ OneDriveScope.valueOfByMicrosoftScopeString(appCredential.getScope()));
String url = client.getAuthenticationURL();
MicrosoftOAuth2 oauth2 = new MicrosoftOAuth2(wrap(appCredential, url), userCredential.getId());
@@ -123,7 +123,7 @@ public FileSystemDriver createDriver(final URI uri, final Map env) th
return new OneDriveFileSystemDriver(fileStore, factoryProvider, client, env);
} catch (OneDriveException e) {
- throw new IllegalStateException(e);
+ throw new IOException(e);
}
}
}
diff --git a/vavi-nio-file-onedrive/src/main/java/vavi/nio/file/onedrive/OneDriveUploadOption.java b/vavi-nio-file-onedrive/src/main/java/vavi/nio/file/onedrive/OneDriveUploadOption.java
index 55482580..b832f58d 100644
--- a/vavi-nio-file-onedrive/src/main/java/vavi/nio/file/onedrive/OneDriveUploadOption.java
+++ b/vavi-nio-file-onedrive/src/main/java/vavi/nio/file/onedrive/OneDriveUploadOption.java
@@ -14,6 +14,10 @@
/**
* OneDriveUploadOption.
*
+ * in {@link com.github.fge.filesystem.options.FileSystemOptionsFactory},
+ * instances of this class are compared by contains method. so i override
+ * {@link #equals(Object)} and {@link #hashCode()}.
+ *
* TODO CopyOption doesn't work.
*
* @author Naohide Sano (umjammer)
@@ -21,6 +25,9 @@
*/
public class OneDriveUploadOption implements OpenOption, CopyOption {
+ /** */
+ private static final long serialVersionUID = -3760090552182064957L;
+
/** */
private Path source;
@@ -41,7 +48,7 @@ public boolean equals(Object other) {
@Override
public int hashCode() {
- return Long.hashCode(-3760090552182064957L); // TODO ad-hoc
+ return Long.hashCode(serialVersionUID); // TODO ad-hoc
}
}
diff --git a/vavi-nio-file-onedrive/src/main/java/vavi/nio/file/onedrive/OneDriveWatchService.java b/vavi-nio-file-onedrive/src/main/java/vavi/nio/file/onedrive/OneDriveWatchService.java
new file mode 100644
index 00000000..fcfda7a8
--- /dev/null
+++ b/vavi-nio-file-onedrive/src/main/java/vavi/nio/file/onedrive/OneDriveWatchService.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.onedrive;
+
+import java.io.IOException;
+
+import vavi.nio.file.watch.webhook.WebHookBaseWatchService;
+import vavi.util.Debug;
+
+import de.tuberlin.onedrivesdk.OneDriveSDK;
+
+
+/**
+ * OneDriveWatchService.
+ *
+ * system properties
+ *
+ * vavi.nio.file.watch.webhook.NotificationProvider.onedrive
+ *
+ *
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/07/22 umjammer initial version
+ */
+public class OneDriveWatchService extends WebHookBaseWatchService {
+
+ private static final String WEBHOOK_NOTIFICATION_PROVIDER =
+ System.getProperty("vavi.nio.file.watch.webhook.NotificationProvider.onedrive", ".onedrive.webhook.websocket");
+
+// private OneDriveSDK client;
+
+// private String savedStartPageToken;
+
+ /** */
+ public OneDriveWatchService(OneDriveSDK client) throws IOException {
+// this.client = client;
+
+ setupNotification(this, WEBHOOK_NOTIFICATION_PROVIDER);
+ }
+
+ @Override
+ protected void onNotifyMessage(String notification) throws IOException {
+Debug.println(">> notification: done");
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (isOpen()) {
+ super.close();
+ }
+ }
+}
diff --git a/vavi-nio-file-onedrive/src/main/java/vavi/nio/file/onedrive/webhook/websocket/OneDriveWebSocketNotification.java b/vavi-nio-file-onedrive/src/main/java/vavi/nio/file/onedrive/webhook/websocket/OneDriveWebSocketNotification.java
new file mode 100644
index 00000000..ac7d9d42
--- /dev/null
+++ b/vavi-nio-file-onedrive/src/main/java/vavi/nio/file/onedrive/webhook/websocket/OneDriveWebSocketNotification.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.onedrive.webhook.websocket;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.function.Consumer;
+
+import javax.websocket.ClientEndpoint;
+import javax.websocket.Session;
+
+import vavi.nio.file.watch.webhook.websocket.BasicAuthorizationConfigurator;
+import vavi.nio.file.watch.webhook.websocket.StringWebSocketNotification;
+
+
+/**
+ * OneDriveWebSocketNotification.
+ *
+ * environment variables
+ *
+ * VAVI_APPS_WEBHOOK_WEBSOCKET_BASE_URL
+ * VAVI_APPS_WEBHOOK_WEBSOCKET_ONEDRIVE_PATH
+ *
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/07/23 umjammer initial version
+ */
+@ClientEndpoint(configurator = BasicAuthorizationConfigurator.class)
+public class OneDriveWebSocketNotification extends StringWebSocketNotification {
+
+ private static final String websocketBaseUrl = System.getenv("VAVI_APPS_WEBHOOK_WEBSOCKET_BASE_URL");
+ private static final String websocketPath = System.getenv("VAVI_APPS_WEBHOOK_WEBSOCKET_ONEDRIVE_PATH");
+
+ private static final URI uri = URI.create(websocketBaseUrl + websocketPath);
+
+ private Consumer callback;
+
+ /**
+ * @param args
+ */
+ public OneDriveWebSocketNotification(Consumer callback, Object... args) throws IOException {
+ super(uri, args);
+ this.callback = callback;
+ }
+
+ @Override
+ public void onOpenImpl(Session session) throws IOException {
+ }
+
+ @Override
+ protected void onNotifyMessageImpl(String notification) throws IOException {
+ callback.accept(notification);
+ }
+
+ @Override
+ protected void onCloseImpl(Session session) throws IOException {
+ }
+}
+
+/* */
diff --git a/vavi-nio-file-onedrive/src/main/java/vavi/nio/file/onedrive/webhook/websocket/OneDriveWebSocketNotificationProvider.java b/vavi-nio-file-onedrive/src/main/java/vavi/nio/file/onedrive/webhook/websocket/OneDriveWebSocketNotificationProvider.java
new file mode 100644
index 00000000..0e9c94b8
--- /dev/null
+++ b/vavi-nio-file-onedrive/src/main/java/vavi/nio/file/onedrive/webhook/websocket/OneDriveWebSocketNotificationProvider.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.onedrive.webhook.websocket;
+
+import java.io.IOException;
+import java.util.function.Consumer;
+
+import vavi.nio.file.watch.webhook.Notification;
+import vavi.nio.file.watch.webhook.NotificationProvider;
+
+
+/**
+ * OneDriveWebSocketNotificationProvider.
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/07/23 umjammer initial version
+ */
+public class OneDriveWebSocketNotificationProvider implements NotificationProvider {
+
+ @Override
+ public Notification getNotification(Consumer callback, Object... args) throws IOException {
+ return Notification.class.cast(new OneDriveWebSocketNotification(Consumer.class.cast(callback), args));
+ }
+}
+
+/* */
diff --git a/vavi-nio-file-onedrive/src/main/resources/META-INF/services/java.nio.file.spi.FileSystemProvider b/vavi-nio-file-onedrive/src/main/resources/META-INF/services/java.nio.file.spi.FileSystemProvider
index 6cb6a07f..7a82ad29 100644
--- a/vavi-nio-file-onedrive/src/main/resources/META-INF/services/java.nio.file.spi.FileSystemProvider
+++ b/vavi-nio-file-onedrive/src/main/resources/META-INF/services/java.nio.file.spi.FileSystemProvider
@@ -1 +1 @@
-#vavi.nio.file.onedrive.OneDriveFileSystemProvider
+vavi.nio.file.onedrive.OneDriveFileSystemProvider
diff --git a/vavi-nio-file-onedrive/src/main/resources/META-INF/services/vavi.nio.file.watch.webhook.NotificationProvider b/vavi-nio-file-onedrive/src/main/resources/META-INF/services/vavi.nio.file.watch.webhook.NotificationProvider
new file mode 100644
index 00000000..6cb0a51f
--- /dev/null
+++ b/vavi-nio-file-onedrive/src/main/resources/META-INF/services/vavi.nio.file.watch.webhook.NotificationProvider
@@ -0,0 +1 @@
+vavi.nio.file.onedrive.webhook.websocket.OneDriveWebSocketNotificationProvider
diff --git a/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/App.java b/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/App.java
index 62e4bfb9..763d707b 100644
--- a/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/App.java
+++ b/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/App.java
@@ -19,6 +19,9 @@
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
+import com.budhash.cliche.Command;
+import com.budhash.cliche.Param;
+import com.budhash.cliche.ShellFactory;
import com.google.common.collect.Maps;
import vavi.net.auth.WithTotpUserCredential;
@@ -30,9 +33,6 @@
import static vavi.net.auth.oauth2.OAuth2AppCredential.wrap;
-import asg.cliche.Command;
-import asg.cliche.Param;
-import asg.cliche.ShellFactory;
import de.tuberlin.onedrivesdk.OneDriveException;
import de.tuberlin.onedrivesdk.OneDriveFactory;
import de.tuberlin.onedrivesdk.OneDriveSDK;
diff --git a/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/Main.java b/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/Main.java
index 9fce9c0e..dbd99cea 100644
--- a/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/Main.java
+++ b/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/Main.java
@@ -26,8 +26,8 @@ public class Main {
void test01() throws Exception {
String email = System.getenv("MICROSOFT_TEST_ACCOUNT");
- URI uri = URI.create("onedrive:///?id=" + email);
+ URI uri = URI.create("onedrive1:///?id=" + email);
- testAll(new OneDriveFileSystemProvider().newFileSystem(uri, Collections.EMPTY_MAP));
+ testAll(new OneDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap()));
}
}
\ No newline at end of file
diff --git a/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/Main2.java b/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/Main2.java
index d68302c4..1f6ac487 100644
--- a/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/Main2.java
+++ b/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/Main2.java
@@ -27,8 +27,8 @@ public class Main2 {
void test01() throws Exception {
String email = System.getenv("MICROSOFT_TEST_ACCOUNT");
- URI uri = URI.create("onedrive:///?id=" + email);
- FileSystem fs = new OneDriveFileSystemProvider().newFileSystem(uri, Collections.EMPTY_MAP);
+ URI uri = URI.create("onedrive1:///?id=" + email);
+ FileSystem fs = new OneDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap());
testLargeFile(fs, OneDriveUploadOption.class);
}
diff --git a/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/Main3.java b/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/Main3.java
index 6a7ef269..acde8c5c 100644
--- a/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/Main3.java
+++ b/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/Main3.java
@@ -28,8 +28,8 @@ public final class Main3 {
void test01() throws Exception {
String email = System.getenv("MICROSOFT_TEST_ACCOUNT");
- URI uri = URI.create("onedrive:///?id=" + email);
- FileSystem fs = new OneDriveFileSystemProvider().newFileSystem(uri, Collections.EMPTY_MAP);
+ URI uri = URI.create("onedrive1:///?id=" + email);
+ FileSystem fs = new OneDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap());
testMoveFolder(fs);
}
diff --git a/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/Main4.java b/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/Main4.java
index 2bd24341..c253e7ba 100644
--- a/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/Main4.java
+++ b/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/Main4.java
@@ -78,7 +78,7 @@ public static void main(final String... args) throws IOException {
Map env = new HashMap<>();
env.put("ignoreAppleDouble", true);
- URI uri = URI.create("onedrive:///?id=" + email);
+ URI uri = URI.create("onedrive1:///?id=" + email);
FileSystem fs = new OneDriveFileSystemProvider().newFileSystem(uri, env);
diff --git a/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/Main5.java b/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/Main5.java
index 3b83ef01..d23d1ad3 100644
--- a/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/Main5.java
+++ b/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/Main5.java
@@ -35,13 +35,13 @@ public class Main5 {
void test01() throws Exception {
String email = System.getenv("TEST5_ACCOUNT");
- URI uri = URI.create("onedrive:///?id=" + email);
+ URI uri = URI.create("onedrive1:///?id=" + email);
Path src;
Path dstDir;
Path dst;
String a, b;
- try (FileSystem onedrivefs = new OneDriveFileSystemProvider().newFileSystem(uri, Collections.EMPTY_MAP)) {
+ try (FileSystem onedrivefs = new OneDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap())) {
src = Paths.get("src/test/resources/Hello.java");
dstDir = onedrivefs.getPath("/").resolve("TEST_FUSE_5");
@@ -60,7 +60,7 @@ void test01() throws Exception {
a = Util.toFilenameString(Files.list(dstDir).findFirst().get());
}
- try (FileSystem onedrivefs = new OneDriveFileSystemProvider().newFileSystem(uri, Collections.EMPTY_MAP)) {
+ try (FileSystem onedrivefs = new OneDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap())) {
dstDir = onedrivefs.getPath("/").resolve("TEST_FUSE_5");
dst = dstDir.resolve("ããšã 001");
diff --git a/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/OneDriveFS.java b/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/OneDriveFS.java
index bb3d877b..1758b2a9 100644
--- a/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/OneDriveFS.java
+++ b/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/OneDriveFS.java
@@ -37,7 +37,7 @@ public static void main(String[] args) throws Exception {
String email = args[1];
- URI uri = URI.create("onedrive:///?id=" + email);
+ URI uri = URI.create("onedrive1:///?id=" + email);
OAuth2AppCredential appCredential = new MicrosoftLocalAppCredential();
PropsEntity.Util.bind(appCredential);
@@ -48,7 +48,7 @@ public static void main(String[] args) throws Exception {
FileSystem fs = new OneDriveFileSystemProvider().newFileSystem(uri, env);
- Fuse.getFuse().mount(fs, args[0], Collections.EMPTY_MAP);
+ Fuse.getFuse().mount(fs, args[0], Collections.emptyMap());
}
}
diff --git a/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/Rename.java b/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/Rename.java
index 2c857502..f9bb7f29 100644
--- a/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/Rename.java
+++ b/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/Rename.java
@@ -41,7 +41,7 @@ public static void main(final String... args) throws IOException {
// Create the necessary elements to create a filesystem.
// Note: the URI _must_ have a scheme of "onedrive", and
// _must_ be hierarchical.
- URI uri = URI.create("onedrive:///?id=" + email);
+ URI uri = URI.create("onedrive1:///?id=" + email);
OAuth2AppCredential appCredential = new MicrosoftLocalAppCredential();
PropsEntity.Util.bind(appCredential);
diff --git a/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/WebHookApiTest.java b/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/WebHookApiTest.java
new file mode 100644
index 00000000..06430db8
--- /dev/null
+++ b/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/WebHookApiTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.onedrive;
+
+import java.io.IOException;
+import java.net.URI;
+
+import vavi.net.auth.oauth2.microsoft.MicrosoftLocalAppCredential;
+import vavi.net.auth.oauth2.microsoft.MicrosoftOAuth2;
+import vavi.net.auth.web.microsoft.MicrosoftLocalUserCredential;
+import vavi.util.Debug;
+
+import static vavi.net.auth.oauth2.OAuth2AppCredential.wrap;
+
+import de.tuberlin.onedrivesdk.OneDriveException;
+import de.tuberlin.onedrivesdk.OneDriveFactory;
+import de.tuberlin.onedrivesdk.OneDriveSDK;
+import de.tuberlin.onedrivesdk.common.OneDriveScope;
+import de.tuberlin.onedrivesdk.common.OneItem;
+import de.tuberlin.onedrivesdk.common.Subscription;
+import de.tuberlin.onedrivesdk.folder.OneFolder;
+import de.tuberlin.onedrivesdk.networking.OneDriveAuthenticationException;
+
+
+/**
+ * WebHookApiTest. onedrive
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/07/03 umjammer initial version
+ * @see "https://app.box.com/developers/console/app/216798/webhooks"
+ * @see "https://developer.box.com/guides/webhooks/"
+ */
+public class WebHookApiTest {
+
+ static final String VAVI_APPS_WEBHOOK_SECRET = System.getenv("VAVI_APPS_WEBHOOK_SECRET");
+ static String webhooktUrl = System.getenv("VAVI_APPS_WEBHOOK_WEBHOOK_ONEDRIVE_URL");
+ static String websocketBaseUrl = System.getenv("VAVI_APPS_WEBHOOK_WEBSOCKET_BASE_URL");
+ static String websocketPath = System.getenv("VAVI_APPS_WEBHOOK_WEBSOCKET_ONEDRIVE_PATH");
+ static String email = System.getenv("MICROSOFT_TEST_ACCOUNT");
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args) throws Exception {
+
+ MicrosoftLocalUserCredential userCredential = new MicrosoftLocalUserCredential(email);
+ MicrosoftLocalAppCredential appCredential = new MicrosoftLocalAppCredential();
+
+ OneDriveSDK client = null;
+ try {
+ client = OneDriveFactory.createOneDriveSDK(appCredential.getClientId(),
+ appCredential.getClientSecret(),
+ appCredential.getRedirectUrl(),
+ OneDriveScope.OFFLINE_ACCESS); // TODO out source
+ String url = client.getAuthenticationURL();
+
+ MicrosoftOAuth2 oauth2 = new MicrosoftOAuth2(wrap(appCredential, url), userCredential.getId());
+ String code = null;
+ String refreshToken = oauth2.readRefreshToken();
+ if (refreshToken == null || refreshToken.isEmpty()) {
+ code = oauth2.authorize(userCredential);
+ client.authenticate(code);
+ } else {
+ try {
+ client.authenticateWithRefreshToken(refreshToken);
+ } catch (OneDriveAuthenticationException e) {
+Debug.println("refreshToken: timeout?");
+ code = oauth2.authorize(userCredential);
+ client.authenticate(code);
+ }
+ }
+
+ } catch (OneDriveException e) {
+ throw new IOException(e);
+ }
+
+ // create
+ URI uri = URI.create(webhooktUrl);
+ // Listen for file upload events in the specified folder
+ OneFolder rootFolder = client.getRootFolder();
+ for (OneItem i : rootFolder.getChildren()) {
+ if (i.getName().equals("TEST_WEBHOOK")) {
+System.out.println("rmdir " + i.getName());
+ i.delete();
+ }
+ }
+System.out.println("mkdir " + "TEST_WEBHOOK");
+ OneFolder newFolder = rootFolder.createFolder("TEST_WEBHOOK");
+ // cannot set to root folder!
+System.out.println("[create] webhook");
+ Subscription subscription = client.subscribe(uri.toURL().toString(), VAVI_APPS_WEBHOOK_SECRET);
+Debug.println(subscription.getId());
+
+System.out.println("mkdir " + "TEST_WEBHOOK/" + "NEW FOLDER");
+ OneFolder subFolder = newFolder.createFolder("NEW FOLDER");
+
+ Thread.sleep(5000);
+
+ // update
+System.out.println("[update] webhook");
+ subscription = subscription.update();
+
+ // delete
+System.out.println("[delete] webhook");
+ subscription.delete();
+
+System.out.println("rmdir " + subFolder.getName());
+ subFolder.delete();
+System.out.println("rmdir " + newFolder.getName());
+ newFolder.delete();
+ }
+}
+
+/* */
diff --git a/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/WebHookTest3.java b/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/WebHookTest3.java
new file mode 100644
index 00000000..595ea7b1
--- /dev/null
+++ b/vavi-nio-file-onedrive/src/test/java/vavi/nio/file/onedrive/WebHookTest3.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.onedrive;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collections;
+
+import vavi.net.auth.oauth2.microsoft.MicrosoftLocalAppCredential;
+import vavi.net.auth.oauth2.microsoft.MicrosoftOAuth2;
+import vavi.net.auth.web.microsoft.MicrosoftLocalUserCredential;
+import vavi.util.Debug;
+
+import static vavi.net.auth.oauth2.OAuth2AppCredential.wrap;
+
+import de.tuberlin.onedrivesdk.OneDriveException;
+import de.tuberlin.onedrivesdk.OneDriveFactory;
+import de.tuberlin.onedrivesdk.OneDriveSDK;
+import de.tuberlin.onedrivesdk.common.OneDriveScope;
+import de.tuberlin.onedrivesdk.networking.OneDriveAuthenticationException;
+
+
+/**
+ * WebHookTest3. onedrive, using now construction libraries.
+ *
+ * @depends "file://${HOME}.vavifuse/onedrive/?"
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2016/02/29 umjammer initial version
+ * @see "https://stackoverflow.com/a/25794109/6102938"
+ */
+public class WebHookTest3 {
+
+ static String email = System.getenv("MICROSOFT_TEST_ACCOUNT");
+
+ /**
+ * @param args 0: email
+ */
+ public static void main(String[] args) throws Exception {
+ WebHookTest3 app = new WebHookTest3();
+ app.test();
+ }
+
+ void test() throws Exception {
+ MicrosoftLocalUserCredential userCredential = new MicrosoftLocalUserCredential(email);
+ MicrosoftLocalAppCredential appCredential = new MicrosoftLocalAppCredential();
+
+ OneDriveSDK client = null;
+ try {
+ client = OneDriveFactory.createOneDriveSDK(appCredential.getClientId(),
+ appCredential.getClientSecret(),
+ appCredential.getRedirectUrl(),
+ OneDriveScope.OFFLINE_ACCESS); // TODO out source
+ String url = client.getAuthenticationURL();
+
+ MicrosoftOAuth2 oauth2 = new MicrosoftOAuth2(wrap(appCredential, url), userCredential.getId());
+ String code = null;
+ String refreshToken = oauth2.readRefreshToken();
+ if (refreshToken == null || refreshToken.isEmpty()) {
+ code = oauth2.authorize(userCredential);
+ client.authenticate(code);
+ } else {
+ try {
+ client.authenticateWithRefreshToken(refreshToken);
+ } catch (OneDriveAuthenticationException e) {
+Debug.println("refreshToken: timeout?");
+ code = oauth2.authorize(userCredential);
+ client.authenticate(code);
+ }
+ }
+
+ } catch (OneDriveException e) {
+ throw new IOException(e);
+ }
+
+ OneDriveWatchService service = new OneDriveWatchService(client);
+Debug.println("WEBSOCKET: start: " + service);
+ try {
+ URI uri = URI.create("onedrive1:///?id=" + email);
+ FileSystem fs = FileSystems.newFileSystem(uri, Collections.emptyMap());
+
+ Path tmpDir = fs.getPath("tmp");
+ if (!Files.exists(tmpDir)) {
+System.out.println("rmdir " + tmpDir);
+ Files.createDirectory(tmpDir);
+ }
+ Path remote = tmpDir.resolve("Test+Watch");
+ if (Files.exists(remote)) {
+System.out.println("rm " + remote);
+ Files.delete(remote);
+ }
+ Path source = Paths.get("src/test/resources", "Hello.java");
+System.out.println("cp " + source + " " + remote);
+ Files.copy(source, remote);
+
+System.out.println("rm " + remote);
+ Files.delete(remote);
+
+ Thread.sleep(10000);
+
+ fs.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ service.close();
+ }
+Debug.println("APP: done");
+ OneDriveWatchService.dispose();
+//Thread.getAllStackTraces().keySet().forEach(System.err::println);
+ }
+}
diff --git a/vavi-nio-file-onedrive/src/test/resources/log4j.properties b/vavi-nio-file-onedrive/src/test/resources/log4j.properties
deleted file mode 100644
index b46df5a7..00000000
--- a/vavi-nio-file-onedrive/src/test/resources/log4j.properties
+++ /dev/null
@@ -1,44 +0,0 @@
-#
-# Copyright (c) 2004 by Naohide Sano, All rights reserved.
-#
-# Written by Naohide Sano
-#
-
-#
-# ALL, DEBUG, INFO, WARN, ERROR, FATAL and OFF
-#
-log4j.rootLogger=ALL, ROOT
-log4j.appender.ROOT=org.apache.log4j.ConsoleAppender
-log4j.appender.ROOT.target=System.err
-log4j.appender.ROOT.layout=org.apache.log4j.PatternLayout
-log4j.appender.ROOT.layout.ConversionPattern=%d{ISO8601} [%p] %m%n\tat %t%x %c.%M(%F:%L)\n
-log4j.appender.ROOT.encoding=${file.encoding}
-
-#
-log4j.logger.org.apache=ERROR, APACHE
-log4j.additivity.org.apache=false
-log4j.appender.APACHE=org.apache.log4j.ConsoleAppender
-log4j.appender.APACHE.target=System.err
-log4j.appender.APACHE.layout=org.apache.log4j.PatternLayout
-log4j.appender.APACHE.layout.ConversionPattern=%d{ISO8601} [%p] %m%n\tat %t%x %c.%M(%F:%L)\n
-log4j.appender.APACHE.encoding=${file.encoding}
-
-#
-log4j.logger.org.apache.http=DEBUG, HTTPCLIENT
-log4j.additivity.org.apache=false
-log4j.appender.HTTPCLIENT=org.apache.log4j.ConsoleAppender
-log4j.appender.HTTPCLIENT.target=System.err
-log4j.appender.HTTPCLIENT.layout=org.apache.log4j.PatternLayout
-log4j.appender.HTTPCLIENT.layout.ConversionPattern=%d{ISO8601} [%p] %m%n\tat %t%x %c.%M(%F:%L)\n
-log4j.appender.HTTPCLIENT.encoding=${file.encoding}
-
-#
-log4j.logger.net.java.sen=ERROR, SEN
-log4j.additivity.org.apache=false
-log4j.appender.SEN=org.apache.log4j.ConsoleAppender
-log4j.appender.SEN.target=System.err
-log4j.appender.SEN.layout=org.apache.log4j.PatternLayout
-log4j.appender.SEN.layout.ConversionPattern=%d{ISO8601} [%p] %m%n\tat %t%x %c.%M(%F:%L)\n
-log4j.appender.SEN.encoding=${file.encoding}
-
-#
diff --git a/vavi-nio-file-onedrive/src/test/resources/log4j2.xml b/vavi-nio-file-onedrive/src/test/resources/log4j2.xml
index daa4f7f6..38c7b1ce 100644
--- a/vavi-nio-file-onedrive/src/test/resources/log4j2.xml
+++ b/vavi-nio-file-onedrive/src/test/resources/log4j2.xml
@@ -1,13 +1,14 @@
+
-
+
diff --git a/vavi-nio-file-onedrive/src/test/resources/onedrive.properties b/vavi-nio-file-onedrive/src/test/resources/onedrive.properties
index 298c42c4..3f300320 100644
--- a/vavi-nio-file-onedrive/src/test/resources/onedrive.properties
+++ b/vavi-nio-file-onedrive/src/test/resources/onedrive.properties
@@ -1 +1 @@
-authenticatorClassName=vavi.net.auth.oauth2.microsoft.MicrosoftLocalAuthenticator
+authenticatorClassName=vavi.net.auth.oauth2.microsoft.MicrosoftBasicAuthenticator
diff --git a/vavi-nio-file-onedrive3/pom.xml b/vavi-nio-file-onedrive3/pom.xml
index fc985f29..beae35fe 100644
--- a/vavi-nio-file-onedrive3/pom.xml
+++ b/vavi-nio-file-onedrive3/pom.xml
@@ -4,7 +4,7 @@
vavi-apps-fuse
vavi
- 0.1.6
+ 0.1.7
vavi-nio-file-onedrive3
@@ -20,8 +20,8 @@
- maven.cyberduck.io-release
- http://repo.maven.cyberduck.io.s3.amazonaws.com/releases
+ jitpack.io
+ https://jitpack.io
@@ -38,16 +38,21 @@
- com.github.umjammer.vavi-net-auth
+ ${vavi-net-auth.groupId}
vavi-net-auth-microsoft
${vavi-net-auth.version}
- ch.iterate.onedrive
+ com.github.iterate-ch
onedrive-java-client
- 2.0.16
+ onedrive-java-client-3.1.8
+
+
+
+ vavi
+ vavi-nio-file-commons
@@ -68,7 +73,6 @@
org.junit.jupiter
junit-jupiter-params
- 5.3.0
test
diff --git a/vavi-nio-file-onedrive3/src/main/java/org/nuxeo/onedrive/client/OneDriveSubscriptions.java b/vavi-nio-file-onedrive3/src/main/java/org/nuxeo/onedrive/client/OneDriveSubscriptions.java
new file mode 100644
index 00000000..cf9c25bc
--- /dev/null
+++ b/vavi-nio-file-onedrive3/src/main/java/org/nuxeo/onedrive/client/OneDriveSubscriptions.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package org.nuxeo.onedrive.client;
+
+import java.io.IOException;
+import java.net.URL;
+
+import com.eclipsesource.json.JsonObject;
+import com.eclipsesource.json.JsonValue;
+import com.eclipsesource.json.ParseException;
+
+
+/**
+ * OneDriveSubscriptions.
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/07/05 umjammer initial version
+ */
+public class OneDriveSubscriptions extends OneDriveResource {
+ private OneDriveSubscriptions(OneDriveAPI api) {
+ super(api);
+ }
+
+ public Metadata getMetadata(OneDriveExpand... expands) throws IOException {
+ QueryStringBuilder query = new QueryStringBuilder().set("expand", expands);
+ final URL url = getMetadataUrl().build(getApi().getBaseURL(), query, getItemIdentifier());
+ OneDriveJsonRequest request = new OneDriveJsonRequest(url, "POST");
+ OneDriveJsonResponse response = request.sendRequest(getApi().getExecutor());
+ JsonObject jsonObject = response.getContent();
+ response.close();
+ return new OneDriveSubscriptions.Metadata(jsonObject);
+ }
+
+ public URLTemplate getMetadataUrl() {
+ return new URLTemplate(getPath());
+ }
+
+ public String getPath() {
+ return "/subscriptions";
+ }
+
+ @Override
+ public String getFullyQualifiedPath() {
+ return getPath();
+ }
+
+ public class Metadata extends OneDriveResource.Metadata {
+ public String id;
+ public String resource;
+ public String changeType;
+ public String clientState;
+ public String notificationUrl;
+ public String expirationDateTime;
+ public String applicationId;
+ public String creatorId;
+
+ public Metadata(final JsonObject json) {
+ super(json);
+ }
+
+ @Override
+ public OneDriveResource getResource() {
+ return OneDriveSubscriptions.this;
+ }
+
+ @Override
+ protected void parseMember(JsonObject.Member member) {
+ super.parseMember(member);
+ try {
+ JsonValue value = member.getValue();
+ String memberName = member.getName();
+ if ("id".equals(memberName)) {
+ id = value.asString();
+ } else if ("resource".equals(memberName)) {
+ resource = value.asString();
+ } else if ("changeType".equals(memberName)) {
+ changeType = value.asString();
+ } else if ("clientState".equals(memberName)) {
+ clientState = value.asString();
+ } else if ("notificationUrl".equals(memberName)) {
+ notificationUrl = value.asString();
+ } else if ("expirationDateTime".equals(memberName)) {
+ expirationDateTime = value.asString();
+ } else if ("applicationId".equals(memberName)) {
+ applicationId = value.asString();
+ } else if ("creatorId".equals(memberName)) {
+ creatorId = value.asString();
+ }
+ } catch (ParseException e) {
+ throw new OneDriveRuntimeException(new OneDriveAPIException(e.getMessage(), e));
+ }
+ }
+
+ public String getResource_() {
+ return resource;
+ }
+
+ public String getChangeType() {
+ return changeType;
+ }
+
+ public String getClientState() {
+ return clientState;
+ }
+
+ public String getNotificationUrl() {
+ return notificationUrl;
+ }
+
+ public String getExpirationDateTime() {
+ return expirationDateTime;
+ }
+
+ public String getApplicationId() {
+ return applicationId;
+ }
+
+ public String getCreatorId() {
+ return creatorId;
+ }
+
+ @Override
+ public String getId() {
+ return id;
+ }
+ }
+}
diff --git a/vavi-nio-file-onedrive3/src/main/java/org/nuxeo/onedrive/client/OneDriveSubscriptionsIterator.java b/vavi-nio-file-onedrive3/src/main/java/org/nuxeo/onedrive/client/OneDriveSubscriptionsIterator.java
new file mode 100644
index 00000000..ae75c8b7
--- /dev/null
+++ b/vavi-nio-file-onedrive3/src/main/java/org/nuxeo/onedrive/client/OneDriveSubscriptionsIterator.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package org.nuxeo.onedrive.client;
+
+import java.net.URL;
+import java.util.Iterator;
+import java.util.Objects;
+
+import com.eclipsesource.json.JsonObject;
+
+
+/**
+ * OneDriveSubscriptionsIterator.
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/07/05 umjammer initial version
+ */
+public class OneDriveSubscriptionsIterator implements Iterator {
+
+ private final OneDriveAPI api;
+
+ private final JsonObjectIterator jsonObjectIterator;
+
+ public OneDriveSubscriptionsIterator(OneDriveAPI api, URL url) {
+ this.api = Objects.requireNonNull(api);
+ this.jsonObjectIterator = new JsonObjectIterator(api, url) {
+
+ @Override
+ protected void onResponse(JsonObject response) {
+ OneDriveSubscriptionsIterator.this.onResponse(response);
+ }
+
+ };
+ }
+
+ @Override
+ public boolean hasNext() throws OneDriveRuntimeException {
+ return jsonObjectIterator.hasNext();
+ }
+
+ @Override
+ public OneDriveSubscriptions.Metadata next() throws OneDriveRuntimeException {
+ return null; //OneDriveSubscriptions.parseJson(api, jsonObjectIterator.next());
+ }
+
+ /**
+ * @since 1.1
+ */
+ protected void onResponse(JsonObject response) {
+ // Hook method
+ }
+
+}
diff --git a/vavi-nio-file-onedrive3/src/main/java/org/nuxeo/onedrive/client/OneDriveSubscriptionsOperation.java b/vavi-nio-file-onedrive3/src/main/java/org/nuxeo/onedrive/client/OneDriveSubscriptionsOperation.java
new file mode 100644
index 00000000..720d2879
--- /dev/null
+++ b/vavi-nio-file-onedrive3/src/main/java/org/nuxeo/onedrive/client/OneDriveSubscriptionsOperation.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package org.nuxeo.onedrive.client;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.TimeZone;
+
+import com.eclipsesource.json.JsonObject;
+
+
+/**
+ * OneDriveSubscriptionsOperation.
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/07/05 umjammer initial version
+ */
+public class OneDriveSubscriptionsOperation {
+ private final JsonObject jsonObject = new JsonObject();
+
+ public void subscribe(String notificationUrl, String clientState) {
+ jsonObject.add("changeType", "updated");
+ jsonObject.add("notificationUrl", notificationUrl);
+ jsonObject.add("resource", "me/drive/root");
+ jsonObject.add("expirationDateTime", getExpireTime());
+ jsonObject.add("clientState", clientState);
+ }
+
+ JsonObject build() {
+ return jsonObject;
+ }
+
+ static String getExpireTime() {
+ long time = System.currentTimeMillis() + 3 * 24 * 60 * 60 * 1000;
+ DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
+ df.setTimeZone(TimeZone.getTimeZone("GMT"));
+ return df.format(new Date(time));
+ }
+}
diff --git a/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveBasicFileAttributesProvider.java b/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveBasicFileAttributesProvider.java
index 9d2927af..c59c2292 100644
--- a/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveBasicFileAttributesProvider.java
+++ b/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveBasicFileAttributesProvider.java
@@ -20,7 +20,7 @@
import javax.annotation.Nonnull;
-import org.nuxeo.onedrive.client.OneDriveItem;
+import org.nuxeo.onedrive.client.types.DriveItem;
import com.github.fge.filesystem.attributes.provider.BasicFileAttributesProvider;
@@ -37,9 +37,9 @@
*/
public final class OneDriveBasicFileAttributesProvider extends BasicFileAttributesProvider implements PosixFileAttributes {
- private final OneDriveItem.Metadata entry;
+ private final DriveItem.Metadata entry;
- public OneDriveBasicFileAttributesProvider(@Nonnull final OneDriveItem.Metadata entry) throws IOException {
+ public OneDriveBasicFileAttributesProvider(@Nonnull final DriveItem.Metadata entry) throws IOException {
this.entry = Objects.requireNonNull(entry);
}
diff --git a/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveFileAttributesFactory.java b/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveFileAttributesFactory.java
index b4e20c62..64d5a2a0 100644
--- a/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveFileAttributesFactory.java
+++ b/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveFileAttributesFactory.java
@@ -6,9 +6,9 @@
package vavi.nio.file.onedrive3;
-import org.nuxeo.onedrive.client.OneDriveItem;
+import org.nuxeo.onedrive.client.types.DriveItem;
-import com.github.fge.filesystem.attributes.FileAttributesFactory;
+import com.github.fge.filesystem.driver.ExtendedFileSystemDriverBase.ExtendsdFileAttributesFactory;
/**
@@ -17,10 +17,10 @@
* @author Naohide Sano (umjammer)
* @version 0.00 2016/03/11 umjammer initial version
*/
-public final class OneDriveFileAttributesFactory extends FileAttributesFactory {
+public final class OneDriveFileAttributesFactory extends ExtendsdFileAttributesFactory {
public OneDriveFileAttributesFactory() {
- setMetadataClass(OneDriveItem.Metadata.class);
+ setMetadataClass(DriveItem.Metadata.class);
addImplementation("basic", OneDriveBasicFileAttributesProvider.class);
}
}
diff --git a/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveFileStore.java b/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveFileStore.java
index 5197f394..012808d8 100644
--- a/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveFileStore.java
+++ b/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveFileStore.java
@@ -9,8 +9,9 @@
import java.io.IOException;
import java.nio.file.FileStore;
-import org.nuxeo.onedrive.client.OneDriveDrive;
-import org.nuxeo.onedrive.client.OneDriveDrive.Metadata;
+import org.nuxeo.onedrive.client.types.Drive;
+import org.nuxeo.onedrive.client.types.Quota;
+import org.nuxeo.onedrive.client.types.Drive.Metadata;
import com.github.fge.filesystem.attributes.FileAttributesFactory;
import com.github.fge.filesystem.filestore.FileStoreBase;
@@ -26,14 +27,14 @@
*/
public final class OneDriveFileStore extends FileStoreBase {
- private final OneDriveDrive drive;
+ private final Drive.Metadata drive;
/**
* Constructor
*
* @param drive the (valid) OneDrive client to use
*/
- public OneDriveFileStore(final OneDriveDrive drive, final FileAttributesFactory factory) {
+ public OneDriveFileStore(final Drive.Metadata drive, final FileAttributesFactory factory) {
super("onedrive", factory, false);
this.drive = drive;
}
@@ -47,7 +48,7 @@ public OneDriveFileStore(final OneDriveDrive drive, final FileAttributesFactory
*/
@Override
public long getTotalSpace() throws IOException {
- final Metadata quota = getMetadata();
+ final Quota quota = getQuota();
return quota == null ? 0 : quota.getTotal();
}
@@ -69,7 +70,7 @@ public long getTotalSpace() throws IOException {
*/
@Override
public long getUsableSpace() throws IOException {
- final Metadata quota = getMetadata();
+ final Quota quota = getQuota();
if (quota == null) {
return 0;
} else {
@@ -93,7 +94,7 @@ public long getUsableSpace() throws IOException {
*/
@Override
public long getUnallocatedSpace() throws IOException {
- final Metadata quota = getMetadata();
+ final Quota quota = getQuota();
if (quota == null) {
return 0;
} else {
@@ -102,14 +103,14 @@ public long getUnallocatedSpace() throws IOException {
}
/** */
- private Metadata cache; // TODO refresh
+ private Quota cache; // TODO refresh
/** */
- private Metadata getMetadata() throws IOException {
+ private Quota getQuota() throws IOException {
if (cache != null) {
return cache;
} else {
- cache = drive.getMetadata();
+ cache = drive.getQuota();
return cache;
}
}
diff --git a/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveFileSystemDriver.java b/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveFileSystemDriver.java
index 2879db56..57a0b83f 100644
--- a/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveFileSystemDriver.java
+++ b/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveFileSystemDriver.java
@@ -12,54 +12,46 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
-import java.nio.file.AccessDeniedException;
-import java.nio.file.AccessMode;
import java.nio.file.CopyOption;
-import java.nio.file.DirectoryNotEmptyException;
-import java.nio.file.DirectoryStream;
-import java.nio.file.FileAlreadyExistsException;
import java.nio.file.FileStore;
-import java.nio.file.Files;
-import java.nio.file.NoSuchFileException;
-import java.nio.file.NotDirectoryException;
import java.nio.file.OpenOption;
import java.nio.file.Path;
-import java.nio.file.StandardCopyOption;
-import java.nio.file.attribute.FileAttribute;
-import java.nio.file.spi.FileSystemProvider;
+import java.nio.file.WatchEvent.Kind;
+import java.nio.file.WatchService;
import java.time.Instant;
import java.time.ZoneOffset;
-import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.Optional;
+import java.util.NoSuchElementException;
import java.util.Set;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
+import org.nuxeo.onedrive.client.CopyOperation;
+import org.nuxeo.onedrive.client.Files;
import org.nuxeo.onedrive.client.OneDriveAPI;
-import org.nuxeo.onedrive.client.OneDriveCopyOperation;
-import org.nuxeo.onedrive.client.OneDriveDrive;
-import org.nuxeo.onedrive.client.OneDriveFile;
-import org.nuxeo.onedrive.client.OneDriveFolder;
-import org.nuxeo.onedrive.client.OneDriveItem;
-import org.nuxeo.onedrive.client.OneDriveItem.ItemIdentifierType;
import org.nuxeo.onedrive.client.OneDriveLongRunningAction;
-import org.nuxeo.onedrive.client.OneDrivePatchOperation;
-import org.nuxeo.onedrive.client.OneDriveUploadSession;
-import org.nuxeo.onedrive.client.facets.FileSystemInfoFacet;
+import org.nuxeo.onedrive.client.PatchOperation;
+import org.nuxeo.onedrive.client.UploadSession;
+import org.nuxeo.onedrive.client.types.Drive;
+import org.nuxeo.onedrive.client.types.DriveItem;
+import org.nuxeo.onedrive.client.types.FileSystemInfo;
-import com.github.fge.filesystem.driver.ExtendedFileSystemDriverBase;
-import com.github.fge.filesystem.exceptions.IsDirectoryException;
+import com.github.fge.filesystem.driver.CachedFileSystemDriver;
import com.github.fge.filesystem.provider.FileSystemFactoryProvider;
-import vavi.nio.file.Cache;
import vavi.nio.file.Util;
import vavi.util.Debug;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
import static vavi.nio.file.Util.toFilenameString;
+import static vavi.nio.file.onedrive3.OneDriveFileSystemProvider.ENV_USE_SYSTEM_WATCHER;
/**
@@ -69,95 +61,101 @@
* @version 0.00 2016/03/11 umjammer initial version
*/
@ParametersAreNonnullByDefault
-public final class OneDriveFileSystemDriver extends ExtendedFileSystemDriverBase {
+public final class OneDriveFileSystemDriver extends CachedFileSystemDriver {
private final OneDriveAPI client;
- private final OneDriveDrive drive;
- private boolean ignoreAppleDouble = false;
+ private final Drive.Metadata drive;
+
+ private Runnable closer;
+ private OneDriveWatchService systemWatcher;
@SuppressWarnings("unchecked")
public OneDriveFileSystemDriver(final FileStore fileStore,
final FileSystemFactoryProvider provider,
final OneDriveAPI client,
- final OneDriveDrive drive,
- final Map env) {
+ Runnable closer,
+ final Drive.Metadata drive,
+ final Map env) throws IOException {
super(fileStore, provider);
this.client = client;
- ignoreAppleDouble = (Boolean) ((Map) env).getOrDefault("ignoreAppleDouble", Boolean.FALSE);
-//System.err.println("ignoreAppleDouble: " + ignoreAppleDouble);
+ this.closer = closer;
+ setEnv(env);
this.drive = drive;
- }
+ boolean useSystemWatcher = (Boolean) ((Map) env).getOrDefault(ENV_USE_SYSTEM_WATCHER, false);
- /** */
- private Cache cache = new Cache() {
- /**
- * @see #ignoreAppleDouble
- * @throws NoSuchFileException must be thrown when the path is not found in this cache
- */
- public OneDriveItem.Metadata getEntry(Path path) throws IOException {
- if (cache.containsFile(path)) {
- return cache.getFile(path);
- } else {
- if (ignoreAppleDouble && path.getFileName() != null && Util.isAppleDouble(path)) {
- throw new NoSuchFileException("ignore apple double file: " + path);
- }
+ if (useSystemWatcher) {
+ systemWatcher = new OneDriveWatchService(client);
+ systemWatcher.setNotificationListener(this::processNotification);
+ }
+ }
-// String pathString = toPathString(path);
-//Debug.println("path: " + pathString);
- OneDriveItem.Metadata entry;
- if (path.getNameCount() == 0) {
- entry = drive.getRoot().getMetadata();
- cache.putFile(path, entry);
- return entry;
- } else {
- List siblings = getDirectoryEntries(path.getParent(), false);
- Optional found = siblings.stream().filter(p -> path.getFileName().equals(p.getFileName())).findFirst();
- if (found.isPresent()) {
- return cache.getEntry(found.get());
- } else {
- throw new NoSuchFileException(path.toString());
- }
+ /** for system watcher */
+ private void processNotification(String id, Kind> kind) {
+ if (ENTRY_DELETE == kind) {
+ try {
+ Path path = cache.getEntry(e -> id.equals(e.getId()));
+ cache.removeEntry(path);
+ } catch (NoSuchElementException e) {
+Debug.println("NOTIFICATION: already deleted: " + id);
+ }
+ } else {
+ try {
+ try {
+ Path path = cache.getEntry(e -> id.equals(e.getId()));
+Debug.println("NOTIFICATION: maybe updated: " + path);
+ cache.removeEntry(path);
+ cache.getEntry(path);
+ } catch (NoSuchElementException e) {
+// TODO impl
+// OneDriveItem.Metadata entry = drive.getApi().getMetadata(id);
+// Path parent = cache.getEntry(f -> entry.getParentReference().getId().equals(f.getId()));
+// Path path = parent.resolve(entry.getName());
+//Debug.println("NOTIFICATION: maybe created: " + path);
+// cache.addEntry(path, entry);
}
+ } catch (NoSuchElementException e) {
+Debug.println("NOTIFICATION: parent not found: " + e);
+ } catch (IOException e) {
+ e.printStackTrace();
}
}
- };
+ }
- @Nonnull
- @Override
- public InputStream newInputStream(final Path path, final Set extends OpenOption> options) throws IOException {
- final OneDriveItem.Metadata entry = cache.getEntry(path);
+ /** */
+ private static DriveItem asDriveItem(DriveItem.Metadata entry) {
+ return DriveItem.class.cast(entry.getItem());
+ }
- if (entry.isFolder()) {
- throw new IsDirectoryException("path: " + path);
- }
+ @Override
+ protected String getFilenameString(DriveItem.Metadata entry) {
+ return entry.getName();
+ }
- return new BufferedInputStream(OneDriveFile.class.cast(entry.getResource()).download(), Util.BUFFER_SIZE);
+ @Override
+ protected boolean isFolder(DriveItem.Metadata entry) {
+ return entry.isFolder();
}
- @Nonnull
@Override
- public OutputStream newOutputStream(final Path path, final Set extends OpenOption> options) throws IOException {
- OneDriveItem.Metadata entry = null;
- try {
- entry = cache.getEntry(path);
+ protected DriveItem.Metadata getRootEntry(Path root) throws IOException {
+ return new Drive(client, drive.getId()).getRoot().getMetadata();
+ }
- if (entry.isFolder()) {
- throw new IsDirectoryException("path: " + path);
- } else {
- throw new FileAlreadyExistsException("path: " + path);
- }
- } catch (NoSuchFileException e) {
-Debug.println("newOutputStream: " + e.getMessage());
- }
+ @Override
+ protected InputStream downloadEntry(DriveItem.Metadata entry, Path path, Set extends OpenOption> options) throws IOException {
+ return new BufferedInputStream(Files.download(asDriveItem(entry)), Util.BUFFER_SIZE);
+ }
+ @Override
+ protected OutputStream uploadEntry(DriveItem.Metadata parentEntry, Path path, Set extends OpenOption> options) throws IOException {
OneDriveUploadOption uploadOption = Util.getOneOfOptions(OneDriveUploadOption.class, options);
if (uploadOption != null) {
// java.nio.file is highly abstracted, so here source information is lost.
// but onedrive graph api requires content length for upload.
- // so reluctantly we provide {@link OneDriveUploadOpenOption} for {@link java.nio.file.Files#copy} options.
+ // so reluctantly we provide {@link OneDriveUploadOption} for {@link java.nio.file.Files#copy} options.
Path source = uploadOption.getSource();
Debug.println("upload w/ option: " + source);
- return uploadEntry(path, (int) Files.size(source));
+ return uploadEntry(parentEntry, path, (int) java.nio.file.Files.size(source));
} else {
Debug.println("upload w/o option");
return new Util.OutputStreamForUploading() { // TODO used for only getting file length
@@ -165,7 +163,7 @@ public OutputStream newOutputStream(final Path path, final Set extends OpenOpt
protected void onClosed() throws IOException {
InputStream is = getInputStream();
Debug.println("upload w/o option: " + is.available());
- OutputStream os = uploadEntry(path, is.available());
+ OutputStream os = uploadEntry(parentEntry, path, is.available());
Util.transfer(is, os);
is.close();
os.close();
@@ -175,258 +173,108 @@ protected void onClosed() throws IOException {
}
/** */
- private OutputStream uploadEntry(Path path, int size) throws IOException {
- OneDriveFolder folder = OneDriveFolder.class.cast(cache.getEntry(path.getParent()).getResource());
- OneDriveFile file = new OneDriveFile(client, folder, toItemPathString(toFilenameString(path)), ItemIdentifierType.Path);
- final OneDriveUploadSession uploadSession = file.createUploadSession();
+ private OutputStream uploadEntry(DriveItem.Metadata parentEntry, Path path, int size) throws IOException {
+ DriveItem file = new DriveItem(asDriveItem(parentEntry), toItemPathString(toFilenameString(path)));
+ final UploadSession uploadSession = Files.createUploadSession(file);
return new BufferedOutputStream(new OneDriveOutputStream(uploadSession, path, size, newEntry -> {
- cache.addEntry(path, newEntry);
+ updateEntry(path, newEntry);
}), Util.BUFFER_SIZE);
}
- /** */
+ /** ms-graph doesn't accept '+' in a path string */
private String toItemPathString(String pathString) throws IOException {
return URLEncoder.encode(pathString, "utf-8").replace("+", "%20");
}
- @Nonnull
@Override
- public DirectoryStream newDirectoryStream(final Path dir,
- final DirectoryStream.Filter super Path> filter) throws IOException {
- return Util.newDirectoryStream(getDirectoryEntries(dir, true), filter);
+ protected List getDirectoryEntries(DriveItem.Metadata dirEntry, Path dir) throws IOException {
+ Iterator iterator = Files.getFiles(asDriveItem(dirEntry));
+ Spliterator spliterator = Spliterators.spliteratorUnknownSize(iterator, 0);
+ return StreamSupport.stream(spliterator, false).collect(Collectors.toList());
}
-
@Override
- public void createDirectory(final Path dir, final FileAttribute>... attrs) throws IOException {
- OneDriveItem.Metadata parentEntry = cache.getEntry(dir.getParent());
-
+ protected DriveItem.Metadata createDirectoryEntry(DriveItem.Metadata parentEntry, Path dir) throws IOException {
// TODO: how to diagnose?
- OneDriveFolder.Metadata dirEntry = OneDriveFolder.class.cast(parentEntry.getResource()).create(toFilenameString(dir));
+ return Files.createFolder(asDriveItem(parentEntry), toFilenameString(dir));
+ }
- cache.addEntry(dir, dirEntry);
+ @Override
+ protected boolean hasChildren(DriveItem.Metadata dirEntry, Path dir) throws IOException {
+ return getDirectoryEntries(dir, false).size() > 0;
}
@Override
- public void delete(final Path path) throws IOException {
- removeEntry(path);
+ protected void removeEntry(DriveItem.Metadata entry, Path path) throws IOException {
+ // TODO: unknown what happens when a move operation is performed
+ // and the target already exists
+ Files.delete(asDriveItem(entry));
}
@Override
- public void copy(final Path source, final Path target, final Set options) throws IOException {
- if (cache.existsEntry(target)) {
- if (options != null && options.stream().anyMatch(o -> o.equals(StandardCopyOption.REPLACE_EXISTING))) {
- removeEntry(target);
- } else {
- throw new FileAlreadyExistsException(target.toString());
- }
- }
- copyEntry(source, target);
+ protected DriveItem.Metadata copyEntry(DriveItem.Metadata sourceEntry, DriveItem.Metadata targetParentEntry, Path source, Path target, Set options) throws IOException {
+ CopyOperation operation = new CopyOperation();
+ operation.rename(toFilenameString(target));
+Debug.println("target: " + targetParentEntry.getName());
+ operation.copy(asDriveItem(targetParentEntry));
+ OneDriveLongRunningAction action = Files.copy(asDriveItem(sourceEntry), operation);
+ action.await(statusObject -> {
+Debug.printf("Copy Progress Operation %s progress %.0f %%, status %s",
+statusObject.getOperation(),
+statusObject.getPercentage(),
+statusObject.getStatus());
+ });
+ return getEntry(null, target);
}
@Override
- public void move(final Path source, final Path target, final Set options) throws IOException {
- if (cache.existsEntry(target)) {
- if (cache.getEntry(target).isFolder()) {
- if (options != null && options.stream().anyMatch(o -> o.equals(StandardCopyOption.REPLACE_EXISTING))) {
- // replace the target
- if (cache.getChildCount(target) > 0) {
- throw new DirectoryNotEmptyException(target.toString());
- } else {
- removeEntry(target);
- moveEntry(source, target, false);
- }
- } else {
- // move into the target
- // TODO SPEC is FileAlreadyExistsException ?
- moveEntry(source, target, true);
- }
- } else {
- if (options != null && options.stream().anyMatch(o -> o.equals(StandardCopyOption.REPLACE_EXISTING))) {
- removeEntry(target);
- moveEntry(source, target, false);
- } else {
- throw new FileAlreadyExistsException(target.toString());
- }
- }
+ protected DriveItem.Metadata moveEntry(DriveItem.Metadata sourceEntry, DriveItem.Metadata targetParentEntry, Path source, Path target, boolean targetIsParent) throws IOException {
+ PatchOperation operation = new PatchOperation();
+ operation.rename(targetIsParent ? toFilenameString(source) : toFilenameString(target));
+ operation.move(asDriveItem(targetParentEntry));
+ final FileSystemInfo info = new FileSystemInfo();
+ info.setLastModifiedDateTime(Instant.ofEpochMilli(sourceEntry.getLastModifiedDateTime().toEpochSecond()).atOffset(ZoneOffset.UTC));
+ operation.facet("fileSystemInfo", info);
+ Files.patch(asDriveItem(sourceEntry), operation);
+ if (targetIsParent) {
+ return getEntry(null, target.resolve(source.getFileName()));
} else {
- if (source.getParent().equals(target.getParent())) {
- // rename
- renameEntry(source, target);
- } else {
- moveEntry(source, target, false);
- }
+ return getEntry(null, target);
}
}
- /**
- * Check access modes for a path on this filesystem
- *
- * If no modes are provided to check for, this simply checks for the
- * existence of the path.
- *
- *
- * @param path the path to check
- * @param modes the modes to check for, if any
- * @throws IOException filesystem level error, or a plain I/O error
- * if you use this with javafs (jnr-fuse), you should throw {@link NoSuchFileException} when the file not found.
- * @see FileSystemProvider#checkAccess(Path, AccessMode...)
- */
@Override
- protected void checkAccessImpl(final Path path, final AccessMode... modes) throws IOException {
- final OneDriveItem.Metadata entry = cache.getEntry(path);
-
- if (!entry.isFile()) {
- return;
- }
+ protected DriveItem.Metadata moveFolderEntry(DriveItem.Metadata sourceEntry, DriveItem.Metadata targetParentEntry, Path source, Path target, boolean targetIsParent) throws IOException {
+ PatchOperation operation = new PatchOperation();
+ operation.rename(toFilenameString(target));
+ operation.move(asDriveItem(targetParentEntry));
+ final FileSystemInfo info = new FileSystemInfo();
+ info.setLastModifiedDateTime(Instant.ofEpochMilli(sourceEntry.getLastModifiedDateTime().toEpochSecond()).atOffset(ZoneOffset.UTC));
+ operation.facet("fileSystemInfo", info);
+ Files.patch(asDriveItem(sourceEntry), operation);
+ return getEntry(null, target);
+ }
- // TODO: assumed; not a file == directory
- for (final AccessMode mode : modes) {
- if (mode == AccessMode.EXECUTE) {
- throw new AccessDeniedException(path.toString());
- }
- }
+ @Override
+ protected DriveItem.Metadata renameEntry(DriveItem.Metadata sourceEntry, DriveItem.Metadata targetParentEntry, Path source, Path target) throws IOException {
+ PatchOperation operation = new PatchOperation();
+ operation.rename(toFilenameString(target));
+ Files.patch(asDriveItem(sourceEntry), operation);
+ return getEntry(null, target);
}
@Override
public void close() throws IOException {
- // TODO: what to do here? OneDriveClient does not implement Closeable :(
+ closer.run();
}
- /**
- * @throws IOException if you use this with javafs (jnr-fuse), you should throw {@link NoSuchFileException} when the file not found.
- */
@Nonnull
@Override
- protected Object getPathMetadataImpl(final Path path) throws IOException {
- return cache.getEntry(path);
- }
-
- /** */
- private List getDirectoryEntries(Path dir, boolean useCache) throws IOException {
- final OneDriveItem.Metadata entry = cache.getEntry(dir);
-
- if (!entry.isFolder()) {
- throw new NotDirectoryException(dir.toString());
- }
-
- List list = null;
- if (useCache && cache.containsFolder(dir)) {
- list = cache.getFolder(dir);
- } else {
- list = new ArrayList<>();
-
- for (final OneDriveItem.Metadata child : OneDriveFolder.class.cast(entry.getResource()).getChildren()) {
- Path childPath = dir.resolve(child.getName());
- list.add(childPath);
-//System.err.println("child: " + childPath.toRealPath().toString());
-
- cache.putFile(childPath, child);
- }
-
- cache.putFolder(dir, list);
- }
-
- return list;
- }
-
- /** for created entry */
- private OneDriveItem.Metadata getEntry(Path path) throws IOException {
- final OneDriveItem.Metadata parentEntry = cache.getEntry(path.getParent());
-
- Optional found = StreamSupport.stream(OneDriveFolder.class.cast(parentEntry.getResource()).getChildren().spliterator(), false)
- .filter(child -> {
- try {
-System.err.println(child.getName() + ", " + toFilenameString(path));
- return child.getName().equals(toFilenameString(path));
- } catch (IOException e) {
- throw new IllegalStateException(e);
- }
- }).findFirst();
- if (found.isPresent()) {
- return found.get();
- } else {
- throw new NoSuchFileException(path.toString());
- }
- }
-
- /** */
- private void removeEntry(Path path) throws IOException {
- OneDriveItem.Metadata entry = cache.getEntry(path);
- if (entry.isFolder()) {
- if (getDirectoryEntries(path, false).size() > 0) {
- throw new DirectoryNotEmptyException(path.toString());
- }
- }
-
- // TODO: unknown what happens when a move operation is performed
- // and the target already exists
- entry.getResource().delete();
-
- cache.removeEntry(path);
- }
-
- /** */
- private void copyEntry(final Path source, final Path target) throws IOException {
- OneDriveItem.Metadata sourceEntry = cache.getEntry(source);
- OneDriveItem.Metadata targetParentEntry = cache.getEntry(target.getParent());
- if (sourceEntry.isFile()) {
- OneDriveCopyOperation operation = new OneDriveCopyOperation();
- operation.rename(toFilenameString(target));
- operation.copy(OneDriveFolder.class.cast(targetParentEntry.getResource()));
- OneDriveLongRunningAction action = sourceEntry.getResource().copy(operation);
- action.await(statusObject -> {
-Debug.printf("Copy Progress Operation %s progress %.0f %%, status %s",
- statusObject.getOperation(),
- statusObject.getPercentage(),
- statusObject.getStatus());
- });
- cache.addEntry(target, getEntry(target));
- } else if (sourceEntry.isFolder()) {
- throw new IsDirectoryException("source can not be a folder: " + source);
- }
- }
-
- /**
- * @param targetIsParent if the target is folder
- */
- private void moveEntry(final Path source, final Path target, boolean targetIsParent) throws IOException {
- OneDriveItem.Metadata sourceEntry = cache.getEntry(source);
- OneDriveItem.Metadata targetParentEntry = cache.getEntry(targetIsParent ? target : target.getParent());
- if (sourceEntry.isFile()) {
- OneDrivePatchOperation operation = new OneDrivePatchOperation();
- operation.rename(targetIsParent ? toFilenameString(source) : toFilenameString(target));
- operation.move(OneDriveFolder.class.cast(targetParentEntry.getResource()));
- final FileSystemInfoFacet info = new FileSystemInfoFacet();
- info.setLastModifiedDateTime(Instant.ofEpochMilli(sourceEntry.getLastModifiedDateTime().toEpochSecond()).atOffset(ZoneOffset.UTC));
- operation.facet("fileSystemInfo", info);
- sourceEntry.getResource().patch(operation);
- cache.removeEntry(source);
- if (targetIsParent) {
- cache.addEntry(target.resolve(source.getFileName()), getEntry(target.resolve(source.getFileName())));
- } else {
- cache.addEntry(target, getEntry(target));
- }
- } else if (sourceEntry.isFolder()) {
- OneDrivePatchOperation operation = new OneDrivePatchOperation();
- operation.rename(toFilenameString(target));
- operation.move(OneDriveFolder.class.cast(targetParentEntry.getResource()));
- final FileSystemInfoFacet info = new FileSystemInfoFacet();
- info.setLastModifiedDateTime(Instant.ofEpochMilli(sourceEntry.getLastModifiedDateTime().toEpochSecond()).atOffset(ZoneOffset.UTC));
- operation.facet("fileSystemInfo", info);
- sourceEntry.getResource().patch(operation);
- cache.moveEntry(source, target, getEntry(target));
+ public WatchService newWatchService() {
+ try {
+ return new OneDriveWatchService(client);
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
}
}
-
- /** */
- private void renameEntry(final Path source, final Path target) throws IOException {
- OneDriveItem.Metadata sourceEntry = cache.getEntry(source);
-
- OneDrivePatchOperation operation = new OneDrivePatchOperation();
- operation.rename(toFilenameString(target));
- sourceEntry.getResource().patch(operation);
- cache.removeEntry(source);
- cache.addEntry(target, getEntry(target));
- }
}
diff --git a/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveFileSystemProvider.java b/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveFileSystemProvider.java
index 3e4974d9..6850b7a4 100644
--- a/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveFileSystemProvider.java
+++ b/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveFileSystemProvider.java
@@ -26,6 +26,8 @@ public final class OneDriveFileSystemProvider extends FileSystemProviderBase {
public static final String ENV_APP_CREDENTIAL = "app_credential";
+ public static final String ENV_USE_SYSTEM_WATCHER = "use_system_watcher";
+
public OneDriveFileSystemProvider() {
super(new OneDriveFileSystemRepository());
}
diff --git a/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveFileSystemRepository.java b/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveFileSystemRepository.java
index 5a753be1..10ad7cc1 100644
--- a/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveFileSystemRepository.java
+++ b/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveFileSystemRepository.java
@@ -16,12 +16,13 @@
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
+import org.nuxeo.onedrive.client.Drives;
import org.nuxeo.onedrive.client.JavaNetRequestExecutor;
import org.nuxeo.onedrive.client.OneDriveAPI;
import org.nuxeo.onedrive.client.OneDriveBasicAPI;
-import org.nuxeo.onedrive.client.OneDriveDrive;
import org.nuxeo.onedrive.client.RequestExecutor;
import org.nuxeo.onedrive.client.RequestHeader;
+import org.nuxeo.onedrive.client.types.Drive;
import com.github.fge.filesystem.driver.FileSystemDriver;
import com.github.fge.filesystem.provider.FileSystemRepositoryBase;
@@ -44,7 +45,7 @@ public final class OneDriveFileSystemRepository extends FileSystemRepositoryBase
/** */
public OneDriveFileSystemRepository() {
- super("onedrive", new OneDriveFileSystemFactoryProvider());
+ super("onedrive3", new OneDriveFileSystemFactoryProvider());
}
/**
@@ -84,7 +85,8 @@ public FileSystemDriver createDriver(final URI uri, final Map env) th
}
// 3. process
- String accessToken = new MicrosoftGraphOAuth2(appCredential, true).authorize(userCredential);
+ MicrosoftGraphOAuth2 oAuth2 = new MicrosoftGraphOAuth2(appCredential, true);
+ String accessToken = oAuth2.authorize(userCredential);
//Debug.println("accessToken: " + accessToken);
RequestExecutor executor = new JavaNetRequestExecutor(accessToken) {
@@ -130,8 +132,8 @@ public String getEmailURL() {
}
};
- OneDriveDrive drive = OneDriveDrive.getDefaultDrive(client);
+ Drive.Metadata drive = Drives.getDrives(client).next();
final OneDriveFileStore fileStore = new OneDriveFileStore(drive, factoryProvider.getAttributesFactory());
- return new OneDriveFileSystemDriver(fileStore, factoryProvider, client, drive, env);
+ return new OneDriveFileSystemDriver(fileStore, factoryProvider, client, () -> oAuth2.close(), drive, env);
}
}
diff --git a/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveOutputStream.java b/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveOutputStream.java
index 279a9ba0..283d134c 100644
--- a/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveOutputStream.java
+++ b/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveOutputStream.java
@@ -14,9 +14,9 @@
import java.util.function.Consumer;
import java.util.logging.Level;
-import org.nuxeo.onedrive.client.OneDriveFile;
import org.nuxeo.onedrive.client.OneDriveJsonObject;
-import org.nuxeo.onedrive.client.OneDriveUploadSession;
+import org.nuxeo.onedrive.client.UploadSession;
+import org.nuxeo.onedrive.client.types.DriveItem;
import vavi.util.Debug;
@@ -47,15 +47,15 @@
*/
public final class OneDriveOutputStream extends OutputStream {
- private final OneDriveUploadSession upload;
+ private final UploadSession upload;
private final Path file;
private final AtomicBoolean close = new AtomicBoolean();
private long offset = 0L;
private int length;
- private OneDriveFile.Metadata entry;
- private Consumer consumer;
+ private DriveItem.Metadata entry;
+ private Consumer consumer;
- public OneDriveOutputStream(final OneDriveUploadSession upload, final Path file, int length, Consumer consumer) {
+ public OneDriveOutputStream(final UploadSession upload, final Path file, int length, Consumer consumer) {
this.upload = upload;
this.file = file;
this.length = length;
@@ -79,8 +79,8 @@ public void write(final byte[] b, final int off, final int len) throws IOExcepti
}
Debug.printf("header %s", header);
OneDriveJsonObject object = upload.uploadFragment(header, content);
- if (OneDriveFile.Metadata.class.isInstance(object)) {
- entry = OneDriveFile.Metadata.class.cast(object);
+ if (DriveItem.Metadata.class.isInstance(object)) {
+ entry = DriveItem.Metadata.class.cast(object);
Debug.printf("Completed upload for %s", file);
} else {
Debug.printf(Level.FINE, "Uploaded fragment %s for file %s", header, file);
diff --git a/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveUploadOption.java b/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveUploadOption.java
index 38f17dae..ce3ab8f9 100644
--- a/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveUploadOption.java
+++ b/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveUploadOption.java
@@ -15,6 +15,10 @@
* OneDriveUploadOption.
*
* for large file.
+ *
+ * in {@link com.github.fge.filesystem.options.FileSystemOptionsFactory},
+ * instances of this class are compared by contains method. so i override
+ * {@link #equals(Object)} and {@link #hashCode()}.
*
* TODO CopyOption doesn't work.
*
@@ -23,6 +27,9 @@
*/
public class OneDriveUploadOption implements OpenOption, CopyOption {
+ /** */
+ private static final long serialVersionUID = 5575546140441990410L;
+
/** */
private Path source;
@@ -43,7 +50,7 @@ public boolean equals(Object other) {
@Override
public int hashCode() {
- return Long.hashCode(5575546140441990410L); // TODO ad-hoc
+ return Long.hashCode(serialVersionUID); // TODO ad-hoc
}
}
diff --git a/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveWatchService.java b/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveWatchService.java
new file mode 100644
index 00000000..499ed531
--- /dev/null
+++ b/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/OneDriveWatchService.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.onedrive3;
+
+import java.io.IOException;
+
+import org.nuxeo.onedrive.client.OneDriveAPI;
+
+import vavi.nio.file.watch.webhook.WebHookBaseWatchService;
+import vavi.util.Debug;
+
+
+/**
+ * OneDriveWatchService.
+ *
+ * system properties
+ *
+ * vavi.nio.file.watch.webhook.NotificationProvider.onedrive3
+ *
+ *
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/07/23 umjammer initial version
+ */
+public class OneDriveWatchService extends WebHookBaseWatchService {
+
+ private static final String WEBHOOK_NOTIFICATION_PROVIDER =
+ System.getProperty("vavi.nio.file.watch.webhook.NotificationProvider.onedrive3", ".onedrive3.webhook.websocket");
+
+// private OneDriveAPI client;
+
+// private String savedStartPageToken;
+
+ /** */
+ public OneDriveWatchService(OneDriveAPI client) throws IOException {
+// this.client = client;
+
+ setupNotification(this, WEBHOOK_NOTIFICATION_PROVIDER);
+ }
+
+ @Override
+ protected void onNotifyMessage(String notification) throws IOException {
+Debug.println(">> notification: done");
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (isOpen()) {
+ super.close();
+ }
+ }
+}
diff --git a/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/webhook/websocket/MicrosoftWebSocketNotification.java b/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/webhook/websocket/MicrosoftWebSocketNotification.java
new file mode 100644
index 00000000..f4c09b11
--- /dev/null
+++ b/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/webhook/websocket/MicrosoftWebSocketNotification.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.onedrive3.webhook.websocket;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.function.Consumer;
+
+import javax.websocket.ClientEndpoint;
+import javax.websocket.Session;
+
+import vavi.nio.file.watch.webhook.websocket.BasicAuthorizationConfigurator;
+import vavi.nio.file.watch.webhook.websocket.StringWebSocketNotification;
+
+
+/**
+ * MicrosoftWebSocketNotification.
+ *
+ * environment variables
+ *
+ * VAVI_APPS_WEBHOOK_WEBSOCKET_BASE_URL
+ * VAVI_APPS_WEBHOOK_WEBSOCKET_MICROSOFT_PATH
+ *
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/07/23 umjammer initial version
+ */
+@ClientEndpoint(configurator = BasicAuthorizationConfigurator.class)
+public class MicrosoftWebSocketNotification extends StringWebSocketNotification {
+
+ private static final String websocketBaseUrl = System.getenv("VAVI_APPS_WEBHOOK_WEBSOCKET_BASE_URL");
+ private static final String websocketPath = System.getenv("VAVI_APPS_WEBHOOK_WEBSOCKET_MICROSOFT_PATH");
+
+ private static final URI uri = URI.create(websocketBaseUrl + websocketPath);
+
+ private Consumer callback;
+
+ /**
+ * @param args
+ */
+ public MicrosoftWebSocketNotification(Consumer callback, Object... args) throws IOException {
+ super(uri, args);
+ this.callback = callback;
+ }
+
+ @Override
+ public void onOpenImpl(Session session) throws IOException {
+ }
+
+ @Override
+ protected void onNotifyMessageImpl(String notification) throws IOException {
+ callback.accept(notification);
+ }
+
+ @Override
+ protected void onCloseImpl(Session session) throws IOException {
+ }
+}
+
+/* */
diff --git a/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/webhook/websocket/MicrosoftWebSocketNotificationProvider.java b/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/webhook/websocket/MicrosoftWebSocketNotificationProvider.java
new file mode 100644
index 00000000..799e3e11
--- /dev/null
+++ b/vavi-nio-file-onedrive3/src/main/java/vavi/nio/file/onedrive3/webhook/websocket/MicrosoftWebSocketNotificationProvider.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.onedrive3.webhook.websocket;
+
+import java.io.IOException;
+import java.util.function.Consumer;
+
+import vavi.nio.file.watch.webhook.Notification;
+import vavi.nio.file.watch.webhook.NotificationProvider;
+
+
+/**
+ * MicrosoftWebSocketNotificationProvider.
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/07/23 umjammer initial version
+ */
+public class MicrosoftWebSocketNotificationProvider implements NotificationProvider {
+
+ @Override
+ public Notification getNotification(Consumer callback, Object... args) throws IOException {
+ return Notification.class.cast(new MicrosoftWebSocketNotification(Consumer.class.cast(callback), args));
+ }
+}
+
+/* */
diff --git a/vavi-nio-file-onedrive3/src/main/resources/META-INF/services/java.nio.file.spi.FileSystemProvider b/vavi-nio-file-onedrive3/src/main/resources/META-INF/services/java.nio.file.spi.FileSystemProvider
index a3dc7617..7b51461b 100644
--- a/vavi-nio-file-onedrive3/src/main/resources/META-INF/services/java.nio.file.spi.FileSystemProvider
+++ b/vavi-nio-file-onedrive3/src/main/resources/META-INF/services/java.nio.file.spi.FileSystemProvider
@@ -1 +1 @@
-#vavi.nio.file.onedrive3.OneDriveFileSystemProvider
+vavi.nio.file.onedrive3.OneDriveFileSystemProvider
diff --git a/vavi-nio-file-onedrive3/src/main/resources/META-INF/services/vavi.nio.file.watch.webhook.NotificationProvider b/vavi-nio-file-onedrive3/src/main/resources/META-INF/services/vavi.nio.file.watch.webhook.NotificationProvider
new file mode 100644
index 00000000..58c62b5f
--- /dev/null
+++ b/vavi-nio-file-onedrive3/src/main/resources/META-INF/services/vavi.nio.file.watch.webhook.NotificationProvider
@@ -0,0 +1 @@
+vavi.nio.file.onedrive3.webhook.websocket.MicrosoftWebSocketNotificationProvider
diff --git a/vavi-nio-file-onedrive3/src/test/java/vavi/nio/file/onedrive3/Main.java b/vavi-nio-file-onedrive3/src/test/java/vavi/nio/file/onedrive3/Main.java
index 668261e8..8a394290 100644
--- a/vavi-nio-file-onedrive3/src/test/java/vavi/nio/file/onedrive3/Main.java
+++ b/vavi-nio-file-onedrive3/src/test/java/vavi/nio/file/onedrive3/Main.java
@@ -24,10 +24,10 @@ public class Main {
@Test
void test01() throws Exception {
- String email = System.getenv("MICROSOFT3_TEST_ACCOUNT");
+ String email = System.getenv("MICROSOFT_TEST_ACCOUNT");
- URI uri = URI.create("onedrive:///?id=" + email);
+ URI uri = URI.create("onedrive3:///?id=" + email);
- testAll(new OneDriveFileSystemProvider().newFileSystem(uri, Collections.EMPTY_MAP));
+ testAll(new OneDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap()));
}
}
\ No newline at end of file
diff --git a/vavi-nio-file-onedrive3/src/test/java/vavi/nio/file/onedrive3/Main2.java b/vavi-nio-file-onedrive3/src/test/java/vavi/nio/file/onedrive3/Main2.java
index 692f5f56..7161c1a0 100644
--- a/vavi-nio-file-onedrive3/src/test/java/vavi/nio/file/onedrive3/Main2.java
+++ b/vavi-nio-file-onedrive3/src/test/java/vavi/nio/file/onedrive3/Main2.java
@@ -25,10 +25,10 @@ public class Main2 {
@Test
void test01() throws Exception {
- String email = System.getenv("MICROSOFT3_TEST_ACCOUNT");
+ String email = System.getenv("MICROSOFT_TEST_ACCOUNT");
- URI uri = URI.create("onedrive:///?id=" + email);
- FileSystem fs = new OneDriveFileSystemProvider().newFileSystem(uri, Collections.EMPTY_MAP);
+ URI uri = URI.create("onedrive3:///?id=" + email);
+ FileSystem fs = new OneDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap());
testLargeFile(fs, OneDriveUploadOption.class);
}
diff --git a/vavi-nio-file-onedrive3/src/test/java/vavi/nio/file/onedrive3/Main3.java b/vavi-nio-file-onedrive3/src/test/java/vavi/nio/file/onedrive3/Main3.java
index 114ef7d0..029eb3a0 100644
--- a/vavi-nio-file-onedrive3/src/test/java/vavi/nio/file/onedrive3/Main3.java
+++ b/vavi-nio-file-onedrive3/src/test/java/vavi/nio/file/onedrive3/Main3.java
@@ -25,10 +25,10 @@ public class Main3 {
@Test
void test01() throws Exception {
- String email = System.getenv("MICROSOFT3_TEST_ACCOUNT");
+ String email = System.getenv("MICROSOFT_TEST_ACCOUNT");
- URI uri = URI.create("onedrive:///?id=" + email);
- FileSystem fs = new OneDriveFileSystemProvider().newFileSystem(uri, Collections.EMPTY_MAP);
+ URI uri = URI.create("onedrive3:///?id=" + email);
+ FileSystem fs = new OneDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap());
testMoveFolder(fs);
}
diff --git a/vavi-nio-file-onedrive3/src/test/java/vavi/nio/file/onedrive3/Main4.java b/vavi-nio-file-onedrive3/src/test/java/vavi/nio/file/onedrive3/Main4.java
index b71cb5ea..f8d3f6ea 100644
--- a/vavi-nio-file-onedrive3/src/test/java/vavi/nio/file/onedrive3/Main4.java
+++ b/vavi-nio-file-onedrive3/src/test/java/vavi/nio/file/onedrive3/Main4.java
@@ -77,7 +77,7 @@ public void test01(String providerClassName) throws Exception {
public static void main(final String... args) throws IOException {
String email = args[1];
- URI uri = URI.create("onedrive:///?id=" + email);
+ URI uri = URI.create("onedrive3:///?id=" + email);
OAuth2AppCredential appCredential = new MicrosoftGraphLocalAppCredential();
diff --git a/vavi-nio-file-onedrive3/src/test/java/vavi/nio/file/onedrive3/Main5.java b/vavi-nio-file-onedrive3/src/test/java/vavi/nio/file/onedrive3/Main5.java
index a642233c..f044884d 100644
--- a/vavi-nio-file-onedrive3/src/test/java/vavi/nio/file/onedrive3/Main5.java
+++ b/vavi-nio-file-onedrive3/src/test/java/vavi/nio/file/onedrive3/Main5.java
@@ -35,13 +35,13 @@ public class Main5 {
void test01() throws Exception {
String email = System.getenv("TEST5_ACCOUNT");
- URI uri = URI.create("onedrive:///?id=" + email);
+ URI uri = URI.create("onedrive3:///?id=" + email);
Path src;
Path dstDir;
Path dst;
String a, b;
- try (FileSystem onedrivefs = new OneDriveFileSystemProvider().newFileSystem(uri, Collections.EMPTY_MAP)) {
+ try (FileSystem onedrivefs = new OneDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap())) {
src = Paths.get("src/test/resources/Hello.java");
dstDir = onedrivefs.getPath("/").resolve("TEST_FUSE_5");
@@ -60,7 +60,7 @@ void test01() throws Exception {
a = Util.toFilenameString(Files.list(dstDir).findFirst().get());
}
- try (FileSystem onedrivefs = new OneDriveFileSystemProvider().newFileSystem(uri, Collections.EMPTY_MAP)) {
+ try (FileSystem onedrivefs = new OneDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap())) {
dstDir = onedrivefs.getPath("/").resolve("TEST_FUSE_5");
dst = dstDir.resolve("ããšã 001");
diff --git a/vavi-nio-file-onedrive3/src/test/java/vavi/nio/file/onedrive3/WebHookApiTest.java b/vavi-nio-file-onedrive3/src/test/java/vavi/nio/file/onedrive3/WebHookApiTest.java
new file mode 100644
index 00000000..90ae7e71
--- /dev/null
+++ b/vavi-nio-file-onedrive3/src/test/java/vavi/nio/file/onedrive3/WebHookApiTest.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.onedrive3;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URL;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.nuxeo.onedrive.client.Drives;
+import org.nuxeo.onedrive.client.Files;
+import org.nuxeo.onedrive.client.JavaNetRequestExecutor;
+import org.nuxeo.onedrive.client.OneDriveAPI;
+import org.nuxeo.onedrive.client.OneDriveBasicAPI;
+import org.nuxeo.onedrive.client.types.Drive;
+import org.nuxeo.onedrive.client.types.DriveItem;
+import org.nuxeo.onedrive.client.RequestExecutor;
+import org.nuxeo.onedrive.client.RequestHeader;
+
+import vavi.net.auth.oauth2.microsoft.MicrosoftGraphLocalAppCredential;
+import vavi.net.auth.oauth2.microsoft.MicrosoftGraphOAuth2;
+import vavi.net.auth.web.microsoft.MicrosoftLocalUserCredential;
+
+
+/**
+ * WebHookApiTest.
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/07/03 umjammer initial version
+ * @see "https://docs.microsoft.com/graph/api/subscription-post-subscriptions?view=graph-rest-1.0&tabs=http"
+ */
+public class WebHookApiTest {
+
+ static final String VAVI_APPS_WEBHOOK_SECRET = System.getenv("VAVI_APPS_WEBHOOK_SECRET");
+ static String websocketBaseUrl = System.getenv("VAVI_APPS_WEBHOOK_WEBSOCKET_BASE_URL");
+ static String websocketPath = System.getenv("VAVI_APPS_WEBHOOK_WEBSOCKET_MICROSOFT_PATH");
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args) throws Exception {
+ String email = System.getenv("MICROSOFT3_TEST_ACCOUNT");
+
+ MicrosoftLocalUserCredential userCredential = new MicrosoftLocalUserCredential(email);
+ MicrosoftGraphLocalAppCredential appCredential = new MicrosoftGraphLocalAppCredential();
+
+ @SuppressWarnings("resource")
+ String accessToken = new MicrosoftGraphOAuth2(appCredential, true).authorize(userCredential);
+//Debug.println("accessToken: " + accessToken);
+
+ RequestExecutor executor = new JavaNetRequestExecutor(accessToken) {
+ @Override
+ public void addAuthorizationHeader(final Set headers) {
+ super.addAuthorizationHeader(headers);
+ // HttpURLConnection adds "accept" header which is unavailable to onedrive.
+ headers.add(new RequestHeader("Accept", "application/json"));
+ }
+
+ @Override
+ public Upload doPatch(URL url, Set headers) throws IOException {
+ headers.add(new RequestHeader("X-HTTP-Method-Override", "PATCH"));
+ headers.add(new RequestHeader("X-HTTP-Method", "PATCH"));
+ return super.doPost(url, headers);
+ }
+ };
+
+ OneDriveAPI client = new OneDriveBasicAPI(executor) {
+ @Override
+ public RequestExecutor getExecutor() {
+ return executor;
+ }
+
+ @Override
+ public boolean isBusinessConnection() {
+ return false;
+ }
+
+ @Override
+ public boolean isGraphConnection() {
+ return true;
+ }
+
+ @Override
+ public String getBaseURL() {
+ return String.format("https://graph.microsoft.com%s", "/v1.0");
+ }
+
+ @Override
+ public String getEmailURL() {
+ return String.format("https://graph.microsoft.com%s", "/v1.0/me");
+ }
+ };
+
+ Drive.Metadata drive = Drives.getDrives(client).next();
+
+ // create
+ URI uri = URI.create(websocketBaseUrl + websocketPath);
+ // Listen for file upload events in the specified folder
+ DriveItem rootFolder = new Drive(client, drive.getId()).getRoot();
+ Iterator i = Files.getFiles(rootFolder);
+ while (i.hasNext()) {
+ DriveItem.Metadata child = i.next();
+ if (child.getName().equals("TEST_WEBHOOK")) {
+System.out.println("rmdir " + child.getName());
+ Files.delete(DriveItem.class.cast(child.getItem()));
+ }
+ }
+System.out.println("mkdir " + "TEST_WEBHOOK");
+ DriveItem.Metadata newFolder = Files.createFolder(rootFolder, "TEST_WEBHOOK");
+
+System.out.println("[create] webhook");
+// Subscription preSubscription = new Subscription();
+//// preSubscription.changeType = "created,updated,deleted"; // root is only supported update
+// preSubscription.changeType = "created,updated,deleted";
+// preSubscription.notificationUrl = uri.toString();
+// preSubscription.resource = "me/drive/root";
+// preSubscription.expirationDateTime = calendar;
+// preSubscription.clientState = VAVI_APPS_WEBHOOK_SECRET;
+// Subscription subscription = graphClient.subscriptions().buildRequest().post(preSubscription);
+//Debug.println(subscription.id);
+
+System.out.println("[ls] webhook");
+// for (Subscription s : subscPages.getCurrentPage()) {
+//System.out.println(s);
+// }
+
+System.out.println("mkdir " + "TEST_WEBHOOK/" + "NEW FOLDER");
+ DriveItem.Metadata subFolder = Files.createFolder(DriveItem.class.cast(newFolder), "NEW FOLDER");
+
+ // update
+System.out.println("[update] webhook");
+// subscription.expirationDateTime = calendar;
+// subscription = drive.subscriptions(subscription.id).buildRequest().patch(subscription);
+
+ // delete
+System.out.println("[delete] webhook");
+// drive.subscriptions(subscription.id).buildRequest().delete();
+
+System.out.println("rmdir " + subFolder.getName());
+ Files.delete(DriveItem.class.cast(subFolder));
+System.out.println("rmdir " + newFolder.getName());
+ Files.delete(DriveItem.class.cast(newFolder));
+ }
+}
+
+/* */
diff --git a/vavi-nio-file-onedrive4/pom.xml b/vavi-nio-file-onedrive4/pom.xml
index 90bdcbbe..1673ddcf 100644
--- a/vavi-nio-file-onedrive4/pom.xml
+++ b/vavi-nio-file-onedrive4/pom.xml
@@ -5,7 +5,7 @@
vavi
vavi-apps-fuse
- 0.1.6
+ 0.1.7
vavi-nio-file-onedrive4
@@ -32,7 +32,7 @@
- com.github.umjammer.vavi-net-auth
+ ${vavi-net-auth.groupId}
vavi-net-auth-microsoft
${vavi-net-auth.version}
@@ -41,7 +41,18 @@
com.microsoft.graph
microsoft-graph
- 1.4.0
+ 2.0.0
+
+
+ com.google.guava
+ guava
+
+
+
+
+
+ vavi
+ vavi-nio-file-commons
@@ -67,7 +78,6 @@
org.junit.jupiter
junit-jupiter-params
- 5.3.0
test
diff --git a/vavi-nio-file-onedrive4/readme.md b/vavi-nio-file-onedrive4/readme.md
new file mode 100644
index 00000000..90184d0c
--- /dev/null
+++ b/vavi-nio-file-onedrive4/readme.md
@@ -0,0 +1,38 @@
+# vavi-nio-file-onedirve4
+
+nio filsystem provider for onedrive
+
+## feature
+
+ * based on the official sdk
+ * implements upload w/ monitor that *official sdk doesn't support*
+ * OnedriveUploadOption for large file uploading
+ * description as "user:attribute"
+ * thumbnail as "user:attribute" (works but where can we see those?)
+
+## issue
+
+official graph sdk version currently (2022-03-02) is upper 5.15.0.
+but i don't use those new versions for this project.
+because after `com.microsoft.graph:microsoft-graph:2.0.2`,
+the sdk deprecated `com.microsoft.graph.http.IConnection`
+and start using `okhttp3.Response` instead of it.
+this is not oop. (beginner should not use generics and method reference)
+`IConnection` is designed for library independency.
+why the official sdk doesn't implement okhttp3 library as `IConnection`?
+for performance reason? i don't think so. because
+network transportation is very slower than wrapping object.
+
+i tried to adapt v5.x.x to this project. see branch `graph-sdk-5`.
+but it was abandoned. i don't want to make any more effort to adapt
+this project to the bad api's library.
+(it's so hard to adapt lra monitor to official sdk.)
+
+when the official sdk stops supporting v2,
+it's a time to die this project.
+
+there are two other onedrive providers.
+so it's no problem!
+
+ * [vavi-nio-file-onedrive](../vavi-nio-file-onedrive) (based on [onedrivejavasdk](https://github.com/umjammer/OneDriveJavaSDK))
+ * [vavi-nio-file-onedrive3](../vavi-nio-file-onedrive3) (based on [onedrive-java-client](https://github.com/iterate-ch/onedrive-java-client))
\ No newline at end of file
diff --git a/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/OneDriveBasicFileAttributesProvider.java b/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/OneDriveBasicFileAttributesProvider.java
index 5f57d5b1..54a7c8fc 100644
--- a/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/OneDriveBasicFileAttributesProvider.java
+++ b/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/OneDriveBasicFileAttributesProvider.java
@@ -22,6 +22,8 @@
import com.github.fge.filesystem.attributes.provider.BasicFileAttributesProvider;
import com.microsoft.graph.models.extensions.DriveItem;
+import vavi.nio.file.onedrive4.OneDriveFileAttributesFactory.Metadata;
+
/**
* {@link BasicFileAttributes} implementation for OneDrive
@@ -37,8 +39,8 @@ public final class OneDriveBasicFileAttributesProvider extends BasicFileAttribut
private final DriveItem entry;
- public OneDriveBasicFileAttributesProvider(@Nonnull final DriveItem entry) throws IOException {
- this.entry = Objects.requireNonNull(entry);
+ public OneDriveBasicFileAttributesProvider(@Nonnull final Metadata entry) throws IOException {
+ this.entry = Objects.requireNonNull(entry).driveItem;
}
/**
@@ -54,7 +56,7 @@ public OneDriveBasicFileAttributesProvider(@Nonnull final DriveItem entry) throw
*/
@Override
public FileTime lastModifiedTime() {
- return FileTime.fromMillis(entry.lastModifiedDateTime.getTimeInMillis());
+ return FileTime.fromMillis(entry.lastModifiedDateTime.toInstant().toEpochMilli());
}
/**
diff --git a/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/OneDriveFileAttributesFactory.java b/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/OneDriveFileAttributesFactory.java
index 4cc2e6cd..be76167e 100644
--- a/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/OneDriveFileAttributesFactory.java
+++ b/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/OneDriveFileAttributesFactory.java
@@ -6,7 +6,7 @@
package vavi.nio.file.onedrive4;
-import com.github.fge.filesystem.attributes.FileAttributesFactory;
+import com.github.fge.filesystem.driver.ExtendedFileSystemDriverBase.ExtendsdFileAttributesFactory;
import com.microsoft.graph.models.extensions.DriveItem;
@@ -16,10 +16,20 @@
* @author Naohide Sano (umjammer)
* @version 0.00 2016/03/11 umjammer initial version
*/
-public final class OneDriveFileAttributesFactory extends FileAttributesFactory {
+public final class OneDriveFileAttributesFactory extends ExtendsdFileAttributesFactory {
+
+ static class Metadata {
+ OneDriveFileSystemDriver driver;
+ DriveItem driveItem;
+ Metadata(OneDriveFileSystemDriver driver, DriveItem driveItem) {
+ this.driver = driver;
+ this.driveItem = driveItem;
+ }
+ }
public OneDriveFileAttributesFactory() {
- setMetadataClass(DriveItem.class);
+ setMetadataClass(Metadata.class);
addImplementation("basic", OneDriveBasicFileAttributesProvider.class);
+ addImplementation("user", OneDriveUserDefinedFileAttributesProvider.class);
}
}
diff --git a/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/OneDriveFileSystemDriver.java b/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/OneDriveFileSystemDriver.java
index 11910f8d..5748db4e 100644
--- a/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/OneDriveFileSystemDriver.java
+++ b/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/OneDriveFileSystemDriver.java
@@ -11,31 +11,22 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
-import java.nio.file.AccessDeniedException;
-import java.nio.file.AccessMode;
import java.nio.file.CopyOption;
-import java.nio.file.DirectoryNotEmptyException;
-import java.nio.file.DirectoryStream;
-import java.nio.file.FileAlreadyExistsException;
import java.nio.file.FileStore;
import java.nio.file.Files;
-import java.nio.file.NoSuchFileException;
-import java.nio.file.NotDirectoryException;
import java.nio.file.OpenOption;
import java.nio.file.Path;
-import java.nio.file.StandardCopyOption;
-import java.nio.file.attribute.FileAttribute;
-import java.nio.file.spi.FileSystemProvider;
+import java.nio.file.WatchEvent.Kind;
+import java.nio.file.WatchService;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Map;
+import java.util.NoSuchElementException;
import java.util.Set;
+import java.util.logging.Level;
-import javax.annotation.Nonnull;
-import javax.annotation.ParametersAreNonnullByDefault;
-
-import com.github.fge.filesystem.driver.ExtendedFileSystemDriverBase;
-import com.github.fge.filesystem.exceptions.IsDirectoryException;
+import com.github.fge.filesystem.driver.CachedFileSystemDriver;
import com.github.fge.filesystem.provider.FileSystemFactoryProvider;
import com.google.common.io.ByteStreams;
import com.microsoft.graph.concurrency.ChunkedUploadProvider;
@@ -52,20 +43,26 @@
import com.microsoft.graph.models.extensions.Folder;
import com.microsoft.graph.models.extensions.IGraphServiceClient;
import com.microsoft.graph.models.extensions.ItemReference;
+import com.microsoft.graph.models.extensions.ThumbnailSet;
import com.microsoft.graph.models.extensions.UploadSession;
+import com.microsoft.graph.options.QueryOption;
import com.microsoft.graph.requests.extensions.IDriveItemCollectionPage;
import com.microsoft.graph.requests.extensions.IDriveItemCopyRequest;
+import com.microsoft.graph.requests.extensions.IThumbnailSetCollectionPage;
-import vavi.nio.file.Cache;
import vavi.nio.file.Util;
+import vavi.nio.file.onedrive4.OneDriveFileAttributesFactory.Metadata;
import vavi.nio.file.onedrive4.graph.LraMonitorProvider;
import vavi.nio.file.onedrive4.graph.LraMonitorResponseHandler;
import vavi.nio.file.onedrive4.graph.LraMonitorResult;
import vavi.nio.file.onedrive4.graph.LraSession;
+import vavi.nio.file.onedrive4.graph.ThumbnailUploadProvider;
import vavi.util.Debug;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
import static vavi.nio.file.Util.toFilenameString;
import static vavi.nio.file.Util.toPathString;
+import static vavi.nio.file.onedrive4.OneDriveFileSystemProvider.ENV_USE_SYSTEM_WATCHER;
/**
@@ -74,82 +71,92 @@
* @author Naohide Sano (umjammer)
* @version 0.00 2016/03/11 umjammer initial version
*/
-@ParametersAreNonnullByDefault
-public final class OneDriveFileSystemDriver extends ExtendedFileSystemDriverBase {
+public final class OneDriveFileSystemDriver extends CachedFileSystemDriver {
private final IGraphServiceClient client;
- private boolean ignoreAppleDouble = false;
+
+ private Runnable closer;
+ private OneDriveWatchService systemWatcher;
@SuppressWarnings("unchecked")
- public OneDriveFileSystemDriver(final FileStore fileStore,
- final FileSystemFactoryProvider provider,
- final IGraphServiceClient client,
- final Map env) {
+ public OneDriveFileSystemDriver(FileStore fileStore,
+ FileSystemFactoryProvider provider,
+ IGraphServiceClient client,
+ Runnable closer,
+ Map env) throws IOException {
super(fileStore, provider);
this.client = client;
- ignoreAppleDouble = (Boolean) ((Map) env).getOrDefault("ignoreAppleDouble", Boolean.FALSE);
-//System.err.println("ignoreAppleDouble: " + ignoreAppleDouble);
- }
-
- /** ugly */
- private boolean isFile(DriveItem entry) {
- return entry.file != null;
- }
+ this.closer = closer;
+ setEnv(env);
+ boolean useSystemWatcher = (Boolean) ((Map) env).getOrDefault(ENV_USE_SYSTEM_WATCHER, false);
- /** ugly */
- private boolean isFolder(DriveItem entry) {
- return entry.folder != null;
+ if (useSystemWatcher) {
+ systemWatcher = new OneDriveWatchService(client);
+ systemWatcher.setNotificationListener(this::processNotification);
+ }
}
- /** */
- private Cache cache = new Cache() {
- /**
- * TODO when the parent is not cached
- * @see #ignoreAppleDouble
- * @throws NoSuchFileException must be thrown when the path is not found in this cache
- */
- public DriveItem getEntry(Path path) throws IOException {
- if (cache.containsFile(path)) {
- return cache.getFile(path);
- } else {
- if (ignoreAppleDouble && path.getFileName() != null && Util.isAppleDouble(path)) {
- throw new NoSuchFileException("ignore apple double file: " + path);
- }
-
- String pathString = toPathString(path);
-//Debug.println("path: " + pathString);
+ /** for system watcher */
+ private void processNotification(String id, Kind> kind) {
+ if (ENTRY_DELETE == kind) {
+ try {
+ Path path = cache.getEntry(e -> id.equals(e.id));
+ cache.removeEntry(path);
+ } catch (NoSuchElementException e) {
+Debug.println("NOTIFICATION: already deleted: " + id);
+ }
+ } else {
+ try {
try {
- DriveItem entry;
- if (pathString.equals("/")) {
- entry = client.drive().root().buildRequest().get();
- } else {
- entry = client.drive().root().itemWithPath(toItemPathString(pathString.substring(1))).buildRequest().get();
- }
- cache.putFile(path, entry);
- return entry;
- } catch (GraphServiceException e) {
- if (e.getMessage().startsWith("Error code: itemNotFound")) {
- if (cache.containsFile(path)) {
- cache.removeEntry(path);
- }
- throw new NoSuchFileException(pathString);
- } else {
- throw e;
- }
+ Path path = cache.getEntry(e -> id.equals(e.id));
+Debug.println("NOTIFICATION: maybe updated: " + path);
+ cache.removeEntry(path);
+ cache.getEntry(path);
+ } catch (NoSuchElementException e) {
+ DriveItem entry = client.drive().items(id).buildRequest().get();
+ Path parent = cache.getEntry(f -> entry.parentReference.id.equals(f.id));
+ Path path = parent.resolve(entry.name);
+Debug.println("NOTIFICATION: maybe created: " + path);
+ cache.addEntry(path, entry);
}
+ } catch (NoSuchElementException e) {
+Debug.println("NOTIFICATION: parent not found: " + e);
+ } catch (IOException e) {
+ e.printStackTrace();
}
}
- };
+ }
+
+ @Override
+ protected boolean isFolder(DriveItem entry) {
+ return entry.folder != null;
+ }
- @Nonnull
@Override
- public InputStream newInputStream(final Path path, final Set extends OpenOption> options) throws IOException {
- final DriveItem entry = cache.getEntry(path);
+ protected String getFilenameString(DriveItem entry) {
+ return entry.name;
+ }
- if (isFolder(entry)) {
- throw new IsDirectoryException(path.toString());
+ @Override
+ protected DriveItem getRootEntry(Path root) throws IOException {
+ return client.drive().root().buildRequest().get();
+ }
+
+ @Override
+ protected DriveItem getEntry(DriveItem parentEntry, Path path)throws IOException {
+ try {
+ return client.drive().root().itemWithPath(toItemPathString(toPathString(path))).buildRequest().get();
+ } catch (GraphServiceException e) {
+ if (e.getMessage().startsWith("Error code: itemNotFound")) {
+ return null;
+ } else {
+ throw new IOException(e);
+ }
}
+ }
+ @Override
+ protected InputStream downloadEntry(DriveItem entry, Path path, Set extends OpenOption> options) throws IOException {
try {
return client.drive().items(entry.id).content().buildRequest().get();
} catch (ClientException e) {
@@ -157,26 +164,13 @@ public InputStream newInputStream(final Path path, final Set extends OpenOptio
}
}
- @Nonnull
@Override
- public OutputStream newOutputStream(final Path path, final Set extends OpenOption> options) throws IOException {
- try {
- DriveItem entry = cache.getEntry(path);
-
- if (isFolder(entry)) {
- throw new IsDirectoryException(path.toString());
- } else {
- throw new FileAlreadyExistsException(path.toString());
- }
- } catch (NoSuchFileException e) {
-Debug.println("newOutputStream: " + e.getMessage());
- }
-
+ protected OutputStream uploadEntry(DriveItem parentEntry, Path path, Set extends OpenOption> options) throws IOException {
OneDriveUploadOption uploadOption = Util.getOneOfOptions(OneDriveUploadOption.class, options);
if (uploadOption != null) {
// java.nio.file is highly abstracted, so here source information is lost.
// but onedrive graph api requires content length for upload.
- // so reluctantly we provide {@link OneDriveUploadOpenOption} for {@link java.nio.file.Files#copy} options.
+ // so reluctantly we provide {@link OneDriveUploadOption} for {@link java.nio.file.Files#copy} options.
Path source = uploadOption.getSource();
Debug.println("upload w/ option: " + source);
@@ -209,7 +203,7 @@ public void progress(final long current, final long max) {
}
@Override
public void success(final DriveItem result) {
- cache.addEntry(path, result);
+ updateEntry(path, result);
Debug.println("upload done: " + result.name);
}
@Override
@@ -223,7 +217,7 @@ public void failure(final ClientException ex) {
protected void onClosed() throws IOException {
InputStream is = getInputStream();
DriveItem newEntry = client.drive().root().itemWithPath(toItemPathString(toPathString(path))).content().buildRequest().put(ByteStreams.toByteArray(is)); // TODO depends on guava
- cache.addEntry(path, newEntry);
+ updateEntry(path, newEntry);
}
};
}
@@ -242,7 +236,7 @@ public void progress(final long current, final long max) {
}
@Override
public void success(final DriveItem result) {
- cache.addEntry(path, result);
+ updateEntry(path, result);
Debug.println("upload done: " + result.name);
}
@Override
@@ -252,253 +246,165 @@ public void failure(final ClientException ex) {
});
} else {
DriveItem newEntry = client.drive().root().itemWithPath(toItemPathString(toPathString(path))).content().buildRequest().put(ByteStreams.toByteArray(is)); // TODO depends on guava
- cache.addEntry(path, newEntry);
+ updateEntry(path, newEntry);
}
}
- /** */
+ /** ms-graph doesn't accept '+' in a path string */
private String toItemPathString(String pathString) throws IOException {
- return URLEncoder.encode(pathString, "utf-8").replace("+", "%20");
+ return URLEncoder.encode(pathString.replaceFirst("^\\/", ""), "utf-8").replace("+", "%20");
}
- @Nonnull
@Override
- public DirectoryStream newDirectoryStream(final Path dir,
- final DirectoryStream.Filter super Path> filter) throws IOException {
- return Util.newDirectoryStream(getDirectoryEntries(dir, true), filter);
+ protected List getDirectoryEntries(DriveItem dirEntry, Path dir) throws IOException {
+ List list = new ArrayList<>(dirEntry.folder.childCount);
+
+ IDriveItemCollectionPage pages = client.drive().items(dirEntry.id).children().buildRequest().get();
+ while (pages != null) {
+ for (final DriveItem child : pages.getCurrentPage()) {
+ list.add(child);
+//System.err.println("child: " + childPath.toRealPath().toString());
+ }
+ pages = pages.getNextPage() != null ? pages.getNextPage().buildRequest().get() : null;
+ }
+
+ return list;
}
@Override
- public void createDirectory(final Path dir, final FileAttribute>... attrs) throws IOException {
- DriveItem parentEntry = cache.getEntry(dir.getParent());
-
- // TODO: how to diagnose?
+ protected DriveItem createDirectoryEntry(DriveItem parentEntry, Path dir) throws IOException {
DriveItem preEntry = new DriveItem();
preEntry.name = toFilenameString(dir);
preEntry.folder = new Folder();
DriveItem newEntry = client.drive().items(parentEntry.id).children().buildRequest().post(preEntry);
Debug.println(newEntry.id + ", " + newEntry.name + ", folder: " + isFolder(newEntry) + ", " + newEntry.hashCode());
- cache.addEntry(dir, newEntry);
+ return newEntry;
}
@Override
- public void delete(final Path path) throws IOException {
- removeEntry(path);
+ protected boolean hasChildren(DriveItem dirEntry, Path path) throws IOException {
+ IDriveItemCollectionPage pages = client.drive().items(dirEntry.id).children().buildRequest().get();
+ return pages.getCurrentPage().size() > 0;
}
@Override
- public void copy(final Path source, final Path target, final Set options) throws IOException {
- if (cache.existsEntry(target)) {
- if (options != null && options.stream().anyMatch(o -> o.equals(StandardCopyOption.REPLACE_EXISTING))) {
- removeEntry(target);
- } else {
- throw new FileAlreadyExistsException(target.toString());
- }
- }
- copyEntry(source, target);
+ protected void removeEntry(DriveItem entry, Path path) throws IOException {
+ client.drive().items(entry.id).buildRequest().delete();
}
@Override
- public void move(final Path source, final Path target, final Set options) throws IOException {
- if (cache.existsEntry(target)) {
- if (isFolder(cache.getEntry(target))) {
- if (options != null && options.stream().anyMatch(o -> o.equals(StandardCopyOption.REPLACE_EXISTING))) {
- // replace the target
- if (cache.getChildCount(target) > 0) {
- throw new DirectoryNotEmptyException(target.toString());
- } else {
- removeEntry(target);
- moveEntry(source, target, false);
- }
- } else {
- // move into the target
- // TODO SPEC is FileAlreadyExistsException ?
- moveEntry(source, target, true);
- }
- } else {
- if (options != null && options.stream().anyMatch(o -> o.equals(StandardCopyOption.REPLACE_EXISTING))) {
- removeEntry(target);
- moveEntry(source, target, false);
- } else {
- throw new FileAlreadyExistsException(target.toString());
- }
+ protected DriveItem copyEntry(DriveItem sourceEntry, DriveItem targetParentEntry, Path source, Path target, Set options) throws IOException {
+ ItemReference ir = new ItemReference();
+ ir.id = targetParentEntry.id;
+ IDriveItemCopyRequest request = client.drive().items(sourceEntry.id).copy(toFilenameString(target), ir).buildRequest();
+ BaseRequest.class.cast(request).setHttpMethod(HttpMethod.POST); // #send() hides IDriveItemCopyRequest fields already set above.
+ DriveItemCopyBody body = new DriveItemCopyBody(); // ditto
+ body.name = toFilenameString(target); // ditto
+ body.parentReference = ir; // ditto
+ LraMonitorResponseHandler handler = new LraMonitorResponseHandler<>();
+ @SuppressWarnings({ "unchecked", "rawtypes" }) // TODO
+ LraSession copySession = client.getHttpProvider().send((IHttpRequest) request, LraMonitorResult.class, body, (IStatefulResponseHandler) handler).getSession();
+ LraMonitorProvider copyMonitorProvider = new LraMonitorProvider<>(copySession, client, DriveItem.class);
+ copyMonitorProvider.monitor(new IProgressCallback() {
+ @Override
+ public void progress(final long current, final long max) {
+Debug.println("copy progress: " + current + "/" + max);
}
- } else {
- if (source.getParent().equals(target.getParent())) {
- // rename
- renameEntry(source, target);
- } else {
- moveEntry(source, target, false);
+ @Override
+ public void success(final DriveItem result) {
+Debug.println("copy done: " + result.id);
+ updateEntry(target, result);
}
- }
+ @Override
+ public void failure(final ClientException ex) {
+ throw new IllegalStateException(ex);
+ }
+ });
+ // null means that copy is async, cache by your self
+ // @see IProgressCallback#success()
+ return null;
}
- /**
- * Check access modes for a path on this filesystem
- *
- * If no modes are provided to check for, this simply checks for the
- * existence of the path.
- *
- *
- * @param path the path to check
- * @param modes the modes to check for, if any
- * @throws IOException filesystem level error, or a plain I/O error
- * if you use this with javafs (jnr-fuse), you should throw {@link NoSuchFileException} when the file not found.
- * @see FileSystemProvider#checkAccess(Path, AccessMode...)
- */
@Override
- protected void checkAccessImpl(final Path path, final AccessMode... modes) throws IOException {
- final DriveItem entry = cache.getEntry(path);
-
- if (!isFile(entry)) {
- return;
- }
-
- // TODO: assumed; not a file == directory
- for (final AccessMode mode : modes) {
- if (mode == AccessMode.EXECUTE) {
- throw new AccessDeniedException(path.toString());
- }
- }
+ protected DriveItem moveEntry(DriveItem sourceEntry, DriveItem targetParentEntry, Path source, Path target, boolean targetIsParent) throws IOException {
+ DriveItem preEntry = new DriveItem();
+ preEntry.name = toFilenameString(target);
+ preEntry.parentReference = new ItemReference();
+ preEntry.parentReference.id = targetParentEntry.id;
+ return client.drive().items(sourceEntry.id).buildRequest().patch(preEntry);
}
@Override
- public void close() throws IOException {
- // TODO: what to do here? OneDriveClient does not implement Closeable :(
+ protected DriveItem moveFolderEntry(DriveItem sourceEntry, DriveItem targetParentEntry, Path source, Path target, boolean targetIsParent) throws IOException {
+ DriveItem preEntry = new DriveItem();
+ preEntry.name = toFilenameString(target);
+ preEntry.parentReference = new ItemReference();
+ preEntry.parentReference.id = targetParentEntry.id;
+ return client.drive().items(sourceEntry.id).buildRequest().patch(preEntry);
}
- /**
- * @throws IOException you should throw {@link NoSuchFileException} when the file not found.
- */
- @Nonnull
@Override
- protected Object getPathMetadataImpl(final Path path) throws IOException {
- return cache.getEntry(path);
+ protected DriveItem renameEntry(DriveItem sourceEntry, DriveItem targetParentEntry, Path source, Path target) throws IOException {
+ DriveItem preEntry = new DriveItem();
+ preEntry.name = toFilenameString(target);
+ return client.drive().items(sourceEntry.id).buildRequest().patch(preEntry);
}
- /** */
- private List getDirectoryEntries(Path dir, boolean useCache) throws IOException {
- final DriveItem entry = cache.getEntry(dir);
-
- if (!isFolder(entry)) {
-//System.err.println(entry.name + ", " + entry.id + ", " + entry.hashCode());
- throw new NotDirectoryException(dir.toString());
- }
-
- List list = null;
- if (useCache && cache.containsFolder(dir)) {
- list = cache.getFolder(dir);
- } else {
- list = new ArrayList<>(entry.folder.childCount);
-
- IDriveItemCollectionPage pages = client.drive().items(entry.id).children().buildRequest().get();
- while (pages != null) {
- for (final DriveItem child : pages.getCurrentPage()) {
- Path childPath = dir.resolve(child.name);
- list.add(childPath);
-//System.err.println("child: " + childPath.toRealPath().toString());
-
- cache.putFile(childPath, child);
- }
- pages = pages.getNextPage() != null ? pages.getNextPage().buildRequest().get() : null;
- }
- cache.putFolder(dir, list);
- }
+ @Override
+ protected Object getPathMetadata(DriveItem entry) throws IOException {
+ return new Metadata(this, entry);
+ }
- return list;
+ @Override
+ public void close() throws IOException {
+ closer.run();
}
- /** */
- private void removeEntry(Path path) throws IOException {
- DriveItem entry = cache.getEntry(path);
- if (isFolder(entry)) {
- if (getDirectoryEntries(path, false).size() > 0) {
- throw new DirectoryNotEmptyException(path.toString());
- }
+ @Override
+ public WatchService newWatchService() {
+ try {
+ return new OneDriveWatchService(client);
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
}
+ }
- // TODO: unknown what happens when a move operation is performed
- // and the target already exists
- client.drive().items(entry.id).buildRequest().delete();
+ //
+ // user:attributes
+ //
+ /** attributes user:description */
+ void patchEntryDescription(DriveItem sourceEntry, String description) throws IOException {
+ DriveItem preEntry = new DriveItem();
+ preEntry.description = description;
+ DriveItem newEntry = client.drive().items(sourceEntry.id).buildRequest().patch(preEntry);
+ Path path = cache.getEntry(sourceEntry);
cache.removeEntry(path);
- }
-
- /** */
- private void copyEntry(final Path source, final Path target) throws IOException {
- DriveItem sourceEntry = cache.getEntry(source);
- DriveItem targetParentEntry = cache.getEntry(target.getParent());
- if (isFile(sourceEntry)) {
- ItemReference ir = new ItemReference();
- ir.id = targetParentEntry.id;
- IDriveItemCopyRequest request = client.drive().items(sourceEntry.id).copy(toFilenameString(target), ir).buildRequest();
- BaseRequest.class.cast(request).setHttpMethod(HttpMethod.POST); // #send() hides IDriveItemCopyRequest fields already set above.
- DriveItemCopyBody body = new DriveItemCopyBody(); // ditto
- body.name = toFilenameString(target); // ditto
- body.parentReference = ir; // ditto
- LraMonitorResponseHandler handler = new LraMonitorResponseHandler<>();
- @SuppressWarnings({ "unchecked", "rawtypes" }) // TODO
- LraSession copySession = client.getHttpProvider().send((IHttpRequest) request, LraMonitorResult.class, body, (IStatefulResponseHandler) handler).getSession();
- LraMonitorProvider copyMonitorProvider = new LraMonitorProvider<>(copySession, client, DriveItem.class);
- copyMonitorProvider.monitor(new IProgressCallback() {
- @Override
- public void progress(final long current, final long max) {
-Debug.println("copy progress: " + current + "/" + max);
- }
- @Override
- public void success(final DriveItem result) {
-Debug.println("copy done: " + result.id);
- cache.addEntry(target, result);
- }
- @Override
- public void failure(final ClientException ex) {
- throw new IllegalStateException(ex);
- }
- });
- } else if (isFolder(sourceEntry)) {
- // TODO java spec. allows empty folder
- throw new IsDirectoryException("source can not be a folder: " + source);
- }
+ cache.addEntry(path, newEntry);
}
/**
- * @param targetIsParent if the target is folder
+ * attributes user:thumbnail
+ * @param image currently only jpeg is available.
*/
- private void moveEntry(final Path source, final Path target, boolean targetIsParent) throws IOException {
- DriveItem sourceEntry = cache.getEntry(source);
- DriveItem targetParentEntry = cache.getEntry(targetIsParent ? target : target.getParent());
- if (isFile(sourceEntry)) {
- DriveItem preEntry = new DriveItem();
- preEntry.name = targetIsParent ? toFilenameString(source) : toFilenameString(target);
- preEntry.parentReference = new ItemReference();
- preEntry.parentReference.id = targetParentEntry.id;
- DriveItem patchedEntry = client.drive().items(sourceEntry.id).buildRequest().patch(preEntry);
- cache.removeEntry(source);
- if (targetIsParent) {
- cache.addEntry(target.resolve(source.getFileName()), patchedEntry);
- } else {
- cache.addEntry(target, patchedEntry);
- }
- } else if (isFolder(sourceEntry)) {
- DriveItem preEntry = new DriveItem();
- preEntry.name = toFilenameString(target);
- preEntry.folder = new Folder();
- preEntry.parentReference = new ItemReference();
- preEntry.parentReference.id = targetParentEntry.id;
- DriveItem patchedEntry = client.drive().items(sourceEntry.id).buildRequest().patch(preEntry);
- cache.moveEntry(source, target, patchedEntry);
- }
+ void setThumbnail(DriveItem sourceEntry, byte[] image) throws IOException {
+ ThumbnailUploadProvider provider = new ThumbnailUploadProvider(sourceEntry, client);
+ provider.upload(image);
+Debug.println(Level.INFO, "thumbnail updated: " + sourceEntry.name + ", size: " + image.length);
}
- /** */
- private void renameEntry(final Path source, final Path target) throws IOException {
- DriveItem sourceEntry = cache.getEntry(source);
-//Debug.println(sourceEntry.id + ", " + sourceEntry.name);
-
- DriveItem preEntry = new DriveItem();
- preEntry.name = toFilenameString(target);
- DriveItem patchedEntry = client.drive().items(sourceEntry.id).buildRequest().patch(preEntry);
- cache.removeEntry(source);
- cache.addEntry(target, patchedEntry);
+ /**
+ * attributes user:thumbnail
+ * @return url
+ * @see "https://stackoverflow.com/a/45027853"
+ */
+ String getThumbnail(DriveItem sourceEntry) throws IOException {
+ IThumbnailSetCollectionPage page = client.drive().items(sourceEntry.id)
+ .thumbnails()
+ .buildRequest(Arrays.asList(new QueryOption("select", "source")))
+ .get();
+ ThumbnailSet set = page.getCurrentPage().get(0);
+Debug.println(Level.INFO, "thumbnail url: " + set.source.url);
+ return set.source.url;
}
}
diff --git a/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/OneDriveFileSystemProvider.java b/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/OneDriveFileSystemProvider.java
index 62b69198..e61f9482 100644
--- a/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/OneDriveFileSystemProvider.java
+++ b/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/OneDriveFileSystemProvider.java
@@ -26,6 +26,8 @@ public final class OneDriveFileSystemProvider extends FileSystemProviderBase {
public static final String ENV_APP_CREDENTIAL = "app_credential";
+ public static final String ENV_USE_SYSTEM_WATCHER = "use_system_watcher";
+
public OneDriveFileSystemProvider() {
super(new OneDriveFileSystemRepository());
}
diff --git a/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/OneDriveFileSystemRepository.java b/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/OneDriveFileSystemRepository.java
index a75f3a55..4fd3d688 100644
--- a/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/OneDriveFileSystemRepository.java
+++ b/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/OneDriveFileSystemRepository.java
@@ -80,7 +80,8 @@ public FileSystemDriver createDriver(final URI uri, final Map env) th
}
// 3. process
- String accessToken = new MicrosoftGraphOAuth2(appCredential, true).authorize(userCredential);
+ MicrosoftGraphOAuth2 oAuth2 = new MicrosoftGraphOAuth2(appCredential, true);
+ String accessToken = oAuth2.authorize(userCredential);
//Debug.println("accessToken: " + accessToken);
IAuthenticationProvider authenticationProvider = new IAuthenticationProvider() {
@@ -95,6 +96,6 @@ public void authenticateRequest(IHttpRequest request) {
.buildClient();
final OneDriveFileStore fileStore = new OneDriveFileStore(graphClient, factoryProvider.getAttributesFactory());
- return new OneDriveFileSystemDriver(fileStore, factoryProvider, graphClient, env);
+ return new OneDriveFileSystemDriver(fileStore, factoryProvider, graphClient, () -> oAuth2.close(), env);
}
}
diff --git a/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/OneDriveUploadOption.java b/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/OneDriveUploadOption.java
index 73e32e31..83f38eb3 100644
--- a/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/OneDriveUploadOption.java
+++ b/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/OneDriveUploadOption.java
@@ -14,6 +14,10 @@
/**
* OneDriveUploadOption.
*
+ * in {@link com.github.fge.filesystem.options.FileSystemOptionsFactory},
+ * instances of this class are compared by contains method. so i override
+ * {@link #equals(Object)} and {@link #hashCode()}.
+ *
* TODO CopyOption doesn't work.
*
* @author Naohide Sano (umjammer)
@@ -21,6 +25,9 @@
*/
public class OneDriveUploadOption implements OpenOption, CopyOption {
+ /** */
+ private static final long serialVersionUID = -3760090552182064957L;
+
/** */
private Path source;
@@ -41,7 +48,7 @@ public boolean equals(Object other) {
@Override
public int hashCode() {
- return Long.hashCode(-3760090552182064957L); // TODO ad-hoc
+ return Long.hashCode(serialVersionUID); // TODO ad-hoc
}
}
diff --git a/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/OneDriveUserDefinedFileAttributesProvider.java b/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/OneDriveUserDefinedFileAttributesProvider.java
new file mode 100644
index 00000000..1f7c8b43
--- /dev/null
+++ b/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/OneDriveUserDefinedFileAttributesProvider.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.onedrive4;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
+import com.github.fge.filesystem.attributes.provider.UserDefinedFileAttributesProvider;
+import com.microsoft.graph.models.extensions.DriveItem;
+
+import vavi.nio.file.onedrive4.OneDriveFileAttributesFactory.Metadata;
+import vavi.util.Debug;
+
+
+/**
+ * OneDriveUserDefinedFileAttributesProvider.
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/09/08 umjammer initial version
+ */
+public class OneDriveUserDefinedFileAttributesProvider extends UserDefinedFileAttributesProvider {
+
+ /** driver & file entry */
+ private final Metadata entry;
+
+ /** */
+ public OneDriveUserDefinedFileAttributesProvider(Metadata entry) throws IOException {
+ this.entry = entry;
+ }
+
+ /** pre-listed */
+ private static final List list = Arrays.stream(UserAttributes.values()).map(e -> e.name()).collect(Collectors.toList());
+
+ @Override
+ public List list() throws IOException {
+ return list;
+ }
+
+ @Override
+ public int size(String name) throws IOException {
+ return UserAttributes.valueOf(name).size(entry);
+ }
+
+ @Override
+ public int read(String name, ByteBuffer dst) throws IOException {
+ return UserAttributes.valueOf(name).read(entry, dst);
+ }
+
+ @Override
+ public int write(final String name, final ByteBuffer src) throws IOException {
+ return UserAttributes.valueOf(name).write(entry, src);
+ }
+
+ private interface UserAttribute {
+ int size(T entry) throws IOException;
+ int read(T entry, ByteBuffer dst) throws IOException;
+ int write(T entry, ByteBuffer src) throws IOException;
+ }
+
+ private enum UserAttributes implements UserAttribute {
+ description {
+ public int size(Metadata entry) throws IOException {
+ String description = entry.driveItem.description;
+Debug.println("size " + name() + ": " + description);
+ return description == null ? 0 : description.getBytes().length;
+ }
+ public int read(Metadata entry, ByteBuffer dst) throws IOException {
+ String description = entry.driveItem.description;
+Debug.println("read " + name() + ": " + description);
+ if (description != null) {
+ dst.put(description.getBytes());
+ }
+ return dst.array().length;
+ }
+ public int write(Metadata entry, ByteBuffer src) throws IOException {
+ String description = new String(src.array());
+Debug.println("write " + name() + ": " + description);
+ entry.driver.patchEntryDescription(entry.driveItem, description);
+ return description.getBytes().length;
+ }
+ },
+ /** whole image file */
+ thumbnail {
+ /** */
+ Map thumbnailCache = new ConcurrentHashMap<>(); // TODO LRU
+
+ /** */
+ private String getUrl(Metadata entry) throws IOException {
+ String url = thumbnailCache.get(entry.driveItem);
+ if (url != null) {
+ return url;
+ } else {
+ url = entry.driver.getThumbnail(entry.driveItem);
+ if (url != null) {
+ thumbnailCache.put(entry.driveItem, url);
+ }
+ return url;
+ }
+ }
+
+ /** */
+ private byte[] getThumbnail(Metadata entry) throws IOException {
+ String url = getUrl(entry);
+ InputStream is = new BufferedInputStream(new URL(url).openStream());
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ byte[] buffer = new byte[8024];
+ int l = 0;
+ while ((l = is.read(buffer)) != -1) {
+ baos.write(buffer, 0, l);
+ }
+ return baos.toByteArray();
+ }
+
+ @Override
+ public int size(Metadata entry) throws IOException {
+ String url = getUrl(entry);
+ if (url != null) {
+ byte[] thumbnail = getThumbnail(entry);
+ if (thumbnail != null) {
+ return thumbnail.length;
+ }
+ }
+ return 0;
+ }
+
+ @Override
+ public int read(Metadata entry, ByteBuffer dst) throws IOException {
+ String url = getUrl(entry);
+ if (url != null) {
+ byte[] thumbnail = getThumbnail(entry);
+ if (thumbnail != null) {
+ dst.put(thumbnail);
+ return thumbnail.length;
+ }
+ }
+ return 0;
+ }
+
+ @Override
+ public int write(Metadata entry, ByteBuffer src) throws IOException {
+ byte[] thumbnail = src.array();
+ entry.driver.setThumbnail(entry.driveItem, thumbnail);
+ return thumbnail.length;
+ }
+ };
+ }
+}
+
+/* */
diff --git a/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/OneDriveWatchService.java b/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/OneDriveWatchService.java
new file mode 100644
index 00000000..c59e1543
--- /dev/null
+++ b/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/OneDriveWatchService.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.onedrive4;
+
+import java.io.IOException;
+
+import com.microsoft.graph.models.extensions.IGraphServiceClient;
+
+import vavi.nio.file.watch.webhook.WebHookBaseWatchService;
+import vavi.util.Debug;
+
+
+/**
+ * OneDriveWatchService.
+ *
+ * system properties
+ *
+ * vavi.nio.file.watch.webhook.NotificationProvider.onedrive4
+ *
+ *
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/07/23 umjammer initial version
+ */
+public class OneDriveWatchService extends WebHookBaseWatchService {
+
+ private static final String WEBHOOK_NOTIFICATION_PROVIDER =
+ System.getProperty("vavi.nio.file.watch.webhook.NotificationProvider.onedrive4", ".onedrive4.webhook.websocket");
+
+// private IGraphServiceClient client;
+
+// private String savedStartPageToken;
+
+ /** */
+ public OneDriveWatchService(IGraphServiceClient client) throws IOException {
+// this.client = client;
+
+ setupNotification(this, WEBHOOK_NOTIFICATION_PROVIDER);
+ }
+
+ @Override
+ protected void onNotifyMessage(String notification) throws IOException {
+Debug.println(">> notification: done");
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (isOpen()) {
+ super.close();
+ }
+ }
+}
diff --git a/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/graph/LraMonitorResponseHandler.java b/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/graph/LraMonitorResponseHandler.java
index d5959944..d47ab9d4 100644
--- a/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/graph/LraMonitorResponseHandler.java
+++ b/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/graph/LraMonitorResponseHandler.java
@@ -18,6 +18,9 @@
import com.microsoft.graph.logger.ILogger;
import com.microsoft.graph.serializer.ISerializer;
+import okhttp3.Response; // TODO WTF??? why not be encapsulated in IConnection??? who did this??? crazy!
+
+
/**
* Handles the stateful response from the OneDrive LRA session
*
@@ -33,7 +36,44 @@ public class LraMonitorResponseHandler
*/
@Override
public void configConnection(final IConnection connection) {
- return;
+ }
+
+ @Override
+ public void configConnection(Response response) {
+ }
+
+ @Override
+ public LraMonitorResult generateResult(IHttpRequest request,
+ Response response,
+ ISerializer serializer,
+ ILogger logger) throws Exception {
+ // TODO all about response can be encapsulated into IConnection!
+ // why i need to write twice...
+ if (response.code() == HttpResponseCode.HTTP_ACCEPTED) {
+logger.logDebug("LRA has been accepted by the server.");
+ final LraSession session = new LraSession();
+ session.monitorUrl = response.header("Location");
+ return new LraMonitorResult(session);
+ } else if (response.code() == HttpResponseCode.HTTP_SEE_OTHER) {
+logger.logDebug("see other url.");
+ String seeOtherUrl = response.header("Location");
+ return new LraMonitorResult(seeOtherUrl);
+ } else if (response.code() == HttpResponseCode.HTTP_CREATED
+ || response.code() == HttpResponseCode.HTTP_OK) {
+logger.logDebug("LRA session is completed, drive item returned.");
+ String rawJson = response.body().string();
+ MonitorObject monitoredItem = serializer.deserializeObject(rawJson, MonitorObject.class);
+
+ return new LraMonitorResult(monitoredItem);
+ } else if (response.code() >= HttpResponseCode.HTTP_CLIENT_ERROR) {
+logger.logDebug("LRA error during monitor, see detail on result error");
+ return new LraMonitorResult(
+ GraphServiceException.createFromConnection(request, null, serializer,
+ response, logger));
+ } else {
+logger.logDebug("unhandled response code: " + response.code());
+ return null;
+ }
}
/**
diff --git a/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/graph/MyLogger.java b/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/graph/MyLogger.java
index ec20850b..7eeb30ca 100644
--- a/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/graph/MyLogger.java
+++ b/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/graph/MyLogger.java
@@ -26,7 +26,7 @@ public class MyLogger implements ILogger {
/**
* Sets the logging level of this logger
- *
+ *
* @param level the level to log at
*/
public void setLoggingLevel(final LoggerLevel level) {
@@ -36,7 +36,7 @@ public void setLoggingLevel(final LoggerLevel level) {
/**
* Gets the logging level of this logger
- *
+ *
* @return the level the logger is set to
*/
public LoggerLevel getLoggingLevel() {
@@ -45,7 +45,7 @@ public LoggerLevel getLoggingLevel() {
/**
* Creates the tag automatically
- *
+ *
* @return the tag for the current method Sourced from
* https://gist.github.com/eefret/a9c7ac052854a10a8936
*/
@@ -68,7 +68,7 @@ private String getTag() {
/**
* Logs a debug message
- *
+ *
* @param message the message
*/
@Override
@@ -81,7 +81,7 @@ public void logDebug(final String message) {
/**
* Logs an error message with throwable
- *
+ *
* @param message the message
* @param throwable the throwable
*/
diff --git a/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/graph/ThumbnailUploadProvider.java b/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/graph/ThumbnailUploadProvider.java
new file mode 100644
index 00000000..e2b6943c
--- /dev/null
+++ b/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/graph/ThumbnailUploadProvider.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.onedrive4.graph;
+
+
+import java.io.IOException;
+import java.security.InvalidParameterException;
+
+import com.microsoft.graph.http.BaseRequest;
+import com.microsoft.graph.http.HttpMethod;
+import com.microsoft.graph.http.HttpResponseCode;
+import com.microsoft.graph.http.IHttpRequest;
+import com.microsoft.graph.models.extensions.DriveItem;
+import com.microsoft.graph.models.extensions.IGraphServiceClient;
+
+import vavi.util.Debug;
+
+
+/**
+ * ThumbnailUpload service provider
+ *
+ * @param the upload item type
+ */
+public class ThumbnailUploadProvider {
+
+ /**
+ * The client
+ */
+ private final IGraphServiceClient client;
+
+ /**
+ * The upload URL
+ */
+ private final String uploadUrl;
+
+ /**
+ * Creates the ChunkedUploadProvider
+ *
+ * @param uploadSession the initial upload session
+ * @param client the Graph client
+ * @param streamSize the stream size
+ * @param uploadTypeClass the upload type class
+ */
+ public ThumbnailUploadProvider(final DriveItem item,
+ final IGraphServiceClient client) {
+ if (item == null) {
+ throw new InvalidParameterException("item is null.");
+ }
+
+ if (client == null) {
+ throw new InvalidParameterException("OneDrive client is null.");
+ }
+
+ this.client = client;
+ this.uploadUrl = client.getServiceRoot() + "/drive/items/" + item.id + "/thumbnails/0/source/content";
+Debug.println("url: " + uploadUrl);
+ }
+
+ /**
+ * Uploads a thumbnail.
+ *
+ * @param image the thumbnail bytes
+ * @throws IOException the IO exception that occurred during upload
+ */
+ public void upload(byte[] image)
+ throws IOException {
+
+ BaseRequest request = new BaseRequest(uploadUrl, client, null, Integer.class) {{
+ setHttpMethod(HttpMethod.PUT);
+ }};
+ int result = client.getHttpProvider().send(
+ (IHttpRequest) request,
+ Integer.class,
+ image,
+ new ThumbnailUploadResponseHandler());
+
+ if (result != HttpResponseCode.HTTP_OK) {
+ throw new IOException(String.valueOf(result));
+ }
+ }
+}
diff --git a/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/graph/ThumbnailUploadResponseHandler.java b/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/graph/ThumbnailUploadResponseHandler.java
new file mode 100644
index 00000000..0bbd3daf
--- /dev/null
+++ b/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/graph/ThumbnailUploadResponseHandler.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2019 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.onedrive4.graph;
+
+import com.microsoft.graph.http.IConnection;
+import com.microsoft.graph.http.IHttpRequest;
+import com.microsoft.graph.http.IStatefulResponseHandler;
+import com.microsoft.graph.logger.ILogger;
+import com.microsoft.graph.serializer.ISerializer;
+
+import okhttp3.Response; // TODO WTF??? why not be encapsulated in IConnection??? who did this??? crazy!
+
+
+/**
+ * Handles the response from the ThumbnailUpload
+ */
+public class ThumbnailUploadResponseHandler
+ implements IStatefulResponseHandler {
+
+ /**
+ * Do nothing before getting the response
+ *
+ * @param connection the connection
+ */
+ @Override
+ public void configConnection(final IConnection connection) {
+ }
+
+ @Override
+ public void configConnection(Response response) {
+ }
+
+ @Override
+ public Integer generateResult(IHttpRequest request,
+ Response response,
+ ISerializer serializer,
+ ILogger logger) throws Exception {
+ // why i need to write twice...
+ return response.code();
+ }
+
+ /**
+ * Generate the LRA monitor response result
+ *
+ * @param request the HTTP request
+ * @param connection the HTTP connection
+ * @param serializer the serializer
+ * @param logger the system logger
+ * @return the LRA monitor result, which could be either an LRA monitor or error
+ * @throws Exception an exception occurs if the request was unable to complete for any reason
+ */
+ @Override
+ public Integer generateResult(
+ final IHttpRequest request,
+ final IConnection connection,
+ final ISerializer serializer,
+ final ILogger logger) throws Exception {
+
+ return connection.getResponseCode();
+ }
+}
diff --git a/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/webhook/websocket/MicrosoftWebSocketNotification.java b/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/webhook/websocket/MicrosoftWebSocketNotification.java
new file mode 100644
index 00000000..d12f3bde
--- /dev/null
+++ b/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/webhook/websocket/MicrosoftWebSocketNotification.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.onedrive4.webhook.websocket;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.function.Consumer;
+
+import javax.websocket.ClientEndpoint;
+import javax.websocket.Session;
+
+import vavi.nio.file.watch.webhook.websocket.BasicAuthorizationConfigurator;
+import vavi.nio.file.watch.webhook.websocket.StringWebSocketNotification;
+
+
+/**
+ * MicrosoftWebSocketNotification.
+ *
+ * environment variables
+ *
+ * VAVI_APPS_WEBHOOK_WEBSOCKET_BASE_URL
+ * VAVI_APPS_WEBHOOK_WEBSOCKET_MICROSOFT_PATH
+ *
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/07/23 umjammer initial version
+ */
+@ClientEndpoint(configurator = BasicAuthorizationConfigurator.class)
+public class MicrosoftWebSocketNotification extends StringWebSocketNotification {
+
+ private static final String websocketBaseUrl = System.getenv("VAVI_APPS_WEBHOOK_WEBSOCKET_BASE_URL");
+ private static final String websocketPath = System.getenv("VAVI_APPS_WEBHOOK_WEBSOCKET_MICROSOFT_PATH");
+
+ private static final URI uri = URI.create(websocketBaseUrl + websocketPath);
+
+ private Consumer callback;
+
+ /**
+ * @param args
+ */
+ public MicrosoftWebSocketNotification(Consumer callback, Object... args) throws IOException {
+ super(uri, args);
+ this.callback = callback;
+ }
+
+ @Override
+ public void onOpenImpl(Session session) throws IOException {
+ }
+
+ @Override
+ protected void onNotifyMessageImpl(String notification) throws IOException {
+ callback.accept(notification);
+ }
+
+ @Override
+ protected void onCloseImpl(Session session) throws IOException {
+ }
+}
+
+/* */
diff --git a/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/webhook/websocket/MicrosoftWebSocketNotificationProvider.java b/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/webhook/websocket/MicrosoftWebSocketNotificationProvider.java
new file mode 100644
index 00000000..ba77c469
--- /dev/null
+++ b/vavi-nio-file-onedrive4/src/main/java/vavi/nio/file/onedrive4/webhook/websocket/MicrosoftWebSocketNotificationProvider.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.onedrive4.webhook.websocket;
+
+import java.io.IOException;
+import java.util.function.Consumer;
+
+import vavi.nio.file.watch.webhook.Notification;
+import vavi.nio.file.watch.webhook.NotificationProvider;
+
+
+/**
+ * MicrosoftWebSocketNotificationProvider.
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/07/23 umjammer initial version
+ */
+public class MicrosoftWebSocketNotificationProvider implements NotificationProvider {
+
+ @Override
+ public Notification getNotification(Consumer callback, Object... args) throws IOException {
+ return Notification.class.cast(new MicrosoftWebSocketNotification(Consumer.class.cast(callback), args));
+ }
+}
+
+/* */
diff --git a/vavi-nio-file-onedrive4/src/main/resources/META-INF/services/vavi.nio.file.watch.webhook.NotificationProvider b/vavi-nio-file-onedrive4/src/main/resources/META-INF/services/vavi.nio.file.watch.webhook.NotificationProvider
new file mode 100644
index 00000000..19b2e9d9
--- /dev/null
+++ b/vavi-nio-file-onedrive4/src/main/resources/META-INF/services/vavi.nio.file.watch.webhook.NotificationProvider
@@ -0,0 +1 @@
+vavi.nio.file.onedrive4.webhook.websocket.MicrosoftWebSocketNotificationProvider
diff --git a/vavi-nio-file-onedrive4/src/test/java/vavi/nio/file/onedrive4/Main.java b/vavi-nio-file-onedrive4/src/test/java/vavi/nio/file/onedrive4/Main.java
index 0bb19eec..5bf7c384 100644
--- a/vavi-nio-file-onedrive4/src/test/java/vavi/nio/file/onedrive4/Main.java
+++ b/vavi-nio-file-onedrive4/src/test/java/vavi/nio/file/onedrive4/Main.java
@@ -7,6 +7,8 @@
package vavi.nio.file.onedrive4;
import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.Files;
import java.util.Collections;
import org.junit.jupiter.api.Test;
@@ -28,10 +30,20 @@ public class Main {
@Test
void test01() throws Exception {
- String email = System.getenv("MICROSOFT4_TEST_ACCOUNT");
+ String email = System.getenv("MICROSOFT_TEST_ACCOUNT");
URI uri = URI.create("onedrive:///?id=" + email);
- testAll(new OneDriveFileSystemProvider().newFileSystem(uri, Collections.EMPTY_MAP));
+ testAll(new OneDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap()));
+ }
+
+ /** */
+ public static void main(String[] args) throws Exception {
+ String email = System.getenv("MICROSOFT_TEST_ACCOUNT");
+
+ URI uri = URI.create("onedrive:///?id=" + email);
+
+ FileSystem fs = new OneDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap());
+ Files.list(fs.getPath("/")).forEach(System.out::println);
}
}
\ No newline at end of file
diff --git a/vavi-nio-file-onedrive4/src/test/java/vavi/nio/file/onedrive4/Main2.java b/vavi-nio-file-onedrive4/src/test/java/vavi/nio/file/onedrive4/Main2.java
index ad48f75b..5c9a24b7 100644
--- a/vavi-nio-file-onedrive4/src/test/java/vavi/nio/file/onedrive4/Main2.java
+++ b/vavi-nio-file-onedrive4/src/test/java/vavi/nio/file/onedrive4/Main2.java
@@ -25,10 +25,10 @@ public class Main2 {
@Test
void test01() throws Exception {
- String email = System.getenv("MICROSOFT4_TEST_ACCOUNT");
+ String email = System.getenv("MICROSOFT_TEST_ACCOUNT");
URI uri = URI.create("onedrive:///?id=" + email);
- FileSystem fs = new OneDriveFileSystemProvider().newFileSystem(uri, Collections.EMPTY_MAP);
+ FileSystem fs = new OneDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap());
testLargeFile(fs, OneDriveUploadOption.class);
}
diff --git a/vavi-nio-file-onedrive4/src/test/java/vavi/nio/file/onedrive4/Main3.java b/vavi-nio-file-onedrive4/src/test/java/vavi/nio/file/onedrive4/Main3.java
index db5bebd7..40206e39 100644
--- a/vavi-nio-file-onedrive4/src/test/java/vavi/nio/file/onedrive4/Main3.java
+++ b/vavi-nio-file-onedrive4/src/test/java/vavi/nio/file/onedrive4/Main3.java
@@ -28,7 +28,7 @@ void test01() throws Exception {
String email = System.getenv("MICROSOFT4_TEST_ACCOUNT");
URI uri = URI.create("onedrive:///?id=" + email);
- FileSystem fs = new OneDriveFileSystemProvider().newFileSystem(uri, Collections.EMPTY_MAP);
+ FileSystem fs = new OneDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap());
testMoveFolder(fs);
}
diff --git a/vavi-nio-file-onedrive4/src/test/java/vavi/nio/file/onedrive4/Main4.java b/vavi-nio-file-onedrive4/src/test/java/vavi/nio/file/onedrive4/Main4.java
index 8f6dcbd9..e645c5d4 100644
--- a/vavi-nio-file-onedrive4/src/test/java/vavi/nio/file/onedrive4/Main4.java
+++ b/vavi-nio-file-onedrive4/src/test/java/vavi/nio/file/onedrive4/Main4.java
@@ -73,7 +73,7 @@ public void test01(String providerClassName) throws Exception {
//
- public static void main(final String... args) throws IOException {
+ public static void main(String[] args) throws IOException {
String email = args[1];
Map env = new HashMap<>();
@@ -83,13 +83,13 @@ public static void main(final String... args) throws IOException {
FileSystem fs = new OneDriveFileSystemProvider().newFileSystem(uri, env);
-// System.setProperty("vavi.net.fuse.FuseProvider.class", "vavi.net.fuse.javafs.JavaFSFuseProvider");
+ System.setProperty("vavi.net.fuse.FuseProvider.class", "vavi.net.fuse.javafs.JavaFSFuseProvider");
// System.setProperty("vavi.net.fuse.FuseProvider.class", "vavi.net.fuse.jnrfuse.JnrFuseFuseProvider");
Map options = new HashMap<>();
options.put("fsname", "onedrive_fs" + "@" + System.currentTimeMillis());
options.put("noappledouble", null);
- options.put(vavi.net.fuse.javafs.JavaFSFuse.ENV_DEBUG, true);
+ options.put(vavi.net.fuse.javafs.JavaFSFuse.ENV_DEBUG, false);
options.put(vavi.net.fuse.javafs.JavaFSFuse.ENV_READ_ONLY, false);
Fuse.getFuse().mount(fs, args[0], options);
diff --git a/vavi-nio-file-onedrive4/src/test/java/vavi/nio/file/onedrive4/Main5.java b/vavi-nio-file-onedrive4/src/test/java/vavi/nio/file/onedrive4/Main5.java
index d2446466..db3e20b9 100644
--- a/vavi-nio-file-onedrive4/src/test/java/vavi/nio/file/onedrive4/Main5.java
+++ b/vavi-nio-file-onedrive4/src/test/java/vavi/nio/file/onedrive4/Main5.java
@@ -41,7 +41,7 @@ void test01() throws Exception {
Path dstDir;
Path dst;
String a, b;
- try (FileSystem onedrivefs = new OneDriveFileSystemProvider().newFileSystem(uri, Collections.EMPTY_MAP)) {
+ try (FileSystem onedrivefs = new OneDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap())) {
src = Paths.get("src/test/resources/Hello.java");
dstDir = onedrivefs.getPath("/").resolve("TEST_FUSE_5");
@@ -60,7 +60,7 @@ void test01() throws Exception {
a = Util.toFilenameString(Files.list(dstDir).findFirst().get());
}
- try (FileSystem onedrivefs = new OneDriveFileSystemProvider().newFileSystem(uri, Collections.EMPTY_MAP)) {
+ try (FileSystem onedrivefs = new OneDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap())) {
dstDir = onedrivefs.getPath("/").resolve("TEST_FUSE_5");
dst = dstDir.resolve("ããšã 001");
diff --git a/vavi-nio-file-onedrive4/src/test/java/vavi/nio/file/onedrive4/Main6.java b/vavi-nio-file-onedrive4/src/test/java/vavi/nio/file/onedrive4/Main6.java
new file mode 100644
index 00000000..72e22434
--- /dev/null
+++ b/vavi-nio-file-onedrive4/src/test/java/vavi/nio/file/onedrive4/Main6.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.onedrive4;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.Files;
+import java.util.Collections;
+
+import org.junit.jupiter.api.Test;
+
+import static vavi.nio.file.Base.testDescription;
+
+
+/**
+ * OneDrive. (v2.0 graph api, msgraph engine)
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/05/31 umjammer initial version
+ */
+public class Main6 {
+
+ @Test
+ void test01() throws Exception {
+ String email = System.getenv("MICROSOFT4_TEST_ACCOUNT");
+
+ URI uri = URI.create("onedrive:///?id=" + email);
+ FileSystem fs = new OneDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap());
+
+ testDescription(fs);
+ }
+
+ //
+
+ public static void main(String[] args) throws IOException {
+ String email = System.getenv("MICROSOFT4_TEST_ACCOUNT");
+
+ URI uri = URI.create("onedrive:///?id=" + email);
+ FileSystem fs = new OneDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap());
+
+ Files.setAttribute(fs.getPath("tmp/Cyberduck.jpg"), "user:description", ("čĒŦæããšã " + System.currentTimeMillis()).getBytes());
+
+ fs.close();
+ }
+}
diff --git a/vavi-nio-file-onedrive4/src/test/java/vavi/nio/file/onedrive4/TestGraph.java b/vavi-nio-file-onedrive4/src/test/java/vavi/nio/file/onedrive4/TestGraph.java
index 42f1febb..3b4ad60c 100644
--- a/vavi-nio-file-onedrive4/src/test/java/vavi/nio/file/onedrive4/TestGraph.java
+++ b/vavi-nio-file-onedrive4/src/test/java/vavi/nio/file/onedrive4/TestGraph.java
@@ -9,9 +9,13 @@
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.net.URL;
import java.net.URLEncoder;
+import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.Arrays;
import com.microsoft.graph.authentication.IAuthenticationProvider;
import com.microsoft.graph.concurrency.ChunkedUploadProvider;
@@ -27,9 +31,12 @@
import com.microsoft.graph.models.extensions.DriveItemUploadableProperties;
import com.microsoft.graph.models.extensions.IGraphServiceClient;
import com.microsoft.graph.models.extensions.ItemReference;
+import com.microsoft.graph.models.extensions.ThumbnailSet;
import com.microsoft.graph.models.extensions.UploadSession;
+import com.microsoft.graph.options.QueryOption;
import com.microsoft.graph.requests.extensions.GraphServiceClient;
import com.microsoft.graph.requests.extensions.IDriveItemCopyRequest;
+import com.microsoft.graph.requests.extensions.IThumbnailSetCollectionPage;
import vavi.net.auth.WithTotpUserCredential;
import vavi.net.auth.oauth2.OAuth2AppCredential;
@@ -40,6 +47,9 @@
import vavi.nio.file.onedrive4.graph.LraMonitorResponseHandler;
import vavi.nio.file.onedrive4.graph.LraMonitorResult;
import vavi.nio.file.onedrive4.graph.LraSession;
+import vavi.nio.file.onedrive4.graph.ThumbnailUploadProvider;
+import vavi.util.Debug;
+import vavi.util.StringUtil;
import vavi.util.properties.annotation.PropsEntity;
@@ -51,27 +61,42 @@
*/
public class TestGraph {
+ static {
+ System.setProperty("vavi.util.logging.VaviFormatter.extraClassMethod", "(" +
+ "sun\\.util\\.logging\\.\\w*Log\\w*#\\w+" + "|" +
+ "jdk\\.internal\\.event\\.EventHelper#log\\w+" +
+ ")");
+ }
+
/**
* @param args 0: email
*/
public static void main(String[] args) throws Exception {
- String email = args[0];
+// String email = args[0];
+ String email = "snaohide@hotmail.com";
TestGraph app = new TestGraph();
app.auth(email);
- app.testCopy();
+// app.testCopy();
+ app.testThumbnail();
+ app.close();
}
- /** */
+ void close() {
+ auth2.close();
+ }
+
+ MicrosoftGraphOAuth2 auth2;
+
+ /** @after {@link #client} */
void auth(String email) throws IOException {
OAuth2AppCredential appCredential = new MicrosoftGraphLocalAppCredential();
PropsEntity.Util.bind(appCredential);
- PropsEntity.Util.bind(this);
-
WithTotpUserCredential userCredential = new MicrosoftLocalUserCredential(email);
- String accesssToken = new MicrosoftGraphOAuth2(appCredential, true).authorize(userCredential);
+ auth2 = new MicrosoftGraphOAuth2(appCredential, true);
+ String accesssToken = auth2.authorize(userCredential);
client = GraphServiceClient.builder()
.authenticationProvider(new IAuthenticationProvider() {
@@ -167,6 +192,33 @@ public void failure(final ClientException ex) {
}
});
}
+
+ /** */
+ void testThumbnail() throws Exception {
+ Path p = Paths.get(TestGraph.class.getResource("/duke.jpg").toURI());
+ byte[] b = Files.readAllBytes(p);
+
+ DriveItem sourceEntry = client.drive().root().itemWithPath("tmp/test.zip").buildRequest().get();
+
+ ThumbnailUploadProvider provider = new ThumbnailUploadProvider(sourceEntry, client);
+ provider.upload(b);
+Debug.println("upload done");
+
+ Thread.sleep(3000);
+
+ IThumbnailSetCollectionPage page = client.drive().items(sourceEntry.id)
+ .thumbnails()
+ .buildRequest(Arrays.asList(new QueryOption("select", "source")))
+ .get();
+ ThumbnailSet set = page.getCurrentPage().get(0);
+Debug.println("set: " + StringUtil.paramString(set));
+Debug.println("thumbnail url: " + set.source.url);
+
+ Path dir = Paths.get("tmp");
+ Path out = dir.resolve("thumbnail.jpg");
+
+ Files.copy(new URL(set.source.url).openStream(), out, StandardCopyOption.REPLACE_EXISTING);
+ }
}
/* */
diff --git a/vavi-nio-file-onedrive4/src/test/java/vavi/nio/file/onedrive4/WebHookApiTest.java b/vavi-nio-file-onedrive4/src/test/java/vavi/nio/file/onedrive4/WebHookApiTest.java
new file mode 100644
index 00000000..9f90f5db
--- /dev/null
+++ b/vavi-nio-file-onedrive4/src/test/java/vavi/nio/file/onedrive4/WebHookApiTest.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+package vavi.nio.file.onedrive4;
+
+import java.net.URI;
+import java.util.Calendar;
+
+import com.microsoft.graph.authentication.IAuthenticationProvider;
+import com.microsoft.graph.http.IHttpRequest;
+import com.microsoft.graph.models.extensions.DriveItem;
+import com.microsoft.graph.models.extensions.Folder;
+import com.microsoft.graph.models.extensions.IGraphServiceClient;
+import com.microsoft.graph.models.extensions.Subscription;
+import com.microsoft.graph.requests.extensions.GraphServiceClient;
+import com.microsoft.graph.requests.extensions.IDriveItemCollectionPage;
+import com.microsoft.graph.requests.extensions.ISubscriptionCollectionPage;
+
+import vavi.net.auth.oauth2.microsoft.MicrosoftGraphLocalAppCredential;
+import vavi.net.auth.oauth2.microsoft.MicrosoftGraphOAuth2;
+import vavi.net.auth.web.microsoft.MicrosoftLocalUserCredential;
+import vavi.nio.file.onedrive4.graph.MyLogger;
+import vavi.util.Debug;
+
+
+/**
+ * WebHookApiTest.
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/07/03 umjammer initial version
+ * @see "https://docs.microsoft.com/graph/api/subscription-post-subscriptions?view=graph-rest-1.0&tabs=http"
+ */
+public class WebHookApiTest {
+
+ static final String VAVI_APPS_WEBHOOK_SECRET = System.getenv("VAVI_APPS_WEBHOOK_SECRET");
+ static String websocketBaseUrl = System.getenv("VAVI_APPS_WEBHOOK_WEBSOCKET_BASE_URL");
+ static String websocketPath = System.getenv("VAVI_APPS_WEBHOOK_WEBSOCKET_MICROSOFT_PATH");
+ static String email = System.getenv("MICROSOFT4_TEST_ACCOUNT");
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args) throws Exception {
+
+ MicrosoftLocalUserCredential userCredential = new MicrosoftLocalUserCredential(email);
+ MicrosoftGraphLocalAppCredential appCredential = new MicrosoftGraphLocalAppCredential();
+
+ @SuppressWarnings("resource")
+ String accessToken = new MicrosoftGraphOAuth2(appCredential, true).authorize(userCredential);
+//Debug.println("accessToken: " + accessToken);
+
+ IAuthenticationProvider authenticationProvider = new IAuthenticationProvider() {
+ @Override
+ public void authenticateRequest(IHttpRequest request) {
+ request.addHeader("Authorization", "Bearer " + accessToken);
+ }
+ };
+ IGraphServiceClient graphClient = GraphServiceClient.builder()
+ .authenticationProvider(authenticationProvider)
+ .logger(new MyLogger())
+ .buildClient();
+ graphClient.getHttpProvider().getConnectionConfig().setReadTimeout(30 * 1000);
+
+ // create
+ URI uri = URI.create(websocketBaseUrl + websocketPath);
+ // Listen for file upload events in the specified folder
+ DriveItem rootFolder = graphClient.drive().root().buildRequest().get();
+ IDriveItemCollectionPage pages = graphClient.drive().items(rootFolder.id).children().buildRequest().get();
+ for (DriveItem i : pages.getCurrentPage()) {
+ if (i.name.equals("TEST_WEBHOOK")) {
+System.out.println("rmdir " + i.name);
+ graphClient.drive().items(i.id).buildRequest().delete();
+ }
+ }
+System.out.println("mkdir " + "TEST_WEBHOOK");
+ DriveItem preEntry = new DriveItem();
+ preEntry.name = "TEST_WEBHOOK";
+ preEntry.folder = new Folder();
+ DriveItem newFolder = graphClient.drive().items(rootFolder.id).children().buildRequest().post(preEntry);
+
+System.out.println("[create] webhook");
+ Subscription preSubscription = new Subscription();
+// preSubscription.id = UUID.randomUUID().toString(); // doesn't work (spec.)
+// preSubscription.changeType = "created,updated,deleted"; // root is only supported 'update'
+ preSubscription.changeType = "updated";
+ preSubscription.notificationUrl = uri.toString();
+ preSubscription.resource = "me/drive/root";
+ Calendar calendar = Calendar.getInstance();
+ calendar.roll(Calendar.DATE, true);
+ preSubscription.expirationDateTime = calendar;
+ preSubscription.clientState = VAVI_APPS_WEBHOOK_SECRET;
+// Subscription subscription = graphClient.subscriptions().buildRequest().post(preSubscription);
+ Subscription subscription = graphClient.subscriptions().buildRequest().post(preSubscription);
+Debug.println(subscription.id);
+
+System.out.println("[ls] webhook");
+ ISubscriptionCollectionPage subscPages = graphClient.subscriptions().buildRequest().get();
+ for (Subscription s : subscPages.getCurrentPage()) {
+System.out.println(s);
+ }
+
+System.out.println("mkdir " + "TEST_WEBHOOK/" + "NEW FOLDER");
+ preEntry = new DriveItem();
+ preEntry.name = "NEW FOLDER";
+ preEntry.folder = new Folder();
+ DriveItem subFolder = graphClient.drive().items(newFolder.id).children().buildRequest().post(preEntry);
+
+ Thread.sleep(5000);
+
+ // update
+System.out.println("[update] webhook");
+ calendar.roll(Calendar.DATE, true);
+ subscription.expirationDateTime = calendar;
+ subscription = graphClient.subscriptions(subscription.id).buildRequest().patch(subscription);
+
+ // delete
+System.out.println("[delete] webhook");
+ graphClient.subscriptions(subscription.id).buildRequest().delete();
+
+System.out.println("rmdir " + subFolder.name);
+ graphClient.drive().items(subFolder.id).buildRequest().delete();
+System.out.println("rmdir " + newFolder.name);
+ graphClient.drive().items(newFolder.id).buildRequest().delete();
+ }
+}
+
+/* */
diff --git a/vavi-nio-file-onedrive4/src/test/resources/duke.jpg b/vavi-nio-file-onedrive4/src/test/resources/duke.jpg
new file mode 100644
index 00000000..3402f12e
Binary files /dev/null and b/vavi-nio-file-onedrive4/src/test/resources/duke.jpg differ
diff --git a/vavi-nio-file-onedrive4/src/test/resources/logging.properties b/vavi-nio-file-onedrive4/src/test/resources/logging.properties
index c2e69d4c..d613ede0 100644
--- a/vavi-nio-file-onedrive4/src/test/resources/logging.properties
+++ b/vavi-nio-file-onedrive4/src/test/resources/logging.properties
@@ -11,7 +11,13 @@ handlers=java.util.logging.ConsoleHandler
# HttpUrlConnection
java.util.logging.ConsoleHandler.level=INFO
#sun.net.www.protocol.http.HttpURLConnection.level=OFF
-vavi.nio.file.onedrive4.graph.MyLogger.level=OFF
+vavi.nio.file.onedrive4.graph.MyLogger.level=ALL
+sun.util.logging.level=WARNING
+com.sun.jersey.level=WARNING
+sun.security.level=WARNING
+vavi.util.properties.level=WARNING
+vavi.beans.level=WARNING
+sun.net.level=WARNING
java.util.logging.ConsoleHandler.formatter=vavi.util.logging.VaviFormatter
#java.util.logging.ConsoleHandler.formatter=vavi.util.logging.BetterFormatter
diff --git a/vavi-nio-file-onedrive4/src/test/resources/onedrive.properties b/vavi-nio-file-onedrive4/src/test/resources/onedrive.properties
index 298c42c4..3f300320 100644
--- a/vavi-nio-file-onedrive4/src/test/resources/onedrive.properties
+++ b/vavi-nio-file-onedrive4/src/test/resources/onedrive.properties
@@ -1 +1 @@
-authenticatorClassName=vavi.net.auth.oauth2.microsoft.MicrosoftLocalAuthenticator
+authenticatorClassName=vavi.net.auth.oauth2.microsoft.MicrosoftBasicAuthenticator
diff --git a/vavi-nio-file-sandbox/pom.xml b/vavi-nio-file-sandbox/pom.xml
index a056db1c..50a2d3e3 100644
--- a/vavi-nio-file-sandbox/pom.xml
+++ b/vavi-nio-file-sandbox/pom.xml
@@ -7,7 +7,7 @@
vavi
vavi-apps-fuse
- 0.1.6
+ 0.1.7
vavi-nio-file-sandbox
@@ -21,19 +21,50 @@
https://github.com/umjammer/vavi-nio-file-sandbox/issues
+
+
+
+ maven-dependency-plugin
+ 2.10
+
+
+ copy
+ generate-resources
+
+ copy
+
+
+
+
+ vavi
+ vavi-image-ffmpeg
+ 1.0.9
+ dylib
+ false
+ ${project.build.testOutputDirectory}
+ libFfmpegResampleOpWrapper.dylib
+
+
+
+
+
+
+
+
+
- central
- bintray
- https://jcenter.bintray.com
+ jitpack.io
+ https://jitpack.io
+
+
+ github
+ GitHub umjammer Apache Maven Packages
+ https://maven.pkg.github.com/umjammer/*
umjammer-mvn-repo
https://raw.github.com/umjammer/umjammer/mvn-repo/
-
- true
- always
-
seasar
@@ -51,7 +82,32 @@
com.github.umjammer
vavi-commons
- 1.1.0
+ 1.1.6
+
+
+
+ org.jsoup
+ jsoup
+ 1.14.3
+ test
+
+
+ org.jdom
+ jdom
+ 2.0.2
+ test
+
+
+ jaxen
+ jaxen
+ 1.2.0
+ test
+
+
+ net.sf.saxon
+ Saxon-HE
+ 11.2
+ test
@@ -70,29 +126,42 @@
test
+
+ com.rainerhahnekamp
+ sneakythrow
+ test
+
+
vavi
vavi-nio-file-onedrive
- 0.1.6
+ 0.1.7
test
vavi
vavi-nio-file-onedrive4
- 0.1.6
+ 0.1.7
test
vavi
vavi-nio-file-googledrive
- 0.1.6
+ 0.1.7
test
com.github.umjammer
vavi-util-archive
- 1.0.6
+ 1.1.0
+ test
+
+
+
+ com.github.umjammer
+ vavi-image
+ 1.0.9
test
@@ -113,22 +182,34 @@
com.github.umjammer
klab-commons-csv
- 2.0.2
+ 2.0.3
test
- com.github.Querz
- NBT
- 4.0
+ org.cryptomator
+ fuse-nio-adapter
+ 1.2.3
test
- org.cryptomator
- fuse-nio-adapter
+ com.github.umjammer
+ vavi-util-screenscraping
+ 1.0.9
+ test
+
+
+ ch.qos.logback
+ logback-classic
1.2.3
test
+
+ ${vavi-nio-file.groupId}
+ vavi-nio-file
+ test-jar
+ test
+
diff --git a/vavi-nio-file-sandbox/readme.md b/vavi-nio-file-sandbox/readme.md
new file mode 100644
index 00000000..aeec751b
--- /dev/null
+++ b/vavi-nio-file-sandbox/readme.md
@@ -0,0 +1,9 @@
+# vavi-nio-file-sandbox
+
+sandbox
+
+## samples
+
+ * google drive thumbnail using `user:attribute` for *googledrive* file system
+
+ ![](https://lh3.googleusercontent.com/pw/AM-JKLUGXSshFc0wm7QRsYZ6tvvEV94Fv7nutU-fcNV8naSbTiSXawGAQfPwIlDtTSuDYpV7pYi_GXwMLJ2rEr0FjvgBD0fGD00R-yGczAnik8fXYTM8rFAf1apvFfP14KHZ1peruG8_RV_--jH4xJbOTNOR=w1024-h724-no?authuser=0)
\ No newline at end of file
diff --git a/vavi-nio-file-sandbox/src/test/java/Classification.java b/vavi-nio-file-sandbox/src/test/java/Classification.java
index d831e1e0..c199c06e 100644
--- a/vavi-nio-file-sandbox/src/test/java/Classification.java
+++ b/vavi-nio-file-sandbox/src/test/java/Classification.java
@@ -14,112 +14,129 @@
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-
-import vavi.net.auth.oauth2.OAuth2AppCredential;
-import vavi.net.auth.oauth2.microsoft.MicrosoftLocalAppCredential;
-import vavi.nio.file.onedrive.OneDriveFileSystemProvider;
-import vavi.util.properties.annotation.PropsEntity;
import static java.nio.file.FileVisitResult.CONTINUE;
/**
* onedrive classification
- *
+ *
+ * if an author has three more novels, create author folder and move those into there.
+ *
* @author Naohide Sano (umjammer)
* @version 0.00 2017/03/14 umjammer initial version
*/
public final class Classification {
+ static {
+ System.setProperty("vavi.util.logging.VaviFormatter.extraClassMethod",
+ "com\\.microsoft\\.graph\\.logger\\.DefaultLogger#logDebug");
+ }
+
/**
* @param args 0: email, 1: dir
*/
- public static void main(final String... args) throws IOException {
- String email = args[0];
- String cwd = args[1];
- boolean dryRun = true;
+ public static void main(String[] args) throws Exception {
+ Classification app = new Classification(args[0]);
+ app.exec(args[1]);
+ }
- URI uri = URI.create("onedrive:///?id=" + email);
+ boolean dryRun = true;
- OAuth2AppCredential appCredential = new MicrosoftLocalAppCredential();
- PropsEntity.Util.bind(appCredential);
-
- Map env = new HashMap<>();
- env.put(OneDriveFileSystemProvider.ENV_APP_CREDENTIAL, appCredential);
-
- FileSystem onedrivefs = FileSystems.newFileSystem(uri, env);
-
- Path root = onedrivefs.getPath(cwd);
- FileSearcher fileSearcher = new FileSearcher();
- Files.walkFileTree(root, fileSearcher);
- Pattern pattern = Pattern.compile("\\[(.+?)\\]");
- Map authors = fileSearcher.result().stream()
- .map(path -> pattern.matcher(path.getFileName().toString()))
- .filter(matcher -> matcher.find())
- .collect(Collectors.groupingBy(matcher -> matcher.group(1), Collectors.counting()));
- authors.entrySet().stream()
- .filter(e -> e.getValue() >= 3)
- .forEach(e -> {
- fileSearcher.result().stream()
- .filter(path -> path.getFileName().toString().indexOf("[" + e.getKey() + "]") > 0)
- .forEach(path -> {
- try {
- Path dir = path.getParent().resolve(e.getKey());
- if (!Files.exists(dir)) {
- System.err.println("mkdir " + dir);
- if (!dryRun) {
- Files.createDirectory(dir);
- }
- }
-
- System.err.println("mv " + path + " " + dir);
- if (!dryRun) {
- Files.move(path, dir.resolve(path.getFileName()));
- }
- } catch (IOException f) {
- throw new IllegalStateException(f);
- }
- });
- });
+ FileSystem fs;
- System.exit(0);
- }
+ Classification(String email) throws IOException {
- static class FileSearcher extends SimpleFileVisitor {
+ URI uri = URI.create("onedrive:///?id=" + email);
- private List list = new ArrayList<>();
+ fs = FileSystems.newFileSystem(uri, Collections.emptyMap());
+ }
+
+ void exec(String cwd) throws IOException {
+ Path root = fs.getPath(cwd);
+ Files.walkFileTree(root, new MyFileVisitor1());
+System.err.println("\ndone counting");
+ exec2();
+System.err.println("done");
+ }
- Pattern pattern = Pattern.compile("[ãããããĒã¯ãžããã]");
+ class MyFileVisitor1 extends SimpleFileVisitor {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attr) {
if (attr.isRegularFile()) {
- if (pattern.matcher(file.getParent().getFileName().toString()).matches()) {
- System.err.println(file);
- list.add(file);
+System.err.print(".");
+ if (filter1(file)) {
+ func1(file);
+ targets.add(file);
}
}
return CONTINUE;
}
+ }
- @Override
- public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
- return CONTINUE;
- }
+ static final Pattern pattern1 = Pattern.compile("[ãããããĒã¯ãžããã]");
- @Override
- public FileVisitResult visitFileFailed(Path file, IOException exc) {
- System.err.println(exc);
- return CONTINUE;
+ // novels parent is one of ka sa ta na ... only
+ boolean filter1(Path file) {
+ return pattern1.matcher(file.getParent().getFileName().toString()).matches();
+ }
+
+ static final Pattern pattern2 = Pattern.compile("\\[(.+?)\\]");
+
+ Map counter = new HashMap<>();
+
+ List targets = new ArrayList<>();
+
+ /** counter */
+ void func1(Path file) {
+ Matcher matcher = pattern2.matcher(file.getFileName().toString());
+ if (matcher.find()) {
+ String author = matcher.group(1);
+ if (counter.get(author) == null) {
+ counter.put(author, 1);
+ } else {
+ counter.put(author, counter.get(author) + 1);
+ }
}
+ }
- List result() {
- return list;
+ void exec2() {
+ targets.stream()
+ .forEach(file -> {
+ Matcher matcher = pattern2.matcher(file.getFileName().toString());
+ if (matcher.find()) {
+ func2(file, matcher.group(1));
+ }
+ });
+ }
+
+ /** */
+ void func2(Path file, String author) {
+ try {
+ if (counter.get(author) >= 3) {
+System.err.println("author " + author);
+ Path dir = file.getParent().resolve(author);
+ if (!Files.exists(dir)) {
+System.err.println("mkdir " + dir);
+ if (!dryRun) {
+ Files.createDirectory(dir);
+ }
+ }
+
+System.err.println("mv " + file + " " + dir);
+ if (!dryRun) {
+ Files.move(file, dir.resolve(file.getFileName()));
+ }
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
}
}
}
diff --git a/vavi-nio-file-sandbox/src/test/java/Classification2.java b/vavi-nio-file-sandbox/src/test/java/Classification2.java
index 0444c41b..8cf9b3d2 100644
--- a/vavi-nio-file-sandbox/src/test/java/Classification2.java
+++ b/vavi-nio-file-sandbox/src/test/java/Classification2.java
@@ -50,12 +50,12 @@ public final class Classification2 {
/**
* @param args 0: dir
*/
- public static void main(final String... args) throws IOException {
+ public static void main(String[] args) throws IOException {
String cwd = args[0];
boolean dryRun = true;
Path root = Paths.get(cwd);
- FileSearcher fileSearcher = new FileSearcher(root);
+ MyFileVisitor fileSearcher = new MyFileVisitor(root);
Files.walkFileTree(root, fileSearcher);
Pattern pattern = Pattern.compile("\\[(.+?)\\]");
fileSearcher.result().forEach(path -> {
@@ -124,7 +124,7 @@ private static String toKana(String text) throws IOException{
return sb.length() == 0 ? text : sb.toString();
}
- static class FileSearcher extends SimpleFileVisitor {
+ static class MyFileVisitor extends SimpleFileVisitor {
private List list = new ArrayList<>();
@@ -133,7 +133,7 @@ static class FileSearcher extends SimpleFileVisitor {
Pattern patternF = Pattern.compile("\\[(.+?)\\]");
Pattern patternD = Pattern.compile("[ãããããĒã¯ãžããã]");
- FileSearcher(Path root) {
+ MyFileVisitor(Path root) {
this.root = root;
}
@@ -161,12 +161,6 @@ public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
return CONTINUE;
}
- @Override
- public FileVisitResult visitFileFailed(Path file, IOException exc) {
- System.err.println(exc);
- return CONTINUE;
- }
-
List result() {
return list;
}
diff --git a/vavi-nio-file-sandbox/src/test/java/Classification3.java b/vavi-nio-file-sandbox/src/test/java/Classification3.java
index 84d1b055..a5e82a46 100644
--- a/vavi-nio-file-sandbox/src/test/java/Classification3.java
+++ b/vavi-nio-file-sandbox/src/test/java/Classification3.java
@@ -14,17 +14,12 @@
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Collections;
import java.util.List;
-import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import vavi.net.auth.oauth2.OAuth2AppCredential;
-import vavi.net.auth.oauth2.microsoft.MicrosoftLocalAppCredential;
import vavi.nio.file.Util;
-import vavi.nio.file.onedrive.OneDriveFileSystemProvider;
-import vavi.util.properties.annotation.PropsEntity;
import static java.nio.file.FileVisitResult.CONTINUE;
@@ -47,16 +42,10 @@ public static void main(final String... args) throws IOException {
URI uri = URI.create("onedrive:///?id=" + email);
- OAuth2AppCredential appCredential = new MicrosoftLocalAppCredential();
- PropsEntity.Util.bind(appCredential);
-
- Map env = new HashMap<>();
- env.put(OneDriveFileSystemProvider.ENV_APP_CREDENTIAL, appCredential);
-
- FileSystem onedrivefs = FileSystems.newFileSystem(uri, env);
+ FileSystem onedrivefs = FileSystems.newFileSystem(uri, Collections.emptyMap());
Path root = onedrivefs.getPath(cwd);
- FileSearcher fileSearcher = new FileSearcher();
+ MyFileVisitor fileSearcher = new MyFileVisitor();
Files.walkFileTree(root, fileSearcher);
Pattern pattern = Pattern.compile("\\[(.+?)\\]");
fileSearcher.result().stream()
@@ -82,11 +71,9 @@ public static void main(final String... args) throws IOException {
System.err.println(f);
}
});
-
- System.exit(0);
}
- static class FileSearcher extends SimpleFileVisitor {
+ static class MyFileVisitor extends SimpleFileVisitor {
private List list = new ArrayList<>();
@@ -103,17 +90,6 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attr) {
return CONTINUE;
}
- @Override
- public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
- return CONTINUE;
- }
-
- @Override
- public FileVisitResult visitFileFailed(Path file, IOException exc) {
- System.err.println(exc);
- return CONTINUE;
- }
-
public List result() {
return list;
}
diff --git a/vavi-nio-file-sandbox/src/test/java/CloserFinder.java b/vavi-nio-file-sandbox/src/test/java/CloserFinder.java
index d37b7e7b..c4d34540 100644
--- a/vavi-nio-file-sandbox/src/test/java/CloserFinder.java
+++ b/vavi-nio-file-sandbox/src/test/java/CloserFinder.java
@@ -14,16 +14,11 @@
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Collections;
import java.util.List;
-import java.util.Map;
-import vavi.net.auth.oauth2.OAuth2AppCredential;
-import vavi.net.auth.oauth2.microsoft.MicrosoftLocalAppCredential;
import vavi.nio.file.Util;
-import vavi.nio.file.onedrive.OneDriveFileSystemProvider;
import vavi.util.LevenshteinDistance;
-import vavi.util.properties.annotation.PropsEntity;
import static java.nio.file.FileVisitResult.CONTINUE;
@@ -39,22 +34,16 @@ public final class CloserFinder {
/**
* @param args 0: email, 1: dir
*/
- public static void main(final String... args) throws IOException {
+ public static void main(String[] args) throws IOException {
String email = args[0];
String cwd = args[1];
URI uri = URI.create("onedrive:///?id=" + email);
- OAuth2AppCredential appCredential = new MicrosoftLocalAppCredential();
- PropsEntity.Util.bind(appCredential);
-
- Map env = new HashMap<>();
- env.put(OneDriveFileSystemProvider.ENV_APP_CREDENTIAL, appCredential);
-
- FileSystem onedrivefs = FileSystems.newFileSystem(uri, env);
+ FileSystem onedrivefs = FileSystems.newFileSystem(uri, Collections.emptyMap());
Path root = onedrivefs.getPath(cwd);
- FileSearcher fileSearcher = new FileSearcher();
+ MyFileVisitor fileSearcher = new MyFileVisitor();
Files.walkFileTree(root, fileSearcher);
fileSearcher.result().parallelStream()
.forEach(path1 -> {
@@ -74,11 +63,9 @@ public static void main(final String... args) throws IOException {
}
});
});
-
- System.exit(0);
}
- static class FileSearcher extends SimpleFileVisitor {
+ static class MyFileVisitor extends SimpleFileVisitor {
private List list = new ArrayList<>();
@@ -90,17 +77,6 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attr) {
return CONTINUE;
}
- @Override
- public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
- return CONTINUE;
- }
-
- @Override
- public FileVisitResult visitFileFailed(Path file, IOException exc) {
- System.err.println(exc);
- return CONTINUE;
- }
-
public List result() {
return list;
}
diff --git a/vavi-nio-file-sandbox/src/test/java/Del.java b/vavi-nio-file-sandbox/src/test/java/Del.java
new file mode 100644
index 00000000..1840e68b
--- /dev/null
+++ b/vavi-nio-file-sandbox/src/test/java/Del.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+
+/**
+ * Del.
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/07/01 umjammer initial version
+ */
+public class Del {
+
+ public static void main(String[] args) throws Exception {
+
+ Path trash = Paths.get("./Trash");
+// Files.list(trash).forEach(p -> Sneaky.sneaked(Files::delete));
+ Files.list(trash).forEach(System.out::println);
+ }
+}
\ No newline at end of file
diff --git a/vavi-nio-file-sandbox/src/test/java/Descriptor.java b/vavi-nio-file-sandbox/src/test/java/Descriptor.java
new file mode 100644
index 00000000..721ac474
--- /dev/null
+++ b/vavi-nio-file-sandbox/src/test/java/Descriptor.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import vavix.util.screenscrape.annotation.JsonPathParser;
+import vavix.util.screenscrape.annotation.PlainInputHandler;
+import vavix.util.screenscrape.annotation.Target;
+import vavix.util.screenscrape.annotation.WebScraper;
+
+import static java.nio.file.FileVisitResult.CONTINUE;
+
+
+/**
+ * cloud drive description adder
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/09/08 umjammer initial version
+ * @see "https://manablog.org/google-books-apis/"
+ */
+public final class Descriptor {
+
+ /**
+ * @param args 0: email, 1: dir
+ */
+ public static void main(String[] args) throws IOException {
+ String email = args[0];
+ String cwd = args[1];
+
+ URI uri = URI.create("onedrive:///?id=" + email);
+
+ try (FileSystem fs = FileSystems.newFileSystem(uri, Collections.emptyMap())) {
+
+ Path root = fs.getPath(cwd);
+ MyFileVisitor fileSearcher = new MyFileVisitor();
+ Files.walkFileTree(root, fileSearcher);
+
+// String query = args[2];
+// Result result = query(query);
+//System.err.println(result);
+
+ }
+//Thread.getAllStackTraces().keySet().forEach(System.err::println);
+ }
+
+ @WebScraper(url = "https://www.googleapis.com/books/v1/volumes?q={0}",
+ parser = JsonPathParser.class,
+ input = PlainInputHandler.class,
+ value = "$..items",
+ isDebug = false,
+ isCollection = false)
+ public static class Result {
+ @Target(value = "$.volumeInfo.title")
+ String title;
+ @Target(value = "$.volumeInfo.authors", optional = true)
+ List authors;
+ @Target(value = "$.volumeInfo.publishedDate", optional = true)
+ String publishedDate;
+ @Target(value = "$.volumeInfo.description", optional = true)
+ String description;
+ @Target(value = "$.volumeInfo.industryIdentifiers[0].identifier", optional = true)
+ String isbn10;
+ @Target(value = "$.volumeInfo.industryIdentifiers[1].identifier", optional = true)
+ String isbn13;
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("Result [title=");
+ builder.append(title);
+ builder.append(", authors=");
+ builder.append(authors);
+ builder.append(", publishedDate=");
+ builder.append(publishedDate);
+ builder.append(", description=");
+ builder.append(description);
+ builder.append(", isbn10=");
+ builder.append(isbn10);
+ builder.append(", isbn13=");
+ builder.append(isbn13);
+ builder.append("]");
+ return builder.toString();
+ }
+ public String toFormatedString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append(authors == null ? "[]" : authors);
+ builder.append(" ");
+ builder.append(title);
+ builder.append("\n");
+ builder.append(publishedDate == null ? "" : publishedDate);
+ builder.append("\n");
+ if (isbn10 != null) {
+ builder.append(isbn10);
+ builder.append("\n");
+ }
+ if (isbn13 != null) {
+ builder.append(isbn13);
+ builder.append("\n");
+ }
+ builder.append("\n");
+ builder.append(description == null ? "" : description);
+ return builder.toString();
+ }
+ }
+
+ static Result query(String query) throws IOException {
+ return WebScraper.Util.scrape(Result.class, query).get(0);
+ }
+
+ static class MyFileVisitor extends SimpleFileVisitor {
+
+ static final Pattern pattern = Pattern.compile("^\\(ä¸čŦå°čĒŦ\\)\\s\\[(.+?)\\]\\s(.+?)(\\(.+?\\)){0,1}\\..+$");
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attr) {
+ if (attr.isRegularFile()) {
+ String filename = file.getFileName().toString();
+//System.err.println(filename);
+ Matcher matcher = pattern.matcher(filename);
+ if (matcher.find()) {
+//System.out.println(matcher.group(1) + " - " + matcher.group(2));
+ try {
+ byte[] bytes = (byte[]) Files.getAttribute(file, "user:description");
+ if (bytes == null || bytes.length == 0) {
+
+ Result result = query(matcher.group(1) + " " + matcher.group(2));
+ String description = result.toFormatedString();
+System.out.println(description + "\n\n");
+ Files.setAttribute(file, "user:description", description.getBytes());
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ return CONTINUE;
+ }
+ }
+}
diff --git a/vavi-nio-file-sandbox/src/test/java/EpubManipulator.java b/vavi-nio-file-sandbox/src/test/java/EpubManipulator.java
new file mode 100644
index 00000000..4f7b4ac4
--- /dev/null
+++ b/vavi-nio-file-sandbox/src/test/java/EpubManipulator.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2022 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URL;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.StandardOpenOption;
+import java.util.Collections;
+import java.util.List;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathFactory;
+
+import org.jdom2.JDOMException;
+import org.jdom2.filter.Filters;
+import org.jdom2.input.SAXBuilder;
+import org.jdom2.output.XMLOutputter;
+import org.jsoup.Jsoup;
+import org.jsoup.select.Elements;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.xml.sax.InputSource;
+
+import vavi.util.Debug;
+import vavi.xml.util.XPathDebugger;
+
+import net.sf.saxon.dom.DOMNodeList;
+import net.sf.saxon.dom.NodeOverNodeInfo;
+import net.sf.saxon.om.NodeInfo;
+
+
+/**
+ * EpubManipulator.
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2022/02/28 umjammer initial version
+ */
+public class EpubManipulator {
+
+ /**
+ * @param args dir
+ */
+ public static void main(String[] args) throws Exception {
+ EpubManipulator app = new EpubManipulator();
+ app.exec();
+ }
+
+ void exec() throws Exception {
+// Path src = Paths.get(Test1.class.getResource("/test.zip").toURI());
+
+ Path dir = Paths.get("tmp");
+// Files.createDirectories(dir);
+
+ Path target = dir.resolve("(ä¸čŦå°čĒŦ) [éĻŗæå¨] ããŗã´ãŧãģãŦã¤ãŗ (č§åˇæåēĢ).epub");
+// Files.copy(src, target, StandardCopyOption.REPLACE_EXISTING);
+ URI uri = URI.create("jar:" + target.toUri());
+Debug.println("uri: " + uri);
+
+ FileSystem fs = FileSystems.newFileSystem(uri, Collections.emptyMap());
+Debug.println("fs: " + fs.getClass().getName());
+
+// jsoup(fs);
+// jdom2(fs);
+ saxon(fs);
+
+ fs.close();
+ }
+
+ /**
+ * @see "https://www.ipentec.com/document/internet-get-amazon-product-image"
+ */
+ static String amazon(String asin) {
+ int countryCode = 9;
+ String imageType = "LZZZZZZZ";
+ return String.format("http://images-jp.amazon.com/images/P/%s.%02d.%s.jpg", asin, countryCode, imageType);
+ }
+
+ /**
+ * TODO jsoup doesn't handle attribute namespace
+ * @see "https://github.com/jhy/jsoup/pull/1682"
+ */
+ static void jsoup(FileSystem fs) throws IOException {
+
+ Path conatiner = fs.getPath("META-INF/container.xml");
+Debug.println(conatiner + ": " + Files.exists(conatiner));
+
+ org.jsoup.nodes.Document document = Jsoup.parse(Files.newInputStream(conatiner), "utf8", conatiner.toUri().toString());
+Debug.println("conatiner: " + document);
+ Elements elements = document.select("container > rootfiles > rootfile[full-path]");
+ org.jsoup.nodes.Element element = elements.first();
+ String fullPath = element.attr("full-path");
+Debug.println("full-path: " + fullPath);
+
+ Path content = fs.getPath(fullPath);
+ document = Jsoup.parse(Files.newInputStream(content), "utf8", conatiner.toUri().toString());
+Debug.println("content: " + document);
+
+ elements = document.select("dc|identifier[opfU00003Ascheme]");
+Debug.println("elements: " + elements);
+ element = elements.first();
+ String asin = element.ownText();
+Debug.println("asin: " + asin);
+ String url = amazon(asin);
+Debug.println("url: " + url);
+
+ Path out = fs.getPath("vavi", asin + ".jpg");
+ Files.copy(new URL(url).openStream(), out, StandardCopyOption.REPLACE_EXISTING);
+Debug.println("out: " + Files.size(out));
+ }
+
+ /** */
+ static void jdom2(FileSystem fs) throws IOException, JDOMException {
+
+ Path conatiner = fs.getPath("META-INF/container.xml");
+Debug.println(conatiner + ": " + Files.exists(conatiner));
+
+ SAXBuilder builder = new SAXBuilder();
+ org.jdom2.xpath.XPathFactory factory = org.jdom2.xpath.XPathFactory.instance();
+
+XPathDebugger.getEntryList(new InputSource(Files.newInputStream(conatiner))).forEach(System.err::println);
+
+ org.jdom2.Document document = builder.build(Files.newInputStream(conatiner));
+Debug.println("conatiner: " + new XMLOutputter().outputString(document));
+
+ org.jdom2.xpath.XPathExpression expression =
+ factory.compile("//*[local-name() = 'rootfile']", Filters.element());
+ org.jdom2.Element element = expression.evaluateFirst(document);
+Debug.println("element: " + element);
+ String fullPath = element.getAttributeValue("full-path");
+Debug.println("full-path: " + fullPath);
+
+ Path content = fs.getPath(fullPath);
+ document = builder.build(Files.newInputStream(content));
+Debug.println("content: " + document);
+
+ expression = factory.compile("//*[local-name() = 'identifier'][@*[local-name() = 'scheme']]", Filters.element());
+ element = expression.evaluateFirst(document);
+Debug.println("element: " + element);
+ String asin = element.getText();
+Debug.println("asin: " + asin);
+ String url = amazon(asin);
+Debug.println("url: " + url);
+
+ Path out = fs.getPath("vavi", asin + ".jpg");
+ Files.copy(new URL(url).openStream(), out, StandardCopyOption.REPLACE_EXISTING);
+Debug.println("out: " + Files.size(out));
+ }
+
+ /** */
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ static void saxon(FileSystem fs) throws Exception {
+
+ Path conatiner = fs.getPath("META-INF/container.xml");
+Debug.println(conatiner + ": " + Files.exists(conatiner));
+
+ System.setProperty(XPathFactory.DEFAULT_PROPERTY_NAME + ":" + XPathFactory.DEFAULT_OBJECT_MODEL_URI,
+ "net.sf.saxon.xpath.XPathFactoryImpl");
+ XPath xpath = XPathFactory.newInstance().newXPath();
+
+ InputSource is = new InputSource(Files.newInputStream(conatiner));
+//XPathDebugger.getEntryList(is).forEach(System.err::println);
+
+ List elements = (List) xpath.evaluate("//*[local-name() = 'rootfile']", is, XPathConstants.NODESET);
+ Element element = (Element) NodeOverNodeInfo.wrap(elements.get(0));
+Debug.println("element: " + element.getTagName());
+ String fullPath = element.getAttribute("full-path");
+Debug.println("full-path: " + fullPath);
+
+ Path content = fs.getPath(fullPath);
+ is = new InputSource(Files.newInputStream(content));
+//Debug.println("content: " + content);
+
+// System.setProperty("javax.xml.parsers.DocumentBuilderFactory", "net.sf.saxon.dom.DocumentBuilderFactoryImpl");
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ Document document = db.parse(new InputSource(Files.newInputStream(content)));
+
+ DOMNodeList elements2 = (DOMNodeList) xpath.evaluate("//*[local-name() = 'identifier'][@*[local-name() = 'scheme']]", document, XPathConstants.NODESET);
+ element = (Element) elements2.item(0);
+Debug.println("element: " + element.getTagName());
+ String asin = element.getTextContent();
+Debug.println("asin: " + asin);
+ String url = amazon(asin);
+Debug.println("url: " + url);
+
+ Path outDir = fs.getPath("vavi");
+ if (!Files.exists(outDir)) {
+ Files.createDirectory(outDir);
+ }
+ Path out = outDir.resolve(asin + ".jpg");
+ Files.copy(new URL(url).openStream(), out, StandardCopyOption.REPLACE_EXISTING);
+Debug.println("out: " + Files.size(out));
+
+ elements2 = (DOMNodeList) xpath.evaluate("//*[local-name() = 'manifest']/*[local-name() = 'item'][@*[local-name() = 'id']='cover']", document, XPathConstants.NODESET);
+ element = (Element) elements2.item(0);
+Debug.println("href:B: " + element.getAttribute("href"));
+ element.setAttribute("href", out.toString());
+Debug.println("href:A: " + element.getAttribute("href"));
+
+ TransformerFactory tf = TransformerFactory.newInstance();
+ Transformer transformer = tf.newTransformer();
+
+ DOMSource source = new DOMSource(document);
+ OutputStream os = Files.newOutputStream(content, StandardOpenOption.TRUNCATE_EXISTING);
+ StreamResult result = new StreamResult(os);
+ transformer.transform(source, result);
+ os.flush(); // needed
+ os.close(); // needed
+StreamResult result2 = new StreamResult(System.out);
+transformer.transform(source, result2);
+
+Debug.println("content: " + Files.size(content));
+ }
+}
+
+/* */
diff --git a/vavi-nio-file-sandbox/src/test/java/GoogleDriveThumbnail.java b/vavi-nio-file-sandbox/src/test/java/GoogleDriveThumbnail.java
new file mode 100644
index 00000000..a105706c
--- /dev/null
+++ b/vavi-nio-file-sandbox/src/test/java/GoogleDriveThumbnail.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 2022 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+import java.awt.image.BufferedImage;
+import java.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URL;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import javax.imageio.ImageIO;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathFactory;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+import vavi.awt.image.resample.FfmpegResampleOp;
+import vavi.util.Debug;
+
+import static java.nio.file.FileVisitResult.CONTINUE;
+
+
+/**
+ * GoogleDriveThumbnail.
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2022/01/26 umjammer initial version
+ */
+public class GoogleDriveThumbnail {
+
+ static byte[] duke;
+
+ static String string;
+ static String asin;
+
+ /**
+ * @param args dir
+ */
+ public static void main(String[] args) throws Exception {
+
+ String email = System.getenv("GOOGLE_TEST_ACCOUNT");
+
+ URI uri = URI.create("googledrive:///?id=" + email);
+ FileSystem fs = FileSystems.newFileSystem(uri, Collections.emptyMap());
+
+// String start = args[0];
+ String start = "/Books/Novels/ãããŽãã¤ã";
+ string = "09";
+ asin = "B00M98X8SM";
+
+// Files.createDirectories(Paths.get("tmp"));
+ duke = Files.readAllBytes(Paths.get(GoogleDriveThumbnail.class.getResource("/duke.jpg").toURI()));
+
+ Path dir = fs.getPath(start);
+ Files.walkFileTree(dir, new MyFileVisitor());
+
+ fs.close();
+ }
+
+ static class MyFileVisitor extends SimpleFileVisitor {
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attr) {
+ if (attr.isRegularFile()) {
+ try {
+ if (filter1(file)) {
+ func4(file);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ return CONTINUE;
+ }
+ }
+
+ // filters
+
+ static final String ext = ".epub";
+ static final Pattern pattern = Pattern.compile("^\\(ä¸čŦå°čĒŦ\\)\\s\\[(.+?)\\]\\s(.+?)\\" + ext + "$");
+
+ /** comic zip */
+ static boolean filter1(Path file) {
+ String filename = file.getFileName().toString();
+//System.err.println(filename);
+ Matcher matcher = pattern.matcher(filename);
+ if (matcher.find() && filename.contains(string)) {
+System.out.println(matcher.group(1) + " - " + matcher.group(2));
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ // functions
+
+ /** get thumbnail and save it to local */
+ static void func1(Path file) throws IOException {
+ byte[] bytes = (byte[]) Files.getAttribute(file, "user:thumbnail");
+ if (bytes != null && bytes.length != 0) {
+ String name = file.getFileName().toString().replace(".zip", ".jpg");
+System.err.println("output: " + name);
+ Path path = Paths.get("tmp", name);
+ Files.write(path, bytes);
+ } else {
+System.err.println("skip: " + file);
+ }
+ }
+
+
+ static final boolean DRY_RUN = false;
+ static final boolean OVERWRITE = true;
+
+// static final Pattern jpg = Pattern.compile("^.+?\\.jpg$");
+ static final Pattern jpg = Pattern.compile("^[\\w+\\/]+\\.jpe?g$");
+
+ /** extract self and set first jpg as a thumbnail */
+ static void func2(Path file) throws IOException {
+ // check existence
+ byte[] bytes = (byte[]) Files.getAttribute(file, "user:thumbnail");
+ if (!OVERWRITE && bytes != null && bytes.length != 0) {
+System.err.println("skip: " + file);
+ return;
+ }
+
+ // exec
+ ZipInputStream zis = new ZipInputStream(new BufferedInputStream(Files.newInputStream(file)));
+ ZipEntry entry;
+ List names = new ArrayList<>();
+ while ((entry = zis.getNextEntry()) != null) {
+ Matcher m = jpg.matcher(entry.getName());
+ if (m.matches()) {
+ names.add(entry.getName());
+ }
+ }
+
+ // determine cover
+ Collections.sort(names, (a, b) -> {
+ if (a.contains("cover") && !b.contains("cover")) {
+ return -1;
+ } else if (!a.contains("cover") && b.contains("cover")) {
+ return 1;
+ } else {
+ return a.compareTo(b);
+ }
+ });
+ if (names.size() == 0) {
+zis = new ZipInputStream(new BufferedInputStream(Files.newInputStream(file)));
+while ((entry = zis.getNextEntry()) != null) {
+ System.err.println(entry.getName());
+}
+Debug.print(Level.WARNING, "no images in: " + file);
+ return;
+ }
+ String name = names.get(0);
+
+ // extract image
+ zis = new ZipInputStream(new BufferedInputStream(Files.newInputStream(file)));
+
+ BufferedImage image = null;
+ while ((entry = zis.getNextEntry()) != null) {
+ if (name.equals(entry.getName())) {
+ image = ImageIO.read(zis);
+ break;
+ }
+ }
+
+ // resize image
+ double sx = 600d / image.getWidth();
+ BufferedImage thumbnail = new FfmpegResampleOp(sx, sx).filter(image, null);
+System.err.println(entry.getName() + ": " + thumbnail.getWidth() + "x" + thumbnail.getHeight());
+
+ // set image
+ if (DRY_RUN) {
+ Path path = Paths.get("tmp", file.getFileName().toString().replace(ext, ".jpg"));
+ ImageIO.write(thumbnail, "JPG", Files.newOutputStream(path));
+ } else {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ImageIO.write(thumbnail, "JPG", baos);
+ bytes = baos.toByteArray();
+ Files.setAttribute(file, "user:thumbnail", bytes);
+ }
+ }
+
+ /** set amazon thumbnail asin from self meta data */
+ static void func3(Path file) throws Exception {
+ // check existence
+ byte[] bytes = (byte[]) Files.getAttribute(file, "user:thumbnail");
+ if (!OVERWRITE && bytes != null && bytes.length != 0) {
+System.err.println("skip: " + file);
+ return;
+ }
+
+ // exec
+ Path gd = Paths.get("/Volumes/GoogleDrive/My Drive", file.toString());
+ URI uri = URI.create("jar:" + gd.toUri().toString());
+Debug.println("uri: " + uri);
+
+ FileSystem fs = FileSystems.newFileSystem(uri, Collections.emptyMap());
+Debug.println("fs: " + fs.getClass().getName());
+
+
+ Path conatiner = fs.getPath("META-INF/container.xml");
+Debug.println(conatiner + ": " + Files.exists(conatiner));
+
+ XPath xpath = XPathFactory.newInstance().newXPath();
+
+ InputSource is = new InputSource(Files.newInputStream(conatiner));
+
+ NodeList elements = (NodeList) xpath.evaluate("//*[local-name() = 'rootfile']", is, XPathConstants.NODESET);
+ Element element = (Element) elements.item(0);
+Debug.println("element: " + element.getTagName());
+ String fullPath = element.getAttribute("full-path");
+Debug.println("full-path: " + fullPath);
+
+ Path content = fs.getPath(fullPath);
+ is = new InputSource(Files.newInputStream(content));
+
+ is = new InputSource(Files.newInputStream(content));
+
+ elements = (NodeList) xpath.evaluate("//*[local-name() = 'identifier'][@*[local-name() = 'scheme']]", is, XPathConstants.NODESET);
+ element = (Element) elements.item(0);
+Debug.println("element: " + element.getTagName());
+ String asin = element.getTextContent();
+Debug.println("asin: " + asin);
+ String url = EpubManipulator.amazon(asin);
+Debug.println("url: " + url);
+
+
+ InputStream in = new BufferedInputStream(new URL(url).openStream());
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ byte[] buffer = new byte[8024];
+ int l = 0;
+ while ((l = in.read(buffer)) != -1) {
+ baos.write(buffer, 0, l);
+ }
+ bytes = baos.toByteArray();
+Debug.println("image: " + bytes.length);
+ if (bytes.length < 100) {
+ throw new IllegalStateException("no image in amazon? for: " + asin);
+ }
+
+
+ if (DRY_RUN) {
+ Path path = Paths.get("tmp", file.getFileName().toString().replace(ext, ".jpg"));
+ Files.write(path, bytes);
+ } else {
+ Files.setAttribute(file, "user:thumbnail", bytes);
+ }
+ }
+
+ /** set amazon thumbnail specify asin directly */
+ static void func4(Path file) throws Exception {
+ // check existence
+ byte[] bytes = (byte[]) Files.getAttribute(file, "user:thumbnail");
+ if (!OVERWRITE && bytes != null && bytes.length != 0) {
+System.err.println("skip: " + file);
+ return;
+ }
+
+ // exec
+Debug.println("asin: " + asin);
+ String url = EpubManipulator.amazon(asin);
+Debug.println("url: " + url);
+
+
+ InputStream in = new BufferedInputStream(new URL(url).openStream());
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ byte[] buffer = new byte[8024];
+ int l = 0;
+ while ((l = in.read(buffer)) != -1) {
+ baos.write(buffer, 0, l);
+ }
+ bytes = baos.toByteArray();
+Debug.println("image: " + bytes.length);
+ if (bytes.length < 100) {
+ throw new IllegalStateException("no image in amazon? for: " + asin);
+ }
+
+
+ if (DRY_RUN) {
+ Path path = Paths.get("tmp", file.getFileName().toString().replace(ext, ".jpg"));
+ Files.write(path, bytes);
+ } else {
+ Files.setAttribute(file, "user:thumbnail", bytes);
+ }
+ }
+}
+
+/* */
diff --git a/vavi-nio-file-sandbox/src/test/java/GoogleOCR.java b/vavi-nio-file-sandbox/src/test/java/GoogleOCR.java
index c845ff25..db7af70b 100644
--- a/vavi-nio-file-sandbox/src/test/java/GoogleOCR.java
+++ b/vavi-nio-file-sandbox/src/test/java/GoogleOCR.java
@@ -35,7 +35,7 @@ public final class GoogleOCR {
/**
* @param args 0: email, 1: zip file, 2: extract to dir, 3: extracted dir, 4: output ocr dir
*/
- public static void main(final String... args) {
+ public static void main(String[] args) {
int exitCode = 0;
try {
GoogleOCR app = new GoogleOCR();
@@ -61,7 +61,7 @@ FileSystem prepare(final String... args) throws IOException {
URI uri = URI.create("googledrive:///?id=" + email);
- return FileSystems.newFileSystem(uri, Collections.EMPTY_MAP);
+ return FileSystems.newFileSystem(uri, Collections.emptyMap());
}
/**
diff --git a/vavi-nio-file-sandbox/src/test/java/Main8.java b/vavi-nio-file-sandbox/src/test/java/Main8.java
new file mode 100644
index 00000000..a67bfbe4
--- /dev/null
+++ b/vavi-nio-file-sandbox/src/test/java/Main8.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+import java.nio.file.FileSystems;
+import java.nio.file.Paths;
+import java.nio.file.WatchEvent;
+import java.nio.file.WatchEvent.Kind;
+import java.nio.file.WatchKey;
+import java.nio.file.WatchService;
+import java.nio.file.Watchable;
+
+import vavi.util.Debug;
+
+import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
+
+
+/**
+ * WatchService.
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2020/07/01 umjammer initial version
+ */
+public class Main8 {
+
+ public static void main(String[] args) throws Exception {
+ WatchService watcher = FileSystems.getDefault().newWatchService();
+
+ Watchable path = Paths.get("./tmp");
+ path.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
+
+ while (true) {
+ WatchKey watchKey = watcher.take();
+
+ for (WatchEvent> event : watchKey.pollEvents()) {
+ Kind> kind = event.kind();
+ Object context = event.context();
+Debug.println("kind: " + kind + ", context: " + context);
+ }
+
+ if (!watchKey.reset()) {
+ System.out.println("WatchKey has reset");
+ return;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/vavi-nio-file-sandbox/src/test/java/MavenRepoCleaner.java b/vavi-nio-file-sandbox/src/test/java/MavenRepoCleaner.java
new file mode 100644
index 00000000..3cdc6f71
--- /dev/null
+++ b/vavi-nio-file-sandbox/src/test/java/MavenRepoCleaner.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2021 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+import java.io.IOException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.util.stream.StreamSupport;
+
+import vavi.util.Debug;
+
+import static com.rainerhahnekamp.sneakythrow.Sneaky.sneaked;
+import static java.nio.file.FileVisitResult.CONTINUE;
+
+
+/**
+ * maven repo cleaner.
+ *
+ * fu*king eclipse content assist leaves half way named junk files and folders
+ * in the repository.
+ *
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2021/11/12 umjammer initial version
+ */
+public class MavenRepoCleaner {
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args) throws IOException {
+ Files.walkFileTree(Paths.get(System.getProperty("user.home"), ".m2/repository"), new MyFileVisitor());
+Debug.println("Done");
+ }
+
+ static class MyFileVisitor extends SimpleFileVisitor {
+
+ @Override
+ public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
+ try {
+ long c1 = Files.list(dir).count();
+
+ DirectoryStream iterable = Files.newDirectoryStream(dir, "*.lastUpdated");
+ long c2 = StreamSupport.stream(iterable.spliterator(), false).count();
+ iterable.close();
+
+ iterable = Files.newDirectoryStream(dir, ".DS_Store");
+ long c3 = StreamSupport.stream(iterable.spliterator(), false).count();
+ iterable.close();
+
+ iterable = Files.newDirectoryStream(dir, "resolver-status.properties");
+ long c4 = StreamSupport.stream(iterable.spliterator(), false).count();
+ iterable.close();
+
+ if (c1 == 0) {
+ // no files
+ System.out.println("DIR0: " + dir);
+
+ Files.delete(dir);
+ } else if (c1 == c2) {
+ // only eclipse files
+ System.out.println("DIR1: " + dir);
+
+ Files.list(dir).forEach(sneaked(Files::delete));
+ Files.delete(dir);
+ } else if (c1 == c2 + c4) {
+ // only eclipse files 2
+ System.out.println("DIR2: " + dir);
+
+ Files.list(dir).forEach(sneaked(Files::delete));
+ Files.delete(dir);
+ } else if (c1 == c3) {
+ // only mac files
+ System.out.println("DIRX " + dir);
+
+ Files.list(dir).forEach(sneaked(Files::delete));
+ Files.delete(dir);
+ }
+ } catch (IOException e) {
+ System.err.println("ERROR: " + dir + ", " + e.getMessage());
+ }
+ return CONTINUE;
+ }
+ }
+}
\ No newline at end of file
diff --git a/vavi-nio-file-sandbox/src/test/java/Renamer.java b/vavi-nio-file-sandbox/src/test/java/Renamer.java
index e27e7427..a829a2f7 100644
--- a/vavi-nio-file-sandbox/src/test/java/Renamer.java
+++ b/vavi-nio-file-sandbox/src/test/java/Renamer.java
@@ -29,7 +29,7 @@ public final class Renamer {
/**
* @param args 0: dir, 1: regex, 2: replacement
*/
- public static void main(final String... args) throws IOException {
+ public static void main(String[] args) throws IOException {
String cwd = args[0];
String regex = args[1];
String replacement = args[2];
diff --git a/vavi-nio-file-sandbox/src/test/java/ShowEmptyFolder.java b/vavi-nio-file-sandbox/src/test/java/ShowEmptyFolder.java
new file mode 100644
index 00000000..05769b87
--- /dev/null
+++ b/vavi-nio-file-sandbox/src/test/java/ShowEmptyFolder.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2021 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.DirectoryStream;
+import java.nio.file.FileSystem;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Collections;
+import java.util.stream.StreamSupport;
+
+import vavi.nio.file.googledrive.GoogleDriveFileSystemProvider;
+import vavi.util.Debug;
+
+import static com.rainerhahnekamp.sneakythrow.Sneaky.sneaked;
+import static java.nio.file.FileVisitResult.CONTINUE;
+
+
+/**
+ * apply something to filtered folders
+ *
+ * @author Naohide Sano (umjammer)
+ * @version 0.00 2021/10/30 umjammer initial version
+ */
+public class ShowEmptyFolder {
+
+ public static void main(String[] args) throws IOException {
+ ShowEmptyFolder app = new ShowEmptyFolder();
+ app.exec(args);
+ }
+
+ void exec(String[] args) throws IOException {
+ String email = System.getenv("GOOGLE_TEST_ACCOUNT");
+
+ URI uri = URI.create("googledrive:///?id=" + email);
+ FileSystem fs = new GoogleDriveFileSystemProvider().newFileSystem(uri, Collections.emptyMap());
+
+ Files.walkFileTree(fs.getPath("/Music/midi"), new MyFileVisitor());
+
+ fs.close();
+Debug.println("Done");
+ }
+
+ class MyFileVisitor extends SimpleFileVisitor {
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attr) {
+ return CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
+ try {
+ if (filter2(dir)) {
+ func2(dir);
+ }
+ } catch (IOException e) {
+ System.err.println("ERROR: " + dir + ", " + e.getMessage());
+ }
+ return CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFileFailed(Path file, IOException exc) {
+ System.err.println(exc);
+ return CONTINUE;
+ }
+ }
+
+ boolean filter1(Path path) throws IOException {
+ return Files.list(path).count() == 0;
+ }
+
+ boolean filter2(Path path) throws IOException {
+ long c1 = Files.list(path).count();
+
+ DirectoryStream iterable = Files.newDirectoryStream(path, ".DS_Store");
+ long c3 = StreamSupport.stream(iterable.spliterator(), false).count();
+ iterable.close();
+
+ if (c1 == 0) {
+ System.out.println("DIR0: " + path);
+ return true;
+ } else if (c1 == c3) {
+ System.out.println("DIR1X " + path);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ void func1(Path path) throws IOException {
+ System.out.println("DIR0: " + path);
+ }
+
+ void func2(Path path) throws IOException {
+ Files.list(path).forEach(sneaked(Files::delete));
+ Files.delete(path);
+ }
+}
\ No newline at end of file
diff --git a/vavi-nio-file-sandbox/src/test/java/Synchronizer.java b/vavi-nio-file-sandbox/src/test/java/Synchronizer.java
index 4125a2cf..39d9a9a5 100644
--- a/vavi-nio-file-sandbox/src/test/java/Synchronizer.java
+++ b/vavi-nio-file-sandbox/src/test/java/Synchronizer.java
@@ -15,15 +15,10 @@
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Collections;
import java.util.List;
-import java.util.Map;
-import vavi.net.auth.oauth2.OAuth2AppCredential;
-import vavi.net.auth.oauth2.microsoft.MicrosoftLocalAppCredential;
import vavi.nio.file.Util;
-import vavi.nio.file.onedrive.OneDriveFileSystemProvider;
-import vavi.util.properties.annotation.PropsEntity;
import static java.nio.file.FileVisitResult.CONTINUE;
@@ -39,7 +34,7 @@ public final class Synchronizer {
/**
* @param args 0: dir, 1: dir1, 2: dir2
*/
- public static void main(final String... args) throws IOException {
+ public static void main(String[] args) throws IOException {
String email = args[0];
String cwd1 = args[1];
String cwd2 = args[2];
@@ -47,22 +42,16 @@ public static void main(final String... args) throws IOException {
URI uri = URI.create("onedrive:///?id=" + email);
- OAuth2AppCredential appCredential = new MicrosoftLocalAppCredential();
- PropsEntity.Util.bind(appCredential);
-
- Map env = new HashMap<>();
- env.put(OneDriveFileSystemProvider.ENV_APP_CREDENTIAL, appCredential);
-
- FileSystem onedrivefs = FileSystems.newFileSystem(uri, env);
+ FileSystem onedrivefs = FileSystems.newFileSystem(uri, Collections.emptyMap());
// onedrive
Path root1 = onedrivefs.getPath(cwd1);
- FileSearcher fileSearcher1 = new FileSearcher();
+ MyFileVisitor fileSearcher1 = new MyFileVisitor();
Files.walkFileTree(root1, fileSearcher1);
// local
Path root2 = Paths.get(cwd2);
- FileSearcher fileSearcher2 = new FileSearcher();
+ MyFileVisitor fileSearcher2 = new MyFileVisitor();
Files.walkFileTree(root2, fileSearcher2);
fileSearcher2.result().parallelStream()
@@ -83,11 +72,9 @@ public static void main(final String... args) throws IOException {
throw new IllegalStateException(e);
}
});
-
- System.exit(0);
}
- static class FileSearcher extends SimpleFileVisitor {
+ static class MyFileVisitor extends SimpleFileVisitor {
private List list = new ArrayList<>();
diff --git a/vavi-nio-file-sandbox/src/test/java/Test1.java b/vavi-nio-file-sandbox/src/test/java/Test1.java
index 44798ae5..5f485b0c 100644
--- a/vavi-nio-file-sandbox/src/test/java/Test1.java
+++ b/vavi-nio-file-sandbox/src/test/java/Test1.java
@@ -4,15 +4,36 @@
* Programmed by Naohide Sano
*/
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystemNotFoundException;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.attribute.UserDefinedFileAttributeView;
+import java.util.Collections;
+import java.util.List;
+
+import org.jdom2.filter.Filters;
+import org.jdom2.input.SAXBuilder;
+import org.jdom2.xpath.XPathExpression;
+import org.jdom2.xpath.XPathFactory;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable;
+
+import vavi.util.Debug;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
/**
- * Test.
+ * Test1.
*
* @author Naohide Sano (umjammer)
* @version 0.00 2016/02/27 umjammer initial version
@@ -34,7 +55,7 @@ public void test() {
public void test2() {
SecurityManager security = System.getSecurityManager();
if (security == null) {
- System.err.println("no security manager");
+Debug.println("no security manager");
return;
}
try {
@@ -46,7 +67,7 @@ public void test2() {
@Test
void test01() {
- System.out.printf("file: %1$s, %2$tF %2$tT.%2$tL, %3$d\n", "a", System.currentTimeMillis(), 1);
+Debug.printf("file: %1$s, %2$tF %2$tT.%2$tL, %3$d\n", "a", System.currentTimeMillis(), 1);
}
@Test
@@ -55,6 +76,76 @@ void test04() {
long o = Long.parseLong(m.substring(9, m.length() - 1));
assertEquals(123456L, o);
}
+
+ @Test
+ void test05() throws Exception {
+ Path path = Paths.get("/");
+ boolean r = Files.getFileStore(path).supportsFileAttributeView(UserDefinedFileAttributeView.class);
+Debug.println("support user attr view: " + r);
+ }
+
+ @Test
+ @DisabledIfEnvironmentVariable(named = "GITHUB_WORKFLOW", matches = ".*")
+ void test06() throws Exception {
+ Path path = Paths.get("/Volumes/GoogleDrive/Books/Comics");
+ UserDefinedFileAttributeView userDefinedFAView = Files.getFileAttributeView(path, UserDefinedFileAttributeView.class);
+ if (userDefinedFAView != null) {
+ List attributes = userDefinedFAView.list();
+attributes.forEach(Debug::println);
+ }
+ }
+
+ @SuppressWarnings("restriction")
+ @Test
+ void test07() throws Exception {
+ Path src = Paths.get(Test1.class.getResource("/test.zip").toURI());
+ Path dir = Paths.get("tmp");
+ Files.createDirectories(dir);
+ Path target = dir.resolve(src.getFileName());
+ Files.copy(src, target, StandardCopyOption.REPLACE_EXISTING);
+ URI uri = URI.create("jar:" + target.toUri());
+Debug.println("uri: " + uri);
+ assertThrows(FileSystemNotFoundException.class, () -> {
+ // first time uri is not instance of ZipPath
+ // cause not found
+ // @see "https://stackoverflow.com/a/25033217"
+ FileSystems.getFileSystem(uri);
+ });
+
+ FileSystem fs = FileSystems.newFileSystem(uri, Collections.emptyMap());
+Debug.println("fs: " + fs.getClass().getName());
+ assertInstanceOf(com.sun.nio.zipfs.ZipFileSystem.class, fs);
+
+ // why second time pass test?
+ fs = FileSystems.getFileSystem(uri);
+Debug.println("fs: " + fs.getClass().getName());
+ assertInstanceOf(com.sun.nio.zipfs.ZipFileSystem.class, fs);
+ }
+
+ @Test
+ void test08() throws Exception {
+ SAXBuilder builder = new SAXBuilder();
+ XPathFactory factory = XPathFactory.instance();
+ Path p = Paths.get(Test1.class.getResource("/log4j2.xml").toURI());
+ org.jdom2.Document document = builder.build(Files.newInputStream(p));
+Debug.println("conatiner: " + document);
+
+ XPathExpression expression =
+ factory.compile("/Configuration", Filters.element());
+ org.jdom2.Element element = expression.evaluateFirst(document);
+Debug.println("element: " + element);
+ assertEquals("Configuration", element.getName());
+
+ expression = factory.compile("/Configuration/Loggers/Root/AppenderRef", Filters.element());
+ element = expression.evaluateFirst(document);
+Debug.println("element: " + element);
+ assertEquals("AppenderRef", element.getName());
+
+ expression = factory.compile("*", Filters.element());
+ element = expression.evaluateFirst(document);
+Debug.println("element: " + element);
+ assertEquals("Configuration", element.getName());
+ }
}
/* */
diff --git a/vavi-nio-file-sandbox/src/test/java/Test5.java b/vavi-nio-file-sandbox/src/test/java/Test5.java
index f40238f1..3bba4c79 100644
--- a/vavi-nio-file-sandbox/src/test/java/Test5.java
+++ b/vavi-nio-file-sandbox/src/test/java/Test5.java
@@ -23,9 +23,8 @@
*/
public class Test5 {
- // TODO doesn't work
@Test
- @Disabled
+ @Disabled("doesn't work")
public void test01() throws Exception {
// String email = System.getenv("TEST5_GOOGLE_ACCOUNT");
String mp = System.getenv("TEST5_GOOGLE_MOUNT_POINT");
diff --git a/vavi-nio-file-sandbox/src/test/java/TestAozora.java b/vavi-nio-file-sandbox/src/test/java/TestAozora.java
index 2d625cb4..921ea63e 100644
--- a/vavi-nio-file-sandbox/src/test/java/TestAozora.java
+++ b/vavi-nio-file-sandbox/src/test/java/TestAozora.java
@@ -41,7 +41,7 @@ public static void main(String[] args) throws Exception {
//result.forEach(System.err::println);
Path root = Paths.get(cwd);
- FileSearcher fileSearcher = new FileSearcher();
+ MyFileVisitor fileSearcher = new MyFileVisitor();
Files.walkFileTree(root, fileSearcher);
fileSearcher.result().stream().filter(path -> {
final String name = path.getFileName().toString();
@@ -75,7 +75,7 @@ public String getAuthor() {
}
}
- static class FileSearcher extends SimpleFileVisitor {
+ static class MyFileVisitor extends SimpleFileVisitor {
private List list = new ArrayList<>();
diff --git a/vavi-nio-file-sandbox/src/test/java/TestNbt.java b/vavi-nio-file-sandbox/src/test/java/TestNbt.java
deleted file mode 100644
index c777636e..00000000
--- a/vavi-nio-file-sandbox/src/test/java/TestNbt.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (c) 2019 by Naohide Sano, All rights reserved.
- *
- * Programmed by Naohide Sano
- */
-
-import java.io.IOException;
-
-import com.google.gson.GsonBuilder;
-import com.google.gson.JsonParser;
-
-import net.querz.nbt.NBTUtil;
-import net.querz.nbt.Tag;
-
-
-/**
- * TestNbt.
- *
- * @author Naohide Sano (umjammer)
- * @version 0.00 2019/07/08 umjammer initial version
- */
-public class TestNbt {
-
- /**
- * @param args
- */
- public static void main(String[] args) throws IOException {
- Tag> tag = NBTUtil.readTag(args[0]);
- System.out.println(new GsonBuilder().setPrettyPrinting().create().toJson(new JsonParser().parse(tag.toString())));
- }
-}
-
-/* */
diff --git a/vavi-nio-file-sandbox/src/test/java/vavi/nio/file/watch/WatchServiceTest.java b/vavi-nio-file-sandbox/src/test/java/vavi/nio/file/watch/WatchServiceTest.java
new file mode 100644
index 00000000..39db84d9
--- /dev/null
+++ b/vavi-nio-file-sandbox/src/test/java/vavi/nio/file/watch/WatchServiceTest.java
@@ -0,0 +1,546 @@
+package vavi.nio.file.watch;
+/*
+ * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 4313887 6838333 7017446 8011537 8042470
+ * @summary Unit test for java.nio.file.WatchService
+ * @library ..
+ * @run main Basic
+ */
+
+
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URI;
+import java.nio.file.ClosedWatchServiceException;
+import java.nio.file.FileSystem;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.nio.file.StandardWatchEventKinds;
+import java.nio.file.WatchEvent;
+import java.nio.file.WatchKey;
+import java.nio.file.WatchService;
+import java.util.Collections;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
+import vavi.nio.file.googledrive.GoogleDriveFileSystemProvider;
+
+import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
+import static java.nio.file.StandardWatchEventKinds.OVERFLOW;
+import static vavi.nio.file.Base.removeTree;
+
+
+/**
+ * Unit test for WatchService that exercises all methods in various scenarios.
+ */
+@Disabled
+public class WatchServiceTest {
+
+ void checkKey(WatchKey key, Path dir) {
+ if (!key.isValid())
+ throw new RuntimeException("Key is not valid");
+ if (key.watchable() != dir)
+ throw new RuntimeException("Unexpected watchable");
+ }
+
+ void takeExpectedKey(WatchService watcher, WatchKey expected) {
+ System.out.println("take events...");
+ WatchKey key;
+ try {
+ key = watcher.take();
+ } catch (InterruptedException x) {
+ // not expected
+ throw new RuntimeException(x);
+ }
+ if (key != expected)
+ throw new RuntimeException("removed unexpected key");
+ }
+
+ void checkExpectedEvent(Iterable> events,
+ WatchEvent.Kind> expectedKind,
+ Object expectedContext)
+ {
+ WatchEvent> event = events.iterator().next();
+ System.out.format("got event: type=%s, count=%d, context=%s\n",
+ event.kind(), event.count(), event.context());
+ if (event.kind() != expectedKind)
+ throw new RuntimeException("unexpected event");
+ if (!expectedContext.equals(event.context()))
+ throw new RuntimeException("unexpected context");
+ }
+
+ static FileSystem fs;
+
+ /**
+ * Simple test of each of the standard events
+ */
+ @Test
+ void testEvents() throws IOException {
+ System.out.println("-- Standard Events --");
+
+ Path name = fs.getPath("foo");
+
+ try (WatchService watcher = fs.newWatchService()) {
+ // --- ENTRY_CREATE ---
+
+ // register for event
+ System.out.format("register %s for ENTRY_CREATE\n", dir);
+ WatchKey myKey = dir.register(watcher,
+ new WatchEvent.Kind>[]{ ENTRY_CREATE });
+ checkKey(myKey, dir);
+
+ // create file
+ Path file = dir.resolve("foo");
+ System.out.format("create %s\n", file);
+ Files.createFile(file);
+
+ // remove key and check that we got the ENTRY_CREATE event
+ takeExpectedKey(watcher, myKey);
+ checkExpectedEvent(myKey.pollEvents(),
+ StandardWatchEventKinds.ENTRY_CREATE, name);
+
+ System.out.println("reset key");
+ if (!myKey.reset())
+ throw new RuntimeException("key has been cancalled");
+
+ System.out.println("OKAY");
+
+ // --- ENTRY_DELETE ---
+
+ System.out.format("register %s for ENTRY_DELETE\n", dir);
+ WatchKey deleteKey = dir.register(watcher,
+ new WatchEvent.Kind>[]{ ENTRY_DELETE });
+ if (deleteKey != myKey)
+ throw new RuntimeException("register did not return existing key");
+ checkKey(deleteKey, dir);
+
+ System.out.format("delete %s\n", file);
+ Files.delete(file);
+ takeExpectedKey(watcher, myKey);
+ checkExpectedEvent(myKey.pollEvents(),
+ StandardWatchEventKinds.ENTRY_DELETE, name);
+
+ System.out.println("reset key");
+ if (!myKey.reset())
+ throw new RuntimeException("key has been cancalled");
+
+ System.out.println("OKAY");
+
+ // create the file for the next test
+ Files.createFile(file);
+
+ // --- ENTRY_MODIFY ---
+
+ System.out.format("register %s for ENTRY_MODIFY\n", dir);
+ WatchKey newKey = dir.register(watcher,
+ new WatchEvent.Kind>[]{ ENTRY_MODIFY });
+ if (newKey != myKey)
+ throw new RuntimeException("register did not return existing key");
+ checkKey(newKey, dir);
+
+ System.out.format("update: %s\n", file);
+ try (OutputStream out = Files.newOutputStream(file, StandardOpenOption.APPEND)) {
+ out.write("I am a small file".getBytes("UTF-8"));
+ }
+
+ // remove key and check that we got the ENTRY_MODIFY event
+ takeExpectedKey(watcher, myKey);
+ checkExpectedEvent(myKey.pollEvents(),
+ StandardWatchEventKinds.ENTRY_MODIFY, name);
+ System.out.println("OKAY");
+
+ // done
+ Files.delete(file);
+ }
+ }
+
+ /**
+ * Check that a cancelled key will never be queued
+ */
+ @Test
+ void testCancel() throws IOException {
+ System.out.println("-- Cancel --");
+
+ try (WatchService watcher = fs.newWatchService()) {
+
+ System.out.format("register %s for events\n", dir);
+ WatchKey myKey = dir.register(watcher,
+ new WatchEvent.Kind>[]{ ENTRY_CREATE });
+ checkKey(myKey, dir);
+
+ System.out.println("cancel key");
+ myKey.cancel();
+
+ // create a file in the directory
+ Path file = dir.resolve("mars");
+ System.out.format("create: %s\n", file);
+ Files.createFile(file);
+
+ // poll for keys - there will be none
+ System.out.println("poll...");
+ try {
+ WatchKey key = watcher.poll(3000, TimeUnit.MILLISECONDS);
+ if (key != null)
+ throw new RuntimeException("key should not be queued");
+ } catch (InterruptedException x) {
+ throw new RuntimeException(x);
+ }
+
+ // done
+ Files.delete(file);
+
+ System.out.println("OKAY");
+ }
+ }
+
+ /**
+ * Check that deleting a registered directory causes the key to be
+ * cancelled and queued.
+ */
+ @Test
+ void testAutomaticCancel() throws IOException {
+ System.out.println("-- Automatic Cancel --");
+
+ Path subdir = Files.createDirectory(dir.resolve("bar"));
+
+ try (WatchService watcher = fs.newWatchService()) {
+
+ System.out.format("register %s for events\n", subdir);
+ WatchKey myKey = subdir.register(watcher,
+ new WatchEvent.Kind>[]{ ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY });
+
+ System.out.format("delete: %s\n", subdir);
+ Files.delete(subdir);
+ takeExpectedKey(watcher, myKey);
+
+ System.out.println("reset key");
+ if (myKey.reset())
+ throw new RuntimeException("Key was not cancelled");
+ if (myKey.isValid())
+ throw new RuntimeException("Key is still valid");
+
+ System.out.println("OKAY");
+
+ }
+ }
+
+ /**
+ * Asynchronous close of watcher causes blocked threads to wakeup
+ */
+ @Test
+ void testWakeup() throws IOException {
+ System.out.println("-- Wakeup Tests --");
+ final WatchService watcher = fs.newWatchService();
+ Runnable r = new Runnable() {
+ public void run() {
+ try {
+ Thread.sleep(5000);
+ System.out.println("close WatchService...");
+ watcher.close();
+ } catch (InterruptedException x) {
+ x.printStackTrace();
+ } catch (IOException x) {
+ x.printStackTrace();
+ }
+ }
+ };
+
+ // start thread to close watch service after delay
+ new Thread(r).start();
+
+ try {
+ System.out.println("take...");
+ watcher.take();
+ throw new RuntimeException("ClosedWatchServiceException not thrown");
+ } catch (InterruptedException x) {
+ throw new RuntimeException(x);
+ } catch (ClosedWatchServiceException x) {
+ System.out.println("ClosedWatchServiceException thrown");
+ }
+
+ System.out.println("OKAY");
+ }
+
+ /**
+ * Simple test to check exceptions and other cases
+ */
+ @Test
+ void testExceptions() throws IOException {
+ System.out.println("-- Exceptions and other simple tests --");
+
+ WatchService watcher = fs.newWatchService();
+ try {
+
+ // Poll tests
+
+ WatchKey key;
+ System.out.println("poll...");
+ key = watcher.poll();
+ if (key != null)
+ throw new RuntimeException("no keys registered");
+
+ System.out.println("poll with timeout...");
+ try {
+ long start = System.nanoTime();
+ key = watcher.poll(3000, TimeUnit.MILLISECONDS);
+ if (key != null)
+ throw new RuntimeException("no keys registered");
+ long waited = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
+ if (waited < 2900)
+ throw new RuntimeException("poll was too short");
+ } catch (InterruptedException x) {
+ throw new RuntimeException(x);
+ }
+
+ // IllegalArgumentException
+ System.out.println("IllegalArgumentException tests...");
+ try {
+ dir.register(watcher /*empty event list*/);
+ throw new RuntimeException("IllegalArgumentException not thrown");
+ } catch (IllegalArgumentException x) {
+ }
+ try {
+ // OVERFLOW is ignored so this is equivalent to the empty set
+ dir.register(watcher, OVERFLOW);
+ throw new RuntimeException("IllegalArgumentException not thrown");
+ } catch (IllegalArgumentException x) {
+ }
+ try {
+ // OVERFLOW is ignored even if specified multiple times
+ dir.register(watcher, OVERFLOW, OVERFLOW);
+ throw new RuntimeException("IllegalArgumentException not thrown");
+ } catch (IllegalArgumentException x) {
+ }
+
+ // UnsupportedOperationException
+ try {
+ dir.register(watcher,
+ new WatchEvent.Kind() {
+ @Override public String name() { return "custom"; }
+ @Override public Class type() { return Object.class; }
+ });
+ throw new RuntimeException("UnsupportedOperationException not thrown");
+ } catch (UnsupportedOperationException x) {
+ }
+ try {
+ dir.register(watcher,
+ new WatchEvent.Kind>[]{ ENTRY_CREATE },
+ new WatchEvent.Modifier() {
+ @Override public String name() { return "custom"; }
+ });
+ throw new RuntimeException("UnsupportedOperationException not thrown");
+ } catch (UnsupportedOperationException x) {
+ }
+
+ // NullPointerException
+ System.out.println("NullPointerException tests...");
+ try {
+ dir.register(null, ENTRY_CREATE);
+ throw new RuntimeException("NullPointerException not thrown");
+ } catch (NullPointerException x) {
+ }
+ try {
+ dir.register(watcher, new WatchEvent.Kind>[]{ null });
+ throw new RuntimeException("NullPointerException not thrown");
+ } catch (NullPointerException x) {
+ }
+ try {
+ dir.register(watcher, new WatchEvent.Kind>[]{ ENTRY_CREATE },
+ (WatchEvent.Modifier)null);
+ throw new RuntimeException("NullPointerException not thrown");
+ } catch (NullPointerException x) {
+ }
+ } finally {
+ watcher.close();
+ }
+
+ // -- ClosedWatchServiceException --
+
+ System.out.println("ClosedWatchServiceException tests...");
+
+ try {
+ watcher.poll();
+ throw new RuntimeException("ClosedWatchServiceException not thrown");
+ } catch (ClosedWatchServiceException x) {
+ }
+
+ // assume that poll throws exception immediately
+ long start = System.nanoTime();
+ try {
+ watcher.poll(10000, TimeUnit.MILLISECONDS);
+ throw new RuntimeException("ClosedWatchServiceException not thrown");
+ } catch (InterruptedException x) {
+ throw new RuntimeException(x);
+ } catch (ClosedWatchServiceException x) {
+ long waited = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
+ if (waited > 5000)
+ throw new RuntimeException("poll was too long");
+ }
+
+ try {
+ watcher.take();
+ throw new RuntimeException("ClosedWatchServiceException not thrown");
+ } catch (InterruptedException x) {
+ throw new RuntimeException(x);
+ } catch (ClosedWatchServiceException x) {
+ }
+
+ try {
+ dir.register(watcher, new WatchEvent.Kind>[]{ ENTRY_CREATE });
+ throw new RuntimeException("ClosedWatchServiceException not thrown");
+ } catch (ClosedWatchServiceException x) {
+ }
+
+ System.out.println("OKAY");
+ }
+
+ /**
+ * Test that directory can be registered with more than one watch service
+ * and that events don't interfere with each other
+ */
+ @Test
+ void testTwoWatchers() throws IOException {
+ System.out.println("-- Two watchers test --");
+
+ WatchService watcher1 = fs.newWatchService();
+ WatchService watcher2 = fs.newWatchService();
+ try {
+ Path name1 = fs.getPath("gus1");
+ Path name2 = fs.getPath("gus2");
+
+ // create gus1
+ Path file1 = dir.resolve(name1);
+ System.out.format("create %s\n", file1);
+ Files.createFile(file1);
+
+ // register with both watch services (different events)
+ System.out.println("register for different events");
+ WatchKey key1 = dir.register(watcher1,
+ new WatchEvent.Kind>[]{ ENTRY_CREATE });
+ WatchKey key2 = dir.register(watcher2,
+ new WatchEvent.Kind>[]{ ENTRY_DELETE });
+
+ if (key1 == key2)
+ throw new RuntimeException("keys should be different");
+
+ // create gus2
+ Path file2 = dir.resolve(name2);
+ System.out.format("create %s\n", file2);
+ Files.createFile(file2);
+
+ // check that key1 got ENTRY_CREATE
+ takeExpectedKey(watcher1, key1);
+ checkExpectedEvent(key1.pollEvents(),
+ StandardWatchEventKinds.ENTRY_CREATE, name2);
+
+ // check that key2 got zero events
+ WatchKey key = watcher2.poll();
+ if (key != null)
+ throw new RuntimeException("key not expected");
+
+ // delete gus1
+ Files.delete(file1);
+
+ // check that key2 got ENTRY_DELETE
+ takeExpectedKey(watcher2, key2);
+ checkExpectedEvent(key2.pollEvents(),
+ StandardWatchEventKinds.ENTRY_DELETE, name1);
+
+ // check that key1 got zero events
+ key = watcher1.poll();
+ if (key != null)
+ throw new RuntimeException("key not expected");
+
+ // reset for next test
+ key1.reset();
+ key2.reset();
+
+ // change registration with watcher2 so that they are both
+ // registered for the same event
+ System.out.println("register for same event");
+ key2 = dir.register(watcher2, new WatchEvent.Kind>[]{ ENTRY_CREATE });
+
+ // create file and key2 should be queued
+ System.out.format("create %s\n", file1);
+ Files.createFile(file1);
+ takeExpectedKey(watcher2, key2);
+ checkExpectedEvent(key2.pollEvents(),
+ StandardWatchEventKinds.ENTRY_CREATE, name1);
+
+ System.out.println("OKAY");
+
+ } finally {
+ watcher2.close();
+ watcher1.close();
+ }
+ }
+
+ /**
+ * Test that thread interruped status is preserved upon a call
+ * to register()
+ */
+ @Test
+ void testThreadInterrupt() throws IOException {
+ System.out.println("-- Thread interrupted status test --");
+
+ Thread curr = Thread.currentThread();
+ try (WatchService watcher = fs.newWatchService()) {
+ System.out.println("interrupting current thread");
+ curr.interrupt();
+ dir.register(watcher, ENTRY_CREATE);
+ if (!curr.isInterrupted())
+ throw new RuntimeException("thread should remain interrupted");
+ System.out.println("current thread is still interrupted");
+ System.out.println("OKAY");
+ } finally {
+ Thread.interrupted();
+ }
+ }
+
+ static Path dir;
+
+ @BeforeAll
+ static void before() throws IOException {
+ String email = System.getenv("GOOGLE_TEST_ACCOUNT");
+
+ URI uri = URI.create("googledrive:///?id=" + email);
+ fs = new GoogleDriveFileSystemProvider().newFileSystem(uri, Collections.EMPTY_MAP);
+
+ dir = Files.createTempDirectory(fs.getRootDirectories().iterator().next(), "VAVIFUSE-TEST-WATCHSERVICE");
+ }
+
+ @AfterAll
+ static void after() throws Exception {
+ removeTree(dir);
+ }
+}
diff --git a/vavi-nio-file-sandbox/src/test/resources/duke.jpg b/vavi-nio-file-sandbox/src/test/resources/duke.jpg
new file mode 100644
index 00000000..3402f12e
Binary files /dev/null and b/vavi-nio-file-sandbox/src/test/resources/duke.jpg differ
diff --git a/vavi-nio-file-sandbox/src/test/resources/log4j.properties b/vavi-nio-file-sandbox/src/test/resources/log4j.properties
index b46df5a7..44b4ae61 100644
--- a/vavi-nio-file-sandbox/src/test/resources/log4j.properties
+++ b/vavi-nio-file-sandbox/src/test/resources/log4j.properties
@@ -1,9 +1,3 @@
-#
-# Copyright (c) 2004 by Naohide Sano, All rights reserved.
-#
-# Written by Naohide Sano
-#
-
#
# ALL, DEBUG, INFO, WARN, ERROR, FATAL and OFF
#
diff --git a/vavi-nio-file-sandbox/src/test/resources/log4j2.xml b/vavi-nio-file-sandbox/src/test/resources/log4j2.xml
index daa4f7f6..22f2742d 100644
--- a/vavi-nio-file-sandbox/src/test/resources/log4j2.xml
+++ b/vavi-nio-file-sandbox/src/test/resources/log4j2.xml
@@ -7,7 +7,7 @@
-
+
diff --git a/vavi-nio-file-sandbox/src/test/resources/logging.properties b/vavi-nio-file-sandbox/src/test/resources/logging.properties
index 0a62dc8f..32c1270b 100644
--- a/vavi-nio-file-sandbox/src/test/resources/logging.properties
+++ b/vavi-nio-file-sandbox/src/test/resources/logging.properties
@@ -12,5 +12,7 @@ java.util.logging.ConsoleHandler.level=INFO
java.util.logging.ConsoleHandler.formatter=vavi.util.logging.VaviFormatter
#java.util.logging.ConsoleHandler.formatter=vavi.util.logging.BetterFormatter
+vavi.nio.file.onedrive4.graph.MyLogger.level=OFF
#com.box.sdk.level=ALL
+#vavi.level=OFF
diff --git a/vavi-nio-file-sandbox/src/test/resources/test.zip b/vavi-nio-file-sandbox/src/test/resources/test.zip
new file mode 100644
index 00000000..8fcb7600
Binary files /dev/null and b/vavi-nio-file-sandbox/src/test/resources/test.zip differ
diff --git a/vavi-nio-file-vfs/pom.xml b/vavi-nio-file-vfs/pom.xml
index 6c67b6a2..dd12d64c 100644
--- a/vavi-nio-file-vfs/pom.xml
+++ b/vavi-nio-file-vfs/pom.xml
@@ -4,7 +4,7 @@
vavi-apps-fuse
vavi
- 0.1.6
+ 0.1.7
vavi-nio-file-vfs
@@ -42,7 +42,7 @@
- com.github.umjammer.vavi-net-auth
+ ${vavi-net-auth.groupId}
vavi-net-auth-common
${vavi-net-auth.version}
@@ -51,31 +51,33 @@
org.apache.commons
commons-vfs2
- 2.6.0
+ 2.9.0
+
org.apache.commons
commons-vfs2-jackrabbit2
- 2.6.0
+ 2.9.0
- jcifs
- jcifs
- 1.3.17
-
-
com.jcraft
jsch
0.1.55
+
- commons-httpclient
- commons-httpclient
- 3.1
+ com.github.vbauer
+ commons-vfs2-cifs
+ 1.2.0
-
+ com.github.mikhasd
+ commons-vfs2-smb
+ 1.0.0
+
+
+
org.junit.jupiter
junit-jupiter-api
test
@@ -93,7 +95,6 @@
org.junit.jupiter
junit-jupiter-params
- 5.3.0
test
@@ -123,8 +124,8 @@
org.slf4j
- slf4j-log4j12
- 1.7.2
+ slf4j-jdk14
+ 1.7.5
test
diff --git a/vavi-nio-file-vfs/src/main/java/vavi/net/auth/proprietary/vfs/SftpVfsAuthenticator.java b/vavi-nio-file-vfs/src/main/java/vavi/net/auth/proprietary/vfs/SftpVfsAuthenticator.java
index ba8bc1ff..aae32272 100644
--- a/vavi-nio-file-vfs/src/main/java/vavi/net/auth/proprietary/vfs/SftpVfsAuthenticator.java
+++ b/vavi-nio-file-vfs/src/main/java/vavi/net/auth/proprietary/vfs/SftpVfsAuthenticator.java
@@ -9,6 +9,7 @@
import java.io.File;
import java.io.IOException;
import java.net.URI;
+import java.time.Duration;
import java.util.Map;
import java.util.NoSuchElementException;
@@ -145,8 +146,8 @@ public FileSystemOptions authorize(VfsCredential credential) throws IOException
FileSystemOptions options = new FileSystemOptions();
SftpFileSystemConfigBuilder builder = SftpFileSystemConfigBuilder.getInstance();
builder.setUserDirIsRoot(options, false);
- builder.setConnectTimeoutMillis(options, 30000);
- builder.setSessionTimeoutMillis(options, 30000);
+ builder.setConnectTimeout(options, Duration.ofMillis(30000));
+ builder.setSessionTimeout(options, Duration.ofMillis(30000));
builder.setUserInfo(options, new SftpUserInfo(pkc ? c.passphrase : c.password, pkc));
if (pkc) {
builder.setIdentityProvider(options, new IdentityInfo(new File(c.keyPath)));
diff --git a/vavi-nio-file-vfs/src/main/java/vavi/nio/file/vfs/VfsFileAttributesFactory.java b/vavi-nio-file-vfs/src/main/java/vavi/nio/file/vfs/VfsFileAttributesFactory.java
index eec4bfa7..688455d0 100644
--- a/vavi-nio-file-vfs/src/main/java/vavi/nio/file/vfs/VfsFileAttributesFactory.java
+++ b/vavi-nio-file-vfs/src/main/java/vavi/nio/file/vfs/VfsFileAttributesFactory.java
@@ -8,7 +8,7 @@
import org.apache.commons.vfs2.FileObject;
-import com.github.fge.filesystem.attributes.FileAttributesFactory;
+import com.github.fge.filesystem.driver.ExtendedFileSystemDriverBase.ExtendsdFileAttributesFactory;
/**
@@ -17,7 +17,7 @@
* @author Naohide Sano (umjammer)
* @version 0.00 2016/04/06 umjammer initial version
*/
-public final class VfsFileAttributesFactory extends FileAttributesFactory {
+public final class VfsFileAttributesFactory extends ExtendsdFileAttributesFactory {
public VfsFileAttributesFactory() {
setMetadataClass(FileObject.class);
diff --git a/vavi-nio-file-vfs/src/main/java/vavi/nio/file/vfs/VfsFileStore.java b/vavi-nio-file-vfs/src/main/java/vavi/nio/file/vfs/VfsFileStore.java
index 7018ed72..e530239c 100644
--- a/vavi-nio-file-vfs/src/main/java/vavi/nio/file/vfs/VfsFileStore.java
+++ b/vavi-nio-file-vfs/src/main/java/vavi/nio/file/vfs/VfsFileStore.java
@@ -26,7 +26,7 @@
*/
public final class VfsFileStore extends FileStoreBase {
- private final FileObject root; // TODO
+ private final FileObject root; // TODO how to get quota
/**
* Constructor
diff --git a/vavi-nio-file-vfs/src/main/java/vavi/nio/file/vfs/VfsFileSystemDriver.java b/vavi-nio-file-vfs/src/main/java/vavi/nio/file/vfs/VfsFileSystemDriver.java
index a289dbf6..35e800e2 100644
--- a/vavi-nio-file-vfs/src/main/java/vavi/nio/file/vfs/VfsFileSystemDriver.java
+++ b/vavi-nio-file-vfs/src/main/java/vavi/nio/file/vfs/VfsFileSystemDriver.java
@@ -9,26 +9,17 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.nio.file.AccessDeniedException;
-import java.nio.file.AccessMode;
import java.nio.file.CopyOption;
-import java.nio.file.DirectoryNotEmptyException;
-import java.nio.file.DirectoryStream;
-import java.nio.file.FileAlreadyExistsException;
import java.nio.file.FileStore;
import java.nio.file.NoSuchFileException;
-import java.nio.file.NotDirectoryException;
import java.nio.file.OpenOption;
import java.nio.file.Path;
-import java.nio.file.StandardCopyOption;
-import java.nio.file.attribute.FileAttribute;
-import java.nio.file.spi.FileSystemProvider;
-import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.stream.Collectors;
-import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.apache.commons.vfs2.FileObject;
@@ -36,8 +27,7 @@
import org.apache.commons.vfs2.FileSystemOptions;
import org.apache.commons.vfs2.Selectors;
-import com.github.fge.filesystem.driver.ExtendedFileSystemDriverBase;
-import com.github.fge.filesystem.exceptions.IsDirectoryException;
+import com.github.fge.filesystem.driver.ExtendedFileSystemDriver;
import com.github.fge.filesystem.provider.FileSystemFactoryProvider;
import vavi.nio.file.Util;
@@ -54,40 +44,53 @@
* @version 0.00 2016/03/30 umjammer initial version
*/
@ParametersAreNonnullByDefault
-public final class VfsFileSystemDriver extends ExtendedFileSystemDriverBase {
+public final class VfsFileSystemDriver extends ExtendedFileSystemDriver {
private final FileSystemManager manager;
private final FileSystemOptions opts;
- private boolean ignoreAppleDouble = false;
-
private final String baseUrl;
/**
* @param env { "baseUrl": "smb://10.3.1.1/Temporary Share/", "ignoreAppleDouble": boolean }
*/
- @SuppressWarnings("unchecked")
- public VfsFileSystemDriver(final FileStore fileStore,
- final FileSystemFactoryProvider provider,
- final FileSystemManager manager,
- final FileSystemOptions options,
+ public VfsFileSystemDriver(FileStore fileStore,
+ FileSystemFactoryProvider provider,
+ FileSystemManager manager,
+ FileSystemOptions options,
String baseUrl,
- final Map env) throws IOException {
+ Map env) throws IOException {
+
super(fileStore, provider);
+
+ setEnv(env);
+
this.manager = manager;
this.opts = options;
- ignoreAppleDouble = (Boolean) ((Map) env).getOrDefault("ignoreAppleDouble", Boolean.FALSE);
+
//System.err.println("ignoreAppleDouble: " + ignoreAppleDouble);
this.baseUrl = baseUrl;
}
- /**
- * VFS might have cache?
- * @see #ignoreAppleDouble
- * @throws NoSuchFileException apple double file
- */
- private FileObject getEntry(Path path) throws IOException {
+ @Override
+ protected String getFilenameString(FileObject entry) {
+ return entry.getName().getBaseName();
+ }
+
+ @Override
+ protected boolean isFolder(FileObject entry) throws IOException {
+ return entry.isFolder();
+ }
+
+ @Override
+ protected boolean exists(FileObject entry) throws IOException {
+ return entry.exists();
+ }
+
+ // VFS might have cache?
+ @Override
+ protected FileObject getEntry(Path path) throws IOException {
return getEntry(path, true);
}
@@ -95,13 +98,13 @@ private FileObject getEntry(Path path) throws IOException {
* @param check check existence of the path
*/
private FileObject getEntry(Path path, boolean check) throws IOException {
-//System.err.println("path: " + path);
+//Debug.println(Level.FINE, "path: " + path);
if (ignoreAppleDouble && path.getFileName() != null && isAppleDouble(path)) {
throw new NoSuchFileException("ignore apple double file: " + path);
}
FileObject entry = manager.resolveFile(baseUrl + toPathString(path), opts);
-//System.err.println("entry: " + entry + ", " + entry.exists());
+//Debug.println(Level.FINE, "entry: " + entry + ", " + entry.exists());
if (check) {
if (entry.exists()) {
return entry;
@@ -113,226 +116,68 @@ private FileObject getEntry(Path path, boolean check) throws IOException {
}
}
- @Nonnull
@Override
- public InputStream newInputStream(final Path path, final Set extends OpenOption> options) throws IOException {
- final FileObject entry = getEntry(path);
-
- if (entry.isFolder()) {
- throw new IsDirectoryException(path.toString());
- }
-
+ protected InputStream downloadEntry(FileObject entry, Path path, Set extends OpenOption> options) throws IOException {
return entry.getContent().getInputStream(Util.BUFFER_SIZE);
}
- @Nonnull
@Override
- public OutputStream newOutputStream(final Path path, final Set extends OpenOption> options) throws IOException {
- final FileObject entry = getEntry(path, false);
-
- if (entry.exists()) {
- if (entry.isFolder()) {
- throw new IsDirectoryException(path.toString());
- } else {
- throw new FileAlreadyExistsException(path.toString());
- }
- } else {
- entry.createFile();
- }
-
- return entry.getContent().getOutputStream(Util.BUFFER_SIZE);
+ protected OutputStream uploadEntry(FileObject parentEntry, Path path, Set extends OpenOption> options) throws IOException {
+ FileObject targetEntry = getEntry(path, false);
+ targetEntry.createFile();
+ return targetEntry.getContent().getOutputStream(Util.BUFFER_SIZE);
}
- @Nonnull
- @Override
- public DirectoryStream newDirectoryStream(final Path dir,
- final DirectoryStream.Filter super Path> filter) throws IOException {
- return Util.newDirectoryStream(getDirectoryEntries(dir), filter);
+ /** */
+ protected List getDirectoryEntries(FileObject dirEntry, Path dir) throws IOException {
+//System.err.println("path: " + dir);
+//Arrays.stream(dirEntry.getChildren()).forEach(System.err::println);
+ return Arrays.stream(dirEntry.getChildren()).collect(Collectors.toList());
}
@Override
- public void createDirectory(final Path dir, final FileAttribute>... attrs) throws IOException {
+ protected FileObject createDirectoryEntry(FileObject parentEntry, Path dir) throws IOException {
FileObject dirEntry = getEntry(dir, false);
- if (dirEntry.exists()) {
- throw new FileAlreadyExistsException(dir.toString());
- }
-
dirEntry.createFolder();
+ return dirEntry;
}
@Override
- public void delete(final Path path) throws IOException {
- removeEntry(path);
+ protected boolean hasChildren(FileObject dirEntry, Path dir) throws IOException {
+ return dirEntry.getChildren().length > 0;
}
@Override
- public void copy(final Path source, final Path target, final Set options) throws IOException {
- FileObject targetEntry = getEntry(target, false);
- if (targetEntry.exists()) {
- if (options != null && options.stream().anyMatch(o -> o.equals(StandardCopyOption.REPLACE_EXISTING))) {
- removeEntry(target);
- } else {
- throw new FileAlreadyExistsException(target.toString());
- }
+ protected void removeEntry(FileObject entry, Path path) throws IOException {
+ if (!entry.delete()) {
+ throw new IOException("delete failed: " + path);
}
- copyEntry(source, target);
}
@Override
- public void move(final Path source, final Path target, final Set options) throws IOException {
+ protected FileObject copyEntry(FileObject sourceEntry, FileObject targetParentEntry, Path source, Path target, Set options) throws IOException {
FileObject targetEntry = getEntry(target, false);
- if (targetEntry.exists()) {
- if (targetEntry.isFolder()) {
- if (options != null && options.stream().anyMatch(o -> o.equals(StandardCopyOption.REPLACE_EXISTING))) {
- // replace the target
- if (targetEntry.getChildren().length > 0) {
- throw new DirectoryNotEmptyException(target.toString());
- } else {
- removeEntry(target);
- moveEntry(source, target, false);
- }
- } else {
- // move into the target
- // TODO SPEC is FileAlreadyExistsException ?
- moveEntry(source, target, true);
- }
- } else {
- if (options != null && options.stream().anyMatch(o -> o.equals(StandardCopyOption.REPLACE_EXISTING))) {
- removeEntry(target);
- moveEntry(source, target, false);
- } else {
- throw new FileAlreadyExistsException(target.toString());
- }
- }
- } else {
- if (source.getParent().equals(target.getParent())) {
- // rename
- renameEntry(source, target);
- } else {
- moveEntry(source, target, false);
- }
- }
+ targetEntry.copyFrom(sourceEntry, Selectors.SELECT_ALL);
+ return targetEntry;
}
- /**
- * Check access modes for a path on this filesystem
- *
- * If no modes are provided to check for, this simply checks for the
- * existence of the path.
- *
- *
- * @param path the path to check
- * @param modes the modes to check for, if any
- * @throws IOException filesystem level error, or a plain I/O error if you
- * use this with javafs (jnr-fuse), you should throw
- * {@link NoSuchFileException} when the file not found.
- * @see FileSystemProvider#checkAccess(Path, AccessMode...)
- */
@Override
- protected void checkAccessImpl(final Path path, final AccessMode... modes) throws IOException {
- final FileObject entry = getEntry(path);
-
- if (entry.isFolder()) {
- return;
- }
-
- // TODO: assumed; not a file == directory
- for (final AccessMode mode : modes) {
- if (mode == AccessMode.EXECUTE) {
- throw new AccessDeniedException(path.toString());
- }
- }
+ protected FileObject moveEntry(FileObject sourceEntry, FileObject targetParentEntry, Path source, Path target, boolean targetIsParent) throws IOException {
+ FileObject targetEntry = getEntry(targetIsParent ? target.resolve(toFilenameString(source)) : target, false);
+ sourceEntry.moveTo(targetEntry);
+ return targetEntry;
}
@Override
- public void close() throws IOException {
- // don't close the manager here, it will shutdown whole resources.
- // https://issues.apache.org/jira/browse/VFS-454
+ protected FileObject moveFolderEntry(FileObject sourceEntry, FileObject targetParentEntry, Path source, Path target, boolean targetIsParent) throws IOException {
+ return moveEntry(sourceEntry, targetParentEntry, source, target, targetIsParent);
}
- /**
- * @throws IOException if you use this with javafs (jnr-fuse), you should
- * throw {@link NoSuchFileException} when the file not found.
- */
- @Nonnull
@Override
- protected Object getPathMetadataImpl(final Path path) throws IOException {
- return getEntry(path);
- }
-
- /** */
- private List getDirectoryEntries(final Path dir) throws IOException {
- final FileObject entry = getEntry(dir);
-
- if (!entry.isFolder()) {
- throw new NotDirectoryException(dir.toString());
- }
-
- List list = null;
- final FileObject[] children = entry.getChildren();
- list = new ArrayList<>(children.length);
-
- for (final FileObject child : children) {
- Path childPath = dir.resolve(child.getName().getBaseName());
- list.add(childPath);
- }
-
- return list;
+ protected FileObject renameEntry(FileObject sourceEntry, FileObject targetParentEntry, Path source, Path target) throws IOException {
+ return moveEntry(sourceEntry, targetParentEntry, source, target, false);
}
- /** */
- private void removeEntry(Path path) throws IOException {
- final FileObject entry = getEntry(path);
-
- if (entry.isFolder()) {
- final FileObject[] list = entry.getChildren();
-
- if (list.length > 0) {
- throw new DirectoryNotEmptyException(path.toString());
- }
- }
-
- if (!entry.delete()) {
- throw new IOException("delete: " + path);
- }
- }
-
- /** */
- private void copyEntry(final Path source, final Path target) throws IOException {
- FileObject targetEntry = getEntry(target, false);
- FileObject sourceEntry = getEntry(source);
-
- if (sourceEntry.isFile()) {
- targetEntry.copyFrom(sourceEntry, Selectors.SELECT_ALL);
- } else if (sourceEntry.isFolder()) {
- // TODO java spec. allows empty folder
- throw new IsDirectoryException(source.toString());
- }
- }
-
- /**
- * @param targetIsParent if the target is folder
- */
- private void moveEntry(final Path source, final Path target, boolean targetIsParent) throws IOException {
- FileObject sourceEntry = getEntry(source);
- FileObject targetEntry = getEntry(targetIsParent ? target.resolve(toFilenameString(source)) : target, false);
-
- if (sourceEntry.isFile()) {
- sourceEntry.moveTo(targetEntry);
- } else if (sourceEntry.isFolder()) {
- sourceEntry.moveTo(targetEntry);
- }
- }
-
- /** */
- private void renameEntry(final Path source, final Path target) throws IOException {
- FileObject sourceEntry = getEntry(source);
- FileObject targetEntry = getEntry(target, false);
-
- if (sourceEntry.isFile()) {
- sourceEntry.moveTo(targetEntry);
- } else if (sourceEntry.isFolder()) {
- throw new IsDirectoryException(source.toString());
- }
- }
+ // don't close the manager here, it will shutdown whole resources.
+ // https://issues.apache.org/jira/browse/VFS-454
}
diff --git a/vavi-nio-file-vfs/src/main/java/vavi/nio/file/vfs/VfsFileSystemRepository.java b/vavi-nio-file-vfs/src/main/java/vavi/nio/file/vfs/VfsFileSystemRepository.java
index 13dc1b37..3b3504b5 100644
--- a/vavi-nio-file-vfs/src/main/java/vavi/nio/file/vfs/VfsFileSystemRepository.java
+++ b/vavi-nio-file-vfs/src/main/java/vavi/nio/file/vfs/VfsFileSystemRepository.java
@@ -67,10 +67,10 @@ public FileSystemDriver createDriver(final URI uri, final Map env) th
Debug.println("baseUrl: " + baseUrl);
FileSystemManager manager = VFS.getManager();
-//for (String scheme : manager.getSchemes()) {
-// System.err.println("scheme: " + scheme);
-//}
if (!manager.hasProvider(protocol)) {
+for (String scheme : manager.getSchemes()) {
+ System.err.println("scheme: " + scheme);
+}
throw new IllegalStateException("missing provider: " + protocol);
}
diff --git a/vavi-nio-file-vfs/src/test/java/vavi/nio/file/vfs/Main2.java b/vavi-nio-file-vfs/src/test/java/vavi/nio/file/vfs/Main2.java
index 1187d2b4..0ae6b02e 100644
--- a/vavi-nio-file-vfs/src/test/java/vavi/nio/file/vfs/Main2.java
+++ b/vavi-nio-file-vfs/src/test/java/vavi/nio/file/vfs/Main2.java
@@ -44,7 +44,7 @@ void test01() throws Exception {
URI uri = URI.create(String.format("vfs:sftp://%s@%s%s?keyPath=%s&passphrase=%s", username, host, path, keyPath, passPhrase));
- FileSystem fs = new VfsFileSystemProvider().newFileSystem(uri, Collections.EMPTY_MAP);
+ FileSystem fs = new VfsFileSystemProvider().newFileSystem(uri, Collections.emptyMap());
testLargeFile(fs, null);
}
diff --git a/vavi-nio-file-vfs/src/test/java/vavi/nio/file/vfs/Main3.java b/vavi-nio-file-vfs/src/test/java/vavi/nio/file/vfs/Main3.java
index 524690c6..63840ba5 100644
--- a/vavi-nio-file-vfs/src/test/java/vavi/nio/file/vfs/Main3.java
+++ b/vavi-nio-file-vfs/src/test/java/vavi/nio/file/vfs/Main3.java
@@ -44,7 +44,7 @@ void test01() throws Exception {
URI uri = URI.create(String.format("vfs:sftp://%s@%s%s?keyPath=%s&passphrase=%s", username, host, path, keyPath, passPhrase));
- FileSystem fs = new VfsFileSystemProvider().newFileSystem(uri, Collections.EMPTY_MAP);
+ FileSystem fs = new VfsFileSystemProvider().newFileSystem(uri, Collections.emptyMap());
testMoveFolder(fs);
}
diff --git a/vavi-nio-file-vfs/src/test/java/vavi/nio/file/vfs/TestVfs.java b/vavi-nio-file-vfs/src/test/java/vavi/nio/file/vfs/TestVfs.java
index 67241317..48271043 100644
--- a/vavi-nio-file-vfs/src/test/java/vavi/nio/file/vfs/TestVfs.java
+++ b/vavi-nio-file-vfs/src/test/java/vavi/nio/file/vfs/TestVfs.java
@@ -1,10 +1,11 @@
-package vavi.nio.file.vfs;
/*
* Copyright (c) 2016 by Naohide Sano, All rights reserved.
*
* Programmed by Naohide Sano
*/
+package vavi.nio.file.vfs;
+
import java.io.IOException;
import java.net.URI;
diff --git a/vavi-nio-file-vfs/src/test/java/vavi/nio/file/vfs/TestVfsSftp.java b/vavi-nio-file-vfs/src/test/java/vavi/nio/file/vfs/TestVfsSftp.java
index f48a84a7..234f5cda 100644
--- a/vavi-nio-file-vfs/src/test/java/vavi/nio/file/vfs/TestVfsSftp.java
+++ b/vavi-nio-file-vfs/src/test/java/vavi/nio/file/vfs/TestVfsSftp.java
@@ -7,6 +7,7 @@
import java.io.File;
import java.io.IOException;
+import java.time.Duration;
import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemManager;
@@ -82,7 +83,7 @@ void proceed() throws IOException {
FileSystemOptions options = new FileSystemOptions();
// SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(options, "no");
SftpFileSystemConfigBuilder.getInstance().setUserDirIsRoot(options, false);
- SftpFileSystemConfigBuilder.getInstance().setSessionTimeoutMillis(options, 10000);
+ SftpFileSystemConfigBuilder.getInstance().setSessionTimeout(options, Duration.ofMillis(10000));
SftpFileSystemConfigBuilder.getInstance().setUserInfo(options, new SftpPassphraseUserInfo(passphrase));
SftpFileSystemConfigBuilder.getInstance().setIdentityProvider(options, new IdentityInfo(new File(keyPath)));
FileSystemManager fs = VFS.getManager();
diff --git a/vavi-nio-file-vfs/src/test/java/vavi/nio/file/vfs/TestVfsSftp2.java b/vavi-nio-file-vfs/src/test/java/vavi/nio/file/vfs/TestVfsSftp2.java
index f81173ed..4078781a 100644
--- a/vavi-nio-file-vfs/src/test/java/vavi/nio/file/vfs/TestVfsSftp2.java
+++ b/vavi-nio-file-vfs/src/test/java/vavi/nio/file/vfs/TestVfsSftp2.java
@@ -6,6 +6,7 @@
*/
import java.io.IOException;
+import java.time.Duration;
import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemManager;
@@ -78,7 +79,7 @@ void proceed() throws IOException {
FileSystemOptions options = new FileSystemOptions();
// SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(options, "no");
SftpFileSystemConfigBuilder.getInstance().setUserDirIsRoot(options, false);
- SftpFileSystemConfigBuilder.getInstance().setSessionTimeoutMillis(options, 10000);
+ SftpFileSystemConfigBuilder.getInstance().setSessionTimeout(options, Duration.ofMillis(10000));
SftpFileSystemConfigBuilder.getInstance().setUserInfo(options, new SftpPasswordUserInfo(passphrase));
FileSystemManager fs = VFS.getManager();
if (!fs.hasProvider("sftp"))
diff --git a/vavi-nio-file-vfs/src/test/java/vavi/nio/file/vfs/TestVfsWebdav.java b/vavi-nio-file-vfs/src/test/java/vavi/nio/file/vfs/TestVfsWebdav.java
index 6f76c946..76cce34f 100644
--- a/vavi-nio-file-vfs/src/test/java/vavi/nio/file/vfs/TestVfsWebdav.java
+++ b/vavi-nio-file-vfs/src/test/java/vavi/nio/file/vfs/TestVfsWebdav.java
@@ -1,10 +1,11 @@
-package vavi.nio.file.vfs;
/*
* Copyright (c) 2016 by Naohide Sano, All rights reserved.
*
* Programmed by Naohide Sano
*/
+package vavi.nio.file.vfs;
+
import java.io.IOException;
import java.net.URLEncoder;
@@ -66,7 +67,7 @@ void proceed() throws IOException {
//System.err.println(smbFile.exists() + " " + smbFile.getContent().getLastModifiedTime());
if (davFile.isFolder()) {
for (FileObject fo : davFile.getChildren()) {
-System.err.println(fo.getName()); // TODO æååã
+System.err.println(fo.getName()); // TODO garbled text
}
}
}