Commits

Lars J. Nilsson committed a1d07d4

first addition from SVN -> hg

Comments (0)

Files changed (39)

+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.
+=========================================================================
+==  NOTICE file for use with the Apache License, Version 2.0, in this  ==
+==  in this case for the Cubeia Styx Library distribution.             ==
+=========================================================================
+
+This product contains code developed by Cubeia Ltd (http://www.cubeia.com).
+Copyright (c) 2009 Cubeia Ltd, http://www.cubeia.com
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<artifactId>styx-core</artifactId>
+	<name>Styx Core Lib</name>
+
+	<parent>
+	  <groupId>com.cubeia.styx</groupId>
+	  <artifactId>styx-root</artifactId>
+	  <version>1.10-SNAPSHOT</version>
+	</parent>
+
+	<dependencies>
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<version>3.8.1</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.codehaus.jackson</groupId>
+			<artifactId>jackson-mapper-lgpl</artifactId>
+			<version>1.9.3</version>
+		</dependency>
+	</dependencies>
+</project>

core/src/main/java/com/cubeia/firebase/io/BinaryData.java

+/**
+ * Copyright 2009 Cubeia Ltd  
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.cubeia.firebase.io;
+
+/**
+ * Small static utility class for unsigned binary data operations.
+ */
+public class BinaryData {
+	
+	public static int asUnsigned(byte value) {
+		return value & 0xFF;
+	}
+	
+	public static int asUnsigned(short value) {
+		return value & 0xFFFF;
+	}
+	
+	public static long asUnsigned(int value) {
+		return value & 0xFFFFFFFF;
+	}
+}

core/src/main/java/com/cubeia/firebase/io/ObjectFactory.java

+/**
+ * Copyright 2009 Cubeia Ltd  
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.cubeia.firebase.io;
+
+/**
+ * An implementation of this interface is needed for the PacketHandler
+ * to work as expected. The implementation is typically automatically
+ * generated.
+ */
+public interface ObjectFactory {
+    int version();
+    ProtocolObject create(int classId);
+}

core/src/main/java/com/cubeia/firebase/io/PacketInputStream.java

+/**
+ * Copyright 2009 Cubeia Ltd  
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.cubeia.firebase.io;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * Handles the deserialization of the Styx wire format.
+ */
+public final class PacketInputStream {
+	private final ByteBuffer inBuffer;
+
+    public PacketInputStream(ByteBuffer inBuffer) {
+        this.inBuffer = inBuffer;
+    }
+
+    public byte loadByte() throws IOException {
+        return inBuffer.get();
+    }
+
+    public int loadUnsignedByte() throws IOException {
+        return BinaryData.asUnsigned(inBuffer.get());
+    }
+
+    public int loadUnsignedShort() throws IOException {
+        return BinaryData.asUnsigned(inBuffer.getShort());
+    }
+
+    public short loadShort() throws IOException {
+        return inBuffer.getShort();
+    }
+
+    public int loadInt() throws IOException {
+        return inBuffer.getInt();
+    }
+
+    public long loadUnsignedInt() {
+        long uint = 0;
+        uint = uint | inBuffer.get() << 24;
+        uint = uint | inBuffer.get() << 16;
+        uint = uint | inBuffer.get() << 8;
+        uint = uint | inBuffer.get();
+        return uint;
+    }
+    
+    public long loadLong() throws IOException {
+        return inBuffer.getLong();
+    }
+
+    public boolean loadBoolean() throws IOException {
+        return (inBuffer.get() != 0);
+    }
+
+    public String loadString() throws IOException {
+        int length = 0xffff & inBuffer.getShort();
+        byte[] utf8 = new byte[length];
+        inBuffer.get(utf8);
+        return new String(utf8, "UTF-8");
+    }
+
+	public void loadByteArray(byte[] arg0) throws IOException {
+		inBuffer.get(arg0);
+	}
+	
+	public void loadIntArray(int[] data) throws IOException {
+		for (int i = 0; i < data.length; i++) {
+			data[i] = inBuffer.getInt();
+		}
+	}
+
+	public void loadStringArray(String[] removedParams) throws IOException {
+		for (int i = 0; i < removedParams.length; i++) {
+			removedParams[i] = loadString();
+		}
+	}
+}

core/src/main/java/com/cubeia/firebase/io/PacketOutputStream.java

+/**
+ * Copyright 2009 Cubeia Ltd  
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.cubeia.firebase.io;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/**
+ * Handles the serialization of the Styx wire format.
+ */
+public final class PacketOutputStream {
+    /** maximum string legnth in bytes */
+    public static final int STRING_MAX_BYTES = 0xffff;
+    
+    private DataOutputStream os;
+
+    public PacketOutputStream(DataOutputStream os) {
+        this.os = os;
+    }
+
+    public void saveByte(byte val) throws IOException {
+        os.writeByte(val);
+    }
+
+    public void saveUnsignedByte(int val) throws IOException {
+        os.writeByte(val);
+    }
+
+    public void saveUnsignedShort(int val) throws IOException {
+        os.writeShort(val);
+    }
+
+    public void saveShort(short val) throws IOException {
+        os.writeShort(val);
+    }
+
+    public void saveInt(int val) throws IOException {
+        os.writeInt(val);
+    }
+    
+    public void saveUnsignedInt(long val) throws IOException {
+        os.write((byte) (0xff & val >>> 24));
+        os.write((byte) (0xff & val >>> 16));
+        os.write((byte) (0xff & val >>> 8));
+        os.write((byte) (0xff & val));
+    }
+    
+    public void saveLong(long val) throws IOException {
+        os.writeLong(val);
+    }
+
+    public void saveBoolean(boolean val) throws IOException {
+        os.writeByte(val ? 1 : 0);
+    }
+
+    /**
+     * Save the given string. 
+     * An {@link IOException} will be thrown if the number of bytes of the string encoded in 
+     * UTF-8 is greater than {@link #STRING_MAX_BYTES}.
+     * @param val the string
+     * @throws IOException if the number of UTF-8 bytes of the string is >= {@link #STRING_MAX_BYTES}
+     */
+    public void saveString(String val) throws IOException {
+    	if (val == null) val = "";
+        byte[] utf8 = val.getBytes("UTF-8");
+        
+        if (utf8.length > STRING_MAX_BYTES) {
+            throw new IOException("String byte length is too long: bytes = " + utf8.length + ", max allowed = " + 0xffff);
+        }
+        
+        os.writeShort(utf8.length);
+        os.write(utf8, 0, utf8.length);
+    }
+
+	public void saveArray(byte[] gamedata) throws IOException {
+		os.write(gamedata);
+	}
+	
+	public void saveArray(int[] data) throws IOException {
+		for (int val : data) {
+			os.writeInt(val);
+		}
+	}
+
+	public void saveArray(String[] removedParams) throws IOException {
+		for (String name : removedParams) {
+			saveString(name);
+		}
+	}
+}

core/src/main/java/com/cubeia/firebase/io/ProtocolObject.java

+/**
+ * Copyright 2009 Cubeia Ltd  
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.cubeia.firebase.io;
+
+/**
+ * Any object that should be serializable via the Styx wire protocol
+ * should implement this interface. Files implementing this protocol
+ * are typically automatically generated.
+ */
+public interface ProtocolObject extends Visitable {
+    /**
+     * An object needs a unique classId.
+     */
+    int classId();
+
+    /**
+     * Serialisation method.
+     */
+    void save(PacketOutputStream ps) throws java.io.IOException;
+
+    /**
+     * Deserialization method.
+     */
+    void load(PacketInputStream ps) throws java.io.IOException;
+   
+}

core/src/main/java/com/cubeia/firebase/io/ProtocolObjectVisitor.java

+/**
+ * Copyright 2009 Cubeia Ltd  
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.cubeia.firebase.io;
+
+public interface ProtocolObjectVisitor { }

core/src/main/java/com/cubeia/firebase/io/StyxJsonSerializer.java

+package com.cubeia.firebase.io;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.codehaus.jackson.JsonParser;
+import org.codehaus.jackson.JsonProcessingException;
+import org.codehaus.jackson.Version;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.DeserializationConfig;
+import org.codehaus.jackson.map.DeserializationContext;
+import org.codehaus.jackson.map.JsonMappingException;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.deser.std.StdDeserializer;
+import org.codehaus.jackson.map.module.SimpleModule;
+import org.codehaus.jackson.node.ObjectNode;
+import org.codehaus.jackson.type.TypeReference;
+
+/**
+ * This is a JSON wire protocol serializer/deserializer. All protocol
+ * object instances will contain a "classId" property which maps to the
+ * protocol definition.
+ * 
+ * <p>All methods fails with an illegal argument exception if the JSON is
+ * malformed or does not correspond correctly to the protocol objects. However,
+ * unknown properties are ignored.
+ * 
+ * @author Lars J. Nilsson
+ */
+public class StyxJsonSerializer {
+
+	private static final String CLASS_ID_PROPERTY = "classId";
+	
+	private final ObjectFactory factory;
+	private final ObjectMapper objectMapper;
+	
+	/**
+	 * @param factory Object factory, must not be null if factory is used for deserializing
+	 */
+	public StyxJsonSerializer(ObjectFactory factory) {
+		this.objectMapper = createObjectMapper();
+		this.factory = factory;
+	}
+	
+	/**
+	 * @param obj Object to pack, must not be null
+	 * @return A JSON representation of the object, never null
+	 */
+	public String toJson(final ProtocolObject obj) {
+		return doObjectMapperCall(new ObjectMapperCall<String>() {
+			
+			@Override
+			public String call(ObjectMapper mapper) throws JsonProcessingException, IOException {
+				return mapper.writeValueAsString(obj);
+			}
+		});
+	}
+	
+	/**
+	 * @param obj Object list to pack, must not be null
+	 * @return A JSON representation of the object list, never null
+	 */
+	public String toJsonList(final List<ProtocolObject> obj) {
+		return doObjectMapperCall(new ObjectMapperCall<String>() {
+			
+			@Override
+			public String call(ObjectMapper mapper) throws JsonProcessingException, IOException {
+				return mapper.writeValueAsString(obj);
+			}
+		});
+	}
+	
+	/**
+	 * @param json JSON to unmarshall, must not be null
+	 * @return A protocol object, never null
+	 */
+	public ProtocolObject fromJson(final String json) {
+		return doObjectMapperCall(new ObjectMapperCall<ProtocolObject>() {
+			
+			@Override
+			public ProtocolObject call(ObjectMapper mapper) throws JsonProcessingException, IOException {
+				return mapper.readValue(json, ProtocolObject.class);
+			}
+		});
+	}
+	
+	/**
+	 * @param json JSON array to unmarshall, must not be null
+	 * @return A list of protocol objects, never null
+	 */
+	public List<ProtocolObject> fromJsonList(final String json) {
+		return doObjectMapperCall(new ObjectMapperCall<List<ProtocolObject>>() {
+			
+			@Override
+			public List<ProtocolObject> call(ObjectMapper mapper) throws JsonProcessingException, IOException {
+				return mapper.readValue(json, new TypeReference<List<ProtocolObject>>() { });
+			}
+		});
+	}
+	
+	
+	// --- PRIVATE METHODS --- //
+	
+	private ObjectMapper createObjectMapper() {
+		ObjectMapper om = new ObjectMapper();
+		// Add a module with the deserializer for proper class ID resolution. 
+		SimpleModule module = new SimpleModule("ProtocolDeserializer Module", new Version(1, 0, 0, null));  
+		module.addDeserializer(ProtocolObject.class, new StdDeserializer<ProtocolObject>(ProtocolObject.class) {
+
+			@Override
+			public ProtocolObject deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
+				ObjectMapper mapper = (ObjectMapper) jp.getCodec();  
+			    ObjectNode root = (ObjectNode) mapper.readTree(jp); 
+			    /*
+			     * Get the class id and the refer to the factory to map the
+			     * concrete class.
+			     */
+			    int classId = root.get(CLASS_ID_PROPERTY).asInt();
+			    Class<? extends ProtocolObject> cl = factory.create(classId).getClass();
+			    return mapper.readValue(root, cl);
+			}
+		}); 
+		// Add mix-in to mimic a real property for the class ID
+		om.getSerializationConfig().addMixInAnnotations(ProtocolObject.class, StyxClassIdJsonMixIn.class);
+		// Do not fail on unknown properties
+		om.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+		om.registerModule(module); 
+		return om;
+	}
+	
+	private <T> T doObjectMapperCall(ObjectMapperCall<T> call) {
+		try {
+			return call.call(objectMapper);
+		} catch (Exception e) {
+			throw new IllegalArgumentException("Failed to handle JSON in object mapper", e);
+		} 
+	}
+	
+	
+	// --- PRIVATE CLASSES --- //
+	
+	private interface StyxClassIdJsonMixIn {
+
+		@JsonProperty(CLASS_ID_PROPERTY) public int classId();
+		
+	}
+	
+	private interface ObjectMapperCall<T> {
+		
+		public T call(ObjectMapper mapper) throws JsonProcessingException, JsonMappingException, IOException;
+		
+	}
+}

