/**
   * Call beforeModification/Creation/Deletion methods.
   *
   * @param modificationQueue
   * @param securityContext
   * @param errorBuffer
   * @param doValidation
   * @return valid
   * @throws FrameworkException
   */
  public boolean doValidationAndIndexing(
      ModificationQueue modificationQueue,
      SecurityContext securityContext,
      ErrorBuffer errorBuffer,
      boolean doValidation)
      throws FrameworkException {

    boolean valid = true;

    // examine only the last 4 bits here
    switch (status & 0x000f) {
      case 6: // created, modified => only creation callback will be called
      case 4: // created => creation callback
      case 2: // modified => modification callback
        if (doValidation) {
          valid &= validate(securityContext, errorBuffer);
        }
        object.indexPassiveProperties();
        break;

      case 1: // deleted => deletion callback
        object.removeFromIndex();
        break;

      default:
        break;
    }

    return valid;
  }
示例#2
0
  @Override
  public void processMessage(final WebSocketMessage webSocketData) {

    final GraphObject obj = getGraphObject(webSocketData.getId());
    String key = (String) webSocketData.getNodeData().get("key");

    if (obj != null) {

      PropertyKey propertyKey =
          StructrApp.getConfiguration().getPropertyKeyForJSONName(obj.getClass(), key);
      PropertyConverter converter = propertyKey.inputConverter(getWebSocket().getSecurityContext());

      Object value = obj.getProperty(propertyKey);
      if (converter != null) {

        try {
          value = converter.revert(value);

        } catch (FrameworkException ex) {

          getWebSocket()
              .send(MessageBuilder.status().code(400).message(ex.getMessage()).build(), true);
        }
      }

      webSocketData.setNodeData(key, value);

      // send only over local connection (no broadcast)
      getWebSocket().send(webSocketData, true);

    } else {

      getWebSocket().send(MessageBuilder.status().code(404).build(), true);
    }
  }
  @Override
  public List<GraphObject> getProperty(
      SecurityContext securityContext,
      GraphObject obj,
      boolean applyConverter,
      Predicate<GraphObject> predicate) {

    if (obj instanceof AbstractNode) {

      try {

        final String query =
            Scripting.replaceVariables(new ActionContext(securityContext), obj, this.format);
        final Map<String, Object> parameters = new LinkedHashMap<>();

        parameters.put("id", obj.getUuid());
        parameters.put("type", obj.getType());

        return StructrApp.getInstance(securityContext)
            .command(CypherQueryCommand.class)
            .execute(query, parameters);

      } catch (Throwable t) {
        t.printStackTrace();
      }
    }

    return null;
  }
  /**
   * Call validators. This must be synchronized globally
   *
   * @param securityContext
   * @param errorBuffer
   * @return valid
   */
  private boolean validate(SecurityContext securityContext, ErrorBuffer errorBuffer) {

    boolean valid = true;

    for (PropertyKey key : removedProperties.keySet()) {

      List<PropertyValidator> validators = key.getValidators();
      for (PropertyValidator validator : validators) {

        Object value = object.getProperty(key);

        valid &= validator.isValid(securityContext, object, key, value, errorBuffer);
      }
    }

    // explicitly call isValid()
    return valid && object.isValid(errorBuffer);
  }
示例#5
0
  public Object transformOutput(final ActionContext actionContext, final GraphObject source)
      throws FrameworkException {

    if (outputFunction == null) {
      return source.getProperty(sourceProperty);
    }

    // output transformation requested
    actionContext.setConstant("input", source);
    return Scripting.evaluate(actionContext, null, "${" + outputFunction + "}");
  }
