package com.openfeint.internal;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonToken;
import com.openfeint.internal.OpenFeintInternal;
import com.openfeint.internal.resource.ArrayResourceProperty;
import com.openfeint.internal.resource.HashIntResourceProperty;
import com.openfeint.internal.resource.NestedResourceProperty;
import com.openfeint.internal.resource.PrimitiveResourceProperty;
import com.openfeint.internal.resource.Resource;
import com.openfeint.internal.resource.ResourceClass;
import com.openfeint.internal.resource.ResourceProperty;
public class JsonResourceParser {
private static final String TAG = "JsonResourceParser";
private JsonParser mParser;
public JsonResourceParser(JsonParser parser) {
mParser = parser;
}
public Object parse() throws JsonParseException, IOException
{
JsonToken firstTok = mParser.nextToken();
if (firstTok == null) {
// this is like, head :created, that's cool.
// Shouldn't affect our status code.
return null;
}
if (firstTok != JsonToken.START_OBJECT) throw new JsonParseException("Couldn't find toplevel wrapper object.", mParser.getTokenLocation());
if (mParser.nextToken() != JsonToken.FIELD_NAME) throw new JsonParseException("Couldn't find toplevel wrapper object.", mParser.getTokenLocation());
String classOrArrayName = mParser.getText();
Object rv = null;
JsonToken tok = mParser.nextToken();
if (tok == JsonToken.START_ARRAY) {
// just a top-level resources array.
rv = parseOpenedArray();
} else if (tok == JsonToken.START_OBJECT) {
// a singular resource.
ResourceClass klass = Resource.getKlass(classOrArrayName);
if (klass == null) throw new JsonParseException("Unknown toplevel class '"+classOrArrayName+"'.", mParser.getTokenLocation());
rv = parseOpenedResource(klass);
} else {
throw new JsonParseException("Expected object or array at top level.", mParser.getTokenLocation());
}
if (mParser.nextToken() != JsonToken.END_OBJECT) throw new JsonParseException("Expected only one k/v in toplevel wrapper object.", mParser.getTokenLocation());
return rv;
}
public Object parse(ResourceClass resourceClass) throws JsonParseException, IOException
{
JsonToken firstTok = mParser.nextToken();
if (firstTok == null) {
// this is like, head :created, that's cool.
// Shouldn't affect our status code.
return null;
}
if (firstTok != JsonToken.START_OBJECT) throw new JsonParseException("Couldn't find toplevel wrapper object.", mParser.getTokenLocation());
return parseOpenedResource(resourceClass);
}
private Resource parseResource(ResourceClass resourceClass)
throws JsonParseException, IOException {
JsonToken tok = mParser.nextToken();
if (tok == JsonToken.VALUE_NULL) return null;
if (tok != JsonToken.START_OBJECT)
throw new JsonParseException("Expected START_OBJECT of " + resourceClass.mResourceName, mParser.getCurrentLocation());
return parseOpenedResource(resourceClass);
}
private Resource parseOpenedResource(ResourceClass resourceClass)
throws JsonParseException, IOException {
Resource resource = resourceClass.factory();
while (mParser.nextToken() == JsonToken.FIELD_NAME) {
String name = mParser.getText();
ResourceProperty prop = resourceClass.mProperties.get(name);
if (prop == null) {
// Unknown property
mParser.nextToken();
mParser.skipChildren();
} else if (prop instanceof PrimitiveResourceProperty) {
PrimitiveResourceProperty pprop = (PrimitiveResourceProperty)prop;
mParser.nextToken();
pprop.parse(resource, mParser);
} else if (prop instanceof NestedResourceProperty) {
NestedResourceProperty nprop = (NestedResourceProperty)prop;
ResourceClass rc = Resource.getKlass(nprop.getType());
if (rc != null) {
nprop.set(resource, parseResource(rc));
} else {
OpenFeintInternal.log(TAG, "unknown " + nprop.getType());
}
} else if (prop instanceof ArrayResourceProperty) {
ArrayResourceProperty aprop = (ArrayResourceProperty)prop;
aprop.set(resource, parseArray());
} else if (prop instanceof HashIntResourceProperty) {
HashIntResourceProperty hprop = (HashIntResourceProperty)prop;
hprop.set(resource, parseHash());
} else {
OpenFeintInternal.log(TAG, "Totally don't know what to do about this property");
mParser.skipChildren();
}
}
if (mParser.getCurrentToken() != JsonToken.END_OBJECT)
throw new JsonParseException("Expected END_OBJECT of " + resourceClass.mResourceName, mParser.getCurrentLocation());
return resource;
}
private HashMap<String, Integer> parseHash() throws JsonParseException, IOException {
JsonToken tok = mParser.nextToken();
if (tok == JsonToken.VALUE_NULL) return null;
if (tok != JsonToken.START_OBJECT)
throw new JsonParseException("Expected START_OBJECT", mParser.getCurrentLocation());
return parseOpenedHash();
}
private HashMap<String, Integer> parseOpenedHash() throws JsonParseException, IOException {
HashMap<String, Integer> resources = new HashMap<String, Integer>();
while (mParser.nextToken() == JsonToken.FIELD_NAME) {
String className = mParser.getText();
mParser.nextToken();
int v = mParser.getIntValue();
resources.put(className, v);
}
return resources;
}
private Resource parseResource() throws JsonParseException, IOException {
if (mParser.nextToken() != JsonToken.FIELD_NAME) throw new JsonParseException("Couldn't find wrapper object.", mParser.getTokenLocation());
String className = mParser.getText();
ResourceClass klass = Resource.getKlass(className);
if (klass == null) throw new JsonParseException("Don't know class '"+className+"'.", mParser.getTokenLocation());
Resource rv = parseResource(klass);
if (mParser.nextToken() != JsonToken.END_OBJECT) throw new JsonParseException("Expected only one k/v in wrapper object.", mParser.getTokenLocation());
return rv;
}
private ArrayList<Resource> parseArray()
throws JsonParseException, IOException {
JsonToken tok = mParser.nextToken();
if (tok == JsonToken.VALUE_NULL) return null;
if (tok != JsonToken.START_ARRAY) {
throw new JsonParseException("Wanted START_ARRAY", mParser.getCurrentLocation());
}
return parseOpenedArray();
}
private ArrayList<Resource> parseOpenedArray()
throws JsonParseException, IOException {
ArrayList<Resource> resources = new ArrayList<Resource>();
while (mParser.nextToken() != JsonToken.END_ARRAY) {
resources.add(parseResource());
}
return resources;
}
}