summaryrefslogtreecommitdiff
path: root/java-plan3/src
diff options
context:
space:
mode:
authorfrsyuki <frsyuki@users.sourceforge.jp>2009-11-26 11:22:08 +0900
committerfrsyuki <frsyuki@users.sourceforge.jp>2009-11-26 11:22:08 +0900
commiteb9e89249137cbed0ace62de9902e69bd082b2a3 (patch)
treeb4014b1b25e8b20b4dc2ba28eeddf7a989c846ab /java-plan3/src
parente39e1d4f602b0202b830f8e672e2116bdb8b9f34 (diff)
downloadmsgpack-python-eb9e89249137cbed0ace62de9902e69bd082b2a3.tar.gz
import MessagePack for Java implementation plan 3
Diffstat (limited to 'java-plan3/src')
-rw-r--r--java-plan3/src/org/msgpack/MessageMergeable.java23
-rw-r--r--java-plan3/src/org/msgpack/MessagePackable.java25
-rw-r--r--java-plan3/src/org/msgpack/MessageTypeException.java39
-rw-r--r--java-plan3/src/org/msgpack/Packer.java409
-rw-r--r--java-plan3/src/org/msgpack/Schema.java133
-rw-r--r--java-plan3/src/org/msgpack/UnbufferedUnpacker.java82
-rw-r--r--java-plan3/src/org/msgpack/UnpackException.java29
-rw-r--r--java-plan3/src/org/msgpack/UnpackIterator.java66
-rw-r--r--java-plan3/src/org/msgpack/Unpacker.java245
-rw-r--r--java-plan3/src/org/msgpack/impl/UnpackerImpl.java483
-rw-r--r--java-plan3/src/org/msgpack/schema/ArraySchema.java125
-rw-r--r--java-plan3/src/org/msgpack/schema/ByteSchema.java89
-rw-r--r--java-plan3/src/org/msgpack/schema/ClassGenerator.java241
-rw-r--r--java-plan3/src/org/msgpack/schema/ClassSchema.java95
-rw-r--r--java-plan3/src/org/msgpack/schema/DoubleSchema.java84
-rw-r--r--java-plan3/src/org/msgpack/schema/FieldSchema.java43
-rw-r--r--java-plan3/src/org/msgpack/schema/FloatSchema.java84
-rw-r--r--java-plan3/src/org/msgpack/schema/GenericClassSchema.java91
-rw-r--r--java-plan3/src/org/msgpack/schema/GenericSchema.java192
-rw-r--r--java-plan3/src/org/msgpack/schema/IArraySchema.java26
-rw-r--r--java-plan3/src/org/msgpack/schema/IMapSchema.java27
-rw-r--r--java-plan3/src/org/msgpack/schema/IntSchema.java89
-rw-r--r--java-plan3/src/org/msgpack/schema/LongSchema.java89
-rw-r--r--java-plan3/src/org/msgpack/schema/MapSchema.java102
-rw-r--r--java-plan3/src/org/msgpack/schema/RawSchema.java105
-rw-r--r--java-plan3/src/org/msgpack/schema/ReflectionClassSchema.java64
-rw-r--r--java-plan3/src/org/msgpack/schema/SSchemaParser.java254
-rw-r--r--java-plan3/src/org/msgpack/schema/ShortSchema.java89
-rw-r--r--java-plan3/src/org/msgpack/schema/SpecificClassSchema.java122
-rw-r--r--java-plan3/src/org/msgpack/schema/StringSchema.java111
30 files changed, 3656 insertions, 0 deletions
diff --git a/java-plan3/src/org/msgpack/MessageMergeable.java b/java-plan3/src/org/msgpack/MessageMergeable.java
new file mode 100644
index 0000000..e11119c
--- /dev/null
+++ b/java-plan3/src/org/msgpack/MessageMergeable.java
@@ -0,0 +1,23 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 FURUHASHI Sadayuki
+//
+// 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 org.msgpack;
+
+public interface MessageMergeable {
+ public void messageMerge(Object obj) throws MessageTypeException;
+}
+
diff --git a/java-plan3/src/org/msgpack/MessagePackable.java b/java-plan3/src/org/msgpack/MessagePackable.java
new file mode 100644
index 0000000..d8a7db9
--- /dev/null
+++ b/java-plan3/src/org/msgpack/MessagePackable.java
@@ -0,0 +1,25 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 FURUHASHI Sadayuki
+//
+// 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 org.msgpack;
+
+import java.io.IOException;
+
+public interface MessagePackable {
+ public void messagePack(Packer pk) throws IOException;
+}
+
diff --git a/java-plan3/src/org/msgpack/MessageTypeException.java b/java-plan3/src/org/msgpack/MessageTypeException.java
new file mode 100644
index 0000000..09031b2
--- /dev/null
+++ b/java-plan3/src/org/msgpack/MessageTypeException.java
@@ -0,0 +1,39 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 FURUHASHI Sadayuki
+//
+// 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 org.msgpack;
+
+import java.io.IOException;
+
+public class MessageTypeException extends IOException {
+ public MessageTypeException() { }
+
+ public MessageTypeException(String s) {
+ super(s);
+ }
+
+ public static MessageTypeException invalidConvert(Object from, Schema to) {
+ return new MessageTypeException(from.getClass().getName()+" cannot be convert to "+to.getExpression());
+ }
+
+ /* FIXME
+ public static MessageTypeException schemaMismatch(Schema to) {
+ return new MessageTypeException("schema mismatch "+to.getExpression());
+ }
+ */
+}
+
diff --git a/java-plan3/src/org/msgpack/Packer.java b/java-plan3/src/org/msgpack/Packer.java
new file mode 100644
index 0000000..7f2508c
--- /dev/null
+++ b/java-plan3/src/org/msgpack/Packer.java
@@ -0,0 +1,409 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 FURUHASHI Sadayuki
+//
+// 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 org.msgpack;
+
+import java.io.OutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.util.List;
+import java.util.Map;
+
+public class Packer {
+ protected byte[] castBytes = new byte[9];
+ protected ByteBuffer castBuffer = ByteBuffer.wrap(castBytes);
+ protected OutputStream out;
+
+ public Packer(OutputStream out) {
+ this.out = out;
+ }
+
+ public Packer packByte(byte d) throws IOException {
+ if(d < -(1<<5)) {
+ castBytes[0] = (byte)0xd1;
+ castBytes[1] = d;
+ out.write(castBytes, 0, 2);
+ } else {
+ out.write(d);
+ }
+ return this;
+ }
+
+ public Packer packShort(short d) throws IOException {
+ if(d < -(1<<5)) {
+ if(d < -(1<<7)) {
+ // signed 16
+ castBytes[0] = (byte)0xd1;
+ castBuffer.putShort(1, d);
+ out.write(castBytes, 0, 3);
+ } else {
+ // signed 8
+ castBytes[0] = (byte)0xd0;
+ castBytes[1] = (byte)d;
+ out.write(castBytes, 0, 2);
+ }
+ } else if(d < (1<<7)) {
+ // fixnum
+ out.write((byte)d);
+ } else {
+ if(d < (1<<8)) {
+ // unsigned 8
+ castBytes[0] = (byte)0xcc;
+ castBytes[1] = (byte)d;
+ out.write(castBytes, 0, 2);
+ } else {
+ // unsigned 16
+ castBytes[0] = (byte)0xcd;
+ castBuffer.putShort(1, d);
+ out.write(castBytes, 0, 3);
+ }
+ }
+ return this;
+ }
+
+ public Packer packInt(int d) throws IOException {
+ if(d < -(1<<5)) {
+ if(d < -(1<<15)) {
+ // signed 32
+ castBytes[0] = (byte)0xd2;
+ castBuffer.putInt(1, d);
+ out.write(castBytes, 0, 5);
+ } else if(d < -(1<<7)) {
+ // signed 16
+ castBytes[0] = (byte)0xd1;
+ castBuffer.putShort(1, (short)d);
+ out.write(castBytes, 0, 3);
+ } else {
+ // signed 8
+ castBytes[0] = (byte)0xd0;
+ castBytes[1] = (byte)d;
+ out.write(castBytes, 0, 2);
+ }
+ } else if(d < (1<<7)) {
+ // fixnum
+ out.write((byte)d);
+ } else {
+ if(d < (1<<8)) {
+ // unsigned 8
+ castBytes[0] = (byte)0xcc;
+ castBytes[1] = (byte)d;
+ out.write(castBytes, 0, 2);
+ } else if(d < (1<<16)) {
+ // unsigned 16
+ castBytes[0] = (byte)0xcd;
+ castBuffer.putShort(1, (short)d);
+ out.write(castBytes, 0, 3);
+ } else {
+ // unsigned 32
+ castBytes[0] = (byte)0xce;
+ castBuffer.putInt(1, d);
+ out.write(castBytes, 0, 5);
+ }
+ }
+ return this;
+ }
+
+ public Packer packLong(long d) throws IOException {
+ if(d < -(1L<<5)) {
+ if(d < -(1L<<15)) {
+ if(d < -(1L<<31)) {
+ // signed 64
+ castBytes[0] = (byte)0xd3;
+ castBuffer.putLong(1, d);
+ out.write(castBytes, 0, 9);
+ } else {
+ // signed 32
+ castBytes[0] = (byte)0xd2;
+ castBuffer.putInt(1, (int)d);
+ out.write(castBytes, 0, 5);
+ }
+ } else {
+ if(d < -(1<<7)) {
+ // signed 16
+ castBytes[0] = (byte)0xd1;
+ castBuffer.putShort(1, (short)d);
+ out.write(castBytes, 0, 3);
+ } else {
+ // signed 8
+ castBytes[0] = (byte)0xd0;
+ castBytes[1] = (byte)d;
+ out.write(castBytes, 0, 2);
+ }
+ }
+ } else if(d < (1<<7)) {
+ // fixnum
+ out.write((byte)d);
+ } else {
+ if(d < (1L<<16)) {
+ if(d < (1<<8)) {
+ // unsigned 8
+ castBytes[0] = (byte)0xcc;
+ castBytes[1] = (byte)d;
+ out.write(castBytes, 0, 2);
+ } else {
+ // unsigned 16
+ castBytes[0] = (byte)0xcd;
+ castBuffer.putShort(1, (short)d);
+ out.write(castBytes, 0, 3);
+ //System.out.println("pack uint 16 "+(short)d);
+ }
+ } else {
+ if(d < (1L<<32)) {
+ // unsigned 32
+ castBytes[0] = (byte)0xce;
+ castBuffer.putInt(1, (int)d);
+ out.write(castBytes, 0, 5);
+ } else {
+ // unsigned 64
+ castBytes[0] = (byte)0xcf;
+ castBuffer.putLong(1, d);
+ out.write(castBytes, 0, 9);
+ }
+ }
+ }
+ return this;
+ }
+
+ public Packer packFloat(float d) throws IOException {
+ castBytes[0] = (byte)0xca;
+ castBuffer.putFloat(1, d);
+ out.write(castBytes, 0, 5);
+ return this;
+ }
+
+ public Packer packDouble(double d) throws IOException {
+ castBytes[0] = (byte)0xcb;
+ castBuffer.putDouble(1, d);
+ out.write(castBytes, 0, 9);
+ return this;
+ }
+
+ public Packer packNil() throws IOException {
+ out.write((byte)0xc0);
+ return this;
+ }
+
+ public Packer packTrue() throws IOException {
+ out.write((byte)0xc3);
+ return this;
+ }
+
+ public Packer packFalse() throws IOException {
+ out.write((byte)0xc2);
+ return this;
+ }
+
+ public Packer packArray(int n) throws IOException {
+ if(n < 16) {
+ final int d = 0x90 | n;
+ out.write((byte)d);
+ } else if(n < 65536) {
+ castBytes[0] = (byte)0xdc;
+ castBuffer.putShort(1, (short)n);
+ out.write(castBytes, 0, 3);
+ } else {
+ castBytes[0] = (byte)0xdd;
+ castBuffer.putInt(1, n);
+ out.write(castBytes, 0, 5);
+ }
+ return this;
+ }
+
+ public Packer packMap(int n) throws IOException {
+ if(n < 16) {
+ final int d = 0x80 | n;
+ out.write((byte)d);
+ } else if(n < 65536) {
+ castBytes[0] = (byte)0xde;
+ castBuffer.putShort(1, (short)n);
+ out.write(castBytes, 0, 3);
+ } else {
+ castBytes[0] = (byte)0xdf;
+ castBuffer.putInt(1, n);
+ out.write(castBytes, 0, 5);
+ }
+ return this;
+ }
+
+ public Packer packRaw(int n) throws IOException {
+ if(n < 32) {
+ final int d = 0xa0 | n;
+ out.write((byte)d);
+ } else if(n < 65536) {
+ castBytes[0] = (byte)0xda;
+ castBuffer.putShort(1, (short)n);
+ out.write(castBytes, 0, 3);
+ } else {
+ castBytes[0] = (byte)0xdb;
+ castBuffer.putInt(1, n);
+ out.write(castBytes, 0, 5);
+ }
+ return this;
+ }
+
+ public Packer packRawBody(byte[] b) throws IOException {
+ out.write(b);
+ return this;
+ }
+
+ public Packer packRawBody(byte[] b, int off, int length) throws IOException {
+ out.write(b, off, length);
+ return this;
+ }
+
+
+ public Packer packWithSchema(Object o, Schema s) throws IOException {
+ s.pack(this, o);
+ return this;
+ }
+
+
+ public Packer packString(String s) throws IOException {
+ byte[] b = ((String)s).getBytes("UTF-8");
+ packRaw(b.length);
+ return packRawBody(b);
+ }
+
+
+ public Packer pack(String o) throws IOException {
+ if(o == null) { return packNil(); }
+ return packString(o);
+ }
+
+ public Packer pack(MessagePackable o) throws IOException {
+ if(o == null) { return packNil(); }
+ o.messagePack(this);
+ return this;
+ }
+
+ public Packer pack(byte[] o) throws IOException {
+ if(o == null) { return packNil(); }
+ packRaw(o.length);
+ return packRawBody(o);
+ }
+
+ public Packer pack(List o) throws IOException {
+ if(o == null) { return packNil(); }
+ packArray(o.size());
+ for(Object i : o) { pack(i); }
+ return this;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Packer pack(Map o) throws IOException {
+ if(o == null) { return packNil(); }
+ packMap(o.size());
+ for(Map.Entry e : ((Map<Object,Object>)o).entrySet()) {
+ pack(e.getKey());
+ pack(e.getValue());
+ }
+ return this;
+ }
+
+ public Packer pack(Boolean o) throws IOException {
+ if(o == null) { return packNil(); }
+ if(o) {
+ return packTrue();
+ } else {
+ return packFalse();
+ }
+ }
+
+ public Packer pack(Byte o) throws IOException {
+ if(o == null) { return packNil(); }
+ return packByte(o);
+ }
+
+ public Packer pack(Short o) throws IOException {
+ if(o == null) { return packNil(); }
+ return packShort(o);
+ }
+
+ public Packer pack(Integer o) throws IOException {
+ if(o == null) { return packNil(); }
+ return packInt(o);
+ }
+
+ public Packer pack(Long o) throws IOException {
+ if(o == null) { return packNil(); }
+ return packLong(o);
+ }
+
+ public Packer pack(Float o) throws IOException {
+ if(o == null) { return packNil(); }
+ return packFloat(o);
+ }
+
+ public Packer pack(Double o) throws IOException {
+ if(o == null) { return packNil(); }
+ return packDouble(o);
+ }
+
+
+ @SuppressWarnings("unchecked")
+ public Packer pack(Object o) throws IOException {
+ if(o == null) {
+ return packNil();
+ } else if(o instanceof String) {
+ byte[] b = ((String)o).getBytes("UTF-8");
+ packRaw(b.length);
+ return packRawBody(b);
+ } else if(o instanceof MessagePackable) {
+ ((MessagePackable)o).messagePack(this);
+ return this;
+ } else if(o instanceof byte[]) {
+ byte[] b = (byte[])o;
+ packRaw(b.length);
+ return packRawBody(b);
+ } else if(o instanceof List) {
+ List<Object> l = (List<Object>)o;
+ packArray(l.size());
+ for(Object i : l) { pack(i); }
+ return this;
+ } else if(o instanceof Map) {
+ Map<Object,Object> m = (Map<Object,Object>)o;
+ packMap(m.size());
+ for(Map.Entry e : m.entrySet()) {
+ pack(e.getKey());
+ pack(e.getValue());
+ }
+ return this;
+ } else if(o instanceof Boolean) {
+ if((Boolean)o) {
+ return packTrue();
+ } else {
+ return packFalse();
+ }
+ } else if(o instanceof Integer) {
+ return packInt((Integer)o);
+ } else if(o instanceof Long) {
+ return packLong((Long)o);
+ } else if(o instanceof Short) {
+ return packShort((Short)o);
+ } else if(o instanceof Byte) {
+ return packByte((Byte)o);
+ } else if(o instanceof Float) {
+ return packFloat((Float)o);
+ } else if(o instanceof Double) {
+ return packDouble((Double)o);
+ } else {
+ throw new IOException("unknown object "+o+" ("+o.getClass()+")");
+ }
+ }
+}
+
diff --git a/java-plan3/src/org/msgpack/Schema.java b/java-plan3/src/org/msgpack/Schema.java
new file mode 100644
index 0000000..f99b3d0
--- /dev/null
+++ b/java-plan3/src/org/msgpack/Schema.java
@@ -0,0 +1,133 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 FURUHASHI Sadayuki
+//
+// 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 org.msgpack;
+
+import java.io.Writer;
+import java.io.IOException;
+import org.msgpack.schema.SSchemaParser;
+import org.msgpack.schema.ClassGenerator;
+
+public abstract class Schema {
+ private String expression;
+ private String name;
+
+ public Schema(String name) {
+ this.expression = expression;
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getFullName() {
+ return name;
+ }
+
+ public String getExpression() {
+ return name;
+ }
+
+ public static Schema parse(String source) {
+ return SSchemaParser.parse(source);
+ }
+
+ public static Schema load(String source) {
+ return SSchemaParser.load(source);
+ }
+
+ public void write(Writer output) throws IOException {
+ ClassGenerator.write(this, output);
+ }
+
+ public abstract void pack(Packer pk, Object obj) throws IOException;
+
+ public abstract Object convert(Object obj) throws MessageTypeException;
+
+
+ public Object createFromNil() {
+ return null;
+ }
+
+ public Object createFromBoolean(boolean v) {
+ throw new RuntimeException("type error");
+ }
+
+ public Object createFromByte(byte v) {
+ throw new RuntimeException("type error");
+ }
+
+ public Object createFromShort(short v) {
+ throw new RuntimeException("type error");
+ }
+
+ public Object createFromInt(int v) {
+ throw new RuntimeException("type error");
+ }
+
+ public Object createFromLong(long v) {
+ throw new RuntimeException("type error");
+ }
+
+ public Object createFromFloat(float v) {
+ throw new RuntimeException("type error");
+ }
+
+ public Object createFromDouble(double v) {
+ throw new RuntimeException("type error");
+ }
+
+ public Object createFromRaw(byte[] b, int offset, int length) {
+ throw new RuntimeException("type error");
+ }
+
+ /* FIXME
+ public Object createFromBoolean(boolean v) {
+ throw MessageTypeException.schemaMismatch(this);
+ }
+
+ public Object createFromByte(byte v) {
+ throw MessageTypeException.schemaMismatch(this);
+ }
+
+ public Object createFromShort(short v) {
+ throw MessageTypeException.schemaMismatch(this);
+ }
+
+ public Object createFromInt(int v) {
+ throw MessageTypeException.schemaMismatch(this);
+ }
+
+ public Object createFromLong(long v) {
+ throw MessageTypeException.schemaMismatch(this);
+ }
+
+ public Object createFromFloat(float v) {
+ throw MessageTypeException.schemaMismatch(this);
+ }
+
+ public Object createFromDouble(double v) {
+ throw MessageTypeException.schemaMismatch(this);
+ }
+
+ public Object createFromRaw(byte[] b, int offset, int length) {
+ throw MessageTypeException.schemaMismatch(this);
+ }
+ */
+}
+
diff --git a/java-plan3/src/org/msgpack/UnbufferedUnpacker.java b/java-plan3/src/org/msgpack/UnbufferedUnpacker.java
new file mode 100644
index 0000000..471605f
--- /dev/null
+++ b/java-plan3/src/org/msgpack/UnbufferedUnpacker.java
@@ -0,0 +1,82 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 FURUHASHI Sadayuki
+//
+// 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 org.msgpack;
+
+import java.lang.Iterable;
+import java.io.InputStream;
+import java.io.IOException;
+import java.util.Iterator;
+import org.msgpack.impl.UnpackerImpl;
+
+public class UnbufferedUnpacker extends UnpackerImpl {
+ private int offset;
+ private boolean finished;
+ private Object data;
+
+ public UnbufferedUnpacker() {
+ super();
+ this.offset = 0;
+ this.finished = false;
+ }
+
+ public UnbufferedUnpacker useSchema(Schema s) {
+ super.setSchema(s);
+ return this;
+ }
+
+ public Object getData() {
+ return data;
+ }
+
+ public boolean isFinished() {
+ return finished;
+ }
+
+ public void reset() {
+ super.reset();
+ this.offset = 0;
+ }
+
+ int getOffset() {
+ return offset;
+ }
+
+ void setOffset(int offset) {
+ this.offset = offset;
+ }
+
+ public int execute(byte[] buffer) throws UnpackException {
+ return execute(buffer, 0, buffer.length);
+ }
+
+ // FIXME
+ public int execute(byte[] buffer, int offset, int length) throws UnpackException
+ {
+ int noffset = super.execute(buffer, offset + this.offset, length);
+ this.offset = noffset - offset;
+ if(super.isFinished()) {
+ this.data = super.getData();
+ this.finished = true;
+ super.reset();
+ } else {
+ this.finished = false;
+ }
+ return noffset;
+ }
+}
+
diff --git a/java-plan3/src/org/msgpack/UnpackException.java b/java-plan3/src/org/msgpack/UnpackException.java
new file mode 100644
index 0000000..db08d95
--- /dev/null
+++ b/java-plan3/src/org/msgpack/UnpackException.java
@@ -0,0 +1,29 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 FURUHASHI Sadayuki
+//
+// 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 org.msgpack;
+
+import java.io.IOException;
+
+public class UnpackException extends IOException {
+ public UnpackException() { }
+
+ public UnpackException(String s) {
+ super(s);
+ }
+}
+
diff --git a/java-plan3/src/org/msgpack/UnpackIterator.java b/java-plan3/src/org/msgpack/UnpackIterator.java
new file mode 100644
index 0000000..9975b68
--- /dev/null
+++ b/java-plan3/src/org/msgpack/UnpackIterator.java
@@ -0,0 +1,66 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 FURUHASHI Sadayuki
+//
+// 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 org.msgpack;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+public class UnpackIterator implements Iterator<Object> {
+ private Unpacker pac;
+ private boolean have;
+ private Object data;
+
+ UnpackIterator(Unpacker pac) {
+ this.pac = pac;
+ this.have = false;
+ }
+
+ public boolean hasNext() {
+ if(have) { return true; }
+ try {
+ while(true) {
+ if(pac.execute()) {
+ data = pac.getData();
+ pac.reset();
+ have = true;
+ return true;
+ }
+
+ if(!pac.fill()) {
+ return false;
+ }
+ }
+ } catch (IOException e) {
+ return false;
+ }
+ }
+
+ public Object next() {
+ if(!have && !hasNext()) {
+ throw new NoSuchElementException();
+ }
+ have = false;
+ return data;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+}
+
diff --git a/java-plan3/src/org/msgpack/Unpacker.java b/java-plan3/src/org/msgpack/Unpacker.java
new file mode 100644
index 0000000..af211c6
--- /dev/null
+++ b/java-plan3/src/org/msgpack/Unpacker.java
@@ -0,0 +1,245 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 FURUHASHI Sadayuki
+//
+// 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 org.msgpack;
+
+import java.lang.Iterable;
+import java.io.InputStream;
+import java.io.IOException;
+import java.util.Iterator;
+import org.msgpack.impl.UnpackerImpl;
+
+public class Unpacker extends UnpackerImpl implements Iterable<Object> {
+
+ public static final int DEFAULT_BUFFER_SIZE = 32*1024;
+
+ private int used;
+ private int offset;
+ private int parsed;
+ private byte[] buffer;
+ private int bufferReserveSize;
+ private InputStream stream;
+
+ public Unpacker() {
+ this(DEFAULT_BUFFER_SIZE);
+ }
+
+ public Unpacker(int bufferReserveSize) {
+ this(null, bufferReserveSize);
+ }
+
+ public Unpacker(InputStream stream) {
+ this(stream, DEFAULT_BUFFER_SIZE);
+ }
+
+ public Unpacker(InputStream stream, int bufferReserveSize) {
+ super();
+ this.used = 0;
+ this.offset = 0;
+ this.parsed = 0;
+ this.buffer = new byte[bufferReserveSize];
+ this.bufferReserveSize = bufferReserveSize/2;
+ this.stream = stream;
+ }
+
+ public Unpacker useSchema(Schema s) {
+ super.setSchema(s);
+ return this;
+ }
+
+ public void reserveBuffer(int size) {
+ if(buffer.length - used >= size) {
+ return;
+ }
+ /*
+ if(used == parsed && buffer.length >= size) {
+ // rewind buffer
+ used = 0;
+ offset = 0;
+ return;
+ }
+ */
+
+ int nextSize = buffer.length * 2;
+ while(nextSize < size + used) {
+ nextSize *= 2;
+ }
+
+ byte[] tmp = new byte[nextSize];
+ System.arraycopy(buffer, offset, tmp, 0, used - offset);
+
+ buffer = tmp;
+ used -= offset;
+ offset = 0;
+ }
+
+ public byte[] getBuffer() {
+ return buffer;
+ }
+
+ public int getBufferOffset() {
+ return used;
+ }
+
+ public int getBufferCapacity() {
+ return buffer.length - used;
+ }
+
+ public void bufferConsumed(int size) {
+ used += size;
+ }
+
+ public void feed(byte[] buffer) {
+ feed(buffer, 0, buffer.length);
+ }
+
+ public void feed(byte[] buffer, int offset, int length) {
+ reserveBuffer(length);
+ System.arraycopy(buffer, offset, this.buffer, this.offset, length);
+ bufferConsumed(length);
+ }
+
+ public boolean fill() throws IOException {
+ if(stream == null) {
+ return false;
+ }
+ reserveBuffer(bufferReserveSize);
+ int rl = stream.read(getBuffer(), getBufferOffset(), getBufferCapacity());
+ if(rl <= 0) {
+ return false;
+ }
+ bufferConsumed(rl);
+ return true;
+ }
+
+ public Iterator<Object> iterator() {
+ return new UnpackIterator(this);
+ }
+
+ public boolean execute() throws UnpackException {
+ int noffset = super.execute(buffer, offset, used);
+ if(noffset <= offset) {
+ return false;
+ }
+ parsed += noffset - offset;
+ offset = noffset;
+ return super.isFinished();
+ }
+
+ public Object getData() {
+ return super.getData();
+ }
+
+ public void reset() {
+ super.reset();
+ parsed = 0;
+ }
+
+ public int getMessageSize() {
+ return parsed - offset + used;
+ }
+
+ public int getParsedSize() {
+ return parsed;
+ }
+
+ public int getNonParsedSize() {
+ return used - offset;
+ }
+
+ public void skipNonparsedBuffer(int size) {
+ offset += size;
+ }
+
+ public void removeNonparsedBuffer() {
+ used = offset;
+ }
+
+ /*
+ public static class Context {
+ private boolean finished;
+ private Object data;
+ private int offset;
+ private UnpackerImpl impl;
+
+ public Context()
+ {
+ this.finished = false;
+ this.impl = new UnpackerImpl();
+ }
+
+ public boolean isFinished()
+ {
+ return finished;
+ }
+
+ public Object getData()
+ {
+ return data;
+ }
+
+ int getOffset()
+ {
+ return offset;
+ }
+
+ void setFinished(boolean finished)
+ {
+ this.finished = finished;
+ }
+
+ void setData(Object data)
+ {
+ this.data = data;
+ }
+
+ void setOffset(int offset)
+ {
+ this.offset = offset;
+ }
+
+ UnpackerImpl getImpl()
+ {
+ return impl;
+ }
+ }
+
+ public static int unpack(Context ctx, byte[] buffer) throws UnpackException
+ {
+ return unpack(ctx, buffer, 0, buffer.length);
+ }
+
+ public static int unpack(Context ctx, byte[] buffer, int offset, int length) throws UnpackException
+ {
+ UnpackerImpl impl = ctx.getImpl();
+ int noffset = impl.execute(buffer, offset + ctx.getOffset(), length);
+ ctx.setOffset(noffset - offset);
+ if(impl.isFinished()) {
+ ctx.setData(impl.getData());
+ ctx.setFinished(false);
+ impl.reset();
+ } else {
+ ctx.setData(null);
+ ctx.setFinished(true);
+ }
+ int parsed = noffset - offset;
+ ctx.setOffset(parsed);
+ return noffset;
+ }
+ */
+}
+
diff --git a/java-plan3/src/org/msgpack/impl/UnpackerImpl.java b/java-plan3/src/org/msgpack/impl/UnpackerImpl.java
new file mode 100644
index 0000000..47a1800
--- /dev/null
+++ b/java-plan3/src/org/msgpack/impl/UnpackerImpl.java
@@ -0,0 +1,483 @@
+package org.msgpack.impl;
+
+import java.nio.ByteBuffer;
+//import java.math.BigInteger;
+import org.msgpack.*;
+import org.msgpack.schema.GenericSchema;
+import org.msgpack.schema.IMapSchema;
+import org.msgpack.schema.IArraySchema;
+
+public class UnpackerImpl {
+ static final int CS_HEADER = 0x00;
+ static final int CS_FLOAT = 0x0a;
+ static final int CS_DOUBLE = 0x0b;
+ static final int CS_UINT_8 = 0x0c;
+ static final int CS_UINT_16 = 0x0d;
+ static final int CS_UINT_32 = 0x0e;
+ static final int CS_UINT_64 = 0x0f;
+ static final int CS_INT_8 = 0x10;
+ static final int CS_INT_16 = 0x11;
+ static final int CS_INT_32 = 0x12;
+ static final int CS_INT_64 = 0x13;
+ static final int CS_RAW_16 = 0x1a;
+ static final int CS_RAW_32 = 0x1b;
+ static final int CS_ARRAY_16 = 0x1c;
+ static final int CS_ARRAY_32 = 0x1d;
+ static final int CS_MAP_16 = 0x1e;
+ static final int CS_MAP_32 = 0x1f;
+ static final int ACS_RAW_VALUE = 0x20;
+ static final int CT_ARRAY_ITEM = 0x00;
+ static final int CT_MAP_KEY = 0x01;
+ static final int CT_MAP_VALUE = 0x02;
+
+ static final int MAX_STACK_SIZE = 16;
+
+ private int cs;
+ private int trail;
+ private int top;
+ private int[] stack_ct = new int[MAX_STACK_SIZE];
+ private int[] stack_count = new int[MAX_STACK_SIZE];
+ private Object[] stack_obj = new Object[MAX_STACK_SIZE];
+ private Schema[] stack_schema = new Schema[MAX_STACK_SIZE];
+ private int top_ct;
+ private int top_count;
+ private Object top_obj;
+ private Schema top_schema;
+ private ByteBuffer castBuffer = ByteBuffer.allocate(8);
+ private boolean finished = false;
+ private Object data = null;
+
+ private static final Schema GENERIC_SCHEMA = new GenericSchema();
+ private Schema rootSchema;
+
+ protected UnpackerImpl()
+ {
+ setSchema(GENERIC_SCHEMA);
+ }
+
+ protected void setSchema(Schema schema)
+ {
+ this.rootSchema = schema;
+ reset();
+ }
+
+ protected Object getData()
+ {
+ return data;
+ }
+
+ protected boolean isFinished()
+ {
+ return finished;
+ }
+
+ protected void reset()
+ {
+ cs = CS_HEADER;
+ top = -1;
+ finished = false;
+ data = null;
+ top_ct = 0;
+ top_count = 0;
+ top_obj = null;
+ top_schema = rootSchema;
+ }
+
+ @SuppressWarnings("unchecked")
+ protected int execute(byte[] src, int off, int length) throws UnpackException
+ {
+ if(off >= length) { return off; }
+
+ int limit = length;
+ int i = off;
+ int count;
+
+ Object obj = null;
+
+ _out: do {
+ _header_again: {
+ //System.out.println("while i:"+i+" limit:"+limit);
+
+ int b = src[i];
+
+ _push: {
+ _fixed_trail_again:
+ if(cs == CS_HEADER) {
+
+ if((b & 0x80) == 0) { // Positive Fixnum
+ //System.out.println("positive fixnum "+b);
+ obj = top_schema.createFromByte((byte)b);
+ break _push;
+ }
+
+ if((b & 0xe0) == 0xe0) { // Negative Fixnum
+ //System.out.println("negative fixnum "+b);
+ obj = top_schema.createFromByte((byte)b);
+ break _push;
+ }
+
+ if((b & 0xe0) == 0xa0) { // FixRaw
+ trail = b & 0x1f;
+ if(trail == 0) {
+ obj = top_schema.createFromRaw(new byte[0], 0, 0);
+ break _push;
+ }
+ cs = ACS_RAW_VALUE;
+ break _fixed_trail_again;
+ }
+
+ if((b & 0xf0) == 0x90) { // FixArray
+ if(top >= MAX_STACK_SIZE) {
+ throw new UnpackException("parse error");
+ }
+ if(!(top_schema instanceof IArraySchema)) {
+ throw new RuntimeException("type error");
+ }
+ count = b & 0x0f;
+ //System.out.println("fixarray count:"+count);
+ obj = new Object[count];
+ if(count == 0) { break _push; } // FIXME check IArraySchema
+ ++top;
+ stack_obj[top] = top_obj;
+ stack_ct[top] = top_ct;
+ stack_count[top] = top_count;
+ stack_schema[top] = top_schema;
+ top_obj = obj;
+ top_ct = CT_ARRAY_ITEM;
+ top_count = count;
+ top_schema = ((IArraySchema)top_schema).getElementSchema(0);
+ break _header_again;
+ }
+
+ if((b & 0xf0) == 0x80) { // FixMap
+ if(top >= MAX_STACK_SIZE) {
+ throw new UnpackException("parse error");
+ }
+ if(!(top_schema instanceof IMapSchema)) {
+ throw new RuntimeException("type error");
+ }
+ count = b & 0x0f;
+ obj = new Object[count*2];
+ if(count == 0) { break _push; } // FIXME check IMapSchema
+ //System.out.println("fixmap count:"+count);
+ ++top;
+ stack_obj[top] = top_obj;
+ stack_ct[top] = top_ct;
+ stack_count[top] = top_count;
+ stack_schema[top] = top_schema;
+ top_obj = obj;
+ top_ct = CT_MAP_KEY;
+ top_count = count;
+ top_schema = ((IMapSchema)top_schema).getKeySchema();
+ break _header_again;
+ }
+
+ switch(b & 0xff) { // FIXME
+ case 0xc0: // nil
+ obj = top_schema.createFromNil();
+ break _push;
+ case 0xc2: // false
+ obj = top_schema.createFromBoolean(false);
+ break _push;
+ case 0xc3: // true
+ obj = top_schema.createFromBoolean(true);
+ break _push;
+ case 0xca: // float
+ case 0xcb: // double
+ case 0xcc: // unsigned int 8
+ case 0xcd: // unsigned int 16
+ case 0xce: // unsigned int 32
+ case 0xcf: // unsigned int 64
+ case 0xd0: // signed int 8
+ case 0xd1: // signed int 16
+ case 0xd2: // signed int 32
+ case 0xd3: // signed int 64
+ trail = 1 << (b & 0x03);
+ cs = b & 0x1f;
+ //System.out.println("a trail "+trail+" cs:"+cs);
+ break _fixed_trail_again;
+ case 0xda: // raw 16
+ case 0xdb: // raw 32
+ case 0xdc: // array 16
+ case 0xdd: // array 32
+ case 0xde: // map 16
+ case 0xdf: // map 32
+ trail = 2 << (b & 0x01);
+ cs = b & 0x1f;
+ //System.out.println("b trail "+trail+" cs:"+cs);
+ break _fixed_trail_again;
+ default:
+ //System.out.println("unknown b "+(b&0xff));
+ throw new UnpackException("parse error");
+ }
+
+ } // _fixed_trail_again
+
+ do {
+ _fixed_trail_again: {
+
+ if(limit - i <= trail) { break _out; }
+ int n = i + 1;
+ i += trail;
+
+ switch(cs) {
+ case CS_FLOAT:
+ castBuffer.rewind();
+ castBuffer.put(src, n, 4);
+ obj = top_schema.createFromFloat( castBuffer.getFloat(0) );
+ //System.out.println("float "+obj);
+ break _push;
+ case CS_DOUBLE:
+ castBuffer.rewind();
+ castBuffer.put(src, n, 8);
+ obj = top_schema.createFromDouble( castBuffer.getDouble(0) );
+ //System.out.println("double "+obj);
+ break _push;
+ case CS_UINT_8:
+ //System.out.println(n);
+ //System.out.println(src[n]);
+ //System.out.println(src[n+1]);
+ //System.out.println(src[n-1]);
+ obj = top_schema.createFromShort( (short)((src[n]) & 0xff) );
+ //System.out.println("uint8 "+obj);
+ break _push;
+ case CS_UINT_16:
+ //System.out.println(src[n]);
+ //System.out.println(src[n+1]);
+ castBuffer.rewind();
+ castBuffer.put(src, n, 2);
+ obj = top_schema.createFromInt( ((int)castBuffer.getShort(0)) & 0xffff );
+ //System.out.println("uint 16 "+obj);
+ break _push;
+ case CS_UINT_32:
+ castBuffer.rewind();
+ castBuffer.put(src, n, 4);
+ obj = top_schema.createFromLong( ((long)castBuffer.getInt(0)) & 0xffffffffL );
+ //System.out.println("uint 32 "+obj);
+ break _push;
+ case CS_UINT_64:
+ castBuffer.rewind();
+ castBuffer.put(src, n, 8);
+ {
+ long o = castBuffer.getLong(0);
+ if(o < 0) {
+ // FIXME
+ //obj = GenericBigInteger.valueOf(o & 0x7fffffffL).setBit(31);
+ throw new UnpackException("uint 64 bigger than 0x7fffffff is not supported");
+ } else {
+ obj = top_schema.createFromLong( o );
+ }
+ }
+ break _push;
+ case CS_INT_8:
+ obj = top_schema.createFromByte( src[n] );
+ break _push;
+ case CS_INT_16:
+ castBuffer.rewind();
+ castBuffer.put(src, n, 2);
+ obj = top_schema.createFromShort( castBuffer.getShort(0) );
+ break _push;
+ case CS_INT_32:
+ castBuffer.rewind();
+ castBuffer.put(src, n, 4);
+ obj = top_schema.createFromInt( castBuffer.getInt(0) );
+ break _push;
+ case CS_INT_64:
+ castBuffer.rewind();
+ castBuffer.put(src, n, 8);
+ obj = top_schema.createFromLong( castBuffer.getLong(0) );
+ break _push;
+ case CS_RAW_16:
+ castBuffer.rewind();
+ castBuffer.put(src, n, 2);
+ trail = ((int)castBuffer.getShort(0)) & 0xffff;
+ if(trail == 0) {
+ obj = top_schema.createFromRaw(new byte[0], 0, 0);
+ break _push;
+ }
+ cs = ACS_RAW_VALUE;
+ break _fixed_trail_again;
+ case CS_RAW_32:
+ castBuffer.rewind();
+ castBuffer.put(src, n, 4);
+ // FIXME overflow check
+ trail = castBuffer.getInt(0) & 0x7fffffff;
+ if(trail == 0) {
+ obj = top_schema.createFromRaw(new byte[0], 0, 0);
+ break _push;
+ }
+ cs = ACS_RAW_VALUE;
+ case ACS_RAW_VALUE:
+ obj = top_schema.createFromRaw(src, n, trail);
+ break _push;
+ case CS_ARRAY_16:
+ if(top >= MAX_STACK_SIZE) {
+ throw new UnpackException("parse error");
+ }
+ if(!(top_schema instanceof IArraySchema)) {
+ throw new RuntimeException("type error");
+ }
+ castBuffer.rewind();
+ castBuffer.put(src, n, 2);
+ count = ((int)castBuffer.getShort(0)) & 0xffff;
+ obj = new Object[count];
+ if(count == 0) { break _push; } // FIXME check IArraySchema
+ ++top;
+ stack_obj[top] = top_obj;
+ stack_ct[top] = top_ct;
+ stack_count[top] = top_count;
+ stack_schema[top] = top_schema;
+ top_obj = obj;
+ top_ct = CT_ARRAY_ITEM;
+ top_count = count;
+ top_schema = ((IArraySchema)top_schema).getElementSchema(0);
+ break _header_again;
+ case CS_ARRAY_32:
+ if(top >= MAX_STACK_SIZE) {
+ throw new UnpackException("parse error");
+ }
+ if(!(top_schema instanceof IArraySchema)) {
+ throw new RuntimeException("type error");
+ }
+ castBuffer.rewind();
+ castBuffer.put(src, n, 4);
+ // FIXME overflow check
+ count = castBuffer.getInt(0) & 0x7fffffff;
+ obj = new Object[count];
+ if(count == 0) { break _push; } // FIXME check IArraySchema
+ ++top;
+ stack_obj[top] = top_obj;
+ stack_ct[top] = top_ct;
+ stack_count[top] = top_count;
+ stack_schema[top] = top_schema;
+ top_obj = obj;
+ top_ct = CT_ARRAY_ITEM;
+ top_count = count;
+ top_schema = ((IArraySchema)top_schema).getElementSchema(0);
+ break _header_again;
+ case CS_MAP_16:
+ if(top >= MAX_STACK_SIZE) {
+ throw new UnpackException("parse error");
+ }
+ if(!(top_schema instanceof IMapSchema)) {
+ throw new RuntimeException("type error");
+ }
+ castBuffer.rewind();
+ castBuffer.put(src, n, 2);
+ count = ((int)castBuffer.getShort(0)) & 0xffff;
+ obj = new Object[count*2];
+ if(count == 0) { break _push; } // FIXME check IMapSchema
+ //System.out.println("fixmap count:"+count);
+ stack_obj[top] = top_obj;
+ stack_ct[top] = top_ct;
+ stack_count[top] = top_count;
+ stack_schema[top] = top_schema;
+ ++top;
+ top_obj = obj;
+ top_ct = CT_MAP_KEY;
+ top_count = count;
+ top_schema = ((IMapSchema)top_schema).getKeySchema();
+ break _header_again;
+ case CS_MAP_32:
+ if(top >= MAX_STACK_SIZE) {
+ throw new UnpackException("parse error");
+ }
+ if(!(top_schema instanceof IMapSchema)) {
+ throw new RuntimeException("type error");
+ }
+ castBuffer.rewind();
+ castBuffer.put(src, n, 4);
+ // FIXME overflow check
+ count = castBuffer.getInt(0) & 0x7fffffff;
+ obj = new Object[count*2];
+ if(count == 0) { break _push; } // FIXME check IMapSchema
+ //System.out.println("fixmap count:"+count);
+ ++top;
+ stack_obj[top] = top_obj;
+ stack_ct[top] = top_ct;
+ stack_count[top] = top_count;
+ stack_schema[top] = top_schema;
+ top_obj = obj;
+ top_ct = CT_MAP_KEY;
+ top_count = count;
+ top_schema = ((IMapSchema)top_schema).getKeySchema();
+ break _header_again;
+ default:
+ throw new UnpackException("parse error");
+ }
+
+ } // _fixed_trail_again
+ } while(true);
+ } // _push
+
+ do {
+ _push: {
+ //System.out.println("push top:"+top);
+ if(top == -1) {
+ ++i;
+ data = obj;
+ finished = true;
+ break _out;
+ }
+
+ switch(top_ct) {
+ case CT_ARRAY_ITEM: {
+ //System.out.println("array item "+obj);
+ Object[] ar = (Object[])top_obj;
+ ar[ar.length - top_count] = obj;
+ if(--top_count == 0) {
+ top_obj = stack_obj[top];
+ top_ct = stack_ct[top];
+ top_count = stack_count[top];
+ top_schema = stack_schema[top];
+ obj = ((IArraySchema)top_schema).createFromArray(ar);
+ stack_obj[top] = null;
+ stack_schema[top] = null;
+ --top;
+ break _push;
+ } else {
+ top_schema = ((IArraySchema)stack_schema[top]).getElementSchema(ar.length - top_count);
+ }
+ break _header_again;
+ }
+ case CT_MAP_KEY: {
+ //System.out.println("map key:"+top+" "+obj);
+ Object[] mp = (Object[])top_obj;
+ mp[mp.length - top_count*2] = obj;
+ top_ct = CT_MAP_VALUE;
+ top_schema = ((IMapSchema)stack_schema[top]).getValueSchema();
+ break _header_again;
+ }
+ case CT_MAP_VALUE: {
+ //System.out.println("map value:"+top+" "+obj);
+ Object[] mp = (Object[])top_obj;
+ mp[mp.length - top_count*2 + 1] = obj;
+ if(--top_count == 0) {
+ top_obj = stack_obj[top];
+ top_ct = stack_ct[top];
+ top_count = stack_count[top];
+ top_schema = stack_schema[top];
+ obj = ((IMapSchema)top_schema).createFromMap(mp);
+ stack_obj[top] = null;
+ stack_schema[top] = null;
+ --top;
+ break _push;
+ }
+ top_ct = CT_MAP_KEY;
+ break _header_again;
+ }
+ default:
+ throw new UnpackException("parse error");
+ }
+ } // _push
+ } while(true);
+
+ } // _header_again
+ cs = CS_HEADER;
+ ++i;
+ } while(i < limit); // _out
+
+ return i;
+ }
+}
+
diff --git a/java-plan3/src/org/msgpack/schema/ArraySchema.java b/java-plan3/src/org/msgpack/schema/ArraySchema.java
new file mode 100644
index 0000000..24fa758
--- /dev/null
+++ b/java-plan3/src/org/msgpack/schema/ArraySchema.java
@@ -0,0 +1,125 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 FURUHASHI Sadayuki
+//
+// 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 org.msgpack.schema;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Set;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.RandomAccess;
+import java.io.IOException;
+import org.msgpack.*;
+
+public class ArraySchema extends Schema implements IArraySchema {
+ private Schema elementSchema;
+
+ public ArraySchema(Schema elementSchema)
+ {
+ super("array");
+ this.elementSchema = elementSchema;
+ }
+
+ @Override
+ public String getFullName()
+ {
+ return "List<"+elementSchema.getFullName()+">";
+ }
+
+ @Override
+ public String getExpression()
+ {
+ return "(array "+elementSchema.getExpression()+")";
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void pack(Packer pk, Object obj) throws IOException
+ {
+ if(obj instanceof List) {
+ ArrayList<Object> d = (ArrayList<Object>)obj;
+ pk.packArray(d.size());
+ if(obj instanceof RandomAccess) {
+ for(int i=0; i < d.size(); ++i) {
+ elementSchema.pack(pk, d.get(i));
+ }
+ } else {
+ for(Object e : d) {
+ elementSchema.pack(pk, e);
+ }
+ }
+
+ } else if(obj instanceof Set) {
+ Set<Object> d = (Set<Object>)obj;
+ pk.packArray(d.size());
+ for(Object e : d) {
+ elementSchema.pack(pk, e);
+ }
+
+ } else if(obj == null) {
+ pk.packNil();
+
+ } else {
+ throw MessageTypeException.invalidConvert(obj, this);
+ }
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object convert(Object obj) throws MessageTypeException
+ {
+ if(obj instanceof List) {
+ List d = (List)obj;
+ ArrayList ar = new ArrayList(d.size());
+ if(obj instanceof RandomAccess) {
+ for(int i=0; i < d.size(); ++i) {
+ ar.add( elementSchema.convert(d.get(i)) );
+ }
+ } else {
+ for(Object e : d) {
+ ar.add( elementSchema.convert(e) );
+ }
+ }
+ return ar;
+
+ } else if(obj instanceof Collection) {
+ Collection d = (Collection)obj;
+ ArrayList ar = new ArrayList(d.size());
+ for(Object e : (Collection)obj) {
+ ar.add( elementSchema.convert(e) );
+ }
+ return ar;
+
+ } else {
+ throw MessageTypeException.invalidConvert(obj, this);
+ }
+ }
+
+ @Override
+ public Schema getElementSchema(int index)
+ {
+ return elementSchema;
+ }
+
+ @Override
+ public Object createFromArray(Object[] obj)
+ {
+ return Arrays.asList(obj);
+ }
+}
+
diff --git a/java-plan3/src/org/msgpack/schema/ByteSchema.java b/java-plan3/src/org/msgpack/schema/ByteSchema.java
new file mode 100644
index 0000000..3bc7045
--- /dev/null
+++ b/java-plan3/src/org/msgpack/schema/ByteSchema.java
@@ -0,0 +1,89 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 FURUHASHI Sadayuki
+//
+// 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 org.msgpack.schema;
+
+import java.io.IOException;
+import org.msgpack.*;
+
+public class ByteSchema extends Schema {
+ public ByteSchema() {
+ super("Byte");
+ }
+
+ @Override
+ public String getExpression() {
+ return "byte";
+ }
+
+ @Override
+ public void pack(Packer pk, Object obj) throws IOException {
+ if(obj instanceof Number) {
+ pk.packByte( ((Number)obj).byteValue() );
+
+ } else if(obj == null) {
+ pk.packNil();
+
+ } else {
+ throw MessageTypeException.invalidConvert(obj, this);
+ }
+ }
+
+ @Override
+ public Object convert(Object obj) throws MessageTypeException {
+ if(obj instanceof Byte) {
+ return obj;
+
+ } else if(obj instanceof Number) {
+ return ((Number)obj).byteValue();
+
+ } else {
+ throw MessageTypeException.invalidConvert(obj, this);
+ }
+ }
+
+ @Override
+ public Object createFromByte(byte v) {
+ return (byte)v;
+ }
+
+ @Override
+ public Object createFromShort(short v) {
+ return (byte)v;
+ }
+
+ @Override
+ public Object createFromInt(int v) {
+ return (byte)v;
+ }
+
+ @Override
+ public Object createFromLong(long v) {
+ return (byte)v;
+ }
+
+ @Override
+ public Object createFromFloat(float v) {
+ return (byte)v;
+ }
+
+ @Override
+ public Object createFromDouble(double v) {
+ return (byte)v;
+ }
+}
+
diff --git a/java-plan3/src/org/msgpack/schema/ClassGenerator.java b/java-plan3/src/org/msgpack/schema/ClassGenerator.java
new file mode 100644
index 0000000..65213aa
--- /dev/null
+++ b/java-plan3/src/org/msgpack/schema/ClassGenerator.java
@@ -0,0 +1,241 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 FURUHASHI Sadayuki
+//
+// 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 org.msgpack.schema;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.io.IOException;
+import java.io.File;
+import java.io.Writer;
+import org.msgpack.*;
+
+public class ClassGenerator {
+ private ClassSchema schema;
+ private Writer writer;
+ private int indent;
+
+ private ClassGenerator(Writer writer) {
+ this.writer = writer;
+ this.indent = 0;
+ }
+
+ public static void write(Schema schema, Writer dest) throws IOException {
+ if(!(schema instanceof ClassSchema)) {
+ throw new RuntimeException("schema is not class schema");
+ }
+ ClassSchema cs = (ClassSchema)schema;
+ new ClassGenerator(dest).run(cs);
+ }
+
+ private void run(ClassSchema cs) throws IOException {
+ List<ClassSchema> subclasses = new ArrayList<ClassSchema>();
+ for(FieldSchema f : cs.getFields()) {
+ findSubclassSchema(subclasses, f.getSchema());
+ }
+
+ for(ClassSchema sub : subclasses) {
+ sub.setNamespace(cs.getNamespace());
+ sub.setImports(cs.getImports());
+ }
+
+ this.schema = cs;
+
+ writeHeader();
+
+ writeClass();
+
+ for(ClassSchema sub : subclasses) {
+ this.schema = sub;
+ writeSubclass();
+ }
+
+ writeFooter();
+
+ this.schema = null;
+ writer.flush();
+ }
+
+ private void findSubclassSchema(List<ClassSchema> dst, Schema s) {
+ if(s instanceof ClassSchema) {
+ ClassSchema cs = (ClassSchema)s;
+ if(!dst.contains(cs)) { dst.add(cs); }
+ for(FieldSchema f : cs.getFields()) {
+ findSubclassSchema(dst, f.getSchema());
+ }
+ } else if(s instanceof ArraySchema) {
+ ArraySchema as = (ArraySchema)s;
+ findSubclassSchema(dst, as.getElementSchema(0));
+ } else if(s instanceof MapSchema) {
+ MapSchema as = (MapSchema)s;
+ findSubclassSchema(dst, as.getKeySchema());
+ findSubclassSchema(dst, as.getValueSchema());
+ }
+ }
+
+ private void writeHeader() throws IOException {
+ if(schema.getNamespace() != null) {
+ line("package "+schema.getNamespace()+";");
+ line();
+ }
+ line("import java.util.*;");
+ line("import java.io.*;");
+ line("import org.msgpack.*;");
+ line("import org.msgpack.schema.ClassSchema;");
+ line("import org.msgpack.schema.FieldSchema;");
+ }
+
+ private void writeFooter() throws IOException {
+ line();
+ }
+
+ private void writeClass() throws IOException {
+ line();
+ line("public final class "+schema.getName()+" implements MessagePackable, MessageMergeable");
+ line("{");
+ pushIndent();
+ writeSchema();
+ writeMemberVariables();
+ writeMemberFunctions();
+ popIndent();
+ line("}");
+ }
+
+ private void writeSubclass() throws IOException {
+ line();
+ line("final class "+schema.getName()+" implements MessagePackable, MessageMergeable");
+ line("{");
+ pushIndent();
+ writeSchema();
+ writeMemberVariables();
+ writeMemberFunctions();
+ popIndent();
+ line("}");
+ }
+
+ private void writeSchema() throws IOException {
+ line("private static final ClassSchema _SCHEMA = (ClassSchema)Schema.load(\""+schema.getExpression()+"\");");
+ line("public static ClassSchema getSchema() { return _SCHEMA; }");
+ }
+
+ private void writeMemberVariables() throws IOException {
+ line();
+ for(FieldSchema f : schema.getFields()) {
+ line("public "+f.getSchema().getFullName()+" "+f.getName()+";");
+ }
+ }
+
+ private void writeMemberFunctions() throws IOException {
+ // void messagePack(Packer pk)
+ // boolean equals(Object obj)
+ // int hashCode()
+ // void set(int _index, Object _value)
+ // Object get(int _index);
+ // getXxx()
+ // setXxx(Xxx xxx)
+ writeConstructors();
+ writeAccessors();
+ writePackFunction();
+ writeMergeFunction();
+ writeFactoryFunction();
+ }
+
+ private void writeConstructors() throws IOException {
+ line();
+ line("public "+schema.getName()+"() { }");
+ }
+
+ private void writeAccessors() throws IOException {
+ // FIXME
+ //line();
+ //for(FieldSchema f : schema.getFields()) {
+ // line("");
+ //}
+ }
+
+ private void writePackFunction() throws IOException {
+ line();
+ line("@Override");
+ line("public void messagePack(Packer _pk) throws IOException");
+ line("{");
+ pushIndent();
+ line("_pk.packArray("+schema.getFields().length+");");
+ line("FieldSchema[] _fields = _SCHEMA.getFields();");
+ int i = 0;
+ for(FieldSchema f : schema.getFields()) {
+ line("_fields["+i+"].getSchema().pack(_pk, "+f.getName()+");");
+ ++i;
+ }
+ popIndent();
+ line("}");
+ }
+
+ private void writeMergeFunction() throws IOException {
+ line();
+ line("@Override");
+ line("@SuppressWarnings(\"unchecked\")");
+ line("public void messageMerge(Object obj) throws MessageTypeException");
+ line("{");
+ pushIndent();
+ line("Object[] _source = ((List)obj).toArray();");
+ line("FieldSchema[] _fields = _SCHEMA.getFields();");
+ int i = 0;
+ for(FieldSchema f : schema.getFields()) {
+ line("if(_source.length <= "+i+") { return; } this."+f.getName()+" = ("+f.getSchema().getFullName()+")_fields["+i+"].getSchema().convert(_source["+i+"]);");
+ ++i;
+ }
+ popIndent();
+ line("}");
+ }
+
+ private void writeFactoryFunction() throws IOException {
+ line();
+ line("@SuppressWarnings(\"unchecked\")");
+ line("public static "+schema.getName()+" createFromMessage(Object[] _message)");
+ line("{");
+ pushIndent();
+ line(schema.getName()+" _self = new "+schema.getName()+"();");
+ int i = 0;
+ for(FieldSchema f : schema.getFields()) {
+ line("if(_message.length <= "+i+") { return _self; } _self."+f.getName()+" = ("+f.getSchema().getFullName()+")_message["+i+"];");
+ ++i;
+ }
+ line("return _self;");
+ popIndent();
+ line("}");
+ }
+
+ private void line(String str) throws IOException {
+ for(int i=0; i < indent; ++i) {
+ writer.write("\t");
+ }
+ writer.write(str+"\n");
+ }
+
+ private void line() throws IOException {
+ writer.write("\n");
+ }
+
+ private void pushIndent() {
+ indent += 1;
+ }
+
+ private void popIndent() {
+ indent -= 1;
+ }
+}
+
diff --git a/java-plan3/src/org/msgpack/schema/ClassSchema.java b/java-plan3/src/org/msgpack/schema/ClassSchema.java
new file mode 100644
index 0000000..75315e7
--- /dev/null
+++ b/java-plan3/src/org/msgpack/schema/ClassSchema.java
@@ -0,0 +1,95 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 FURUHASHI Sadayuki
+//
+// 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 org.msgpack.schema;
+
+import java.util.Arrays;
+import java.util.List;
+import org.msgpack.*;
+
+public abstract class ClassSchema extends Schema implements IArraySchema {
+ protected FieldSchema[] fields;
+ protected List<String> imports;
+ protected String namespace;
+ protected String fqdn;
+
+ public ClassSchema(
+ String name, String namespace,
+ List<String> imports, List<FieldSchema> fields) {
+ super(name);
+ this.namespace = namespace;
+ this.imports = imports; // FIXME clone?
+ this.fields = new FieldSchema[fields.size()];
+ System.arraycopy(fields.toArray(), 0, this.fields, 0, fields.size());
+ if(namespace == null) {
+ this.fqdn = name;
+ } else {
+ this.fqdn = namespace+"."+name;
+ }
+ }
+
+ public final FieldSchema[] getFields() {
+ return fields;
+ }
+
+ String getNamespace() {
+ return namespace;
+ }
+
+ List<String> getImports() {
+ return imports;
+ }
+
+ void setNamespace(String namespace) {
+ this.namespace = namespace;
+ }
+
+ void setImports(List<String> imports) {
+ this.imports = imports; // FIXME clone?
+ }
+
+ //@Override
+ //public String getFullName()
+ //{
+ // if(namespace == null) {
+ // return getName();
+ // } else {
+ // return namespace+"."+getName();
+ // }
+ //}
+
+ @Override
+ public String getExpression() {
+ StringBuffer b = new StringBuffer();
+ b.append("(class ");
+ b.append(getName());
+ if(namespace != null) {
+ b.append(" (package "+namespace+")");
+ }
+ for(FieldSchema f : fields) {
+ b.append(" "+f.getExpression());
+ }
+ b.append(")");
+ return b.toString();
+ }
+
+ public boolean equals(SpecificClassSchema o) {
+ return (namespace != null ? namespace.equals(o.getNamespace()) : o.getNamespace() == null) &&
+ getName().equals(o.getName());
+ }
+}
+
diff --git a/java-plan3/src/org/msgpack/schema/DoubleSchema.java b/java-plan3/src/org/msgpack/schema/DoubleSchema.java
new file mode 100644
index 0000000..feffbb9
--- /dev/null
+++ b/java-plan3/src/org/msgpack/schema/DoubleSchema.java
@@ -0,0 +1,84 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 FURUHASHI Sadayuki
+//
+// 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 org.msgpack.schema;
+
+import java.io.IOException;
+import org.msgpack.*;
+
+public class DoubleSchema extends Schema {
+ public DoubleSchema() {
+ super("Double");
+ }
+
+ @Override
+ public String getExpression() {
+ return "double";
+ }
+
+ @Override
+ public void pack(Packer pk, Object obj) throws IOException {
+ if(obj instanceof Number) {
+ pk.packDouble( ((Number)obj).doubleValue() );
+
+ } else if(obj == null) {
+ pk.packNil();
+
+ } else {
+ throw MessageTypeException.invalidConvert(obj, this);
+ }
+ }
+
+ @Override
+ public Object convert(Object obj) throws MessageTypeException {
+ if(obj instanceof Double) {
+ return obj;
+
+ } else if(obj instanceof Number) {
+ return ((Number)obj).doubleValue();
+
+ } else {
+ throw MessageTypeException.invalidConvert(obj, this);
+ }
+ }
+
+ @Override
+ public Object createFromByte(byte v) {
+ return (double)v;
+ }
+
+ @Override
+ public Object createFromShort(short v) {
+ return (double)v;
+ }
+
+ @Override
+ public Object createFromInt(int v) {
+ return (double)v;
+ }
+
+ @Override
+ public Object createFromFloat(float v) {
+ return (double)v;
+ }
+
+ @Override
+ public Object createFromDouble(double v) {
+ return (double)v;
+ }
+}
+
diff --git a/java-plan3/src/org/msgpack/schema/FieldSchema.java b/java-plan3/src/org/msgpack/schema/FieldSchema.java
new file mode 100644
index 0000000..3391f2b
--- /dev/null
+++ b/java-plan3/src/org/msgpack/schema/FieldSchema.java
@@ -0,0 +1,43 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 FURUHASHI Sadayuki
+//
+// 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 org.msgpack.schema;
+
+import org.msgpack.Schema;
+
+public class FieldSchema {
+ private String name;
+ private Schema schema;
+
+ public FieldSchema(String name, Schema schema) {
+ this.name = name;
+ this.schema = schema;
+ }
+
+ public final String getName() {
+ return name;
+ }
+
+ public final Schema getSchema() {
+ return schema;
+ }
+
+ public String getExpression() {
+ return "(field "+name+" "+schema.getExpression()+")";
+ }
+}
+
diff --git a/java-plan3/src/org/msgpack/schema/FloatSchema.java b/java-plan3/src/org/msgpack/schema/FloatSchema.java
new file mode 100644
index 0000000..2f4240a
--- /dev/null
+++ b/java-plan3/src/org/msgpack/schema/FloatSchema.java
@@ -0,0 +1,84 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 FURUHASHI Sadayuki
+//
+// 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 org.msgpack.schema;
+
+import java.io.IOException;
+import org.msgpack.*;
+
+public class FloatSchema extends Schema {
+ public FloatSchema() {
+ super("Float");
+ }
+
+ @Override
+ public String getExpression() {
+ return "float";
+ }
+
+ @Override
+ public void pack(Packer pk, Object obj) throws IOException {
+ if(obj instanceof Number) {
+ pk.packFloat( ((Number)obj).floatValue() );
+
+ } else if(obj == null) {
+ pk.packNil();
+
+ } else {
+ throw MessageTypeException.invalidConvert(obj, this);
+ }
+ }
+
+ @Override
+ public Object convert(Object obj) throws MessageTypeException {
+ if(obj instanceof Float) {
+ return obj;
+
+ } else if(obj instanceof Number) {
+ return ((Number)obj).floatValue();
+
+ } else {
+ throw MessageTypeException.invalidConvert(obj, this);
+ }
+ }
+
+ @Override
+ public Object createFromByte(byte v) {
+ return (float)v;
+ }
+
+ @Override
+ public Object createFromShort(short v) {
+ return (float)v;
+ }
+
+ @Override
+ public Object createFromInt(int v) {
+ return (float)v;
+ }
+
+ @Override
+ public Object createFromFloat(float v) {
+ return (float)v;
+ }
+
+ @Override
+ public Object createFromDouble(double v) {
+ return (float)v;
+ }
+}
+
diff --git a/java-plan3/src/org/msgpack/schema/GenericClassSchema.java b/java-plan3/src/org/msgpack/schema/GenericClassSchema.java
new file mode 100644
index 0000000..736bdfa
--- /dev/null
+++ b/java-plan3/src/org/msgpack/schema/GenericClassSchema.java
@@ -0,0 +1,91 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 FURUHASHI Sadayuki
+//
+// 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 org.msgpack.schema;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+import java.io.IOException;
+import org.msgpack.*;
+
+public class GenericClassSchema extends ClassSchema {
+ public GenericClassSchema(
+ String name, String namespace,
+ List<String> imports, List<FieldSchema> fields) {
+ super(name, namespace, imports, fields);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void pack(Packer pk, Object obj) throws IOException {
+ if(obj instanceof Map) {
+ Map d = (Map)obj;
+ pk.packArray(fields.length);
+ for(int i=0; i < fields.length; ++i) {
+ FieldSchema f = fields[i];
+ f.getSchema().pack(pk, d.get(f.getName()));
+ }
+
+ } else if(obj == null) {
+ pk.packNil();
+
+ } else {
+ throw MessageTypeException.invalidConvert(obj, this);
+ }
+ }
+
+ @Override
+ public Object convert(Object obj) throws MessageTypeException {
+ if(obj instanceof Collection) {
+ // FIXME optimize
+ return createFromArray( ((Collection)obj).toArray() );
+
+ } else if(obj instanceof Map) {
+ HashMap<String,Object> m = new HashMap<String,Object>(fields.length);
+ Map d = (Map)obj;
+ for(int i=0; i < fields.length; ++i) {
+ FieldSchema f = fields[i];
+ String fieldName = f.getName();
+ m.put(fieldName, f.getSchema().convert(d.get(fieldName)));
+ }
+ return m;
+
+ } else {
+ throw MessageTypeException.invalidConvert(obj, this);
+ }
+ }
+
+ public Schema getElementSchema(int index) {
+ // FIXME check index < fields.length
+ return fields[index].getSchema();
+ }
+
+ public Object createFromArray(Object[] obj) {
+ HashMap<String,Object> m = new HashMap<String,Object>(fields.length);
+ int i=0;
+ for(; i < obj.length; ++i) {
+ m.put(fields[i].getName(), obj[i]);
+ }
+ for(; i < fields.length; ++i) {
+ m.put(fields[i].getName(), null);
+ }
+ return m;
+ }
+}
+
diff --git a/java-plan3/src/org/msgpack/schema/GenericSchema.java b/java-plan3/src/org/msgpack/schema/GenericSchema.java
new file mode 100644
index 0000000..52e0161
--- /dev/null
+++ b/java-plan3/src/org/msgpack/schema/GenericSchema.java
@@ -0,0 +1,192 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 FURUHASHI Sadayuki
+//
+// 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 org.msgpack.schema;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.HashMap;
+import java.io.IOException;
+import org.msgpack.*;
+//import org.msgpack.generic.*;
+
+public class GenericSchema extends Schema implements IArraySchema, IMapSchema {
+ public GenericSchema() {
+ super("Object");
+ }
+
+ @Override
+ public String getExpression() {
+ return "object";
+ }
+
+ @Override
+ public void pack(Packer pk, Object obj) throws IOException {
+ pk.pack(obj);
+ }
+
+ @Override
+ public Object convert(Object obj) throws MessageTypeException {
+ return obj;
+ }
+
+ @Override
+ public Schema getElementSchema(int index) {
+ return this;
+ }
+
+ @Override
+ public Schema getKeySchema() {
+ return this;
+ }
+
+ @Override
+ public Schema getValueSchema() {
+ return this;
+ }
+
+ @Override
+ public Object createFromNil() {
+ return null;
+ }
+
+ @Override
+ public Object createFromBoolean(boolean v) {
+ return v;
+ }
+
+ @Override
+ public Object createFromByte(byte v) {
+ return v;
+ }
+
+ @Override
+ public Object createFromShort(short v) {
+ return v;
+ }
+
+ @Override
+ public Object createFromInt(int v) {
+ return v;
+ }
+
+ @Override
+ public Object createFromLong(long v) {
+ return v;
+ }
+
+ @Override
+ public Object createFromFloat(float v) {
+ return v;
+ }
+
+ @Override
+ public Object createFromDouble(double v) {
+ return v;
+ }
+
+ @Override
+ public Object createFromRaw(byte[] b, int offset, int length) {
+ byte[] bytes = new byte[length];
+ System.arraycopy(b, offset, bytes, 0, length);
+ return bytes;
+ }
+
+ @Override
+ public Object createFromArray(Object[] obj) {
+ return Arrays.asList(obj);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object createFromMap(Object[] obj) {
+ HashMap m = new HashMap(obj.length / 2);
+ int i = 0;
+ while(i < obj.length) {
+ Object k = obj[i++];
+ Object v = obj[i++];
+ m.put(k, v);
+ }
+ return m;
+ }
+
+ /*
+ @Override
+ public Object createFromNil() {
+ return null;
+ }
+
+ @Override
+ public Object createFromBoolean(boolean v) {
+ return new GenericBoolean(v);
+ }
+
+ @Override
+ public Object createFromFromByte(byte v) {
+ return new GenericByte(v);
+ }
+
+ @Override
+ public Object createFromShort(short v) {
+ return new GenericShort(v);
+ }
+
+ @Override
+ public Object createFromInt(int v) {
+ return new GenericInt(v);
+ }
+
+ @Override
+ public Object createFromLong(long v) {
+ return new GenericLong(v);
+ }
+
+ @Override
+ public Object createFromFloat(float v) {
+ return new GenericFloat(v);
+ }
+
+ @Override
+ public Object createFromDouble(double v) {
+ return new GenericDouble(v);
+ }
+
+ @Override
+ public Object createFromRaw(byte[] b, int offset, int length) {
+ return new GenericRaw(b, offset, length);
+ }
+
+ @Override
+ public Object createFromArray(Object[] obj) {
+ // FIXME GenericArray
+ return Arrays.asList(obj);
+ }
+
+ @Override
+ public Object createFromMap(Object[] obj) {
+ GenericMap m = new GenericMap(obj.length / 2);
+ int i = 0;
+ while(i < obj.length) {
+ Object k = obj[i++];
+ Object v = obj[i++];
+ m.put(k, v);
+ }
+ return m;
+ }
+ */
+}
+
diff --git a/java-plan3/src/org/msgpack/schema/IArraySchema.java b/java-plan3/src/org/msgpack/schema/IArraySchema.java
new file mode 100644
index 0000000..ccc6d14
--- /dev/null
+++ b/java-plan3/src/org/msgpack/schema/IArraySchema.java
@@ -0,0 +1,26 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 FURUHASHI Sadayuki
+//
+// 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 org.msgpack.schema;
+
+import org.msgpack.Schema;
+
+public interface IArraySchema {
+ public Schema getElementSchema(int index);
+ public Object createFromArray(Object[] obj);
+}
+
diff --git a/java-plan3/src/org/msgpack/schema/IMapSchema.java b/java-plan3/src/org/msgpack/schema/IMapSchema.java
new file mode 100644
index 0000000..60b3e8e
--- /dev/null
+++ b/java-plan3/src/org/msgpack/schema/IMapSchema.java
@@ -0,0 +1,27 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 FURUHASHI Sadayuki
+//
+// 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 org.msgpack.schema;
+
+import org.msgpack.Schema;
+
+public interface IMapSchema {
+ public Schema getKeySchema();
+ public Schema getValueSchema();
+ public Object createFromMap(Object[] obj);
+}
+
diff --git a/java-plan3/src/org/msgpack/schema/IntSchema.java b/java-plan3/src/org/msgpack/schema/IntSchema.java
new file mode 100644
index 0000000..c54c0ae
--- /dev/null
+++ b/java-plan3/src/org/msgpack/schema/IntSchema.java
@@ -0,0 +1,89 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 FURUHASHI Sadayuki
+//
+// 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 org.msgpack.schema;
+
+import java.io.IOException;
+import org.msgpack.*;
+
+public class IntSchema extends Schema {
+ public IntSchema() {
+ super("Integer");
+ }
+
+ @Override
+ public String getExpression() {
+ return "int";
+ }
+
+ @Override
+ public void pack(Packer pk, Object obj) throws IOException {
+ if(obj instanceof Number) {
+ pk.packInt( ((Number)obj).intValue() );
+
+ } else if(obj == null) {
+ pk.packNil();
+
+ } else {
+ throw MessageTypeException.invalidConvert(obj, this);
+ }
+ }
+
+ @Override
+ public Object convert(Object obj) throws MessageTypeException {
+ if(obj instanceof Integer) {
+ return obj;
+
+ } else if(obj instanceof Number) {
+ return ((Number)obj).intValue();
+
+ } else {
+ throw MessageTypeException.invalidConvert(obj, this);
+ }
+ }
+
+ @Override
+ public Object createFromByte(byte v) {
+ return (int)v;
+ }
+
+ @Override
+ public Object createFromShort(short v) {
+ return (int)v;
+ }
+
+ @Override
+ public Object createFromInt(int v) {
+ return (int)v;
+ }
+
+ @Override
+ public Object createFromLong(long v) {
+ return (int)v;
+ }
+
+ @Override
+ public Object createFromFloat(float v) {
+ return (int)v;
+ }
+
+ @Override
+ public Object createFromDouble(double v) {
+ return (int)v;
+ }
+}
+
diff --git a/java-plan3/src/org/msgpack/schema/LongSchema.java b/java-plan3/src/org/msgpack/schema/LongSchema.java
new file mode 100644
index 0000000..ccf3043
--- /dev/null
+++ b/java-plan3/src/org/msgpack/schema/LongSchema.java
@@ -0,0 +1,89 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 FURUHASHI Sadayuki
+//
+// 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 org.msgpack.schema;
+
+import java.io.IOException;
+import org.msgpack.*;
+
+public class LongSchema extends Schema {
+ public LongSchema() {
+ super("Long");
+ }
+
+ @Override
+ public String getExpression() {
+ return "long";
+ }
+
+ @Override
+ public void pack(Packer pk, Object obj) throws IOException {
+ if(obj instanceof Number) {
+ pk.packLong( ((Number)obj).longValue() );
+
+ } else if(obj == null) {
+ pk.packNil();
+
+ } else {
+ throw MessageTypeException.invalidConvert(obj, this);
+ }
+ }
+
+ @Override
+ public Object convert(Object obj) throws MessageTypeException {
+ if(obj instanceof Long) {
+ return obj;
+
+ } else if(obj instanceof Number) {
+ return ((Number)obj).longValue();
+
+ } else {
+ throw MessageTypeException.invalidConvert(obj, this);
+ }
+ }
+
+ @Override
+ public Object createFromByte(byte v) {
+ return (long)v;
+ }
+
+ @Override
+ public Object createFromShort(short v) {
+ return (long)v;
+ }
+
+ @Override
+ public Object createFromInt(int v) {
+ return (long)v;
+ }
+
+ @Override
+ public Object createFromLong(long v) {
+ return (long)v;
+ }
+
+ @Override
+ public Object createFromFloat(float v) {
+ return (long)v;
+ }
+
+ @Override
+ public Object createFromDouble(double v) {
+ return (long)v;
+ }
+}
+
diff --git a/java-plan3/src/org/msgpack/schema/MapSchema.java b/java-plan3/src/org/msgpack/schema/MapSchema.java
new file mode 100644
index 0000000..71629b0
--- /dev/null
+++ b/java-plan3/src/org/msgpack/schema/MapSchema.java
@@ -0,0 +1,102 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 FURUHASHI Sadayuki
+//
+// 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 org.msgpack.schema;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.io.IOException;
+import org.msgpack.*;
+
+public class MapSchema extends Schema implements IMapSchema {
+ private Schema keySchema;
+ private Schema valueSchema;
+
+ public MapSchema(Schema keySchema, Schema valueSchema) {
+ super("map");
+ this.keySchema = keySchema;
+ this.valueSchema = valueSchema;
+ }
+
+ @Override
+ public String getFullName() {
+ return "HashList<"+keySchema.getFullName()+", "+valueSchema.getFullName()+">";
+ }
+
+ @Override
+ public String getExpression() {
+ return "(map "+keySchema.getExpression()+" "+valueSchema.getExpression()+")";
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void pack(Packer pk, Object obj) throws IOException {
+ if(obj instanceof Map) {
+ Map<Object,Object> d = (Map<Object,Object>)obj;
+ pk.packMap(d.size());
+ for(Map.Entry<Object,Object> e : d.entrySet()) {
+ keySchema.pack(pk, e.getKey());
+ valueSchema.pack(pk, e.getValue());
+ }
+
+ } else if(obj == null) {
+ pk.packNil();
+
+ } else {
+ throw MessageTypeException.invalidConvert(obj, this);
+ }
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object convert(Object obj) throws MessageTypeException {
+ if(obj instanceof Map) {
+ Map<Object,Object> d = (Map<Object,Object>)obj;
+ Map<Object,Object> m = new HashMap<Object,Object>();
+ for(Map.Entry<Object,Object> e : d.entrySet()) {
+ m.put(keySchema.convert(e.getKey()), valueSchema.convert(e.getValue()));
+ }
+ return m;
+
+ } else {
+ throw MessageTypeException.invalidConvert(obj, this);
+ }
+ }
+
+ @Override
+ public Schema getKeySchema() {
+ return keySchema;
+ }
+
+ @Override
+ public Schema getValueSchema() {
+ return valueSchema;
+ }
+
+ @Override
+ public Object createFromMap(Object[] obj) {
+ HashMap m = new HashMap(obj.length / 2);
+ int i = 0;
+ while(i < obj.length) {
+ Object k = obj[i++];
+ Object v = obj[i++];
+ m.put(k, v);
+ }
+ return m;
+ }
+}
+
diff --git a/java-plan3/src/org/msgpack/schema/RawSchema.java b/java-plan3/src/org/msgpack/schema/RawSchema.java
new file mode 100644
index 0000000..582f766
--- /dev/null
+++ b/java-plan3/src/org/msgpack/schema/RawSchema.java
@@ -0,0 +1,105 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 FURUHASHI Sadayuki
+//
+// 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 org.msgpack.schema;
+
+import java.nio.ByteBuffer;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import org.msgpack.*;
+
+public class RawSchema extends Schema {
+ public RawSchema() {
+ super("raw");
+ }
+
+ public String getFullName() {
+ return "byte[]";
+ }
+
+ @Override
+ public void pack(Packer pk, Object obj) throws IOException {
+ // FIXME instanceof GenericObject
+ if(obj instanceof byte[]) {
+ byte[] d = (byte[])obj;
+ pk.packRaw(d.length);
+ pk.packRawBody(d);
+
+ } else if(obj instanceof ByteBuffer) {
+ ByteBuffer d = (ByteBuffer)obj;
+ if(!d.hasArray()) {
+ throw MessageTypeException.invalidConvert(obj, this);
+ }
+ pk.packRaw(d.capacity());
+ pk.packRawBody(d.array(), d.position(), d.capacity());
+
+ } else if(obj instanceof String) {
+ try {
+ byte[] d = ((String)obj).getBytes("UTF-8");
+ pk.packRaw(d.length);
+ pk.packRawBody(d);
+ } catch (UnsupportedEncodingException e) {
+ throw MessageTypeException.invalidConvert(obj, this);
+ }
+
+ } else if(obj == null) {
+ pk.packNil();
+
+ } else {
+ throw MessageTypeException.invalidConvert(obj, this);
+ }
+ }
+
+ @Override
+ public Object convert(Object obj) throws MessageTypeException {
+ // FIXME instanceof GenericObject
+ if(obj instanceof byte[]) {
+ // FIXME copy?
+ //byte[] d = (byte[])obj;
+ //byte[] v = new byte[d.length];
+ //System.arraycopy(d, 0, v, 0, d.length);
+ //return v;
+ return obj;
+
+ } else if(obj instanceof ByteBuffer) {
+ ByteBuffer d = (ByteBuffer)obj;
+ byte[] v = new byte[d.capacity()];
+ int pos = d.position();
+ d.get(v);
+ d.position(pos);
+ return v;
+
+ } else if(obj instanceof String) {
+ try {
+ return ((String)obj).getBytes("UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw MessageTypeException.invalidConvert(obj, this);
+ }
+
+ } else {
+ throw MessageTypeException.invalidConvert(obj, this);
+ }
+ }
+
+ @Override
+ public Object createFromRaw(byte[] b, int offset, int length) {
+ byte[] d = new byte[length];
+ System.arraycopy(b, offset, d, 0, length);
+ return d;
+ }
+}
+
diff --git a/java-plan3/src/org/msgpack/schema/ReflectionClassSchema.java b/java-plan3/src/org/msgpack/schema/ReflectionClassSchema.java
new file mode 100644
index 0000000..fb94adf
--- /dev/null
+++ b/java-plan3/src/org/msgpack/schema/ReflectionClassSchema.java
@@ -0,0 +1,64 @@
+package org.msgpack.schema;
+
+import java.util.Arrays;
+import java.util.List;
+import java.lang.reflect.*;
+import org.msgpack.*;
+
+// FIXME
+public abstract class ReflectionClassSchema extends ClassSchema {
+ private Constructor constructorCache;
+
+ public ReflectionClassSchema(String name, List<FieldSchema> fields, String namespace, List<String> imports) {
+ super(name, namespace, imports, fields);
+ }
+
+ /*
+ Schema getElementSchema(int index)
+ {
+ // FIXME check index < fields.length
+ fields[index].getSchema();
+ }
+
+ Object createFromArray(Object[] obj)
+ {
+ Object o = newInstance();
+ ((MessageConvertable)o).messageConvert(obj);
+ return o;
+ }
+
+ Object newInstance()
+ {
+ if(constructorCache == null) {
+ cacheConstructor();
+ }
+ try {
+ return constructorCache.newInstance((Object[])null);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException("can't instantiate "+fqdn+": "+e.getMessage());
+ } catch (InstantiationException e) {
+ throw new RuntimeException("can't instantiate "+fqdn+": "+e.getMessage());
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException("can't instantiate "+fqdn+": "+e.getMessage());
+ }
+ }
+
+ private void cacheConstructor()
+ {
+ try {
+ Class c = Class.forName(fqdn);
+ int index = 0;
+ for(SpecificFieldSchema f : fields) {
+ f.cacheField(c, index++);
+ }
+ constructorCache = c.getDeclaredConstructor((Class[])null);
+ constructorCache.setAccessible(true);
+ } catch(ClassNotFoundException e) {
+ throw new RuntimeException("class not found: "+fqdn);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException("class not found: "+fqdn+": "+e.getMessage());
+ }
+ }
+ */
+}
+
diff --git a/java-plan3/src/org/msgpack/schema/SSchemaParser.java b/java-plan3/src/org/msgpack/schema/SSchemaParser.java
new file mode 100644
index 0000000..c6bbc77
--- /dev/null
+++ b/java-plan3/src/org/msgpack/schema/SSchemaParser.java
@@ -0,0 +1,254 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 FURUHASHI Sadayuki
+//
+// 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 org.msgpack.schema;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Stack;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import org.msgpack.*;
+
+// FIXME exception class
+
+public class SSchemaParser {
+ public static Schema parse(String source) {
+ return new SSchemaParser(false).run(source);
+ }
+
+ public static Schema load(String source) {
+ return new SSchemaParser(true).run(source);
+ }
+
+ private static abstract class SExp {
+ boolean isAtom() { return false; }
+ public String getAtom() { return null; }
+
+ boolean isTuple() { return false; }
+ public SExp getTuple(int i) { return null; }
+ public int size() { return 0; }
+ public boolean empty() { return size() == 0; }
+ Iterator<SExp> iterator(int offset) { return null; }
+ }
+
+ private static class SAtom extends SExp {
+ private String atom;
+
+ SAtom(String atom) { this.atom = atom; }
+
+ boolean isAtom() { return true; }
+ public String getAtom() { return atom; }
+
+ public String toString() { return atom; }
+ }
+
+ private static class STuple extends SExp {
+ private List<SExp> tuple;
+
+ STuple() { this.tuple = new ArrayList<SExp>(); }
+
+ public void add(SExp e) { tuple.add(e); }
+
+ boolean isTuple() { return true; }
+ public SExp getTuple(int i) { return tuple.get(i); }
+ public int size() { return tuple.size(); }
+
+ Iterator<SExp> iterator(int skip) {
+ Iterator<SExp> i = tuple.iterator();
+ for(int s=0; s < skip; ++s) { i.next(); }
+ return i;
+ }
+
+ public String toString() {
+ if(tuple.isEmpty()) { return "()"; }
+ Iterator<SExp> i = tuple.iterator();
+ StringBuffer o = new StringBuffer();
+ o.append("(").append(i.next());
+ while(i.hasNext()) { o.append(" ").append(i.next()); }
+ o.append(")");
+ return o.toString();
+ }
+ }
+
+ boolean specificClass;
+
+ private SSchemaParser(boolean specificClass) {
+ this.specificClass = specificClass;
+ }
+
+ private static Pattern pattern = Pattern.compile(
+ "(?:\\s+)|([\\(\\)]|[\\d\\w\\.]+)");
+
+ private Schema run(String source) {
+ Matcher m = pattern.matcher(source);
+
+ Stack<STuple> stack = new Stack<STuple>();
+ String token;
+
+ while(true) {
+ while(true) {
+ if(!m.find()) { throw new RuntimeException("unexpected end of file"); }
+ token = m.group(1);
+ if(token != null) { break; }
+ }
+
+ if(token.equals("(")) {
+ stack.push(new STuple());
+ } else if(token.equals(")")) {
+ STuple top = stack.pop();
+ if(stack.empty()) {
+ stack.push(top);
+ break;
+ }
+ stack.peek().add(top);
+ } else {
+ if(stack.empty()) {
+ throw new RuntimeException("unexpected token '"+token+"'");
+ }
+ stack.peek().add(new SAtom(token));
+ }
+ }
+
+ while(true) {
+ if(!m.find()) { break; }
+ token = m.group(1);
+ if(token != null) { throw new RuntimeException("unexpected token '"+token+"'"); }
+ }
+
+ return readType( stack.pop() );
+ }
+
+ private Schema readType(SExp exp) {
+ if(exp.isAtom()) {
+ String type = exp.getAtom();
+ if(type.equals("string")) {
+ return new StringSchema();
+ } else if(type.equals("raw")) {
+ return new RawSchema();
+ } else if(type.equals("byte")) {
+ return new ByteSchema();
+ } else if(type.equals("short")) {
+ return new ShortSchema();
+ } else if(type.equals("int")) {
+ return new IntSchema();
+ } else if(type.equals("long")) {
+ return new LongSchema();
+ } else if(type.equals("float")) {
+ return new FloatSchema();
+ } else if(type.equals("double")) {
+ return new DoubleSchema();
+ } else if(type.equals("object")) {
+ return new GenericSchema();
+ } else {
+ throw new RuntimeException("byte, short, int, long, float, double, raw, string or object is expected but got '"+type+"': "+exp);
+ }
+ } else {
+ String type = exp.getTuple(0).getAtom();
+ if(type.equals("class")) {
+ return parseClass(exp);
+ } else if(type.equals("array")) {
+ return parseArray(exp);
+ } else if(type.equals("map")) {
+ return parseMap(exp);
+ } else {
+ throw new RuntimeException("class, array or map is expected but got '"+type+"': "+exp);
+ }
+ }
+ }
+
+ private ClassSchema parseClass(SExp exp) {
+ if(exp.size() < 3 || !exp.getTuple(1).isAtom()) {
+ throw new RuntimeException("class is (class NAME CLASS_BODY): "+exp);
+ }
+
+ String namespace = null;
+ List<String> imports = new ArrayList<String>();
+ String name = exp.getTuple(1).getAtom();
+ List<FieldSchema> fields = new ArrayList<FieldSchema>();
+
+ for(Iterator<SExp> i=exp.iterator(2); i.hasNext();) {
+ SExp subexp = i.next();
+ if(!subexp.isTuple() || subexp.empty() || !subexp.getTuple(0).isAtom()) {
+ throw new RuntimeException("field, package or import is expected: "+subexp);
+ }
+ String type = subexp.getTuple(0).getAtom();
+ if(type.equals("field")) {
+ fields.add( parseField(subexp) );
+ } else if(type.equals("package")) {
+ if(namespace != null) {
+ throw new RuntimeException("duplicated package definition: "+subexp);
+ }
+ namespace = parseNamespace(subexp);
+ } else if(type.equals("import")) {
+ imports.add( parseImport(subexp) );
+ } else {
+ throw new RuntimeException("field, package or import is expected but got '"+type+"': "+subexp);
+ }
+ }
+
+ if(specificClass) {
+ return new SpecificClassSchema(name, namespace, imports, fields);
+ } else {
+ return new GenericClassSchema(name, namespace, imports, fields);
+ }
+ }
+
+ private ArraySchema parseArray(SExp exp) {
+ if(exp.size() != 2) {
+ throw new RuntimeException("array is (array ELEMENT_TYPE): "+exp);
+ }
+ Schema elementType = readType(exp.getTuple(1));
+ return new ArraySchema(elementType);
+ }
+
+ private MapSchema parseMap(SExp exp) {
+ if(exp.size() != 3 || !exp.getTuple(1).isAtom()) {
+ throw new RuntimeException("map is (map KEY_TYPE VALUE_TYPE): "+exp);
+ }
+ Schema keyType = readType(exp.getTuple(1));
+ Schema valueType = readType(exp.getTuple(2));
+ return new MapSchema(keyType, valueType);
+ }
+
+ private String parseNamespace(SExp exp) {
+ if(exp.size() != 2 || !exp.getTuple(1).isAtom()) {
+ throw new RuntimeException("package is (package NAME): "+exp);
+ }
+ String name = exp.getTuple(1).getAtom();
+ return name;
+ }
+
+ private String parseImport(SExp exp) {
+ if(exp.size() != 2 || !exp.getTuple(1).isAtom()) {
+ throw new RuntimeException("import is (import NAME): "+exp);
+ }
+ String name = exp.getTuple(1).getAtom();
+ return name;
+ }
+
+ private FieldSchema parseField(SExp exp) {
+ if(exp.size() != 3 || !exp.getTuple(1).isAtom()) {
+ throw new RuntimeException("field is (field NAME TYPE): "+exp);
+ }
+ String name = exp.getTuple(1).getAtom();
+ Schema type = readType(exp.getTuple(2));
+ return new FieldSchema(name, type);
+ }
+}
+
diff --git a/java-plan3/src/org/msgpack/schema/ShortSchema.java b/java-plan3/src/org/msgpack/schema/ShortSchema.java
new file mode 100644
index 0000000..089a024
--- /dev/null
+++ b/java-plan3/src/org/msgpack/schema/ShortSchema.java
@@ -0,0 +1,89 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 FURUHASHI Sadayuki
+//
+// 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 org.msgpack.schema;
+
+import java.io.IOException;
+import org.msgpack.*;
+
+public class ShortSchema extends Schema {
+ public ShortSchema() {
+ super("Short");
+ }
+
+ @Override
+ public String getExpression() {
+ return "short";
+ }
+
+ @Override
+ public void pack(Packer pk, Object obj) throws IOException {
+ if(obj instanceof Number) {
+ pk.packShort( ((Number)obj).shortValue() );
+
+ } else if(obj == null) {
+ pk.packNil();
+
+ } else {
+ throw MessageTypeException.invalidConvert(obj, this);
+ }
+ }
+
+ @Override
+ public Object convert(Object obj) throws MessageTypeException {
+ if(obj instanceof Short) {
+ return obj;
+
+ } else if(obj instanceof Number) {
+ return ((Number)obj).shortValue();
+
+ } else {
+ throw MessageTypeException.invalidConvert(obj, this);
+ }
+ }
+
+ @Override
+ public Object createFromByte(byte v) {
+ return (short)v;
+ }
+
+ @Override
+ public Object createFromShort(short v) {
+ return (short)v;
+ }
+
+ @Override
+ public Object createFromInt(int v) {
+ return (short)v;
+ }
+
+ @Override
+ public Object createFromLong(long v) {
+ return (short)v;
+ }
+
+ @Override
+ public Object createFromFloat(float v) {
+ return (short)v;
+ }
+
+ @Override
+ public Object createFromDouble(double v) {
+ return (short)v;
+ }
+}
+
diff --git a/java-plan3/src/org/msgpack/schema/SpecificClassSchema.java b/java-plan3/src/org/msgpack/schema/SpecificClassSchema.java
new file mode 100644
index 0000000..81e5e00
--- /dev/null
+++ b/java-plan3/src/org/msgpack/schema/SpecificClassSchema.java
@@ -0,0 +1,122 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 FURUHASHI Sadayuki
+//
+// 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 org.msgpack.schema;
+
+import java.util.Collection;
+import java.util.List;
+import java.lang.reflect.*;
+import java.io.IOException;
+import org.msgpack.*;
+
+public class SpecificClassSchema extends ClassSchema {
+ private Class classCache;
+ private Method factoryCache;
+ private Constructor constructorCache;
+
+ public SpecificClassSchema(
+ String name, String namespace,
+ List<String> imports, List<FieldSchema> fields) {
+ super(name, namespace, imports, fields);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void pack(Packer pk, Object obj) throws IOException {
+ if(obj == null) {
+ pk.packNil();
+ return;
+ }
+ if(classCache == null) {
+ cacheFactory();
+ }
+ if(classCache.isInstance(obj)) {
+ ((MessagePackable)obj).messagePack(pk);
+ } else {
+ // FIXME Map<String,Object>
+ throw MessageTypeException.invalidConvert(obj, this);
+ }
+ }
+
+ @Override
+ public Object convert(Object obj) throws MessageTypeException {
+ if(obj instanceof Collection) {
+ if(constructorCache == null) {
+ cacheConstructor();
+ }
+ try {
+ MessageMergeable o = (MessageMergeable)constructorCache.newInstance((Object[])null);
+ o.messageMerge(obj);
+ return o;
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException("can't instantiate "+fqdn+": "+e.getMessage());
+ } catch (InstantiationException e) {
+ throw new RuntimeException("can't instantiate "+fqdn+": "+e.getMessage());
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException("can't instantiate "+fqdn+": "+e.getMessage());
+ }
+
+ } else {
+ throw MessageTypeException.invalidConvert(obj, this);
+ }
+ }
+
+ public Schema getElementSchema(int index) {
+ // FIXME check index < fields.length
+ return fields[index].getSchema();
+ }
+
+ public Object createFromArray(Object[] obj) {
+ if(factoryCache == null) {
+ cacheFactory();
+ }
+ try {
+ return factoryCache.invoke(null, new Object[]{obj});
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException("can't instantiate "+fqdn+": "+e.getCause());
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException("can't instantiate "+fqdn+": "+e.getMessage());
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private void cacheFactory() {
+ try {
+ classCache = Class.forName(fqdn);
+ factoryCache = classCache.getDeclaredMethod("createFromMessage", new Class[]{Object[].class});
+ factoryCache.setAccessible(true);
+ } catch(ClassNotFoundException e) {
+ throw new RuntimeException("class not found: "+fqdn);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException("class not found: "+fqdn+": "+e.getMessage());
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private void cacheConstructor() {
+ try {
+ classCache = Class.forName(fqdn);
+ constructorCache = classCache.getDeclaredConstructor((Class[])null);
+ constructorCache.setAccessible(true);
+ } catch(ClassNotFoundException e) {
+ throw new RuntimeException("class not found: "+fqdn);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException("class not found: "+fqdn+": "+e.getMessage());
+ }
+ }
+}
+
diff --git a/java-plan3/src/org/msgpack/schema/StringSchema.java b/java-plan3/src/org/msgpack/schema/StringSchema.java
new file mode 100644
index 0000000..f5e0bf1
--- /dev/null
+++ b/java-plan3/src/org/msgpack/schema/StringSchema.java
@@ -0,0 +1,111 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009 FURUHASHI Sadayuki
+//
+// 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 org.msgpack.schema;
+
+import java.nio.ByteBuffer;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import org.msgpack.*;
+
+public class StringSchema extends Schema {
+ public StringSchema() {
+ super("string");
+ }
+
+ @Override
+ public String getFullName() {
+ return "String";
+ }
+
+ @Override
+ public void pack(Packer pk, Object obj) throws IOException {
+ // FIXME instanceof GenericObject
+ if(obj instanceof String) {
+ try {
+ byte[] d = ((String)obj).getBytes("UTF-8");
+ pk.packRaw(d.length);
+ pk.packRawBody(d);
+ } catch (UnsupportedEncodingException e) {
+ throw MessageTypeException.invalidConvert(obj, this);
+ }
+
+ } else if(obj instanceof byte[]) {
+ byte[] d = (byte[])obj;
+ pk.packRaw(d.length);
+ pk.packRawBody(d);
+
+ } else if(obj instanceof ByteBuffer) {
+ ByteBuffer d = (ByteBuffer)obj;
+ if(!d.hasArray()) {
+ throw MessageTypeException.invalidConvert(obj, this);
+ }
+ pk.packRaw(d.capacity());
+ pk.packRawBody(d.array(), d.position(), d.capacity());
+
+ } else if(obj == null) {
+ pk.packNil();
+
+ } else {
+ throw MessageTypeException.invalidConvert(obj, this);
+ }
+ }
+
+ @Override
+ public Object convert(Object obj) throws MessageTypeException {
+ // FIXME instanceof GenericObject
+ if(obj instanceof String) {
+ return obj;
+
+ } else if(obj instanceof byte[]) {
+ try {
+ return new String((byte[])obj, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw MessageTypeException.invalidConvert(obj, this);
+ }
+
+ } else if(obj instanceof ByteBuffer) {
+ ByteBuffer d = (ByteBuffer)obj;
+ try {
+ if(d.hasArray()) {
+ return new String(d.array(), d.position(), d.capacity(), "UTF-8");
+ } else {
+ byte[] v = new byte[d.capacity()];
+ int pos = d.position();
+ d.get(v);
+ d.position(pos);
+ return new String(v, "UTF-8");
+ }
+ } catch (UnsupportedEncodingException e) {
+ throw MessageTypeException.invalidConvert(obj, this);
+ }
+
+ } else {
+ throw MessageTypeException.invalidConvert(obj, this);
+ }
+ }
+
+ @Override
+ public Object createFromRaw(byte[] b, int offset, int length) {
+ try {
+ return new String(b, offset, length, "UTF-8");
+ } catch (Exception e) {
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+}
+