示例#6
0
  @Override
  public boolean isValid(GraphObject object, String key, T value, ErrorBuffer errorBuffer) {

    if (value == null) {

      errorBuffer.add(object.getType(), new EmptyPropertyToken(key));

    } else {

      if (values.contains(value)) {

        return true;

      } else {

        errorBuffer.add(object.getType(), new ValueToken(key, values.toArray()));
      }
    }

    return false;
  }
  public void delete(boolean passive) {

    int statusBefore = status;

    if (passive) {
      status |= STATE_DELETED_PASSIVELY;
    }

    status |= STATE_DELETED;

    if (status != statusBefore) {

      // copy all properties on deletion
      for (final PropertyKey key : object.getPropertyKeys(PropertyView.Public)) {
        removedProperties.put(key, object.getProperty(key));
      }

      modified = true;
    }

    updateCache();
  }
  @Override
  public boolean isValid(
      GraphObject object, PropertyKey<String> key, String value, ErrorBuffer errorBuffer) {

    if (key == null) {
      return false;
    }

    if (StringUtils.isBlank(value)) {
      errorBuffer.add(object.getType(), new EmptyPropertyToken(key));
      return false;
    }

    // FIXME: search should be case-sensitive!

    List<SearchAttribute> attrs = new LinkedList<SearchAttribute>();
    attrs.add(Search.andExactName(value));
    attrs.add(Search.andType(type));

    // just check for existance
    try {
      Result nodes = Services.command(securityContext, SearchNodeCommand.class).execute(attrs);
      if (nodes != null && !nodes.isEmpty()) {

        return true;

      } else {

        errorBuffer.add(object.getType(), new PropertyNotFoundToken(key, value));
        return false;
      }

    } catch (FrameworkException fex) {
      // handle error
    }

    return false;
  }
  @Override
  public List<GraphObject> doGet(List<VetoableGraphObjectListener> listeners) throws PathException {

    List<? extends GraphObject> results = relationshipConstraint.doGet(listeners);
    long desiredId = idConstraint.getId();
    GraphObject desiredObject = null;

    for (GraphObject obj : results) {
      if (obj.getId() == desiredId) {
        desiredObject = obj;
        break;
      }
    }

    // if object was found, return it
    if (desiredObject != null) {
      List<GraphObject> resultList = new LinkedList<GraphObject>();
      resultList.add(desiredObject);

      return resultList;
    }

    throw new NotFoundException();
  }
  @Override
  public T getProperty(
      final SecurityContext securityContext,
      final GraphObject obj,
      final boolean applyConverter,
      final Predicate<GraphObject> predicate) {

    Object value = null;

    final PropertyContainer propertyContainer = obj.getPropertyContainer();
    if (propertyContainer != null) {

      // this may throw a java.lang.IllegalStateException: Relationship[<id>] has been deleted in
      // this tx
      if (propertyContainer.hasProperty(dbName())) {

        value = propertyContainer.getProperty(dbName());
      }
    }

    if (applyConverter) {

      // apply property converters
      PropertyConverter converter = databaseConverter(securityContext, obj);
      if (converter != null) {

        try {
          value = converter.revert(value);

        } catch (Throwable t) {

          logger.warn(
              "Unable to convert property {} of type {}: {}",
              new Object[] {dbName(), getClass().getSimpleName(), t});
          logger.warn("", t);
        }
      }
    }

    // no value found, use schema default
    if (value == null) {
      value = defaultValue();
    }

    return (T) value;
  }
  public GraphObjectModificationState(GraphObject object) {

    this.object = object;
    this.isNode = (object instanceof NodeInterface);

    if (!isNode) {
      this.relType = ((RelationshipInterface) object).getRelType();
    }

    // store uuid for later use
    this.uuid = object.getUuid();

    if (changeLogEnabled) {

      // create on demand
      changeLog = new StringBuilder();
    }
  }
 @Override
 public Map<String, Object> getData(final SecurityContext securityContext)
     throws FrameworkException {
   return PropertyMap.javaTypeToInputType(securityContext, object.getClass(), modifiedProperties);
 }