core/src/main/java/com/cubeia/firebase/io/StyxSerializer.java

+/**
+ * Copyright 2009 Cubeia Ltd  
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.cubeia.firebase.io;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * The styx wire protocol serializer/deserializer. This class is the
+ * primary interface to be used by users of the Styx wire protocol.
+ */
+public final class StyxSerializer {
+
+	/**
+	 * Bah. When in rome...
+	 */
+	public static int HEADER_SIZE = 4;
+	
+    /**
+     * Initialize this class with the automatically generated
+     * ObjectFactory
+     */
+    public StyxSerializer(ObjectFactory factory) {
+        this.factory = factory;
+    }
+
+    /**
+     * Unpack a byte sequence into a concrete ProtocolObject.
+     */
+    public ProtocolObject unpack(ByteBuffer inBuffer) throws IOException {
+    	Integer payloadLength = inBuffer.getInt();
+    	
+    	// Styx by default uses length exclusive from the length header
+        if(inBuffer.remaining() < payloadLength-HEADER_SIZE)
+            throw new IllegalStateException("Packet not fully read! Want " + payloadLength + " bytes, available: " + inBuffer.remaining());
+        
+        int classId = BinaryData.asUnsigned(inBuffer.get());
+        ProtocolObject po = factory.create(classId);
+        po.load(new PacketInputStream(inBuffer));
+
+        return po;
+    }
+
+    public byte[] packArray(ProtocolObject obj) throws IOException {
+    	if (obj.classId() > 255 || obj.classId() < 0) {
+    		throw new IllegalArgumentException("classId " + obj.classId() + " is out of range. Legal values are inside a signed byte.");
+    	}
+    	byte[] packed = packObject(obj); // 5 bytes free at the start
+    	writeLengthHeader(packed.length, packed); // write length, 4 bytes
+    	writeClassidHeader(obj, packed); // write class id, 1 byte
+    	return packed;
+    }
+
+	public ByteBuffer pack(ProtocolObject obj) throws IOException {
+    	return ByteBuffer.wrap(packArray(obj));
+    	
+        
+        
+       /* ByteBuffer buf = ByteBuffer.allocate(4+1+packed.length); // Size+type+payload
+        // buf.putShort((short)(1+2+packed.length));
+        buf.putInt(4+1+packed.length); // Size+type+payload
+        buf.put((byte)obj.classId());
+        buf.put(packed);
+        buf.rewind();*/
+        
+//        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+//        DataOutputStream dos = new DataOutputStream(bos);
+//        dos.writeShort(1 + 2 + packed.length);
+//        dos.writeByte(obj.classId());
+//        dos.write(packed, 0, packed.length);
+//        dos.flush();
+        
+        
+        // return buf;
+    }
+	
+    private void writeClassidHeader(ProtocolObject obj, byte[] bytes) {
+		bytes[4] = (byte)obj.classId();
+	}
+    
+	private void writeLengthHeader(int value, byte[] bytes) {
+		int len = 4;
+		for( int i = 0; i < len; i++ ){
+			bytes[len - 1 - i] = (byte)(value & 0xff);
+			value >>= 8;
+		}
+	}
+
+    /**
+     * This method returns a byte array with 5 bytes free at the start (written
+     * as zeroes) for the packet header (size+classid).
+     */
+    private byte[] packObject(ProtocolObject obj) throws IOException {
+        ByteArrayOutputStream bos = new ByteArrayOutputStream(37);
+        for (int i = 0; i < 5; i++) {
+        	// write header bytes...
+        	bos.write(0);
+        }
+        packObject(obj, bos);
+        return bos.toByteArray();
+    }
+
+	private void packObject(ProtocolObject obj, ByteArrayOutputStream bos) throws IOException {
+		DataOutputStream      dos = new DataOutputStream(bos);
+        PacketOutputStream    pos = new PacketOutputStream(dos);
+        obj.save(pos);
+        dos.flush();
+	}
+
+    private final ObjectFactory factory;
+}

