/* vim: set ts=2 et sw=2 cindent fo=qroca: */
package com.globant.katari.core.web;
import org.apache.commons.lang.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import com.globant.katari.core.application.JsonRepresentation;
import freemarker.template.SimpleScalar;
import freemarker.template.TemplateHashModel;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;
import freemarker.template.TemplateSequenceModel;
import freemarker.template.TemplateScalarModel;
import freemarker.template.WrappingTemplateModel;
import freemarker.template.ObjectWrapper;
import freemarker.ext.util.WrapperTemplateModel;
/** A Freemarker JsonRepresentation model to expose the Json objects from the
* JsonRepresentation as freemarker elements.
*/
public final class JsonRepresentationModel extends WrappingTemplateModel
implements WrapperTemplateModel, TemplateHashModel, TemplateSequenceModel,
TemplateScalarModel {
/** The class logger.
*/
private static Logger log = LoggerFactory.getLogger(
JsonRepresentationModel.class);
/** The wrapped JsonRepresentation, never null.
*/
private JsonRepresentation representation;
/** Constructor.
*
* @param object the wrapper JsonRepresentation object, never null.
*/
public JsonRepresentationModel(final JsonRepresentation object,
final ObjectWrapper wrapper) {
super(wrapper);
Validate.notNull(object, "The json representation object cannot be null.");
representation = object;
}
/** {@inheritDoc}
*
* Returns a wrapped array, object or scalar for the given json object
* member.
*
* @throws TemplateModelException if the wrapped object references a json
* array instead of a json object.
*/
public TemplateModel get(final String key) throws TemplateModelException {
log.trace("Entering get {}.", key);
JSONObject object = representation.getJsonObject();
if (object == null) {
// This is not an object, bail out.
throw new TemplateModelException(
"Tried to access an array as an object");
}
JSONObject target = object.optJSONObject(key);
if (target != null) {
TemplateModel model;
model = new JsonRepresentationModel(new JsonRepresentation(target),
getObjectWrapper());
log.trace("Leaving get with json object");
return model;
}
JSONArray array = object.optJSONArray(key);
if (array != null) {
TemplateModel model;
model = new JsonRepresentationModel(new JsonRepresentation(array),
getObjectWrapper());
log.trace("Leaving get with json array");
return model;
}
if (object.has(key)) {
Object value;
try {
value = object.get(key);
} catch (JSONException e) {
throw new RuntimeException("Error converting " + key + " to string.",
e);
}
log.trace("Leaving get with string");
return wrap(value);
} else {
log.trace("Leaving get with null");
return null;
}
}
/** {@inheritDoc}
*
* Returns a wrapped array, object or scalar for the given json array index.
*
* @throws TemplateModelException if the wrapped object references a json
* object instead of a json array.
*/
public TemplateModel get(final int index) throws TemplateModelException {
JSONArray array = representation.getJsonArray();
if (array == null) {
// This is not an array, bail out.
throw new TemplateModelException("Tried to iterate over a json object.");
}
JSONObject object = array.optJSONObject(index);
if (object != null) {
TemplateModel model;
model = new JsonRepresentationModel(new JsonRepresentation(object),
getObjectWrapper());
log.trace("Leaving with json array");
return model;
}
JSONArray target = array.optJSONArray(index);
if (target != null) {
TemplateModel model;
model = new JsonRepresentationModel(new JsonRepresentation(target),
getObjectWrapper());
log.trace("Leaving with json array");
return model;
}
Object value;
try {
value = array.get(index);
} catch (JSONException e) {
throw new RuntimeException("Error converting " + index + " to string.",
e);
}
log.trace("Leaving with string");
return wrap(value);
}
/** {@inheritDoc}
*
* Returns the true if the wrapped json object is empty.
*
* @throws TemplateModelException if the wrapped object references a json
* array instead of a json object.
*/
public boolean isEmpty() throws TemplateModelException {
JSONObject object = representation.getJsonObject();
if (object == null) {
// This is not an array, bail out.
throw new TemplateModelException("isEmpty() only applies to an object");
}
return object.length() == 0;
}
/** {@inheritDoc}
*
* Returns the length of the wrapped json array.
*
* @throws TemplateModelException if the wrapped object references a json
* object instead of a json array.
*/
public int size() throws TemplateModelException {
JSONArray array = representation.getJsonArray();
if (array == null) {
// This is not an array, bail out.
throw new TemplateModelException("size() only applies to an array");
}
return array.length();
}
/** {@inheritDoc}
*
* Returns the json object or array as a string.
*
* This makes it possible to show in the freemarker page the json string with
* ${result}.
*
* This operation is the implementation of the TemplateScalarModel interfase.
*/
public String getAsString() {
return representation.toString();
}
public Object getWrappedObject() {
return representation;
}
}