protected boolean hasPropertyValue(Node node, PropertyKey propertyKey, Object propertyValue) {

    if (node != null && node.hasProperty(propertyKey.dbName())) {

      Object value = node.getProperty(propertyKey.dbName());
      return value.equals(propertyValue);
    }

    return false;
  }
  // ----- protected methods -----
  protected boolean hasPropertyValue(
      Relationship rel, PropertyKey propertyKey, Object propertyValue) {

    if (rel != null && rel.hasProperty(propertyKey.dbName())) {

      Object value = rel.getProperty(propertyKey.dbName());
      return value.equals(propertyValue);
    }

    return false;
  }
  @Override
  public <T> void setProperty(final PropertyKey<T> key, final T value) throws FrameworkException {

    // check for read-only properties
    // if (StructrApp.getConfiguration().isReadOnlyProperty(type, key) ||
    // (StructrApp.getConfiguration().isWriteOnceProperty(type, key) && (dbRelationship != null) &&
    // dbRelationship.hasProperty(key.name()))) {
    if (key.isReadOnly()
        || (key.isWriteOnce()
            && (dbRelationship != null)
            && dbRelationship.hasProperty(key.dbName()))) {

      if (readOnlyPropertiesUnlocked || securityContext.isSuperUser()) {

        // permit write operation once and
        // lock read-only properties again
        readOnlyPropertiesUnlocked = false;

      } else {

        throw new FrameworkException(getClass().getSimpleName(), new ReadOnlyPropertyToken(key));
      }
    }

    key.setProperty(securityContext, this, value);
  }
  @Override
  public <T> Comparable getComparableProperty(final PropertyKey<T> key) {

    if (key != null) {

      final T propertyValue = getProperty(key, false, null); // get "raw" property without converter

      // check property converter
      PropertyConverter converter = key.databaseConverter(securityContext, this);
      if (converter != null) {

        try {
          return converter.convertForSorting(propertyValue);

        } catch (FrameworkException fex) {
          logger.log(
              Level.WARNING,
              "Unable to convert property {0} of type {1}: {2}",
              new Object[] {key.dbName(), getClass().getSimpleName(), fex.getMessage()});
        }
      }

      // conversion failed, may the property value itself is comparable
      if (propertyValue instanceof Comparable) {
        return (Comparable) propertyValue;
      }

      // last try: convertFromInput to String to make comparable
      if (propertyValue != null) {
        return propertyValue.toString();
      }
    }

    return null;
  }
  public Object execute(Object... parameters) throws FrameworkException {

    final NodeFactory nodeFactory = new NodeFactory(securityContext);

    switch (parameters.length) {
      case 1:
        {
          final Index<Node> index = getIndexFromArguments(NodeIndex.user, arguments);

          // we have only a simple user name
          if (parameters[0] instanceof String) {

            final String userName = (String) parameters[0];

            for (final Node n : index.get(AbstractNode.name.dbName(), userName)) {

              final NodeInterface s = nodeFactory.instantiate(n);

              if (s.getType().equals(Principal.class.getSimpleName())) {

                return s;
              }
            }
          }
        }
        break;

      case 3:
        {
          final String userNickName = (String) parameters[0];
          final PropertyKey key = (PropertyKey) parameters[1];
          final NodeIndex idx = (NodeIndex) parameters[2];
          final Index<Node> index = getIndexFromArguments(idx, arguments);
          IndexHits<Node> indexHits = null;

          synchronized (index) {

            // see: http://docs.neo4j.org/chunked/milestone/indexing-create-advanced.html
            indexHits = index.query(key.dbName(), "\"" + userNickName + "\"");
          }

          try {
            for (final Node n : indexHits) {
              final Object u = nodeFactory.instantiate(n);
              if (u != null) {
                return u;
              }
            }
          } finally {
            indexHits.close();
          }
        }
        break;

      default:
        break;
    }

    return null;
  }
  @Override
  public void removeProperty(final PropertyKey key) throws FrameworkException {

    dbRelationship.removeProperty(key.dbName());

    // remove from index
    removeFromIndex(key);
  }
  public void removeFromIndex(PropertyKey key) {

    for (Index<Relationship> index :
        Services.getInstance().getService(NodeService.class).getRelationshipIndices()) {

      synchronized (index) {
        index.remove(dbRelationship, key.dbName());
      }
    }
  }
  private <T> T getProperty(
      final PropertyKey<T> key,
      boolean applyConverter,
      final org.neo4j.helpers.Predicate<GraphObject> predicate) {

    // early null check, this should not happen...
    if (key == null || key.dbName() == null) {
      return null;
    }

    return key.getProperty(securityContext, this, applyConverter, predicate);
  }