core/src/main/java/com/cubeia/firebase/io/Visitable.java

+/**
+ * Copyright 2009 Cubeia Ltd  
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.cubeia.firebase.io;
+
+public interface Visitable {
+    public void accept(ProtocolObjectVisitor visitor);
+}

core/src/main/java/com/cubeia/firebase/styx/util/ArrayUtils.java

+/**
+ * Copyright 2009 Cubeia Ltd  
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.cubeia.firebase.styx.util;
+
+/**
+ * This class contains utility methods for handling arrays.
+ */
+public class ArrayUtils {
+
+	/**
+	 * Gets a {@link String} representation of a byte array.
+	 * 
+	 * The byte {@link String} will only contain the first <code>maxPrintSize</code> bytes.
+	 * If the array is longer than maxPrintSize, the size of the array will be appended at
+	 * the end of the string.
+	 * 
+	 * If the array is null, "null" will be returned.
+	 * 
+	 * @param array
+	 * @param maxPrintSize
+	 * @return a {@link String} representation of the byte array
+	 */
+	public static String toString(final byte[] array, final int maxPrintSize) {
+		if (array == null) {
+			return "null";
+		}
+		if (array.length == 0) {
+			return "{}";
+		}
+		
+		StringBuilder s = new StringBuilder();
+		s.append("{");
+		s.append(array[0]);
+		
+		for (int i = 1; i < Math.min(array.length, maxPrintSize); i++) {
+			s.append(", ").append(array[i]);
+		}
+		
+		if (array.length > maxPrintSize) {
+			s.append("... (" + array.length).append(")");
+		}
+		s.append("}");
+		
+		return s.toString();
+	}	
+}

