package com.openfeint.internal.resource; import java.io.IOException; import java.io.OutputStream; import java.io.StringWriter; import java.util.HashMap; import java.util.List; import java.util.Map; import org.codehaus.jackson.JsonEncoding; import org.codehaus.jackson.JsonFactory; import org.codehaus.jackson.JsonGenerationException; import org.codehaus.jackson.JsonGenerator; import com.openfeint.api.resource.Achievement; import com.openfeint.api.resource.CurrentUser; import com.openfeint.api.resource.Leaderboard; import com.openfeint.api.resource.Score; import com.openfeint.api.resource.ServerTimestamp; import com.openfeint.api.resource.User; import com.openfeint.internal.OpenFeintInternal; public abstract class Resource { private static final String TAG = "Resource"; String mID; public String resourceID() { return mID; } public void setResourceID(String id) { mID = id; } private static HashMap<Class<? extends Resource>, ResourceClass> sSubclassMap = new HashMap<Class<? extends Resource>, ResourceClass>(); private static HashMap<String, ResourceClass> sNameMap = new HashMap<String, ResourceClass>(); public static void registerSubclass(ResourceClass klass) { sSubclassMap.put(klass.mObjectClass, klass); if (null != klass.mResourceName) { sNameMap.put(klass.mResourceName, klass); } } public static ResourceClass getKlass(Class<?> subclass) { return sSubclassMap.get(subclass); } public static ResourceClass getKlass(String klassName) { return sNameMap.get(klassName); } // This guy's a little different: he has no name, and you can never instantiate him. He's just here for the mixin. public static ResourceClass getResourceClass() { ResourceClass klass = new ResourceClass (Resource.class, null) { public Resource factory () { return null; } }; klass.mProperties.put("id", new StringResourceProperty() { public void set(Resource obj, String val) { obj.mID = val; } public String get(Resource obj) { return obj.mID; } }); return klass; } public final void generateToStream(OutputStream out) throws IOException { JsonFactory jf = new JsonFactory(); JsonGenerator jg = jf.createJsonGenerator(out, JsonEncoding.UTF8); generate(jg); jg.close(); } public final String generate() { StringWriter sw = new StringWriter(); JsonFactory jf = new JsonFactory(); try { JsonGenerator jg = jf.createJsonGenerator(sw); generate(jg); jg.close(); } catch (IOException e) { OpenFeintInternal.log(TAG, e.getMessage()); return null; } return sw.toString(); } public final void generate(JsonGenerator generator) throws JsonGenerationException, IOException { ResourceClass rc = getKlass(getClass()); generator.writeStartObject(); generator.writeFieldName(rc.mResourceName); generator.writeStartObject(); for(Map.Entry<String,ResourceProperty> e:rc.mProperties.entrySet()) { ResourceProperty rp = e.getValue(); if (rp instanceof PrimitiveResourceProperty) { ((PrimitiveResourceProperty)rp).generate(this, generator, e.getKey()); } else if (rp instanceof ArrayResourceProperty) { ArrayResourceProperty arp = (ArrayResourceProperty)rp; List<? extends Resource> resources = arp.get(this); if (null != resources) { generator.writeFieldName(e.getKey()); ResourceClass erc = getKlass(arp.elementType()); generator.writeStartObject(); generator.writeFieldName(erc.mResourceName + "s"); generator.writeStartArray(); for (Resource r : resources) { r.generate(generator); } generator.writeEndArray(); generator.writeEndObject(); } } else if (rp instanceof NestedResourceProperty) { Resource r = ((NestedResourceProperty)rp).get(this); if (null != r) { generator.writeFieldName(e.getKey()); r.generate(generator); } } else if (rp instanceof HashIntResourceProperty) { HashMap<String, Integer> r = ((HashIntResourceProperty)rp).get(this); if (null != r && r.size() > 0) { generator.writeFieldName(e.getKey()); generator.writeStartObject(); for (Map.Entry<String, Integer> entry : r.entrySet()) { generator.writeFieldName(entry.getKey()); generator.writeNumber(entry.getValue()); } generator.writeEndObject(); } } } generator.writeEndObject(); generator.writeEndObject(); } public final void shallowCopy(Resource otherResource) { if (otherResource.getClass() != getClass()) { throw new UnsupportedOperationException("You can only shallowCopy the same type of resource"); } unguardedShallowCopy(otherResource); } public final void shallowCopyAncestorType(Resource otherResource) { Class<?> c = getClass(); final Class<?> o = otherResource.getClass(); if (o != Resource.class) { while (c != o && c != Resource.class) { c = c.getSuperclass(); } if (c == Resource.class) { throw new UnsupportedOperationException(o.getName() + " is not a superclass of " + getClass().getName()); } } unguardedShallowCopy(otherResource); } private final void unguardedShallowCopy(Resource otherResource) { ResourceClass rc = getKlass(otherResource.getClass()); for(Map.Entry<String,ResourceProperty> e:rc.mProperties.entrySet()) { ResourceProperty rp = e.getValue(); if (rp instanceof PrimitiveResourceProperty) { ((PrimitiveResourceProperty) rp).copy(this, otherResource); } else if (rp instanceof ArrayResourceProperty) { ((ArrayResourceProperty) rp).set(this, ((ArrayResourceProperty) rp).get(otherResource)); } else if (rp instanceof NestedResourceProperty) { ((NestedResourceProperty) rp).set(this, ((NestedResourceProperty) rp).get(otherResource)); } } } static { // Register all subclasses, for OFX, since it is not in same project // all OFX resources will register itself registerSubclass(Resource.getResourceClass()); registerSubclass(ServerException.getResourceClass()); registerSubclass(ServerTimestamp.getResourceClass()); registerSubclass(BlobUploadParameters.getResourceClass()); registerSubclass(Achievement.getResourceClass()); registerSubclass(Leaderboard.getResourceClass()); registerSubclass(Score.getResourceClass()); registerSubclass(User.getResourceClass()); // CurrentUser after User, due to inheritance registerSubclass(CurrentUser.getResourceClass()); } }