summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShawn O. Pearce <sop@google.com>2010-08-06 08:14:11 -0700
committerShawn O. Pearce <sop@google.com>2010-08-06 15:33:19 -0700
commit7de9ead36336e353e8b0f89b7bc8df9f88adfc81 (patch)
treeb014a4f8d5b1386a1187699e5d3f55a7bbe9d7aa
parent54b1e05c14664e2928db748f0107cf1539033434 (diff)
downloadgwtorm-7de9ead36336e353e8b0f89b7bc8df9f88adfc81.tar.gz
Encode relation id as protobuf tag in content
Because we store all relations in effectively the same column, we use a different protobuf field number wrapped around the individual entity message. This allows scanning programs that just examine every row to be able to tell different relation's types apart and correctly inspect the fields of each entity. Change-Id: I26161a69ba78e97f0145db3d781ae60e96f66e0e Signed-off-by: Shawn O. Pearce <sop@google.com>
-rw-r--r--src/main/java/com/google/gwtorm/nosql/AccessGen.java8
-rw-r--r--src/main/java/com/google/gwtorm/nosql/RelationCodec.java102
-rw-r--r--src/main/java/com/google/gwtorm/schema/RelationModel.java1
3 files changed, 110 insertions, 1 deletions
diff --git a/src/main/java/com/google/gwtorm/nosql/AccessGen.java b/src/main/java/com/google/gwtorm/nosql/AccessGen.java
index 7e01a5c..eb72b15 100644
--- a/src/main/java/com/google/gwtorm/nosql/AccessGen.java
+++ b/src/main/java/com/google/gwtorm/nosql/AccessGen.java
@@ -117,11 +117,17 @@ class AccessGen implements Opcodes {
return c;
}
+ @SuppressWarnings("unchecked")
private void initObjectCodec(final Class<?> clazz) throws OrmException {
+ ProtobufCodec oc = CodecFactory.encoder(modelClass);
+ if (model.getRelationID() > 0) {
+ oc = new RelationCodec(model.getRelationID(), oc);
+ }
+
try {
final Field e = clazz.getDeclaredField(F_OBJECT_CODEC);
e.setAccessible(true);
- e.set(null, CodecFactory.encoder(modelClass));
+ e.set(null, oc);
} catch (IllegalArgumentException err) {
throw new OrmException("Cannot setup ProtobufCodec", err);
} catch (IllegalStateException err) {
diff --git a/src/main/java/com/google/gwtorm/nosql/RelationCodec.java b/src/main/java/com/google/gwtorm/nosql/RelationCodec.java
new file mode 100644
index 0000000..84add28
--- /dev/null
+++ b/src/main/java/com/google/gwtorm/nosql/RelationCodec.java
@@ -0,0 +1,102 @@
+// Copyright 2010 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 com.google.gwtorm.nosql;
+
+import com.google.gwtorm.protobuf.ProtobufCodec;
+import com.google.protobuf.CodedInputStream;
+import com.google.protobuf.CodedOutputStream;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.protobuf.WireFormat;
+
+import java.io.EOFException;
+import java.io.IOException;
+
+/** Encodes a relation number in front of an object. */
+public class RelationCodec<T> extends ProtobufCodec<T> {
+ /**
+ * Pop the field number from the stream and return it.
+ *
+ * @param in the stream to pop the field number from. The caller is
+ * responsible for making sure the underlying stream had a mark set for
+ * at least 8 bytes so the tag can be examined, reset, and later read
+ * again during mergeFrom or decode.
+ * @return the field number of the relation.
+ * @throws IOException the stream cannot be read.
+ */
+ public static int peekId(CodedInputStream in) throws IOException {
+ return in.readTag() >>> 3;
+ }
+
+ private final int fieldId;
+ private final ProtobufCodec<T> objectCodec;
+
+ public RelationCodec(int fieldId, ProtobufCodec<T> objectCodec) {
+ this.fieldId = fieldId;
+ this.objectCodec = objectCodec;
+ }
+
+ @Override
+ public T newInstance() {
+ return objectCodec.newInstance();
+ }
+
+ @Override
+ public int sizeof(T obj) {
+ int sz = objectCodec.sizeof(obj);
+ return CodedOutputStream.computeTagSize(fieldId) //
+ + CodedOutputStream.computeRawVarint32Size(sz) //
+ + sz;
+ }
+
+ @Override
+ public void encode(T obj, CodedOutputStream out) throws IOException {
+ int sz = objectCodec.sizeof(obj);
+ out.writeTag(fieldId, WireFormat.FieldType.MESSAGE.getWireType());
+ out.writeRawVarint32(sz);
+ objectCodec.encode(obj, out);
+ }
+
+ @Override
+ public void mergeFrom(CodedInputStream in, T obj) throws IOException {
+ boolean found = false;
+ for (;;) {
+ int tag = in.readTag();
+ if (tag == 0) {
+ if (found) {
+ break;
+ } else {
+ // Reached EOF. But we require an object in our only field.
+ throw new EOFException("Expected field " + fieldId);
+ }
+ }
+
+ if ((tag >>> 3) == fieldId) {
+ if ((tag & 0x7) == WireFormat.FieldType.MESSAGE.getWireType()) {
+ int sz = in.readRawVarint32();
+ int oldLimit = in.pushLimit(sz);
+ objectCodec.mergeFrom(in, obj);
+ in.checkLastTagWas(0);
+ in.popLimit(oldLimit);
+ found = true;
+ } else {
+ throw new InvalidProtocolBufferException("Field " + fieldId
+ + " should be length delimited (wire type 2)");
+ }
+ } else {
+ in.skipField(tag);
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/google/gwtorm/schema/RelationModel.java b/src/main/java/com/google/gwtorm/schema/RelationModel.java
index d835246..f8060ce 100644
--- a/src/main/java/com/google/gwtorm/schema/RelationModel.java
+++ b/src/main/java/com/google/gwtorm/schema/RelationModel.java
@@ -352,6 +352,7 @@ public abstract class RelationModel {
r.append("Relation[\n");
r.append(" method: " + getMethodName() + "\n");
r.append(" table: " + getRelationName() + "\n");
+ r.append(" id: " + getRelationID() + "\n");
r.append(" access: " + getAccessInterfaceName() + "\n");
r.append(" entity: " + getEntityTypeClassName() + "\n");
r.append("]");