Package org.persvr.remote

Source Code of org.persvr.remote.JsonReceiver$UpdateInfo

package org.persvr.remote;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import org.mozilla.javascript.CompilerEnvirons;
import org.mozilla.javascript.NativeObject;
import org.mozilla.javascript.Undefined;
import org.persvr.Persevere;
import org.persvr.data.FunctionUtils;
import org.persvr.data.Identification;
import org.persvr.data.ObjectId;
import org.persvr.data.ObjectNotFoundId;
import org.persvr.data.Persistable;
import org.persvr.data.PersistableList;
import org.persvr.data.PersistableObject;
import org.persvr.rpc.RPCall;
import org.persvr.security.PermissionLevel;
import org.persvr.security.SystemPermission;
import org.persvr.security.UserSecurity;
import org.persvr.util.JSON;
import org.persvr.util.JSONParser.JSONException;

public class JsonReceiver {
  static Pattern DATE_MATCHER = Pattern.compile("^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$");
  static SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ");
  protected String path = "";
  private static CompilerEnvirons compilerEnvirons = new CompilerEnvirons();
  public Object parseJsponString(String jsponString) {
    if (jsponString == null || jsponString.length() == 0)
      return Undefined.instance;
    return JSON.parse(jsponString);
    /*
   
    compilerEnvirons.setGeneratingSource(true);
    Parser p = new Parser(compilerEnvirons, compilerEnvirons.getErrorReporter());
        ScriptOrFnNode tree;
        //p.enableFunctionSourceTracking();
        jsponString = "(\"hi\")3";
        tree = p.parse(jsponString, "json", 0);
        String encodedSource = p.getEncodedSource();
        return parseNode(tree.getFirstChild().getFirstChild(),tree,jsponString);*/
   
  }
  /*protected Object parseNode(Node node,ScriptOrFnNode tree, String sourceString) {
    switch (node.getType()) {
      case Token.ARRAYLIT :
        node = node.getFirstChild();
            List list = new ArrayList();
          while(node != null) {
            list.add(parseNode(node,tree,sourceString));
            node = node.getNext();
          }
          return list;
      case Token.OBJECTLIT :
        int i = 0;
        Object[] keys = (Object[]) node.getProp(Node.OBJECT_IDS_PROP);
        node = node.getFirstChild();
            Map map = new HashMap();
          while (node != null) {
              map.put(keys[i++], parseNode(node,tree,sourceString));
              node = node.getNext();
          }
          return map;
      case Token.STRING :
            return node.getString();
      case Token.NUMBER :
            return node.getDouble();
      case Token.TRUE :
            return true;
      case Token.FALSE :
        return false;
      case Token.NULL :
            return null;
      case Token.FUNCTION:
        SourceTrackingFunctionNode funcNode = (SourceTrackingFunctionNode) tree.getFunctionNode(node.getIntProp(Node.FUNCTION_PROP, -1));
        String functionSource = sourceString.substring(funcNode.getSourceStart(),funcNode.getSourceEnd());
            return PersistableImpl.createFunction(functionSource,"new function",UserSecurity.currentUser().hasPermission(SystemPermission.javaScriptCoding));
      default :
        throw new RuntimeException("Unknown node type found in JSON expression " + node.getType());
    }
       
  }*/
  /**
   * Converts a string json representation of a value or object into an object
   * @param jsponString
   * @return
   */
  public Object convertJsonStringToObject(String jsponString) {
    return convertParsedToObject(parseJsponString(jsponString));
  }
  protected Object convertParsedToObject(Object value) {
    if (value instanceof List)
      return listFromJSPONArray((List) value,null);
    if (value instanceof Map)
      return convertIdIfNeeded(idFromJSPONObject((Map) value, null, false));
    if (value instanceof String && DATE_MATCHER.matcher((String)value).matches())
      try {
        value = DataSerializer.ISO_SDF.parse(((String) value));
      } catch (ParseException e) {
        System.err.println("date error: " + e.getMessage());         
      }
    return value;
  }
  protected List listFromJSPONArray(List array, ObjectId targetId) {
    List list = null;
    if (targetId != null) {
      Object target = targetId.getTarget();
      if (target instanceof List) {
        list = (List) target;
        list.clear();
      }
    }
    if (list == null)
      list = Persevere.newArray();
      for (int i = 0; i < array.size();i++) {
        try {
        Object value = array.get(i);
        if (value instanceof Map) {
          value = convertIdIfNeeded(idFromJSPONObject((Map) value, null, false));
        }
        else if (value instanceof List) {
          value = listFromJSPONArray((List)value, null);                 
        }
        list.add(value);
      } catch (JSONException e) {
        throw new RuntimeException(e);
      }
      }
      return list;
  }
  public static final String FUNCTION_CODE_KEY = "function";
  static String functionCompression(String code) {
    //code = code.replaceAll("\\([\\w\\s,]*\\)\\{var njf(\\d+)=_frm\\(this,arguments([,\"\\w+\"]*)\\);nj:while\\(1\\)\\{switch\\(njf(\\d+).cp\\)\\{case 0:", "\u00ea$1$2\u00eb");
    //code = code.replaceAll("njf(\\d+).cp=(\\d+);case (\\d+):if\\(\\(njf(\\d+).rv(\\d+)=", "\u00ea$1,$2\u00ec");
    //code = code.replaceAll("\\)==NJSUS\\)\\{return njf(\\d+)\\(\\);\\}", "\u00ea$1\u00ed");

    code = code.replaceAll("\\([\\w|\\s|,]*\\)\\{with\\(_frm\\(this,arguments,([,\\[\\]\\\"\\w+\"]*)\\)\\)\\{nj:while\\(1\\)\\{switch\\(\\_cp\\)\\{case 0:", "\u00ea$1\u00eb");
    code = code.replaceAll("\\_cp=(\\d+);case (\\d+):if\\(\\(\\_r.v(\\d+)=", "\u00ea$1\u00ec");
    code = code.replaceAll("\\)==NJSUS\\)\\{return \\_S\\(\\);\\}", "\u00ea\u00ed");
    code = code.replaceAll("return;case -1:return _s()\\}\\}\\}\\}", "\u00ea\u00ee");
    //code = code.replaceAll("njf(\\d+)._", "\\xEC\\1");
    return code;
  }
  static interface ListUpdater{
    void update(Object object);
  }
  /*static void doListUpdate(Map updateObject, String command, ListUpdater updater)  {
    if (updateObject.has(command)) {
      List array = (List) updateObject.get(command);
        for (Object value : array) {
          updater.update(value);
        }
    }
   
  }
  protected void updateList(final Persistable listToUpdate,Map updateObject)  {
         doListUpdate(updateObject,"append", new ListUpdater() {
           public void update(Object object) {
             Object obj = convertIdIfNeeded(idOrValueFromJSON(object));
             if (listToUpdate instanceof List)
               ((List) listToUpdate).add(obj);
             else {
               Context cx = PersevereContextFactory.getContext();
                   int length = ScriptRuntime.toInt32(ScriptRuntime.getObjectProp(listToUpdate, "length", cx));
                   ScriptRuntime.setObjectIndex(listToUpdate, length, obj, cx);
                   ScriptRuntime.setObjectProp(listToUpdate, "length", ScriptRuntime.wrapNumber(length+1), cx);
             }
           }
         });
         doListUpdate(updateObject,"delete", new ListUpdater() {
           public void update(Object object) {
             Object obj = convertIdIfNeeded(idOrValueFromJSON(object));
             if (listToUpdate instanceof List)
               ((List) listToUpdate).remove(obj);
             else {
               int length = ScriptRuntime.toInt32(ScriptRuntime.getObjectProp(listToUpdate, "length", PersevereContextFactory.getContext()));
               for (int i = 0; i < length; i++)
                 if (listToUpdate.get(i,listToUpdate) == obj) {
                   NativeArray.splice(listToUpdate,new Object[]{i,1});
                   break;
                 }
             }
           }
         });
         doListUpdate(updateObject,"replace", new ListUpdater() {
           public void update(Object object) {
             Object old = idOrValueFromJSON(((Map)object).get("old"));
             Object newObj = idOrValueFromJSON(((Map)object).get("new"));
             if (listToUpdate instanceof List) {
               int index = ((List)listToUpdate).indexOf(old);
               ((List)listToUpdate).set(index,newObj);
             }
             else {
               int length = ScriptRuntime.toInt32(ScriptRuntime.getObjectProp(listToUpdate, "length", PersevereContextFactory.getContext()));
               for (int i = 0; i < length; i++)
                 if (listToUpdate.get(i,listToUpdate) == old)
                   NativeArray.splice(listToUpdate,new Object[]{i,1,newObj});
                
             }
              
           }
         });
         doListUpdate(updateObject,"splice", new ListUpdater() {
           public void update(Object obj) {
             Map object = (Map) obj;
             List values = null;
             if (object.containsKey("values"))
               values = (List) object.get("values");
             Object args[] = new Object[values == null ? 2 : values.size() + 2];
             args[0] = object.get("index");
             args[1] = object.get("howMany");
             if (values != null)
               for (int i =0; i < values.size(); i++)
                 args[i+2]=convertIdIfNeeded(idOrValueFromJSON(values.get(i)));
             NativeArray.splice(listToUpdate,args);
           }
         });
  }*/
  protected Persistable createInitialObject(Map object) throws JSONException{
    return Persevere.newObject();
  }
  protected void replaceList(final PersistableList listToUpdate, List changes) throws JSONException{
      int i = 0;
      boolean rebuild = false;
      for (; i < changes.size();i++) {
        Object change = changes.get(i);
        if (listToUpdate.size() > i) { // make sure we are still matching
        if  (!listToUpdate.get(i).equals(change)) {
          rebuild = true;
          break;
        }
      }
      else
        listToUpdate.add(change);
    }
    if (listToUpdate.size() != i)
      rebuild = true;
    System.err.println("rebuild: " + rebuild);
    if (rebuild) {
      listToUpdate.clear();
        for (i = 0; i < changes.size();i++) {
          Object change = changes.get(i);
        listToUpdate.add(change);
        }
    }
  }
  public static class UpdateInfo extends NativeObject {
    Map updateObject;
    public UpdateInfo() {
    }
    public UpdateInfo(Map updateObject) {
      this.updateObject = updateObject;
    }
  }
  static protected Object NOT_READY_FIELD = new Object();
  protected Object idOrValueFromJSON(Object value, ObjectId defaultId) throws JSONException{
    if (value instanceof Map) {
      return idFromJSPONObject((Map) value, defaultId, false);
    }
    else if (value instanceof List) {
      return listFromJSPONArray((List)value, defaultId);
    }
    else if (value instanceof String) {
      if (DATE_MATCHER.matcher((String)value).matches())
        try {
          return SDF.parse(((String) value).replace('T', ' ').replace('Z', ' ') + "-0000");
        } catch (ParseException e) {
          System.err.println("date error: " + e.getMessage());         
        }
    }
    else if (value instanceof JSONFunction) {
      boolean authorizedForFullScripting = UserSecurity.hasPermission(SystemPermission.javaScriptCoding);
      if (!authorizedForFullScripting)
        throw new RuntimeException("You do not have sufficient priviledge to create functions, and untrusted scripts are not implementd yet");

      return FunctionUtils.createFunction(((JSONFunction)value).toString(),"new function");     
    }
    return value;
  }
  static Object convertIdIfNeeded(Object value) {
    if (value instanceof Identification)
      return ((Identification<? extends Object>)value).getTarget();
    return value;
  }
  public void handleRPC(Object targetObject,  Map rpcObject) {
    Persistable target = (targetObject instanceof ObjectId) ? ((ObjectId)targetObject).getTarget() : (Persistable)targetObject;
    List params = (List) rpcObject.get("params");
    Object[] paramValues;
    if (params == null) {
      paramValues = new Object[0];
    }
    else {
      paramValues = new Object[params.size()];
          for (int j =0; j < params.size(); j++) {
            paramValues[j] = convertIdIfNeeded(idOrValueFromJSON(params.get(j),null));
          }
    }                     
    String method = (String)rpcObject.get("method");
    RPCall rpCall = new RPCall(target,method,paramValues,rpcObject.get("id"));
    rpCall.executeLocally(); // responses will be added the current connection

  }
  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();
  }
  public String getPath() {
    return path;
  }
  public void setPath(String path) {
    this.path = path;
  }
 
 
 
}
TOP

Related Classes of org.persvr.remote.JsonReceiver$UpdateInfo

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.