You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by ju...@apache.org on 2014/01/23 21:27:07 UTC
svn commit: r1560798 - in
/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak:
api/Blob.java plugins/memory/AbstractBlob.java
plugins/mongomk/MongoBlob.java plugins/segment/SegmentBlob.java
Author: jukka
Date: Thu Jan 23 20:27:06 2014
New Revision: 1560798
URL: http://svn.apache.org/r1560798
Log:
OAK-834: Efficient copying of binaries across repositories
Add Blob.getReference() to give the underlying storage engines a way
to expose the secure reference strings required by this feature.
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Blob.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/AbstractBlob.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoBlob.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentBlob.java
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Blob.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Blob.java?rev=1560798&r1=1560797&r2=1560798&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Blob.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Blob.java Thu Jan 23 20:27:06 2014
@@ -1,59 +1,70 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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 org.apache.jackrabbit.oak.api;
-
-import java.io.InputStream;
-
-import javax.annotation.Nonnull;
-
-/**
- * Immutable representation of a binary value of finite length.
- * <p>
- * Two blobs are considered equal in terms of {@link Object#equals(Object)}
- * if they contain the same sequences of bytes. Implementations can optimize
- * the equality checks by using strong hash codes or other similar means as
- * long as they comply with the above definition of equality.
- * <p>
- * Due to their nature blobs should not be used as keys in hash tables.
- * To highlight that and to ensure semantic correctness of the equality
- * contract across different blob implementations, the {@link #hashCode()}
- * method of all blob instances should return zero.
- */
-public interface Blob {
-
- /**
- * Returns a new stream for this blob. The streams returned from
- * multiple calls to this method are byte wise equals. That is,
- * subsequent calls to {@link java.io.InputStream#read() read}
- * return the same sequence of bytes as long as neither call throws
- * an exception.
- *
- * @return a new stream for this blob
- */
- @Nonnull
- InputStream getNewStream();
-
- /**
- * Returns the length of this blob or -1 if unknown.
- *
- * @return the length of this blob.
- */
- long length();
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.jackrabbit.oak.api;
+
+import java.io.InputStream;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+/**
+ * Immutable representation of a binary value of finite length.
+ * <p>
+ * Two blobs are considered equal in terms of {@link Object#equals(Object)}
+ * if they contain the same sequences of bytes. Implementations can optimize
+ * the equality checks by using strong hash codes or other similar means as
+ * long as they comply with the above definition of equality.
+ * <p>
+ * Due to their nature blobs should not be used as keys in hash tables.
+ * To highlight that and to ensure semantic correctness of the equality
+ * contract across different blob implementations, the {@link #hashCode()}
+ * method of all blob instances should return zero.
+ */
+public interface Blob {
+
+ /**
+ * Returns a new stream for this blob. The streams returned from
+ * multiple calls to this method are byte wise equals. That is,
+ * subsequent calls to {@link java.io.InputStream#read() read}
+ * return the same sequence of bytes as long as neither call throws
+ * an exception.
+ *
+ * @return a new stream for this blob
+ */
+ @Nonnull
+ InputStream getNewStream();
+
+ /**
+ * Returns the length of this blob or -1 if unknown.
+ *
+ * @return the length of this blob.
+ */
+ long length();
+
+ /**
+ * Returns a secure reference to this blob, or {@code null} if such
+ * a reference is not available.
+ *
+ * @see <a href="https://issues.apache.org/jira/browse/OAK-834">OAK-834</a>
+ * @return binary reference, or {@code null}
+ */
+ @CheckForNull
+ String getReference();
+
+}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/AbstractBlob.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/AbstractBlob.java?rev=1560798&r1=1560797&r2=1560798&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/AbstractBlob.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/AbstractBlob.java Thu Jan 23 20:27:06 2014
@@ -1,144 +1,155 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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 org.apache.jackrabbit.oak.plugins.memory;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import com.google.common.hash.HashCode;
-import com.google.common.hash.Hashing;
-import com.google.common.io.ByteStreams;
-import com.google.common.io.InputSupplier;
-
-import org.apache.jackrabbit.oak.api.Blob;
-
-/**
- * Abstract base class for {@link Blob} implementations.
- * This base class provides default implementations for
- * {@code hashCode} and {@code equals}.
- */
-public abstract class AbstractBlob implements Blob {
-
- private static InputSupplier<InputStream> supplier(final Blob blob) {
- return new InputSupplier<InputStream>() {
- @Override
- public InputStream getInput() throws IOException {
- return blob.getNewStream();
- }
- };
- }
-
- public static boolean equal(Blob a, Blob b) {
- try {
- return ByteStreams.equal(supplier(a), supplier(b));
- } catch (IOException e) {
- throw new IllegalStateException("Blob equality check failed", e);
- }
- }
-
- public static HashCode calculateSha256(final Blob blob) {
- AbstractBlob ab;
- if (blob instanceof AbstractBlob) {
- ab = ((AbstractBlob) blob);
- } else {
- ab = new AbstractBlob() {
- @Override
- public long length() {
- return blob.length();
- }
- @Override
- public InputStream getNewStream() {
- return blob.getNewStream();
- }
- };
- }
- return ab.getSha256();
- }
-
- private HashCode hashCode; // synchronized access
-
- protected AbstractBlob(HashCode hashCode) {
- this.hashCode = hashCode;
- }
-
- protected AbstractBlob() {
- this(null);
- }
-
- private synchronized HashCode getSha256() {
- // Blobs are immutable so we can safely cache the hash
- if (hashCode == null) {
- try {
- hashCode = ByteStreams.hash(supplier(this), Hashing.sha256());
- } catch (IOException e) {
- throw new IllegalStateException("Hash calculation failed", e);
- }
- }
- return hashCode;
- }
-
- /**
- * This hash code implementation returns the hash code of the underlying stream
- * @return
- */
- protected byte[] sha256() {
- return getSha256().asBytes();
- }
-
- /**
- * To {@code Blob} instances are considered equal iff they have the
- * same SHA-256 hash code are equal.
- * @param other
- * @return
- */
- @Override
- public boolean equals(Object other) {
- if (other == this) {
- return true;
- }
-
- if (other instanceof AbstractBlob) {
- AbstractBlob that = (AbstractBlob) other;
- // optimize the comparison if both this and the other blob
- // already have pre-computed SHA-256 hash codes
- synchronized (this) {
- if (hashCode != null) {
- synchronized (that) {
- if (that.hashCode != null) {
- return hashCode.equals(that.hashCode);
- }
- }
- }
- }
- }
-
- return other instanceof Blob && equal(this, (Blob) other);
- }
-
- @Override
- public int hashCode() {
- return 0; // see Blob javadoc
- }
-
- @Override
- public String toString() {
- return getSha256().toString();
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.jackrabbit.oak.plugins.memory;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.annotation.CheckForNull;
+
+import com.google.common.hash.HashCode;
+import com.google.common.hash.Hashing;
+import com.google.common.io.ByteStreams;
+import com.google.common.io.InputSupplier;
+
+import org.apache.jackrabbit.oak.api.Blob;
+
+/**
+ * Abstract base class for {@link Blob} implementations.
+ * This base class provides default implementations for
+ * {@code hashCode} and {@code equals}.
+ */
+public abstract class AbstractBlob implements Blob {
+
+ private static InputSupplier<InputStream> supplier(final Blob blob) {
+ return new InputSupplier<InputStream>() {
+ @Override
+ public InputStream getInput() throws IOException {
+ return blob.getNewStream();
+ }
+ };
+ }
+
+ public static boolean equal(Blob a, Blob b) {
+ try {
+ return ByteStreams.equal(supplier(a), supplier(b));
+ } catch (IOException e) {
+ throw new IllegalStateException("Blob equality check failed", e);
+ }
+ }
+
+ public static HashCode calculateSha256(final Blob blob) {
+ AbstractBlob ab;
+ if (blob instanceof AbstractBlob) {
+ ab = ((AbstractBlob) blob);
+ } else {
+ ab = new AbstractBlob() {
+ @Override
+ public long length() {
+ return blob.length();
+ }
+ @Override
+ public InputStream getNewStream() {
+ return blob.getNewStream();
+ }
+ };
+ }
+ return ab.getSha256();
+ }
+
+ private HashCode hashCode; // synchronized access
+
+ protected AbstractBlob(HashCode hashCode) {
+ this.hashCode = hashCode;
+ }
+
+ protected AbstractBlob() {
+ this(null);
+ }
+
+ private synchronized HashCode getSha256() {
+ // Blobs are immutable so we can safely cache the hash
+ if (hashCode == null) {
+ try {
+ hashCode = ByteStreams.hash(supplier(this), Hashing.sha256());
+ } catch (IOException e) {
+ throw new IllegalStateException("Hash calculation failed", e);
+ }
+ }
+ return hashCode;
+ }
+
+ /**
+ * This hash code implementation returns the hash code of the underlying stream
+ * @return
+ */
+ protected byte[] sha256() {
+ return getSha256().asBytes();
+ }
+
+ //--------------------------------------------------------------< Blob >--
+
+ @Override @CheckForNull
+ public String getReference() {
+ return null;
+ }
+
+ //------------------------------------------------------------< Object >--
+
+ /**
+ * To {@code Blob} instances are considered equal iff they have the
+ * same SHA-256 hash code are equal.
+ * @param other
+ * @return
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (other instanceof AbstractBlob) {
+ AbstractBlob that = (AbstractBlob) other;
+ // optimize the comparison if both this and the other blob
+ // already have pre-computed SHA-256 hash codes
+ synchronized (this) {
+ if (hashCode != null) {
+ synchronized (that) {
+ if (that.hashCode != null) {
+ return hashCode.equals(that.hashCode);
+ }
+ }
+ }
+ }
+ }
+
+ return other instanceof Blob && equal(this, (Blob) other);
+ }
+
+ @Override
+ public int hashCode() {
+ return 0; // see Blob javadoc
+ }
+
+ @Override
+ public String toString() {
+ return getSha256().toString();
+ }
+
+}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoBlob.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoBlob.java?rev=1560798&r1=1560797&r2=1560798&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoBlob.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoBlob.java Thu Jan 23 20:27:06 2014
@@ -1,79 +1,87 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.jackrabbit.oak.plugins.mongomk;
-
-import java.io.InputStream;
-
-import javax.annotation.Nonnull;
-
-import org.apache.jackrabbit.mk.blobs.BlobStore;
-import org.apache.jackrabbit.mk.blobs.BlobStoreInputStream;
-import org.apache.jackrabbit.oak.api.Blob;
-
-/**
- * A blob implementation.
- */
-public class MongoBlob implements Blob {
-
- private final BlobStore blobStore;
- private final String id;
-
- public MongoBlob(BlobStore blobStore, String id) {
- this.blobStore = blobStore;
- this.id = id;
- }
-
- @Override
- @Nonnull
- public InputStream getNewStream() {
- return new BlobStoreInputStream(blobStore, id, 0);
- }
-
- @Override
- public long length() {
- try {
- return blobStore.getBlobLength(id);
- } catch (Exception e) {
- throw new IllegalArgumentException("Invalid blob id: " + id);
- }
- }
-
- @Override
- public String toString() {
- return id;
- }
-
- @Override
- public int hashCode() {
- return id.hashCode();
- }
-
- @Override
- public boolean equals(Object other) {
- if (this == other) {
- return true;
- }
- if (other instanceof MongoBlob) {
- MongoBlob b = (MongoBlob) other;
- // theoretically, the data could be the same
- // even if the id is different
- return b.id.equals(id);
- }
- return false;
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.jackrabbit.oak.plugins.mongomk;
+
+import java.io.InputStream;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+import org.apache.jackrabbit.mk.blobs.BlobStore;
+import org.apache.jackrabbit.mk.blobs.BlobStoreInputStream;
+import org.apache.jackrabbit.oak.api.Blob;
+
+/**
+ * A blob implementation.
+ */
+public class MongoBlob implements Blob {
+
+ private final BlobStore blobStore;
+ private final String id;
+
+ public MongoBlob(BlobStore blobStore, String id) {
+ this.blobStore = blobStore;
+ this.id = id;
+ }
+
+ @Override
+ @Nonnull
+ public InputStream getNewStream() {
+ return new BlobStoreInputStream(blobStore, id, 0);
+ }
+
+ @Override
+ public long length() {
+ try {
+ return blobStore.getBlobLength(id);
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Invalid blob id: " + id);
+ }
+ }
+
+ @Override @CheckForNull
+ public String getReference() {
+ return null;
+ }
+
+ //------------------------------------------------------------< Object >--
+
+ @Override
+ public String toString() {
+ return id;
+ }
+
+ @Override
+ public int hashCode() {
+ return id.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (other instanceof MongoBlob) {
+ MongoBlob b = (MongoBlob) other;
+ // theoretically, the data could be the same
+ // even if the id is different
+ return b.id.equals(id);
+ }
+ return false;
+ }
+
+}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentBlob.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentBlob.java?rev=1560798&r1=1560797&r2=1560798&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentBlob.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentBlob.java Thu Jan 23 20:27:06 2014
@@ -1,76 +1,82 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.jackrabbit.oak.plugins.segment;
-
-import javax.annotation.Nonnull;
-
-import org.apache.jackrabbit.oak.api.Blob;
-import org.apache.jackrabbit.oak.plugins.memory.AbstractBlob;
-
-import java.io.InputStream;
-
-class SegmentBlob extends Record implements Blob {
-
- private boolean external;
-
- SegmentBlob(Segment segment, RecordId id, boolean external) {
- super(segment, id);
-
- this.external = external;
- }
-
- @Override @Nonnull
- public InputStream getNewStream() {
- if (external) {
- String refererence = getSegment().readBlobReference(getOffset());
- return getStore().readBlob(refererence).getNewStream();
- }
- return getSegment().readStream(getOffset());
- }
-
- @Override
- public long length() {
- if (external) {
- return getSegment().readBlobLength(getOffset());
- }
-
- SegmentStream stream = (SegmentStream) getNewStream();
- try {
- return stream.getLength();
- } finally {
- stream.close();
- }
- }
-
- //------------------------------------------------------------< Object >--
-
- @Override
- public boolean equals(Object object) {
- if (object == this || fastEquals(this, object)) {
- return true;
- } else {
- return object instanceof Blob
- && AbstractBlob.equal(this, (Blob) object);
- }
- }
-
- @Override
- public int hashCode() {
- return 0;
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.jackrabbit.oak.plugins.segment;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+import org.apache.jackrabbit.oak.api.Blob;
+import org.apache.jackrabbit.oak.plugins.memory.AbstractBlob;
+
+import java.io.InputStream;
+
+class SegmentBlob extends Record implements Blob {
+
+ private boolean external;
+
+ SegmentBlob(Segment segment, RecordId id, boolean external) {
+ super(segment, id);
+
+ this.external = external;
+ }
+
+ @Override @Nonnull
+ public InputStream getNewStream() {
+ if (external) {
+ String refererence = getSegment().readBlobReference(getOffset());
+ return getStore().readBlob(refererence).getNewStream();
+ }
+ return getSegment().readStream(getOffset());
+ }
+
+ @Override
+ public long length() {
+ if (external) {
+ return getSegment().readBlobLength(getOffset());
+ }
+
+ SegmentStream stream = (SegmentStream) getNewStream();
+ try {
+ return stream.getLength();
+ } finally {
+ stream.close();
+ }
+ }
+
+ @Override @CheckForNull
+ public String getReference() {
+ return null;
+ }
+
+ //------------------------------------------------------------< Object >--
+
+ @Override
+ public boolean equals(Object object) {
+ if (object == this || fastEquals(this, object)) {
+ return true;
+ } else {
+ return object instanceof Blob
+ && AbstractBlob.equal(this, (Blob) object);
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return 0;
+ }
+
+}