}
}
Persevere.createNewTable(path, "Object");
return null;
}
Persistable datedTarget = null;
if ("POST".equals(method)) // This is a hack to get POSTs to work on slice operator
path = path.replaceAll("\\[.*\\:.*\\]", "");
target = Client.getCurrentObjectResponse().requestData(path, "PUT".equals(method));
if (targetId instanceof ObjectPath) {
datedTarget = ((ObjectPath) targetId).getSecondToLastTarget();
} else if (target instanceof Persistable)
datedTarget = (Persistable) target;
String subscribe = getParameter(request, "Subscribe");
if (subscribe == null)
subscribe = getParameterFromQueryString(request, "subscribe");
// handle subscription requests
if (null != subscribe) {
final Identification<? extends Object> id = Identification.idForString(path);
if (datedTarget != null) {
if (target instanceof ObservablePersistable)
((ObservablePersistable) target).subscribe();
// TODO: Only do this if the range references "now"
request.setAttribute("org.persvr.servletNow", new Date());
Map<String, String> headers = new HashMap<String, String>();
Enumeration headerEnum = request.getHeaderNames();
while (headerEnum.hasMoreElements()) {
String headerName = (String) headerEnum.nextElement();
String value = request.getHeader(headerName);
headerName = headerName.toLowerCase();
if ("opera-range".equals(headerName))
headerName = "range";
headers.put(headerName, value);
}
headers.put("__now__", new Date().getTime() + "");
headers.put("__pathInfo__", path);
if (connectionId == null) {
} else {
if ("none".equals(subscribe)) {// far future, unsubscribe
requestHelper.connection.removeSubscription(headers);
} else if ("*".equals(subscribe)) {
requestHelper.connection.addSubscription(headers);
PersistableObject.addListener(requestHelper.connection);
}
}
setHeader("Subscribed", "OK", headerTarget);
}
}
byte[] postBytes = null;
String embeddedContent = null;
if ("application/x-www-form-urlencoded".equals(request.getContentType())) {
// if it was POSTed from cross-domain, it may specify it's content in the http-content parameter in the entity
if (postBytes == null)
postBytes = IOUtils.toByteArray(request.getInputStream());
String postBody = new String(postBytes, "UTF-8");
embeddedContent = getParameterFromUrlEncoded(postBody, "http-content");
if (embeddedContent == null)
embeddedContent = getParameterFromQueryString(request, "http_content");
if (embeddedContent != null)
request.setAttribute("cross-site", true);
} else if (!"GET".equals(method)) {
// if it was a GET (that specifies a method beside GET with http-method) from cross-domain,
// it may specify it's content in the http-content parameter in the URL
embeddedContent = getParameterFromQueryString(request, "http-content");
if (embeddedContent == null)
embeddedContent = getParameterFromQueryString(request, "http_content");
if (embeddedContent != null)
request.setAttribute("cross-site", true);
}
if (embeddedContent != null) {
postBytes = embeddedContent.getBytes("UTF-8");
}
// Restart here
String precondition = getParameter(request, "If");
//TODO: Handle relative expressions
if (precondition != null && !ScriptRuntime.toBoolean(Identification.idForString(precondition).getTarget()))
throw new ConditionFailedException("Condition " + precondition + " was not satisfied");
contentType = contentType == null ? null : contentType.split(";")[0];
if ("POST".equals(method)) {
Object postObject = null;
boolean isJson = false;
boolean safeContentType = false;
if (couldBeJson(contentType)) {
try {
// this means that the content may be JSON, we are forgiving if URL encoding is used as it is
// the default for Ajax requests
if (postBytes == null)
postBytes = IOUtils.toByteArray(request.getInputStream());
String postBody = new String(postBytes, "UTF-8");
postObject = requestHelper.parseJsponString(postBody); // TODO: Shouldn't do this twice
// If it parsed we can be assured that it wasn't cross-site browser generated
requestHelper.authorizeCookieAuthentication();
// detect JSON-RPC calls
if (postObject instanceof Map && ((Map) postObject).containsKey("id")
&& ((Map) postObject).containsKey("method") && ((Map) postObject).containsKey("params")
&& ((Map) postObject).get("params") instanceof List) {
// It looks like a JSON-RPC request, treat it as a method call
requestHelper.handleRPC(target, (Map) postObject);
// we set the username again because it may have changed during the RPC
username = UserSecurity.getUserName(UserSecurity.currentUser());
// we set the username so the client side can access it
setHeader("Username", "public".equals(username) ? null : username, headerTarget);
// write out the response (this could actually be a request from the server)
Client.getCurrentObjectResponse().writeWaitingRPCs();
return null;
}
Object bodyData = requestHelper.convertParsedToObject(postObject);
String newLocation = request.getHeader("Content-ID");
// this indicates that the request has a client-assigned id to use temporarily
if (newLocation != null) {
// get rid of the brackets and the contextPath
newLocation = newLocation.substring(request.getContextPath().length() + 2, newLocation.length() - 1);
Client client = Client.getCurrentObjectResponse().getConnection();
Persistable createdObject = client.getClientSideObject(newLocation);
if (createdObject == null)
client.clientSideObject(newLocation, createdObject = Persevere.newObject(((Persistable) target)
.getId()));
target = createdObject;
for (Map.Entry<String, Object> entry : ((Persistable) bodyData).entrySet(0)) {
createdObject.set(entry.getKey(), entry.getValue());
}
} else {
target = postObject((Persistable) target, bodyData);
}
newContent = true;
isJson = true;
} catch (JSONParser.JSONException e) {
// if the content type explicity said it was JSON or JavaScript we will throw an error
if (contentType == null || contentType.indexOf("json") > 0 || contentType.indexOf("javascript") > 0) {
throw e;
}
}
} else
safeContentType = true;
if (!isJson) {
// it wasn't JSON (couldn't be parsed) and so we treat it as a file
if (ServletFileUpload.isMultipartContent(request)) {
if(target instanceof List){
target = Persevere.newObject(((Persistable) target).getId());
}
// Create a factory for disk-based file items
FileItemFactory factory = new DiskFileItemFactory();
// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload(factory);
// Parse the request
List<FileItem> items = upload.parseRequest(request);
for (FileItem item : items) {
if (item.isFormField()) {
((Persistable) target).set(item.getFieldName(), item.getString());
} else {
Persistable fileTarget = createFile(item.getContentType(), null, item.getInputStream());
fileTarget.set("name", item.getName());
if (!(target instanceof List)) {
((Persistable) target).set(item.getFieldName(), fileTarget);
}
}
}
} else {
if (safeContentType)
requestHelper.authorizeCookieAuthentication();
DataSource source = ((Persistable) target).getId().source;
String contentDisposition = request.getHeader("Content-Disposition");
if (postBytes == null)
postBytes = IOUtils.toByteArray(request.getInputStream());
// create a File using the provided file/binary data
Persistable fileTarget = createFile(contentType, contentDisposition, postBytes);
if (!(source instanceof DynaFileDBSource)) {
Persistable resourceTarget = Persevere.newObject(((Persistable) target).getId());
resourceTarget.put("representation:" + contentType, resourceTarget, fileTarget);
((PersistableObject) resourceTarget).setAttributes("representation:" + contentType,
ScriptableObject.DONTENUM);
}
target = fileTarget;
newContent = true;
force204 = true;
}
}
response.setStatus(201);
} else if ("PUT".equals(method)) {
boolean isJson = false;
Identification<? extends Object> id = Identification.idForString(path);
try {
if (couldBeJson(contentType)) {
if (postBytes == null)
postBytes = IOUtils.toByteArray(request.getInputStream());
String postBody = new String(postBytes, "UTF-8");
if (id instanceof ObjectPath) {
Object value = id.getTarget();
if (value instanceof Persistable) {
id = ((Persistable) value).getId();
}
}
target = requestHelper.convertWithKnownId(postBody, id);
isJson = true;
}
} catch (JSONParser.JSONException e) {
if (contentType == null || contentType.indexOf("json") > 0 || contentType.indexOf("javascript") > 0) {
throw e;
}
}
if (!isJson) {
// create an alternate representation for the target object using the provided file/binary data
DataSource source = target instanceof Persistable ? ((Persistable) target).getId().source : null;
String contentDisposition = request.getHeader("Content-Disposition");
if (postBytes == null)
postBytes = IOUtils.toByteArray(request.getInputStream());
Persistable fileTarget = createFile(contentType, contentDisposition, postBytes);
if (!(source instanceof DynaFileDBSource) && !(id instanceof ObjectPath)) {
if (target instanceof Persistable) {
((Persistable) target).set("representation:" + contentType, fileTarget);
((PersistableObject) target).setAttributes("representation:" + contentType, ScriptableObject.DONTENUM);
}
}
newContent = true;
force204 = true;
target = fileTarget;
}
if (id instanceof ObjectPath) {
// if it is a path we set the value of the property
Object key = ((ObjectPath) id).getLastPath();
Persistable secondToLastTarget = (Persistable) ((ObjectPath) id).getSecondToLastTarget();
if (key instanceof Integer)
secondToLastTarget.put((Integer) key, secondToLastTarget, target);
else {
secondToLastTarget.set((String) key, target);
}
} else if (!(target instanceof Persistable))
//TODO: This should be allowed if an ObjectPath is used
throw new RuntimeException("Can not replace an identified object with a primitive value");
if (!isJson) {
target = Undefined.instance;// no need to return the file just uploaded
}
} else if ("DELETE".equals(method)) {
// delete the target object or property
Identification<? extends Object> id = Identification.idForString(path);
if (id instanceof ObjectPath) {
// it is a property
Object key = ((ObjectPath) id).getLastPath();
Persistable secondToLastTarget = (Persistable) ((ObjectPath) id).getSecondToLastTarget();
if (key instanceof Integer)
secondToLastTarget.delete((Integer) key);
else
secondToLastTarget.delete((String) key);
return null;
} else if (id instanceof JsonPath) {
//TODO: Needs to be a way to do delete items from JSONPath queries
for (int i = ((List) target).size(); i > 0;) {
i--;
Persistable item = ((Persistable) ((List) target).get(i));
item.delete();
}
return null;
}
if (target instanceof Persistable) {
((Persistable) target).delete();