package er.rest.example.client; import java.io.IOException; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.HttpMethodBase; import org.apache.commons.httpclient.methods.DeleteMethod; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.PutMethod; import org.apache.commons.httpclient.methods.StringRequestEntity; import com.webobjects.eocontrol.EOClassDescription; import er.extensions.eof.ERXKeyFilter; import er.extensions.foundation.ERXMutableURL; import er.rest.ERXRestClassDescriptionFactory; import er.rest.ERXRestContext; import er.rest.ERXRestRequestNode; import er.rest.format.ERXRestFormat; import er.rest.format.ERXStringBufferRestResponse; import er.rest.format.ERXStringRestRequest; public class ERXRestClient { private String _baseURL; private ERXRestContext _context; private boolean _classDescriptionRequired; private HttpClient _httpClient = null; public ERXRestClient(String baseURL, ERXRestContext context, boolean classDescriptionRequired) { _baseURL = baseURL; _context = context; setClassDescriptionRequired(classDescriptionRequired); } public ERXRestClient(String baseURL, ERXRestContext context) { this(baseURL, context, true); } public void setBaseURL(String baseURL) { _baseURL = baseURL; } public String baseURL() { return _baseURL; } public void setContext(ERXRestContext context) { _context = context; } public ERXRestContext context() { return _context; } public void setClassDescriptionRequired(boolean classDescriptionRequired) { _classDescriptionRequired = classDescriptionRequired; } public boolean isClassDescriptionRequired() { return _classDescriptionRequired; } /* Extract the requestNode from the given method. The method will be asked for it's Content-Type header to determine the format. * This is known to fail if the method doesn't have a Content-Type header. */ protected ERXRestRequestNode requestNodeWithMethod(HttpMethodBase method) throws IOException { ERXRestFormat format = ERXRestFormat.formatNamed(method.getResponseHeader("Content-Type").getValue()); return requestNodeWithMethod(method, format); } /* Extract the requestNode from the given method using the given format. */ protected ERXRestRequestNode requestNodeWithMethod(HttpMethodBase method, ERXRestFormat format) throws IOException { ERXRestRequestNode responseNode = format.parser().parseRestRequest(new ERXStringRestRequest(method.getResponseBodyAsString()), format.delegate(), _context); return responseNode; } protected Object _objectWithRequestNode(ERXRestRequestNode node, String entityName) { Object obj; EOClassDescription classDescription = ERXRestClassDescriptionFactory.classDescriptionForEntityName(entityName); if (entityName != null && classDescription == null && !_classDescriptionRequired) { obj = node; } else { obj = node.objectWithFilter(entityName, ERXKeyFilter.filterWithAllRecursive(), _context); } return obj; } @SuppressWarnings("unchecked") public <T> T objectWithRequestNode(ERXRestRequestNode node) { return (T) _objectWithRequestNode(node, null); } @SuppressWarnings("unchecked") public <T> T objectWithRequestNode(ERXRestRequestNode node, String entityName) { return (T) _objectWithRequestNode(node, entityName); } protected String path(String entityName, String id, String action, ERXRestFormat format) { StringBuffer sb = new StringBuffer(); sb.append(entityName); if (id != null) { sb.append("/"); sb.append(id); } if (action != null) { sb.append("/"); sb.append(action); } if (format != null) { sb.append("."); sb.append(format.name()); } return sb.toString(); } @SuppressWarnings("unchecked") public <T> T object(String entityName, String id, String action, ERXRestFormat format) throws HttpException, IOException { return (T) objectWithPath(path(entityName, id, action, format)); } /* Returns the instance of HttpClient that's used for communcation with the server. * Handy if you want direct access to the object which manages communication. * For example, HttpClient will collect cookies and send them on subsequent requests for you. */ public HttpClient httpClient() { if(_httpClient == null){ _httpClient = new HttpClient(); } return _httpClient; } @SuppressWarnings("unchecked") public <T> T objectWithPath(String path, String entityName) throws HttpException, IOException { HttpClient client = httpClient(); GetMethod fetchObjectMethod = new GetMethod(new ERXMutableURL(_baseURL).appendPath(path).toExternalForm()); client.executeMethod(fetchObjectMethod); ERXRestRequestNode node = requestNodeWithMethod(fetchObjectMethod); return (T) _objectWithRequestNode(node, entityName); } @SuppressWarnings("unchecked") public <T> T objectWithPath(String path) throws HttpException, IOException { HttpClient client = httpClient(); GetMethod fetchObjectMethod = new GetMethod(new ERXMutableURL(_baseURL).appendPath(path).toExternalForm()); client.executeMethod(fetchObjectMethod); ERXRestRequestNode node = requestNodeWithMethod(fetchObjectMethod); String type = node.type(); return (T) _objectWithRequestNode(node, type); } public ERXRestRequestNode update(Object obj, ERXKeyFilter filter, String entityName, String id, String action, ERXRestFormat format) throws HttpException, IOException { return updateObjectWithPath(obj, filter, path(entityName, id, action, format), format); } public ERXRestRequestNode updateObjectWithPath(Object obj, ERXKeyFilter filter, String path, ERXRestFormat format) throws HttpException, IOException { ERXRestRequestNode node = ERXRestRequestNode.requestNodeWithObjectAndFilter(obj, filter, _context); ERXStringBufferRestResponse response = new ERXStringBufferRestResponse(); format.writer().appendToResponse(node, response, format.delegate(), _context); HttpClient client = httpClient(); PutMethod updateObjectMethod = new PutMethod(new ERXMutableURL(_baseURL).appendPath(path).toExternalForm()); updateObjectMethod.setRequestEntity(new StringRequestEntity(response.toString())); client.executeMethod(updateObjectMethod); return requestNodeWithMethod(updateObjectMethod); } public ERXRestRequestNode create(Object obj, ERXKeyFilter filter, String entityName, String id, String action, ERXRestFormat format) throws HttpException, IOException { return createObjectWithPath(obj, filter, path(entityName, id, action, format), format); } public ERXRestRequestNode createObjectWithPath(Object obj, ERXKeyFilter filter, String path, ERXRestFormat format) throws HttpException, IOException { ERXRestRequestNode node = ERXRestRequestNode.requestNodeWithObjectAndFilter(obj, filter, _context); ERXStringBufferRestResponse response = new ERXStringBufferRestResponse(); format.writer().appendToResponse(node, response, format.delegate(), _context); HttpClient client = httpClient(); PostMethod updateObjectMethod = new PostMethod(new ERXMutableURL(_baseURL).appendPath(path).toExternalForm()); updateObjectMethod.setRequestEntity(new StringRequestEntity(response.toString())); client.executeMethod(updateObjectMethod); return requestNodeWithMethod(updateObjectMethod, format); } public ERXRestRequestNode delete(Object obj, String entityName, String id, String action, ERXRestFormat format) throws HttpException, IOException { return deleteObjectWithPath(obj, path(entityName, id, action, format), format); } public ERXRestRequestNode deleteObjectWithPath(Object obj, String path, ERXRestFormat format) throws HttpException, IOException { ERXRestRequestNode node = ERXRestRequestNode.requestNodeWithObjectAndFilter(obj, ERXKeyFilter.filterWithNone(), _context); HttpClient client = httpClient(); DeleteMethod deleteObjectMethod = new DeleteMethod(new ERXMutableURL(_baseURL).appendPath(path).toExternalForm()); client.executeMethod(deleteObjectMethod); return requestNodeWithMethod(deleteObjectMethod); } }