package er.rest.format;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.webobjects.eocontrol.EOClassDescription;
import com.webobjects.eocontrol.EOEditingContext;
import com.webobjects.eocontrol.EOEnterpriseObject;
import er.extensions.eof.ERXEC;
import er.extensions.eof.ERXKeyFilter;
import er.rest.ERXRestContext;
import er.rest.ERXRestRequestNode;
/**
* The ERXRestFormat class encapsulates the details of message formatting. As such it encapsulates the request parser, response formatter, format name and response mime type.
*
*/
public class ERXRestFormat {
public static final String HTML_KEY = "html";
public static final String JSON_KEY = "json";
public static final String JS_KEY = "js";
public static final String RAILS_KEY = "rails";
public static final String PLIST_KEY = "plist";
public static final String SPROUTCORE_KEY = "sc";
public static final String XML_KEY = "xml";
public static final String FORM_KEY = "form";
public static final String BINARY_PLIST_KEY = "bplist";
public static final String EMBER_KEY = "ember";
private static Map<String, ERXRestFormat> _formats = new ConcurrentHashMap<>();
static {
// MS: The whole naming thing is stupid, I know ... we need to separate mime type from extensions from the name
ERXRestFormat.registerFormatNamed(new ERXJSONRestParser(), new ERXJSONRestWriter(), new ERXRestFormatDelegate(), ERXRestFormat.JSON_KEY, "application/json");
ERXRestFormat.registerFormatNamed(new ERXJSONRestParser(), new ERXJSONRestWriter(), new ERXRestFormatDelegate(), ERXRestFormat.JS_KEY, "text/js");
ERXRestFormat.registerFormatNamed(new ERXPListRestParser(), new ERXPListRestWriter(), new ERXRestFormatDelegate(), ERXRestFormat.PLIST_KEY, "text/plist");
ERXRestFormat.registerFormatNamed(new ERXBinaryPListRestParser(), new ERXBinaryPListRestWriter(), new ERXRestFormatDelegate(), ERXRestFormat.BINARY_PLIST_KEY, "application/x-plist");
ERXRestFormat.registerFormatNamed(new ERXXmlRestParser(), new ERXXmlRestWriter(), new ERXRestFormatDelegate("id", "type", "nil", true, true, true, true), ERXRestFormat.RAILS_KEY, "application/xml", "text/xml");
ERXRestFormat.registerFormatNamed(new ERXXmlRestParser(), new ERXXmlRestWriter(), new ERXRestFormatDelegate(), ERXRestFormat.XML_KEY, "application/xml", "text/xml");
ERXRestFormat.registerFormatNamed(null, new ERXSimpleRestWriter(), new ERXRestFormatDelegate(), ERXRestFormat.HTML_KEY, "text/html");
ERXRestFormat.registerFormatNamed(new ERXJSONRestParser(), new ERXSproutCoreRestWriter(), new ERXRestFormatDelegate("guid", "type", "nil", true, true, false, false), ERXRestFormat.SPROUTCORE_KEY, "application/sc");
ERXRestFormat.registerFormatNamed(new ERXFormRestParser(), new ERXJSONRestWriter(), new ERXRestFormatDelegate(), ERXRestFormat.FORM_KEY, "application/x-www-form-urlencoded");
ERXRestFormat.registerFormatNamed(new ERXEmberRestParser(), new ERXEmberRestWriter(), new ERXEmberFormatDelegate("id", "type", "nil", true, true, false, false), ERXRestFormat.EMBER_KEY, "application/json");
}
private final String _name;
private final IERXRestParser _parser;
private final IERXRestWriter _writer;
private final ERXRestFormat.Delegate _delegate;
/**
* Returns the registered html form format.
*
* @return the registered html form format
*/
public static ERXRestFormat form() {
return formatNamed(ERXRestFormat.FORM_KEY);
}
/**
* Returns the registered html format.
*
* @return the registered html format
*/
public static ERXRestFormat html() {
return formatNamed(ERXRestFormat.HTML_KEY);
}
/**
* Returns the registered json format.
*
* @return the registered json format
*/
public static ERXRestFormat json() {
return formatNamed(ERXRestFormat.JSON_KEY);
}
/**
* Returns the registered plist format.
*
* @return the registered plist format
*/
public static ERXRestFormat plist() {
return formatNamed(ERXRestFormat.PLIST_KEY);
}
/**
* Returns the registered xml format.
*
* @return the registered xml format
*/
public static ERXRestFormat xml() {
return formatNamed(ERXRestFormat.XML_KEY);
}
/**
* Returns the registered plist format.
*
* @return the registered plist format
*/
public static ERXRestFormat bplist() {
return formatNamed(ERXRestFormat.BINARY_PLIST_KEY);
}
/**
* Constructs a new ERXRestFormat.
*
* @param name the name of the format
* @param parser the parser
* @param writer the writer
* @param delegate the delegate to use while parsing and writing
*/
public ERXRestFormat(String name, IERXRestParser parser, IERXRestWriter writer, ERXRestFormat.Delegate delegate) {
_name = name;
_parser = parser;
_writer = writer;
_delegate = delegate;
}
/**
* Returns the name of this format.
*
* @return the name of this format
*/
public String name() {
return _name;
}
public IERXRestParser parser() {
return _parser;
}
public IERXRestWriter writer() {
return _writer;
}
public ERXRestFormat.Delegate delegate() {
return _delegate;
}
/**
* Returns a parsed ERXRestRequestNode using this format's parser.
*
* @param str the string to parse
* @return the parsed request node
*/
public ERXRestRequestNode parse(String str) {
EOEditingContext editingContext = ERXEC.newEditingContext();
try {
ERXRestRequestNode node = parse(str, new ERXRestContext(editingContext));
return node;
}
finally {
editingContext.dispose();
}
}
/**
* Returns a parsed ERXRestRequestNode using this format's parser.
*
* @param str the string to parse
* @param context the REST context
* @return the parsed request node
*/
public ERXRestRequestNode parse(String str, ERXRestContext context) {
return parser().parseRestRequest(new ERXStringRestRequest(str), _delegate, context);
}
/**
* Returns a parsed ERXRestRequestNode using this format's parser.
*
* @param request the request
* @param context the REST context
* @return the parsed request node
*/
public ERXRestRequestNode parse(IERXRestRequest request, ERXRestContext context) {
return parser().parseRestRequest(request, _delegate, context);
}
/**
* Returns the formatted version of the given object using a recursive "All" filter and the default rest delegate.
*
* @param obj the object to render
* @return obj rendered using this format
*/
public String toString(Object obj) {
EOEditingContext editingContext = (obj instanceof EOEnterpriseObject) ? ((EOEnterpriseObject)obj).editingContext() : null;
return toString(obj, new ERXRestContext(editingContext));
}
/**
* Returns the formatted version of the given object using a recursive "All" filter.
*
* @param obj the object to render
* @param filter the filter to apply to the object
* @return obj rendered using this format
*/
public String toString(Object obj, ERXKeyFilter filter) {
EOEditingContext editingContext = (obj instanceof EOEnterpriseObject) ? ((EOEnterpriseObject)obj).editingContext() : null;
return toString(obj, filter, new ERXRestContext(editingContext));
}
/**
* Returns the formatted version of the given object using a recursive "All" filter.
*
* @param obj the object to render
* @param context the REST context
* @return obj rendered using this format
*/
public String toString(Object obj, ERXRestContext context) {
return toString(obj, ERXKeyFilter.filterWithAllRecursive(), context);
}
/**
* Returns the formatted version of the given object.
*
* @param obj the object to render
* @param filter the filter to apply to the object
* @param context the REST context
* @return obj rendered using this format
*/
public String toString(Object obj, ERXKeyFilter filter, ERXRestContext context) {
return ERXRestRequestNode.requestNodeWithObjectAndFilter(obj, filter, context).toString(writer(), delegate(), context);
}
/**
* Returns the formatted version of the given list.
*
* @param classDescription the class description for the elements of the list
* @param list the list
* @param filter the filter
* @param context the REST context
* @return list rendered using this format
*/
public String toString(EOClassDescription classDescription, List<?> list, ERXKeyFilter filter, ERXRestContext context) {
return ERXRestRequestNode.requestNodeWithObjectAndFilter(classDescription, list, filter, context).toString(writer(), delegate(), context);
}
@Override
public String toString() {
return "[ERXRestFormat: " + _name + "]";
}
/**
* Returns true if there is a format registered with the given name.
*
* @param name the name to lookup
* @return true if there is a format registered with the given name
*/
public static boolean hasFormatNamed(String name) {
return name != null && _formats.containsKey(name.toLowerCase());
}
public static ERXRestFormat formatNamed(String name) {
ERXRestFormat format = _formats.get(name.toLowerCase());
if (format == null) {
format = new ERXRestFormat(name, null, null, new ERXRestFormat.NoOpDelegate());
}
return format;
}
public static ERXRestFormat registerFormatNamed(IERXRestParser parser, IERXRestWriter writer, ERXRestFormat.Delegate delegate, String... names) {
ERXRestFormat format = new ERXRestFormat(names[0], parser, writer, delegate);
for (String name : names) {
ERXRestFormat.registerFormatNamed(format, name);
}
return format;
}
public static ERXRestFormat registerFormatNamed(ERXRestFormat format, String name) {
_formats.put(name.toLowerCase(), format);
return format;
}
/**
* An ERXRestFormat.Delegate is one component of an ERXRestFormat and is used to customize an ERXRequestNode
* after parsing in the context of reading a request or before writing in the context of a response generation.
*/
public static interface Delegate {
public void nodeDidParse(ERXRestRequestNode node);
public void nodeWillWrite(ERXRestRequestNode node);
}
public static class NoOpDelegate implements Delegate {
public void nodeDidParse(ERXRestRequestNode node) {
// DO NOTHING
}
public void nodeWillWrite(ERXRestRequestNode node) {
// DO NOTHING
}
}
}