core/src/test/java/com/cubeia/firebase/protocol/MyTest.java

+package com.cubeia.firebase.protocol;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.nio.ByteBuffer;
+
+import junit.framework.TestCase;
+
+public class MyTest extends TestCase {
+	
+	/**
+	 * This is test I wrote to make sure that the new ByteBuffer reading of
+	 * unsigned shorts matches the existing DataInputStream's.
+	 * 
+	 * @throws Exception
+	 */
+	public void testUnsigned() throws Exception {
+		byte[] data = new byte[]{ (byte)0xF0, (byte)0xFF };
+		
+		// Read through Datainputstream
+		DataInputStream stream = new DataInputStream(new ByteArrayInputStream(data));
+		short sRead = stream.readShort();
+		stream.reset();
+		int usRead = stream.readUnsignedShort();
+		
+		System.out.println("Stream signed:\t\t"+sRead);
+		System.out.println("Stream unsigned:\t"+usRead);
+		
+		ByteBuffer buffer = ByteBuffer.wrap(data);
+		buffer.mark();
+		
+		short bRead = buffer.getShort();
+		buffer.reset();
+		int ubRead = buffer.getShort() & 0xFFFF;
+		
+		assertEquals(bRead, sRead);
+		assertEquals(ubRead, usRead);
+		
+	}
+	
+}

core/src/test/java/com/cubeia/firebase/protocol/OverflowTest.java

+package com.cubeia.firebase.protocol;
+
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+import com.cubeia.firebase.io.ObjectFactory;
+import com.cubeia.firebase.io.PacketInputStream;
+import com.cubeia.firebase.io.PacketOutputStream;
+import com.cubeia.firebase.io.ProtocolObject;
+import com.cubeia.firebase.io.ProtocolObjectVisitor;
+import com.cubeia.firebase.io.StyxSerializer;
+
+public class OverflowTest extends TestCase {
+
+	public void testOverflow() throws IOException {
+		ProtocolObject p = new ProtocolObject() {
+
+			public int classId() {
+				return 300;
+			}
+			public void load(PacketInputStream ps) throws IOException {
+			}
+			public void save(PacketOutputStream ps) throws IOException {
+			}
+			public void accept(ProtocolObjectVisitor visitor) {
+			}
+		};
+		
+		StyxSerializer s = new StyxSerializer(new ObjectFactory() {
+
+			public ProtocolObject create(int classId) {
+				return null;
+			}
+			public int version() {
+				return 0;
+			}
+			
+		});
+		
+		try {
+			s.pack(p);
+			fail("Class id is out of range.");
+		} catch (IllegalArgumentException e) {
+			// Expected
+		}
+	}
+}

core/src/test/java/com/cubeia/firebase/protocol/ProtocolObjectAdapter.java

+package com.cubeia.firebase.protocol;
+
+import java.io.IOException;
+
+import com.cubeia.firebase.io.PacketInputStream;
+import com.cubeia.firebase.io.PacketOutputStream;
+import com.cubeia.firebase.io.ProtocolObject;
+import com.cubeia.firebase.io.ProtocolObjectVisitor;
+
+public class ProtocolObjectAdapter implements ProtocolObject {
+
+	@Override
+	public void accept(ProtocolObjectVisitor visitor) { }
+
+	@Override
+	public int classId() {
+		return 0;
+	}
+
+	@Override
+	public void save(PacketOutputStream ps) throws IOException { }
+
+	@Override
+	public void load(PacketInputStream ps) throws IOException { }
+
+}