示例#13
0
  @Override
  public int compare(GraphObject n1, GraphObject n2) {

    if (n1 == null || n2 == null) {
      logger.log(Level.WARNING, "Cannot compare null objects!");
      return -1;

      // FIXME: this should throw a NPE!
    }

    try {

      Comparable c1 = n1.getComparableProperty(sortKey);
      Comparable c2 = n2.getComparableProperty(sortKey);

      if (c1 == null || c2 == null) {

        try {
          logger.log(
              Level.WARNING,
              "Cannot compare {0} of type {1} to {2} of type {3}, sort key {4} not found.",
              new Object[] {
                n1.getProperty(AbstractNode.uuid),
                n1.getProperty(AbstractNode.type),
                n2.getProperty(AbstractNode.uuid),
                n2.getProperty(AbstractNode.type),
                sortKey
              });

        } catch (Throwable t) {
          logger.log(Level.SEVERE, "Error in comparator", t);
        }

        return -1;
      }

      if (DESCENDING.equalsIgnoreCase(sortOrder)) {

        return (c2.compareTo(c1));

      } else {

        return (c1.compareTo(c2));
      }

    } catch (Throwable t) {

      t.printStackTrace();

      logger.log(
          Level.WARNING,
          "Cannot compare properties {0} of type {1} to {2} of type {3}, property {4} error.",
          new Object[] {
            n1.getProperty(AbstractNode.uuid),
            n1.getProperty(AbstractNode.type),
            n2.getProperty(AbstractNode.uuid),
            n2.getProperty(AbstractNode.type),
            sortKey
          });
    }

    return 0;
  }
 @Override
 public String toString() {
   return object.getClass().getSimpleName() + "(" + object + "); " + status;
 }
  /**
   * Call beforeModification/Creation/Deletion methods.
   *
   * @param modificationQueue
   * @param securityContext
   * @param errorBuffer
   * @return valid
   * @throws FrameworkException
   */
  public boolean doInnerCallback(
      ModificationQueue modificationQueue, SecurityContext securityContext, ErrorBuffer errorBuffer)
      throws FrameworkException {

    boolean valid = true;

    // check for modification propagation along the relationships
    if ((status & STATE_PROPAGATING_MODIFICATION) == STATE_PROPAGATING_MODIFICATION
        && object instanceof AbstractNode) {

      Set<AbstractNode> nodes = ((AbstractNode) object).getNodesForModificationPropagation();
      if (nodes != null) {

        for (AbstractNode node : nodes) {

          modificationQueue.propagatedModification(node);
        }
      }
    }

    // examine only the last 4 bits here
    switch (status & 0x000f) {
      case 15:
      case 14:
      case 13:
      case 12:
      case 11:
      case 10:
      case 9:
      case 8: // since all values >= 8 mean that the object was passively deleted, no action has to
        // be taken
        // (no callback for passive deletion!)
        break;

      case 7: // created, modified, deleted, poor guy => no callback
        break;

      case 6: // created, modified => only creation callback will be called
        valid &= object.onCreation(securityContext, errorBuffer);
        break;

      case 5: // created, deleted => no callback
        break;

      case 4: // created => creation callback
        valid &= object.onCreation(securityContext, errorBuffer);
        break;

      case 3: // modified, deleted => deletion callback
        valid &= object.onDeletion(securityContext, errorBuffer, removedProperties);
        break;

      case 2: // modified => modification callback
        valid &= object.onModification(securityContext, errorBuffer);
        break;

      case 1: // deleted => deletion callback
        valid &= object.onDeletion(securityContext, errorBuffer, removedProperties);
        break;

      case 0: // no action, no callback
        break;

      default:
        break;
    }

    // mark as finished
    modified = false;

    return valid;
  }
