package er.rest;
import com.webobjects.eoaccess.EOEntityClassDescription;
import com.webobjects.eocontrol.EOClassDescription;
import com.webobjects.eocontrol.EOEnterpriseObject;
import com.webobjects.foundation.NSMutableDictionary;
import com.webobjects.foundation._NSUtilities;
/**
* The delegate interface used to convert objects to and from request nodes.
*
* @author mschrag
*/
public interface IERXRestDelegate {
/**
* Returns the primary key for the specified object.
*
* @param obj
* the object to return a pk for
* @param context
* the REST context
* @return the primary key of the object
*/
public Object primaryKeyForObject(Object obj, ERXRestContext context);
/**
* Creates a new instance of the entity.
*
* @param entity
* the entity
* @param id
* the ID of the object
* @param context
* the REST context
* @return a new instance of the entity
*/
public Object createObjectOfEntityWithID(EOClassDescription entity, Object id, ERXRestContext context);
/**
* Returns the object with the given entity and ID.
*
* @param entity
* the entity
* @param id
* the ID of the object
* @param context
* the REST context
* @return the object with the given entity and ID
*/
public Object objectOfEntityWithID(EOClassDescription entity, Object id, ERXRestContext context);
/**
* This API will likely change. Override if you have to for now, but I'm not
* sure if it makes more sense to return an array of pk classes, a map of
* pk to pk class, this boolean, or an array of pk attribute names. If we
* return pk names, we could probably get rid of primaryKeyForObject, or
* at least fully implement it in ERXAbstractRestDelegate, but I don't
* want to fully commit to this API yet. In the meantime, this at least
* provides a stapgap for automatic registration.
*
* @param classDescription
* the class description in question
* @return whether or not the given class description has numeric pks
*/
public boolean __hasNumericPrimaryKeys(EOClassDescription classDescription);
/**
* A Factory for creating IERXRestDelegates. Right now it's just hard-coded, but this is being added for a later
* extension point.
*
* @author mschrag
*/
public static class Factory {
private static NSMutableDictionary<String, IERXRestDelegate> _delegates = new NSMutableDictionary<>();
private static IERXRestDelegate _defaultDelegate = new ERXEORestDelegate();
private static IERXRestDelegate _defaultBeanDelegate = new ERXNoOpRestDelegate();
/**
* Sets the default rest delegate to use for EO's when no other can be found. The default is ERXEORestDelegate.
*
* @param defaultDelegate
* the default delegate to use
*/
public static void setDefaultDelegate(IERXRestDelegate defaultDelegate) {
IERXRestDelegate.Factory._defaultDelegate = defaultDelegate;
}
/**
* Sets the default rest delegate to use for non-EO's when no other can be found. The default is
* ERXNoOpRestDelegate.
*
* @param defaultDelegate
* the default delegate to use
*/
public static void setDefaultBeanDelegate(IERXRestDelegate defaultDelegate) {
IERXRestDelegate.Factory._defaultBeanDelegate = defaultDelegate;
}
/**
* Registers a rest delegate for the given entity name.
*
* @param delegate
* the delegate to register
* @param entityName
* the entity name to register for
*/
public static void setDelegateForEntityNamed(IERXRestDelegate delegate, String entityName) {
_delegates.setObjectForKey(delegate, entityName);
}
/**
* Registers a rest delegate for the given entity name.
*
* @param delegate
* the delegate class to register
* @param entityName
* the entity name to register for
*/
public static void setDelegateForEntityNamed(IERXRestDelegate delegate, String entityName, Class<?> clazz) {
_delegates.setObjectForKey(delegate, entityName);
ERXRestClassDescriptionFactory.registerClass(clazz);
}
/**
* Returns a rest delegate for the given entity name.
*
* @param entityName
* the name o the entity to lookup
* @return a rest delegate
*/
public static IERXRestDelegate delegateForEntityNamed(String entityName) {
return IERXRestDelegate.Factory.delegateForClassDescription(ERXRestClassDescriptionFactory.classDescriptionForEntityName(entityName));
}
public static IERXRestDelegate delegateForObject(Object object) {
IERXRestDelegate delegate = null;
if (object instanceof EOEnterpriseObject) {
delegate = IERXRestDelegate.Factory.delegateForClassDescription(((EOEnterpriseObject) object).classDescription());
}
else if (object != null) {
delegate = IERXRestDelegate.Factory.delegateForClassDescription(ERXRestClassDescriptionFactory.classDescriptionForObject(object, false));
}
return delegate;
}
public static IERXRestDelegate delegateForClassDescription(EOClassDescription classDescription) {
String entityName = classDescription.entityName();
IERXRestDelegate delegate = _delegates.objectForKey(entityName);
if (delegate == null) {
Class<?> possibleDelegateClass = _NSUtilities.classWithName(entityName + "RestDelegate");
if (possibleDelegateClass != null) {
try {
delegate = possibleDelegateClass.asSubclass(IERXRestDelegate.class).newInstance();
setDelegateForEntityNamed(delegate, entityName);
}
catch (Throwable t) {
throw new RuntimeException("Failed to create a delegate for the entity '" + entityName + "'.", t);
}
}
}
if (delegate == null) {
try {
if (classDescription instanceof EOEntityClassDescription) {
delegate = IERXRestDelegate.Factory._defaultDelegate;
}
else {
delegate = IERXRestDelegate.Factory._defaultBeanDelegate;
}
setDelegateForEntityNamed(delegate, entityName);
}
catch (Exception e) {
throw new RuntimeException("Failed to create the rest delegate '" + _defaultDelegate + ".", e);
}
}
return delegate;
}
}
}