core/src/test/java/com/cubeia/firebase/protocol/StyxJsonSerializerTest.java

+package com.cubeia.firebase.protocol;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import com.cubeia.firebase.io.ObjectFactory;
+import com.cubeia.firebase.io.ProtocolObject;
+import com.cubeia.firebase.io.StyxJsonSerializer;
+
+public class StyxJsonSerializerTest extends TestCase {
+
+	public void testSimpleSerialize() {
+		StyxJsonSerializer ser = new StyxJsonSerializer(null);
+		String json = ser.toJson(new SimpleObject());
+//		System.out.println(json);
+//		assertEquals("{\"classId\":1,\"data\":{\"name\":\"kalle\",\"id\":666}}", json);
+		assertEquals("{\"name\":\"kalle\",\"id\":666,\"classId\":1}", json);
+	}
+	
+	public void testSimpleDeserialize() {
+		StyxJsonSerializer ser = new StyxJsonSerializer(new Factory());
+		SimpleObject o1 = new SimpleObject();
+		String json = ser.toJson(o1);
+		SimpleObject o2 = (SimpleObject) ser.fromJson(json);
+		assertEquals(o1, o2);
+	}
+	
+	public void testSimpleListDeserialize() {
+		StyxJsonSerializer ser = new StyxJsonSerializer(new Factory());
+		List<ProtocolObject> l1 = new ArrayList<ProtocolObject>();
+		l1.add(new SimpleObject(1, "kalle"));
+		l1.add(new SimpleObject(2, "olle"));
+		String json = ser.toJsonList(l1);
+		// System.out.println(json);
+		List<ProtocolObject> l2 = (List<ProtocolObject>) ser.fromJsonList(json);
+		assertEquals(l1, l2);
+	}
+	
+	public void testNestedProtocolObjects() {
+		StyxJsonSerializer ser = new StyxJsonSerializer(new Factory());
+		HardObject o1 = new HardObject(true);
+		String json = ser.toJson(o1);
+		System.out.println(json);
+		HardObject o2 = (HardObject) ser.fromJson(json);
+		assertEquals(o1, o2);		
+	}
+	
+	private static class Factory implements ObjectFactory {
+		
+		@Override
+		public ProtocolObject create(int classId) {
+			if(classId == 1) {
+				return new SimpleObject();
+			}
+			if(classId == 2) {
+				return new HardObject();
+			}		
+			fail("unknown class id: " + classId);
+			return null; // will never get here
+		}
+		
+		@Override
+		public int version() {
+			return 1;
+		}
+	}
+	
+	public static enum Gender {
+		MALE,
+		FEMALE
+	}
+	
+	public static class HardObject extends ProtocolObjectAdapter {
+
+		private Gender gender = Gender.MALE;
+		private List<SimpleObject> list = new ArrayList<SimpleObject>();
+		
+		public HardObject() { 
+			this(false);
+		}
+		
+		public HardObject(boolean populate) {
+			if(populate) {
+				list.add(new SimpleObject(1, "olle"));
+				list.add(new SimpleObject(2, "kalle"));
+			}
+		}
+		
+		public Gender getGender() {
+			return gender;
+		}
+		
+		public void setGender(Gender gender) {
+			this.gender = gender;
+		}
+		
+		public List<SimpleObject> getList() {
+			return list;
+		}
+		
+		public void setList(List<SimpleObject> list) {
+			this.list = list;
+		}
+		
+//		public int getClassId() {
+//			return classId();
+//		}
+		
+		@Override
+		public int classId() {
+			return 2;
+		}
+		
+		@Override
+		public int hashCode() {
+			final int prime = 31;
+			int result = 1;
+			result = prime * result
+					+ ((gender == null) ? 0 : gender.hashCode());
+			result = prime * result + ((list == null) ? 0 : list.hashCode());
+			return result;
+		}
+
+		@Override
+		public boolean equals(Object obj) {
+			if (this == obj)
+				return true;
+			if (obj == null)
+				return false;
+			if (getClass() != obj.getClass())
+				return false;
+			HardObject other = (HardObject) obj;
+			if (gender != other.gender)
+				return false;
+			if (list == null) {
+				if (other.list != null)
+					return false;
+			} else if (!list.equals(other.list))
+				return false;
+			return true;
+		}
+	}
+	
+	public static class SimpleObject extends ProtocolObjectAdapter {
+
+		private String name = "kalle";
+		private int id = 666;
+		
+		public SimpleObject() { }
+		
+		public SimpleObject(int i, String string) {
+			this.name = string;
+			this.id = i;
+		}
+		
+//		public int getClassId() {
+//			return classId();
+//		}
+		
+		public int getId() {
+			return id;
+		}
+		
+		public void setId(int id) {
+			this.id = id;
+		}
+		
+		public String getName() {
+			return name;
+		}
+		
+		public void setName(String name) {
+			this.name = name;
+		}
+
+		@Override
+		public int classId() {
+			return 1;
+		}
+		
+		@Override
+		public int hashCode() {
+			final int prime = 31;
+			int result = 1;
+			result = prime * result + id;
+			result = prime * result + ((name == null) ? 0 : name.hashCode());
+			return result;
+		}
+
+		@Override
+		public boolean equals(Object obj) {
+			if (this == obj)
+				return true;
+			if (obj == null)
+				return false;
+			if (getClass() != obj.getClass())
+				return false;
+			SimpleObject other = (SimpleObject) obj;
+			if (id != other.id)
+				return false;
+			if (name == null) {
+				if (other.name != null)
+					return false;
+			} else if (!name.equals(other.name))
+				return false;
+			return true;
+		}
+	}
+}

