org.structr.rest.resource.NamedRelationResource Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of structr-rest Show documentation
Show all versions of structr-rest Show documentation
Structr is an open source framework based on the popular Neo4j graph database.
/**
* Copyright (C) 2010-2013 Axel Morgner, structr
*
* This file is part of structr .
*
* structr is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* structr is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with structr. If not, see .
*/
package org.structr.rest.resource;
import java.util.Collections;
import java.util.Iterator;
import org.structr.common.PagingHelper;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletRequest;
import org.neo4j.graphdb.RelationshipType;
import org.structr.common.GraphObjectComparator;
import org.structr.core.property.PropertyKey;
import org.structr.core.property.PropertyMap;
import org.structr.common.SecurityContext;
import org.structr.common.error.EmptyPropertyToken;
import org.structr.common.error.ErrorBuffer;
import org.structr.common.error.FrameworkException;
import org.structr.core.EntityContext;
import org.structr.core.GraphObject;
import org.structr.core.Predicate;
import org.structr.core.Result;
import org.structr.core.Services;
import org.structr.core.entity.AbstractNode;
import org.structr.core.entity.AbstractRelationship;
import org.structr.core.entity.RelationshipMapping;
import org.structr.core.graph.CreateRelationshipCommand;
import org.structr.core.graph.search.Search;
import org.structr.core.graph.search.SearchAttribute;
import org.structr.core.graph.search.SearchRelationshipCommand;
import org.structr.rest.RestMethodResult;
import org.structr.rest.exception.IllegalMethodException;
/**
*
* @author Christian Morgner
*/
public class NamedRelationResource extends WrappingResource {
private static final Logger logger = Logger.getLogger(NamedRelationResource.class.getName());
private RelationshipMapping namedRelation = null;
private HttpServletRequest request = null;
@Override
public boolean checkAndConfigure(final String part, final SecurityContext securityContext, final HttpServletRequest request) {
this.namedRelation = EntityContext.getNamedRelation(part);
this.securityContext = securityContext;
this.request = request;
return namedRelation != null;
}
@Override
public Result doGet(final PropertyKey sortKey, final boolean sortDescending, final int pageSize, final int page, final String offsetId) throws FrameworkException {
final List relationResults = new LinkedList();
if(wrappedResource != null) {
// extract relationships from wrapped resource
final List results = wrappedResource.doGet(sortKey, sortDescending, pageSize, page, offsetId).getResults();
for(final GraphObject obj : results) {
if (obj instanceof AbstractNode) {
relationResults.addAll(namedRelation.getRelationships(obj));
}
}
// filter by searchable properties
final List filterAttributes = extractSearchableAttributes(securityContext, namedRelation.getEntityClass(), request);
if(!filterAttributes.isEmpty()) {
final Predicate predicate = new Predicate() {
@Override
public boolean evaluate(final SecurityContext securityContext, final GraphObject... objs) {
if(objs.length > 0) {
final GraphObject obj = objs[0];
for(final SearchAttribute attr : filterAttributes) {
final String value = attr.getStringValue();
final PropertyKey key = attr.getKey();
final Object val = obj.getProperty(key);
if(val != null && val.equals(value)) {
return true;
}
}
}
return false;
}
};
for(final Iterator it = relationResults.iterator(); it.hasNext();) {
if(!predicate.evaluate(securityContext, it.next())) {
it.remove();
}
}
}
// sort results
if (sortKey != null) {
Collections.sort(relationResults, new GraphObjectComparator(sortKey, sortDescending));
}
} else {
// fetch all relationships of a specific combinedType and return them
final List searchAttributes = new LinkedList();
searchAttributes.add(Search.andExactRelType(namedRelation));
// add searchable attributes from EntityContext
searchAttributes.addAll(extractSearchableAttributes(securityContext, namedRelation.getEntityClass(), request));
relationResults.addAll(Services.command(securityContext, SearchRelationshipCommand.class).execute(searchAttributes).getResults());
}
return PagingHelper.subResult(new Result(relationResults, null, isCollectionResource(), isPrimitiveArray()), pageSize, page, offsetId);
}
@Override
public RestMethodResult doPost(final Map propertySet) throws FrameworkException {
// create new relationship of specified combinedType here
final AbstractRelationship relationshipEntity = namedRelation.newEntityClass();
if(relationshipEntity != null) {
// initialize entity temporarily
relationshipEntity.init(securityContext);
CreateRelationshipCommand createRel = Services.command(securityContext, CreateRelationshipCommand.class);
AbstractNode startNode = relationshipEntity.identifyStartNode(namedRelation, propertySet);
AbstractNode endNode = relationshipEntity.identifyEndNode(namedRelation, propertySet);
RelationshipType relType = namedRelation.getRelType();
ErrorBuffer errorBuffer = new ErrorBuffer();
boolean hasError = false;
if(startNode == null) {
errorBuffer.add(namedRelation.getName(), new EmptyPropertyToken(relationshipEntity.getStartNodeIdKey()));
hasError = true;
}
if(endNode == null) {
errorBuffer.add(namedRelation.getName(), new EmptyPropertyToken(relationshipEntity.getEndNodeIdKey()));
hasError = true;
}
if(hasError) {
throw new FrameworkException(422, errorBuffer);
}
final Class sourceType = namedRelation.getSourceType();
final Class destType = namedRelation.getDestType();
propertySet.put(AbstractRelationship.combinedType.dbName(), EntityContext.createCombinedRelationshipType(sourceType, relType, destType));
// convertFromInput properties
PropertyMap properties = PropertyMap.inputTypeToJavaType(securityContext, relationshipEntity.getClass(), propertySet);
// create new relationship with startNode, endNode, relType and propertySet
final AbstractRelationship newRel = createRel.execute(startNode, endNode, relType, properties, false);
final RestMethodResult result = new RestMethodResult(201);
result.addHeader("Location", buildLocationHeader(newRel));
return result;
}
throw new FrameworkException(422, "FIXME");
}
@Override
public RestMethodResult doPut(final Map propertySet) throws FrameworkException {
throw new IllegalMethodException();
}
@Override
public RestMethodResult doHead() throws FrameworkException {
return new RestMethodResult(200);
}
@Override
public Resource tryCombineWith(final Resource next) throws FrameworkException {
if(next instanceof UuidResource) {
return new NamedRelationIdResource(this, (UuidResource)next, securityContext);
}
return super.tryCombineWith(next);
}
@Override
public String getUriPart() {
return namedRelation.getName();
}
@Override
public boolean isCollectionResource() {
return true;
}
@Override
public String getResourceSignature() {
return EntityContext.normalizeEntityName(getUriPart());
}
}