Skip to content

Commit 30992ae

Browse files
committed
Merge pull request #261 from mziccard/remove-serializable-channels
Remove Serializable from BlobReadChannel and BlobWriteChannel
2 parents 03dbc8c + 638bd92 commit 30992ae

9 files changed

Lines changed: 512 additions & 55 deletions

File tree

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright 2015 Google Inc. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.gcloud;
18+
19+
/**
20+
* A common interface for restorable states. Implementations of {@code RestorableState} are capable
21+
* of saving the state of an object to restore it for later use.
22+
*
23+
* Implementations of this class must implement {@link java.io.Serializable} to ensure that the
24+
* state of a the object can be correctly serialized.
25+
*/
26+
public interface RestorableState<T> {
27+
28+
/**
29+
* Returns an object whose internal state reflects the one saved in the invocation object.
30+
*/
31+
T restore();
32+
}

gcloud-java-storage/src/main/java/com/google/gcloud/storage/BlobReadChannel.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@
1616

1717
package com.google.gcloud.storage;
1818

19+
import com.google.gcloud.RestorableState;
20+
1921
import java.io.Closeable;
2022
import java.io.IOException;
21-
import java.io.Serializable;
2223
import java.nio.channels.ReadableByteChannel;
2324

2425
/**
@@ -28,7 +29,7 @@
2829
*
2930
* This class is @{link Serializable}, which allows incremental reads.
3031
*/
31-
public interface BlobReadChannel extends ReadableByteChannel, Serializable, Closeable {
32+
public interface BlobReadChannel extends ReadableByteChannel, Closeable {
3233

3334
/**
3435
* Overridden to remove IOException.
@@ -46,4 +47,11 @@ public interface BlobReadChannel extends ReadableByteChannel, Serializable, Clos
4647
*/
4748
void chunkSize(int chunkSize);
4849

50+
/**
51+
* Saves the read channel state.
52+
*
53+
* @return a {@link RestorableState} object that contains the read channel state and can restore
54+
* it afterwards. State object must implement {@link java.io.Serializable}.
55+
*/
56+
public RestorableState<BlobReadChannel> save();
4957
}

gcloud-java-storage/src/main/java/com/google/gcloud/storage/BlobReadChannelImpl.java

Lines changed: 132 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,16 @@
1919
import static com.google.gcloud.RetryHelper.runWithRetries;
2020

2121
import com.google.api.services.storage.model.StorageObject;
22+
import com.google.common.base.MoreObjects;
23+
import com.google.gcloud.RestorableState;
2224
import com.google.gcloud.RetryHelper;
2325
import com.google.gcloud.spi.StorageRpc;
2426

2527
import java.io.IOException;
26-
import java.io.ObjectInputStream;
27-
import java.io.ObjectOutputStream;
28+
import java.io.Serializable;
2829
import java.nio.ByteBuffer;
2930
import java.util.Map;
31+
import java.util.Objects;
3032
import java.util.concurrent.Callable;
3133

3234
/**
@@ -35,7 +37,6 @@
3537
class BlobReadChannelImpl implements BlobReadChannel {
3638

3739
private static final int DEFAULT_CHUNK_SIZE = 2 * 1024 * 1024;
38-
private static final long serialVersionUID = 4821762590742862669L;
3940

4041
private final StorageOptions serviceOptions;
4142
private final BlobId blob;
@@ -45,38 +46,33 @@ class BlobReadChannelImpl implements BlobReadChannel {
4546
private boolean endOfStream;
4647
private int chunkSize = DEFAULT_CHUNK_SIZE;
4748

48-
private transient StorageRpc storageRpc;
49-
private transient StorageObject storageObject;
50-
private transient int bufferPos;
51-
private transient byte[] buffer;
49+
private final StorageRpc storageRpc;
50+
private final StorageObject storageObject;
51+
private int bufferPos;
52+
private byte[] buffer;
5253

5354
BlobReadChannelImpl(StorageOptions serviceOptions, BlobId blob,
5455
Map<StorageRpc.Option, ?> requestOptions) {
5556
this.serviceOptions = serviceOptions;
5657
this.blob = blob;
5758
this.requestOptions = requestOptions;
5859
isOpen = true;
59-
initTransients();
60+
storageRpc = serviceOptions.storageRpc();
61+
storageObject = blob.toPb();
6062
}
6163

62-
private void writeObject(ObjectOutputStream out) throws IOException {
64+
@Override
65+
public RestorableState<BlobReadChannel> save() {
66+
StateImpl.Builder builder = StateImpl.builder(serviceOptions, blob, requestOptions)
67+
.position(position)
68+
.isOpen(isOpen)
69+
.endOfStream(endOfStream)
70+
.chunkSize(chunkSize);
6371
if (buffer != null) {
64-
position += bufferPos;
65-
buffer = null;
66-
bufferPos = 0;
67-
endOfStream = false;
72+
builder.position(position + bufferPos);
73+
builder.endOfStream(false);
6874
}
69-
out.defaultWriteObject();
70-
}
71-
72-
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
73-
in.defaultReadObject();
74-
initTransients();
75-
}
76-
77-
private void initTransients() {
78-
storageRpc = serviceOptions.storageRpc();
79-
storageObject = blob.toPb();
75+
return builder.build();
8076
}
8177

8278
@Override
@@ -148,4 +144,116 @@ public byte[] call() {
148144
}
149145
return toWrite;
150146
}
147+
148+
static class StateImpl implements RestorableState<BlobReadChannel>, Serializable {
149+
150+
private static final long serialVersionUID = 3889420316004453706L;
151+
152+
private final StorageOptions serviceOptions;
153+
private final BlobId blob;
154+
private final Map<StorageRpc.Option, ?> requestOptions;
155+
private final int position;
156+
private final boolean isOpen;
157+
private final boolean endOfStream;
158+
private final int chunkSize;
159+
160+
StateImpl(Builder builder) {
161+
this.serviceOptions = builder.serviceOptions;
162+
this.blob = builder.blob;
163+
this.requestOptions = builder.requestOptions;
164+
this.position = builder.position;
165+
this.isOpen = builder.isOpen;
166+
this.endOfStream = builder.endOfStream;
167+
this.chunkSize = builder.chunkSize;
168+
}
169+
170+
static class Builder {
171+
private final StorageOptions serviceOptions;
172+
private final BlobId blob;
173+
private final Map<StorageRpc.Option, ?> requestOptions;
174+
private int position;
175+
private boolean isOpen;
176+
private boolean endOfStream;
177+
private int chunkSize;
178+
179+
private Builder(StorageOptions options, BlobId blob, Map<StorageRpc.Option, ?> reqOptions) {
180+
this.serviceOptions = options;
181+
this.blob = blob;
182+
this.requestOptions = reqOptions;
183+
}
184+
185+
Builder position(int position) {
186+
this.position = position;
187+
return this;
188+
}
189+
190+
Builder isOpen(boolean isOpen) {
191+
this.isOpen = isOpen;
192+
return this;
193+
}
194+
195+
Builder endOfStream(boolean endOfStream) {
196+
this.endOfStream = endOfStream;
197+
return this;
198+
}
199+
200+
Builder chunkSize(int chunkSize) {
201+
this.chunkSize = chunkSize;
202+
return this;
203+
}
204+
205+
RestorableState<BlobReadChannel> build() {
206+
return new StateImpl(this);
207+
}
208+
}
209+
210+
static Builder builder(
211+
StorageOptions options, BlobId blob, Map<StorageRpc.Option, ?> reqOptions) {
212+
return new Builder(options, blob, reqOptions);
213+
}
214+
215+
@Override
216+
public BlobReadChannel restore() {
217+
BlobReadChannelImpl channel = new BlobReadChannelImpl(serviceOptions, blob, requestOptions);
218+
channel.position = position;
219+
channel.isOpen = isOpen;
220+
channel.endOfStream = endOfStream;
221+
channel.chunkSize = chunkSize;
222+
return channel;
223+
}
224+
225+
@Override
226+
public int hashCode() {
227+
return Objects.hash(serviceOptions, blob, requestOptions, position, isOpen, endOfStream,
228+
chunkSize);
229+
}
230+
231+
@Override
232+
public boolean equals(Object obj) {
233+
if (obj == null) {
234+
return false;
235+
}
236+
if (!(obj instanceof StateImpl)) {
237+
return false;
238+
}
239+
final StateImpl other = (StateImpl) obj;
240+
return Objects.equals(this.serviceOptions, other.serviceOptions)
241+
&& Objects.equals(this.blob, other.blob)
242+
&& Objects.equals(this.requestOptions, other.requestOptions)
243+
&& this.position == other.position
244+
&& this.isOpen == other.isOpen
245+
&& this.endOfStream == other.endOfStream
246+
&& this.chunkSize == other.chunkSize;
247+
}
248+
249+
@Override
250+
public String toString() {
251+
return MoreObjects.toStringHelper(this)
252+
.add("blob", blob)
253+
.add("position", position)
254+
.add("isOpen", isOpen)
255+
.add("endOfStream", endOfStream)
256+
.toString();
257+
}
258+
}
151259
}

gcloud-java-storage/src/main/java/com/google/gcloud/storage/BlobWriteChannel.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@
1616

1717
package com.google.gcloud.storage;
1818

19+
import com.google.gcloud.RestorableState;
20+
1921
import java.io.Closeable;
20-
import java.io.Serializable;
2122
import java.nio.channels.WritableByteChannel;
2223

2324
/**
@@ -27,11 +28,21 @@
2728
* data will only be visible after calling {@link #close()}. This class is serializable, to allow
2829
* incremental writes.
2930
*/
30-
public interface BlobWriteChannel extends WritableByteChannel, Serializable, Closeable {
31+
public interface BlobWriteChannel extends WritableByteChannel, Closeable {
3132

3233
/**
3334
* Sets the minimum size that will be written by a single RPC.
3435
* Written data will be buffered and only flushed upon reaching this size or closing the channel.
3536
*/
3637
void chunkSize(int chunkSize);
38+
39+
/**
40+
* Saves the write channel state so that it can be restored afterwards. The original
41+
* {@code BlobWriteChannel} and the restored one should not both be used. Closing one channel
42+
* causes the other channel to close, subsequent writes will fail.
43+
*
44+
* @return a {@link RestorableState} object that contains the write channel state and can restore
45+
* it afterwards. State object must implement {@link java.io.Serializable}.
46+
*/
47+
public RestorableState<BlobWriteChannel> save();
3748
}

0 commit comments

Comments
 (0)