core/src/test/java/com/cubeia/firebase/protocol/StyxTest.java

+package com.cubeia.firebase.protocol;
+
+import com.cubeia.firebase.io.PacketInputStream;
+import com.cubeia.firebase.io.PacketOutputStream;
+import com.cubeia.firebase.io.StyxSerializer;
+
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import java.io.*;
+import java.nio.ByteBuffer;
+
+public class StyxTest extends TestCase {
+
+    public void testBasicSerialization() throws Exception {
+        Byte in_int8 = -128;
+        Integer in_uint8 = 150;
+        Short in_int16 = -32768;
+        Integer in_uint16 = 65535;
+        Integer in_int32 = -1000000;
+        Integer in_uint32 = 1000000;
+        Long in_uint_big_32 = 3294967296L;
+        Long in_int64 = 1234567891011121314L;
+        String in_string = "LOL, IMHO :)";
+        boolean in_bool = false, in_bool2 = true;
+        
+        StringBuffer longStringBuffer = new StringBuffer();
+        for (int i = 0; i < 50000; i++) {
+            longStringBuffer.append('x');
+        }
+        String in_string_long = longStringBuffer.toString();
+
+        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+        PacketOutputStream out = new PacketOutputStream(new DataOutputStream(bytes));
+        out.saveByte(in_int8);
+        out.saveUnsignedByte(in_uint8);
+        out.saveShort(in_int16);
+        out.saveUnsignedShort(in_uint16);
+        out.saveInt(in_int32);
+        out.saveInt(in_uint32);
+        out.saveUnsignedInt(in_uint_big_32);
+        out.saveLong(in_int64);
+        out.saveString(in_string);
+        out.saveString(in_string_long);
+        out.saveBoolean(in_bool);
+        out.saveBoolean(in_bool2);
+
+        ByteBuffer buffer = ByteBuffer.wrap(bytes.toByteArray());
+        PacketInputStream in = new PacketInputStream(buffer);
+
+        assertEquals(in.loadByte(), in_int8.intValue());
+        assertEquals(in.loadUnsignedByte(), in_uint8.intValue());
+        assertEquals(in.loadShort(), in_int16.intValue());
+        assertEquals(in.loadUnsignedShort(), in_uint16.intValue());
+        assertEquals(in.loadInt(), in_int32.intValue());
+        assertEquals(in.loadInt(), in_uint32.intValue());
+        assertEquals(in.loadUnsignedInt(), in_uint_big_32.intValue());
+        assertEquals(in.loadLong(), in_int64.longValue());
+        assertEquals(in.loadString(), in_string);
+        assertEquals(in.loadString(), in_string_long);
+        assertEquals(in.loadBoolean(), in_bool);
+        assertEquals(in.loadBoolean(), in_bool2);
+    }
+
+    public void testSaveStringSizeOverflow() throws IOException {
+        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
+        PacketOutputStream packetOut = new PacketOutputStream(new DataOutputStream(byteOut));
+        
+        String longString = randomString(PacketOutputStream.STRING_MAX_BYTES + 1);
+        
+        // write a string that is too long and check that we get an exception
+        try {
+            packetOut.saveString(longString);
+            fail("we should have got an IOException, the string was too long");
+        } catch (IOException e) {
+            // this should happen
+        }
+        
+        // test exact length
+        longString = randomString(PacketOutputStream.STRING_MAX_BYTES);
+        packetOut.saveString(longString);
+        
+        ByteBuffer buffer = ByteBuffer.wrap(byteOut.toByteArray());
+        PacketInputStream in = new PacketInputStream(buffer);
+        
+        assertEquals(longString, in.loadString());
+    }
+    
+    public void testStyxSerializer() throws Exception {
+        StyxSerializer styx = new StyxSerializer(new TestFactory());
+
+        TestClass obj = new TestClass();
+        obj.intVal = 761220;
+        obj.strVal = "OMG! åäÖåÄö";
+
+        ByteBuffer packed = styx.pack(obj);
+
+        TestClass unpacked = (TestClass)styx.unpack(packed);
+        assertEquals(obj.intVal, unpacked.intVal);
+        assertEquals(obj.strVal, unpacked.strVal);
+    }
+
+    
+    public void testVersionPacket() throws Exception {
+    	StyxSerializer styx = new StyxSerializer(new TestFactory());
+    	
+    	VersionPacket packet = new VersionPacket();
+    	packet.game = 99;
+    	packet.operatorid = 1;
+    	packet.protocol = 2;
+    	
+    	ByteBuffer packed = styx.pack(packet);
+    	
+    	VersionPacket unpacked = (VersionPacket)styx.unpack(packed);
+    	assertEquals(99, unpacked.game);
+    }
+    
+    private String randomString(int length) {
+        char[] chars = new char[] {'a', 'b', 'c', 'd'};
+        StringBuffer stringBuffer = new StringBuffer();
+        for (int i = 0; i < length; i++) {
+            stringBuffer.append(chars[(int) Math.random() * chars.length]);
+        }
+        return stringBuffer.toString();
+    }
+    
+    public static void main(String[] args) {
+        TestSuite suite = new TestSuite();
+        suite.addTestSuite(StyxTest.class);
+        junit.textui.TestRunner.run(suite);
+    }
+
+}

