Skip to content

Commit

Permalink
Cloud Storage Java 7 nio library
Browse files Browse the repository at this point in the history
This is an import of previous work which was reviewed internally.
  • Loading branch information
jart committed Feb 4, 2016
1 parent 2bb03eb commit 2e2b450
Show file tree
Hide file tree
Showing 37 changed files with 5,050 additions and 1 deletion.
140 changes: 140 additions & 0 deletions gcloud-java-contrib/gcloud-java-nio/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.google.gcloud</groupId>
<artifactId>gcloud-java-nio</artifactId>
<packaging>jar</packaging>
<name>GCloud Java NIO</name>
<description>
FileSystemProvider for Java NIO to access GCS transparently.
</description>
<parent>
<groupId>com.google.gcloud</groupId>
<artifactId>gcloud-java-contrib</artifactId>
<version>0.1.4-SNAPSHOT</version>
</parent>
<properties>
<site.installationModule>nio</site.installationModule>
</properties>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>gcloud-java</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<dependency>
<groupId>com.google.auto.service</groupId>
<artifactId>auto-service</artifactId>
<version>1.0-rc2</version>
<scope>provided</scope> <!-- to leave out of the all-deps jar -->
</dependency>
<dependency>
<groupId>com.google.auto.value</groupId>
<artifactId>auto-value</artifactId>
<version>1.1</version>
<scope>provided</scope> <!-- to leave out of the all-deps jar -->
</dependency>
<dependency>
<groupId>com.google.appengine.tools</groupId>
<artifactId>appengine-gcs-client</artifactId>
<version>0.5</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava-testlib</artifactId>
<version>19.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.truth</groupId>
<artifactId>truth</artifactId>
<version>0.27</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.9.5</version>
</dependency>
<dependency>
<groupId>com.google.appengine</groupId>
<artifactId>appengine-testing</artifactId>
<version>1.9.30</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.appengine</groupId>
<artifactId>appengine-api-stubs</artifactId>
<version>1.9.30</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.appengine</groupId>
<artifactId>appengine-local-endpoints</artifactId>
<version>1.9.30</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<configuration>
<skip>false</skip>
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<encoding>UTF-8</encoding>
<compilerArgument>-Xlint:unchecked</compilerArgument>
</configuration>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<configuration>
<archive>
<addMavenDescriptor>true</addMavenDescriptor>
<index>true</index>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
</manifest>
<manifestEntries>
<artifactId>${project.artifactId}</artifactId>
<groupId>${project.groupId}</groupId>
<version>${project.version}</version>
<buildNumber>${buildNumber}</buildNumber>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package com.google.gcloud.storage.contrib.nio;

import static com.google.common.base.Preconditions.checkArgument;

import com.google.auto.value.AutoValue;

import java.util.Map;

