}
public Identification<? extends Object> idFromJSPONObject(Map<String,Object> object, ObjectId targetId, boolean mustMatchId) {
//TODO: This needs be rearranged so that when you do a put (specifically an alteration), that we use the object
// returned by the put instead of what the id indicates, because it is possible for a aliasId to indicate that we
// should use a new object, when really we should use an existing object (from the childMods list)
Persistable target;
try {
String key;
target = null;
Date changesSince=null;
if (object.containsKey("update") && ((Map) object.get("update")).containsKey("changesSince")) {
String value = (String) ((Map) object.get("update")).get("changesSince");
changesSince = new Date(Long.parseLong(value.substring(1,value.length()-1))); // handle dates
}
if (object.containsKey("$ref")) {
return Identification.idForRelativeString(path, (String) object.get("$ref"));
}
if (object.containsKey("id")) {
Identification currentId = Identification.idForRelativeString(path, object.remove("id").toString());
if (currentId.source instanceof ClientData) // TODO: Surely we can do this more consistently
target = Client.getCurrentObjectResponse().getConnection().clientSideObject(currentId.toString(),createInitialObject(object));
else {
if (currentId instanceof ObjectId){
if(mustMatchId){
if(targetId != currentId){
throw new RuntimeException("id does not match location");
}
}
else {
targetId = (ObjectId) currentId;
}
}
else {
target = (Persistable) currentId.getTarget();
if(mustMatchId && target.getId() != targetId){
throw new RuntimeException("id does not match location");
}
}
}
}
if (targetId == null) {
if (target == null)
target = createInitialObject(object);
}
else {
target= targetId.getOrCreateTarget();
}
PersistableObject.checkSecurity(target, PermissionLevel.WRITE_LEVEL.level);
for (Map.Entry<String,Object> oldEntry : target.entrySet(0)) {
String oldKey = oldEntry.getKey();
if (!object.containsKey(oldKey) && !oldKey.equals("parent"))
target.delete(oldKey);
}
for (Map.Entry<String,Object> entry : object.entrySet()) {
key = entry.getKey(); // TODO: This needs to be limited to alteration lists, so we don't get a conflict with fields that start with c$. This may need to be identified on the client side
Object value = entry.getValue();
if (key.startsWith("client/")) // This is a client id alteration which needs be changed a
{
key = Client.getCurrentObjectResponse().getConnection().clientSideObject(key,object.containsKey("array") ?
Persevere.newArray() : Persevere.newObject()).getId().toString();
}
/*String valueModOriginal = null;
if (GlobalData.CHILDMODS_FIELD.equals(key))
valueModOriginal = GlobalData.CHILDMODS_FIELD;
if (target!=null && (GlobalData.CHILDMODS_FIELD.equals(childModOriginalId) || target.isChildMods()) && !GlobalData.PARENT_FIELD.equals(key))
valueModOriginal = key;*/
/* if ("update".equals(key)) {
if ("delete".equals(value))
return getErasureEntity();
if (value instanceof Map)
updateList(target,(Map) value);
}
else {*/
Object oldValue = target.get(key);
value = idOrValueFromJSON(value, oldValue instanceof Persistable ? ((Persistable)oldValue).getId() : null);
if (value instanceof ObjectNotFoundId)
throw new RuntimeException("Can not set value to an undefined id");
if (key.equals(FUNCTION_CODE_KEY)) {
value = functionCompression((String) value);
}
if (target != null) {
value = convertIdIfNeeded(value);
if (!(oldValue == null ? value == null : oldValue.equals(value))){
PersistableObject.checkSecurity(target, PermissionLevel.WRITE_LEVEL.level);
target.set(key,value);
}
}
//}
}
} catch (JSONException e) {
throw new RuntimeException(e);
}
/* if (parentValue != null) // we will do it at the end so that if it is an append list entry it can be done without security problems
target.set(GlobalData.PARENT_FIELD, parentValue);*/
return target.getId();
}