core/src/test/java/com/cubeia/firebase/protocol/TestClass.java

+package com.cubeia.firebase.protocol;
+
+import java.io.IOException;
+
+import com.cubeia.firebase.io.PacketInputStream;
+import com.cubeia.firebase.io.PacketOutputStream;
+import com.cubeia.firebase.io.ProtocolObject;
+import com.cubeia.firebase.io.ProtocolObjectVisitor;
+
+public class TestClass implements ProtocolObject {
+
+    public int classId() {
+        return 42;
+    }
+
+    public Integer intVal;
+    public String  strVal;
+
+    public void save(PacketOutputStream ps) throws IOException {
+        ps.saveInt(intVal);
+        ps.saveString(strVal);
+    }
+
+    public void load(PacketInputStream ps) throws IOException {
+        intVal = ps.loadInt();
+        strVal = ps.loadString();
+    }
+
+	public void accept(ProtocolObjectVisitor visitor) {
+		
+	}
+
+
+	
+}

core/src/test/java/com/cubeia/firebase/protocol/TestFactory.java

+package com.cubeia.firebase.protocol;
+
+import com.cubeia.firebase.io.ObjectFactory;
+import com.cubeia.firebase.io.ProtocolObject;
+
+
+public class TestFactory implements ObjectFactory {
+    public int version() {
+        return 666;
+    }
+
+    public ProtocolObject create(int classId) {
+        switch(classId) {
+            case 42:
+                return new TestClass();
+            case 0:
+                return new VersionPacket();
+            default:
+                throw new IllegalArgumentException("Unknown classId: " + classId);
+        }
+    }
+
+}

core/src/test/java/com/cubeia/firebase/protocol/VersionPacket.java

+package com.cubeia.firebase.protocol;
+
+import java.io.IOException;
+
+import com.cubeia.firebase.io.PacketInputStream;
+import com.cubeia.firebase.io.PacketOutputStream;
+import com.cubeia.firebase.io.ProtocolObject;
+import com.cubeia.firebase.io.ProtocolObjectVisitor;
+
+public class VersionPacket implements ProtocolObject {
+	
+    public int classId() {
+        return 0;
+    }
+
+    public int game;
+    public int operatorid;
+    public int protocol;
+
+    public void save(PacketOutputStream ps) throws IOException {
+        ps.saveInt(game);
+        ps.saveInt(operatorid);
+        ps.saveInt(protocol);
+    }
+
+    public void load(PacketInputStream ps) throws IOException {
+        game = ps.loadInt();
+        operatorid = ps.loadInt();
+        protocol = ps.loadInt();
+    }
+    
+
+    public String toString() {
+        String result = "VersionPacket :";
+        result += " game["+game+"]" ;
+        result += " operatorid["+operatorid+"]" ;
+        result += " protocol["+protocol+"]" ;
+        return result;
+    }
+
+	public void accept(ProtocolObjectVisitor visitor) {
+		// TODO Auto-generated method stub
+		
+	}
+
+}
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<artifactId>styx-maven</artifactId>
+	<name>Sttyx Maven Tools</name>
+	<packaging>pom</packaging>
+
+	<parent>
+	  <groupId>com.cubeia.styx</groupId>
+	  <artifactId>styx-root</artifactId>
+	  <version>1.10-SNAPSHOT</version>
+	</parent>
+
+	<modules>
+	  <module>protocol-generator-plugin</module>
+	</modules>
+</project>

maven/protocol-generator-plugin/doc/usage.txt

+Parameters:
+
+language=(java|flash|cpp|all) 
+protocol_file=<file name> 
+output_base_dir=<output directory> - default is "target/jruby-protocol-plugin/generated-sources/"
+package_name=<package name> 
+generate_visitors=(false|true)
+fail_on_bad_packet_order=(false|true) - fail on bad packet order in XML file, only needed for C++ generation, false is default
+
+All directories are relative to the project's base directory (${basedir}).
+
+Examples:
+
+Java:
+mvn com.cubeia:protocol-generator-plugin:generate -Dlanguage=java -Dprotocol_file=protocol.xml -Doutput_dir=temp -Dpackage_name=viktor.isbest -Dgenerate_visitors=false
+
+CPP:
+mvn com.cubeia:protocol-generator-plugin:generate -Dlanguage=cpp -Dprotocol_file=protocol.xml -Doutput_dir=temp/Protocol.cpp -Dpackage_name=viktor.isbest -Dgenerate_visitors=false
+
+Flash:
+mvn com.cubeia:protocol-generator-plugin:generate -Dlanguage=flash -Dprotocol_file=protocol.xml -Doutput_dir=temp -Dpackage_name=viktor.isbest -Dgenerate_visitors=false
+
+
+Example POM snippet:
+
+  <build>
+    <plugins>
+      ...
+      <plugin>
+        <groupId>com.cubeia</groupId>
+        <artifactId>protocol-generator-plugin</artifactId>
+        <version>1.7-SNAPSHOT</version>
+        <configuration>
+          <protocol_file>src/main/xml/protocol.xml</protocol_file>
+          <language>all</language>
+          <package_name>com.cubeia.games.poker.io.protocol</package_name>
+          <generate_visitors>true</generate_visitors>
+		  <fail_on_bad_packet_order>true</fail_on_bad_packet_order>
+        </configuration>
+        <executions>
+          <execution>
+            <phase>generate-sources</phase>
+            <goals>
+              <goal>generate</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      ...
+	</plugins>
+  </build>