/** Configuration class for {@link CloudStorageFileSystem#forBucket} */
@AutoValue
public abstract class CloudStorageConfiguration {

/** Returns the path of the current working directory. Defaults to the root directory. */
public abstract String workingDirectory();

/**
* Returns {@code true} if we <i>shouldn't</i> throw an exception when encountering object names
* containing superfluous slashes, e.g. {@code a//b}.
*/
public abstract boolean permitEmptyPathComponents();

/**
* Returns {@code true} if '/' prefix on absolute object names should be removed before I/O.
*
* <p>If you disable this feature, please take into consideration that all paths created from a
* URI will have the leading slash.
*/
public abstract boolean stripPrefixSlash();

/** Return {@code true} if paths with a trailing slash should be treated as fake directories. */
public abstract boolean usePseudoDirectories();

/** Returns the block size (in bytes) used when talking to the GCS HTTP server. */
public abstract int blockSize();

/**
* Creates a new builder, initialized with the following settings:
*
* <ul>
* <li>Performing I/O on paths with extra slashes, e.g. {@code a//b} will throw an error.
* <li>The prefix slash on absolute paths will be removed when converting to an object name.
* <li>Pseudo-directories are enabled, so any path with a trailing slash is a fake directory.
* </ul>
*/
public static Builder builder() {
return new Builder();
}

/** Builder for {@link CloudStorageConfiguration}. */
public static final class Builder {

private String workingDirectory = UnixPath.ROOT;
private boolean permitEmptyPathComponents = false;
private boolean stripPrefixSlash = true;
private boolean usePseudoDirectories = true;
private int blockSize = CloudStorageFileSystem.BLOCK_SIZE_DEFAULT;

/**
* Changes the current working directory for a new filesystem. This cannot be changed once it's
* been set. You'll need to simply create another filesystem object.
*
* @throws IllegalArgumentException if {@code path} is not absolute.
*/
public Builder workingDirectory(String path) {
checkArgument(UnixPath.getPath(false, path).isAbsolute(), "not absolute: %s", path);
workingDirectory = path;
return this;
}

/**
* Configures whether or not we should throw an exception when encountering object names
* containing superfluous slashes, e.g. {@code a//b}
*/
public Builder permitEmptyPathComponents(boolean value) {
permitEmptyPathComponents = value;
return this;
}

/**
* Configures if the '/' prefix on absolute object names should be removed before I/O.
*
* <p>If you disable this feature, please take into consideration that all paths created from a
* URI will have the leading slash.
*/
public Builder stripPrefixSlash(boolean value) {
stripPrefixSlash = value;
return this;
}

/** Configures if paths with a trailing slash should be treated as fake directories. */
public Builder usePseudoDirectories(boolean value) {
usePseudoDirectories = value;
return this;
}

/**
* Sets the block size in bytes that should be used for each HTTP request to the API.
*
* <p>The default is {@value CloudStorageFileSystem#BLOCK_SIZE_DEFAULT}.
*/
public Builder blockSize(int value) {
blockSize = value;
return this;
}

/** Creates a new instance, but does not destroy the builder. */
public CloudStorageConfiguration build() {
return new AutoValue_CloudStorageConfiguration(
workingDirectory,
permitEmptyPathComponents,
stripPrefixSlash,
usePseudoDirectories,
blockSize);
}

Builder() {}
}

static final CloudStorageConfiguration DEFAULT = builder().build();

static CloudStorageConfiguration fromMap(Map<String, ?> env) {
Builder builder = builder();
for (Map.Entry<String, ?> entry : env.entrySet()) {
switch (entry.getKey()) {
case "workingDirectory":
builder.workingDirectory((String) entry.getValue());
break;
case "permitEmptyPathComponents":
builder.permitEmptyPathComponents((Boolean) entry.getValue());
break;
case "stripPrefixSlash":
builder.stripPrefixSlash((Boolean) entry.getValue());
break;
case "usePseudoDirectories":
builder.usePseudoDirectories((Boolean) entry.getValue());
break;
case "blockSize":
builder.blockSize((Integer) entry.getValue());
break;
default:
throw new IllegalArgumentException(entry.getKey());
}
}
return builder.build();
}

CloudStorageConfiguration() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package com.google.gcloud.storage.contrib.nio;

import static com.google.common.base.Verify.verifyNotNull;

import com.google.appengine.tools.cloudstorage.GcsFileMetadata;
import com.google.common.base.MoreObjects;

import java.io.IOException;
import java.nio.file.NoSuchFileException;
import java.nio.file.attribute.BasicFileAttributeView;
import java.nio.file.attribute.FileTime;
import java.util.Objects;

import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;

/** Metadata view for a Google Cloud Storage object. */
@Immutable
public final class CloudStorageFileAttributeView implements BasicFileAttributeView {

private final CloudStorageFileSystemProvider provider;
private final CloudStoragePath path;

CloudStorageFileAttributeView(CloudStorageFileSystemProvider provider, CloudStoragePath path) {
this.provider = verifyNotNull(provider);
this.path = verifyNotNull(path);
}

/** Returns {@value CloudStorageFileSystem#GCS_VIEW} */
@Override
public String name() {
return CloudStorageFileSystem.GCS_VIEW;
}

@Override
public CloudStorageFileAttributes readAttributes() throws IOException {
if (path.seemsLikeADirectory()
&& path.getFileSystem().config().usePseudoDirectories()) {
return CloudStoragePseudoDirectoryAttributes.SINGLETON_INSTANCE;
}
GcsFileMetadata metadata = provider.getGcsService().getMetadata(path.getGcsFilename());
if (metadata == null) {
throw new NoSuchFileException(path.toUri().toString());
}
return new CloudStorageObjectAttributes(metadata);
}

/**
* This feature is not supported, since Cloud Storage objects are immutable.
*
* @throws UnsupportedOperationException
*/
@Override
public void setTimes(FileTime lastModifiedTime, FileTime lastAccessTime, FileTime createTime) {
throw new CloudStorageObjectImmutableException();
}

@Override
public boolean equals(@Nullable Object other) {
return this == other
|| other instanceof CloudStorageFileAttributeView
&& Objects.equals(provider, ((CloudStorageFileAttributeView) other).provider)
&& Objects.equals(path, ((CloudStorageFileAttributeView) other).path);
}

@Override
public int hashCode() {
return Objects.hash(provider, path);
}

@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("provider", provider)
.add("path", path)
.toString();
}
}
Loading

0 comments on commit 2e2b450

Please sign in to comment.