示例#16
0
  public Object evaluate(
      final GraphObject entity,
      final String key,
      final Object data,
      final String defaultValue,
      final int depth)
      throws FrameworkException {

    Object value = constants.get(key);
    if (value == null) {

      // special HttpServletRequest handling
      if (data instanceof HttpServletRequest) {
        value = ((HttpServletRequest) data).getParameter(key);
      }

      // special handling of maps..
      if (data instanceof Map) {
        value = ((Map) data).get(key);
      }

      if (data != null) {

        if (data instanceof GraphObject) {

          value = ((GraphObject) data).evaluate(securityContext, key, defaultValue);

        } else {

          switch (key) {
            case "size":
              if (data instanceof Collection) {
                return ((Collection) data).size();
              }
              if (data.getClass().isArray()) {
                return ((Object[]) data).length;
              }
              break;
          }
        }

      } else {

        // "data-less" keywords to start the evaluation chain
        switch (key) {
          case "request":
            return securityContext.getRequest();

          case "host":
            return securityContext.getRequest().getServerName();

          case "port":
            return securityContext.getRequest().getServerPort();

          case "pathInfo":
          case "path_info":
            return securityContext.getRequest().getPathInfo();

          case "parameterMap":
          case "parameter_map":
            return securityContext.getRequest().getParameterMap();

          case "remoteAddress":
          case "remote_address":
            final String remoteAddress = securityContext.getRequest().getHeader("X-FORWARDED-FOR");
            if (remoteAddress == null) {
              return securityContext.getRequest().getRemoteAddr();
            }
            return remoteAddress;

          case "response":
            if (securityContext != null) {
              final HttpServletResponse response = securityContext.getResponse();
              if (response != null) {

                try {
                  // return output stream of HTTP response for streaming
                  return response.getOutputStream();

                } catch (IOException ioex) {
                  logger.warn("", ioex);
                }
              }
            }
            return null;

          case "now":
            return DatePropertyParser.format(new Date(), DateProperty.DEFAULT_FORMAT);

          case "me":
            return securityContext.getUser(false);

          case "element":
            logger.warn(
                "The \"element\" keyword is deprecated! Please use \"this\" instead. Used in {}",
                entity.getProperty(GraphObject.id));

          case "this":
            return entity;

          case "locale":
            return locale != null ? locale.toString() : null;
        }
      }
    }

    if (value == null && defaultValue != null) {
      return Function.numberOrString(defaultValue);
    }

    return value;
  }
  @Override
  public Object setProperty(
      final SecurityContext securityContext, final GraphObject obj, final T value)
      throws FrameworkException {

    final PropertyConverter converter = databaseConverter(securityContext, obj);
    final Object convertedValue;

    if (converter != null) {

      convertedValue = converter.convert(value);

    } else {

      convertedValue = value;
    }

    final PropertyContainer propertyContainer = obj.getPropertyContainer();
    if (propertyContainer != null) {

      if (!TransactionCommand.inTransaction()) {

        throw new NotInTransactionException("setProperty outside of transaction");
      }

      boolean internalSystemPropertiesUnlocked = (obj instanceof CreationContainer);

      // notify only non-system properties

      // collect modified properties
      if (obj instanceof AbstractNode) {

        if (!unvalidated) {

          TransactionCommand.nodeModified(
              securityContext.getCachedUser(),
              (AbstractNode) obj,
              AbstractPrimitiveProperty.this,
              propertyContainer.hasProperty(dbName())
                  ? propertyContainer.getProperty(dbName())
                  : null,
              value);
        }

        internalSystemPropertiesUnlocked = ((AbstractNode) obj).internalSystemPropertiesUnlocked;

      } else if (obj instanceof AbstractRelationship) {

        if (!unvalidated) {

          TransactionCommand.relationshipModified(
              securityContext.getCachedUser(),
              (AbstractRelationship) obj,
              AbstractPrimitiveProperty.this,
              propertyContainer.hasProperty(dbName())
                  ? propertyContainer.getProperty(dbName())
                  : null,
              value);
        }

        internalSystemPropertiesUnlocked =
            ((AbstractRelationship) obj).internalSystemPropertiesUnlocked;
      }

      // catch all sorts of errors and wrap them in a FrameworkException
      try {

        // save space
        if (convertedValue == null) {

          propertyContainer.removeProperty(dbName());

        } else {

          if (!isSystemInternal() || internalSystemPropertiesUnlocked) {

            propertyContainer.setProperty(dbName(), convertedValue);

          } else {

            logger.warn(
                "Tried to set internal system property {} to {}. Action was denied.",
                new Object[] {dbName(), convertedValue});
          }
        }

        updateAccessInformation(securityContext, propertyContainer);

      } catch (Throwable t) {

        // throw FrameworkException with the given cause
        final FrameworkException fex =
            new FrameworkException(
                500,
                "Unable to set property "
                    + jsonName()
                    + " on entity with ID "
                    + obj.getUuid()
                    + ": "
                    + t.toString());
        fex.initCause(t);

        throw fex;
      }

      if (isIndexed()) {

        // do indexing, needs to be done after
        // setProperty to make spatial index
        // work
        if (!isPassivelyIndexed()) {

          index(obj, convertedValue);
        }
      }
    }

    return null;
  }
  /**
   * Call afterModification/Creation/Deletion methods.
   *
   * @param securityContext
   */
  public void doOuterCallback(SecurityContext securityContext) {

    if ((status & (STATE_DELETED | STATE_DELETED_PASSIVELY)) == 0) {

      if ((status & STATE_PROPAGATED_MODIFICATION) == STATE_PROPAGATED_MODIFICATION) {
        object.propagatedModification(securityContext);
      }

      if ((status & STATE_LOCATION_MODIFIED) == STATE_LOCATION_MODIFIED) {
        object.locationModified(securityContext);
      }

      if ((status & STATE_SECURITY_MODIFIED) == STATE_SECURITY_MODIFIED) {
        object.securityModified(securityContext);
      }

      if ((status & STATE_OWNER_MODIFIED) == STATE_OWNER_MODIFIED) {
        object.ownerModified(securityContext);
      }
    }

    // examine only the last 4 bits here
    switch (status & 0x000f) {
      case 15:
      case 14:
      case 13:
      case 12:
      case 11:
      case 10:
      case 9:
      case 8: // since all values >= 8 mean that the object was passively deleted, no action has to
        // be taken
        // (no callback for passive deletion!)
        break;

      case 7: // created, modified, deleted, poor guy => no callback
        break;

      case 6: // created, modified => only creation callback will be called
        object.afterCreation(securityContext);
        break;

      case 5: // created, deleted => no callback
        break;

      case 4: // created => creation callback
        object.afterCreation(securityContext);
        break;

      case 3: // modified, deleted => deletion callback
        object.afterDeletion(securityContext, removedProperties);
        break;

      case 2: // modified => modification callback
        object.afterModification(securityContext);
        break;

      case 1: // deleted => deletion callback
        object.afterDeletion(securityContext, removedProperties);
        break;

      case 0: // no action, no callback
        break;

      default:
        break;
    }
  }
  // ~--- methods --------------------------------------------------------
  @Override
  public void processMessage(final WebSocketMessage webSocketData) {

    final String keyString = (String) webSocketData.getNodeData().get("key");
    if (keyString == null) {

      logger.error("Unable to remove given object from collection: key is null");
      getWebSocket().send(MessageBuilder.status().code(400).build(), true);
    }

    final String idToRemove = (String) webSocketData.getNodeData().get("idToRemove");
    if (idToRemove == null) {

      logger.error("Unable to remove given object from collection: idToRemove is null");
      getWebSocket().send(MessageBuilder.status().code(400).build(), true);
    }

    GraphObject obj = getNode(webSocketData.getId());
    if (obj != null) {

      if (!((AbstractNode) obj).isGranted(Permission.write, getWebSocket().getSecurityContext())) {

        getWebSocket()
            .send(MessageBuilder.status().message("No write permission").code(400).build(), true);
        logger.warn(
            "No write permission for {} on {}",
            new Object[] {getWebSocket().getCurrentUser().toString(), obj.toString()});
        return;
      }
    }

    if (obj == null) {

      // No node? Try to find relationship
      obj = getRelationship(webSocketData.getId());
    }

    GraphObject objToRemove = getNode(idToRemove);

    if (obj != null && objToRemove != null) {

      try {

        PropertyKey key =
            StructrApp.getConfiguration().getPropertyKeyForJSONName(obj.getClass(), keyString);
        if (key != null) {

          List collection = (List) obj.getProperty(key);
          collection.remove(objToRemove);
          obj.setProperties(obj.getSecurityContext(), new PropertyMap(key, collection));

          if (obj instanceof NodeInterface) {

            TransactionCommand.registerNodeCallback((NodeInterface) obj, callback);

          } else if (obj instanceof RelationshipInterface) {

            TransactionCommand.registerRelCallback((RelationshipInterface) obj, callback);
          }
        }

      } catch (FrameworkException ex) {

        logger.error("Unable to set properties: {}", ((FrameworkException) ex).toString());
        getWebSocket().send(MessageBuilder.status().code(400).build(), true);
      }

    } else {

      logger.warn("Graph object with uuid {} not found.", webSocketData.getId());
      getWebSocket().send(MessageBuilder.status().code(404).build(), true);
    }
  }