maven/protocol-generator-plugin/pom.xml

+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>protocol-generator-plugin</artifactId>
+  <name>Styx Protocol Generator Plugin</name>
+  <packaging>maven-plugin</packaging>
+
+  <parent>
+		<artifactId>styx-maven</artifactId>
+		<groupId>com.cubeia.styx</groupId>
+		<version>1.10-SNAPSHOT</version>
+	</parent>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.jruby</groupId>
+      <artifactId>jruby-complete</artifactId>
+      <version>1.1.5</version>
+    </dependency>
+    <dependency>
+      <groupId>com.sun.script.jruby</groupId>
+      <artifactId>jruby-engine</artifactId>
+      <version>1.1.6</version>
+      <exclusions>
+        <!-- OMG WTF! SUN f****d up the artifact and group id's... -->
+        <exclusion>
+          <groupId>script-api</groupId>
+          <artifactId>javax.script</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+    <dependency>
+      <groupId>javax.script</groupId>
+      <artifactId>script-api</artifactId>
+      <version>1.0</version>
+    </dependency>
+	<dependency>
+			<groupId>commons-io</groupId>
+			<artifactId>commons-io</artifactId>
+			<version>1.4</version>
+		</dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-plugin-api</artifactId>
+      <version>2.0</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-project</artifactId>
+      <version>2.0.9</version>
+    </dependency>
+
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.5</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven.plugin-testing</groupId>
+      <artifactId>maven-plugin-testing-harness</artifactId>
+      <version>1.2</version>
+    </dependency>
+
+  </dependencies>
+
+  <build>
+    <resources>
+      <resource>
+        <directory>src/main/resources</directory>
+      </resource>
+      <resource>
+        <directory>src/main/scripts</directory>
+      </resource>
+    </resources>
+    <testResources>
+      <testResource>
+        <directory>src/test/resources</directory>
+      </testResource>
+    </testResources>
+
+    <plugins>
+
+    </plugins>
+  </build>
+
+
+  <repositories>
+
+    <repository>
+      <id>sun-repo-2</id>
+      <url>http://download.java.net/maven/2/</url>
+      <releases>
+        <enabled>true</enabled>
+      </releases>
+      <snapshots>
+        <enabled>false</enabled>
+      </snapshots>
+    </repository>
+    <repository>
+      <id>codehaus-mule</id>
+      <url>http://dist.codehaus.org/mule/dependencies/maven2/</url>
+      <releases>
+        <enabled>true</enabled>
+      </releases>
+      <snapshots>
+        <enabled>false</enabled>
+      </snapshots>
+    </repository>
+
+
+  </repositories>
+</project>

maven/protocol-generator-plugin/src/main/java/com/cubeia/ProtocolGeneratorMojo.java

+/**
+ * Copyright 2009 Cubeia Ltd  
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.cubeia;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Set;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import javax.script.Invocable;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.project.MavenProject;
+
+/**
+ * 
+ * @goal generate
+ * @phase generate-sources
+ * @requiresDependencyResolution
+ */
+public class ProtocolGeneratorMojo extends AbstractMojo {
+    
+    /**
+     * @parameter
+     * @required
+     */
+    private String language;
+    
+    /**
+     * Protocol definition file. The path is relative to ${basedir}.
+     * @parameter
+     */
+    private String protocol_file;
+    
+    /**
+     * Protocol dependency. In the format:
+     * 
+     * <pre>
+     *     &lt;groupId&gt;:&lt;artifactId&gt;:&lt;fileName&gt;	
+     * </pre>
+     * 
+     * The file will be searched for in the given dependency archive.
+     * 
+     * @parameter
+     */
+    private String protocol_dependency;
+    
+	/**
+	 * @parameter expression="${project.build.directory}"
+	 */
+	private File outputDir;
+
+    /**
+     * @parameter
+     * @required
+     */
+    private String package_name;
+    
+    /**
+     * @parameter
+     */
+    private String javascript_package_name;
+
+    
+    /**
+     * The path is relative to ${basedir}.
+     * @parameter
+     * @deprecated
+     */
+    private String output_dir;
+    
+    /**
+     * Base directory for generated sources. The path is relative to ${basedir}.
+     * @parameter default-value="target/jruby-protocol-plugin/generated-sources"
+     */
+    private String output_base_dir;
+    
+    /**
+     * @parameter default-value="true"
+     */
+    private boolean append_language_to_output_base_dir = true;
+    
+    /**
+     * @parameter default-value="${project.dependencies}" 
+     * @required
+     * @readonly
+     */
+    @SuppressWarnings({ "unused", "rawtypes" })
+	private List dependencies;
+
+    /**
+     * @parameter
+     * @required
+     */
+    private boolean generate_visitors;
+
+    /**
+     * @parameter
+     */
+    private String version;
+    
+    /**
+     * @parameter default-value="false"
+     */
+    private boolean fail_on_bad_packet_order;
+    
+    /**
+     * The maven project.
+     * 
+     * @parameter expression="${project}"
+     * @required
+     */
+    private MavenProject project;
+
+    private enum Languages {java, flash, cpp, csharp, cplusplus, protobuf, javascript};
+    
+    private final String GENERATOR_WRAPPER_SCRIPT = "/code_generator_wrapper.rb";
+    
+    
+    
+    public void execute() throws MojoExecutionException, MojoFailureException {
+        getLog().info("Cubeia protoco