org.structr.common.error 各种错误处理
/**
* Defines a class of relations between a source class and a target class with a direction and a cardinality.
*/
public class RelationClass
{
public static final int DELETE_BOTH = 3;
public static final int DELETE_INCOMING = 2;
public static final int DELETE_NONE = 0;
public static final int DELETE_OUTGOING = 1;
private static final Logger logger = Logger.getLogger(RelationClass.class.getName());
//~--- fields ---------------------------------------------------------
private Cardinality cardinality = null;
private Class destType = null;
private Direction direction = null;
private Notion notion = null;
private RelationshipType relType = null;
private int cascadeDelete = DELETE_NONE;
//~--- constant enums -------------------------------------------------
public enum Cardinality
{
OneToOne, OneToMany, ManyToOne, ManyToMany
}
//~--- constructors ---------------------------------------------------
public RelationClass(Class destType, RelationshipType relType, Direction direction, Cardinality cardinality, Notion notion, int cascadeDelete)
{
this.cascadeDelete = cascadeDelete;
this.cardinality = cardinality;
this.direction = direction;
this.destType = destType;
this.relType = relType;
this.notion = notion;
}
//~--- methods --------------------------------------------------------
public void createRelationship(final SecurityContext securityContext, final AbstractNode sourceNode, final Object value) throws FrameworkException
{
createRelationship(securityContext, sourceNode, value, Collections.EMPTY_MAP);
}
public void createRelationship(final SecurityContext securityContext, final AbstractNode sourceNode, final Object value, final Map properties) throws FrameworkException
{
// create relationship if it does not already exist
final Command createRel = Services.command(securityContext, CreateRelationshipCommand.class);
final Command deleteRel = Services.command(securityContext, DeleteRelationshipCommand.class);
AbstractNode targetNode;
if (value instanceof AbstractNode)
{
targetNode = (AbstractNode) value;
}
else
{
targetNode = (AbstractNode) Services.command(securityContext, FindNodeCommand.class).execute(value);
}
if ((sourceNode != null) && (targetNode != null))
{
final AbstractNode finalTargetNode = targetNode;
StructrTransaction transaction = new StructrTransaction()
{
@Override
public Object execute() throws FrameworkException
{
switch (cardinality)
{
case ManyToOne:
case OneToOne:
{
String destType = finalTargetNode.getType();
// delete previous relationships to nodes of the same destination type and direction
List<AbstractRelationship> rels = sourceNode.getRelationships(relType, direction);
for (AbstractRelationship rel : rels)
{
if (rel.getOtherNode(sourceNode).getType().equals(destType))
{
deleteRel.execute(rel);
}
}
break;
}
case OneToMany:
{
// Here, we have a OneToMany with OUTGOING Rel, so we need to remove all relationships
// of the same type incoming to the target node
List<AbstractRelationship> rels = finalTargetNode.getRelationships(relType, Direction.INCOMING);
for (AbstractRelationship rel : rels)
{
if (rel.getOtherNode(finalTargetNode).getType().equals(sourceNode.getType()))
{
deleteRel.execute(rel);
}
}
}
}
AbstractRelationship newRel;
if (direction.equals(Direction.OUTGOING))
{
newRel = (AbstractRelationship) createRel.execute(sourceNode, finalTargetNode, relType);
}
else
{
newRel = (AbstractRelationship) createRel.execute(finalTargetNode, sourceNode, relType);
}
newRel.setProperties(properties);
// set cascade delete value
if (cascadeDelete > 0)
{
newRel.setProperty(AbstractRelationship.HiddenKey.cascadeDelete, cascadeDelete);
}
return newRel;
}
};
// execute transaction
Services.command(securityContext, TransactionCommand.class).execute(transaction);
}
else
{
String type = "unknown";
if (sourceNode != null)
{
type = sourceNode.getType();
}
else if (targetNode != null)
{
type = targetNode.getType();
}
throw new FrameworkException(type, new IdNotFoundToken(value));
}
}
public void removeRelationship(final SecurityContext securityContext, final AbstractNode sourceNode, final Object value) throws FrameworkException
{
final Command deleteRel = Services.command(securityContext, DeleteRelationshipCommand.class);
AbstractNode targetNode = null;
if (value instanceof AbstractNode)
{
targetNode = (AbstractNode) value;
}
else
{
targetNode = (AbstractNode) Services.command(securityContext, FindNodeCommand.class).execute(value);
}
if ((sourceNode != null) && (targetNode != null))
{
final AbstractNode finalTargetNode = targetNode;
StructrTransaction transaction = new StructrTransaction()
{
@Override
public Object execute() throws FrameworkException
{
switch (cardinality)
{
case ManyToOne:
case OneToOne:
{
String destType = finalTargetNode.getType();
// delete previous relationships to nodes of the same destination type and direction
List<AbstractRelationship> rels = sourceNode.getRelationships(relType, direction);
for (AbstractRelationship rel : rels)
{
if (rel.getOtherNode(sourceNode).getType().equals(destType))
{
deleteRel.execute(rel);
}
}
break;
}
case OneToMany:
{
// Here, we have a OneToMany with OUTGOING Rel, so we need to remove all relationships
// of the same type incoming to the target node
List<AbstractRelationship> rels = finalTargetNode.getRelationships(relType, Direction.INCOMING);
for (AbstractRelationship rel : rels)
{
if (rel.getOtherNode(finalTargetNode).getType().equals(sourceNode.getType()))
{
deleteRel.execute(rel);
}
}
}
case ManyToMany:
{
// In this case, remove exact the relationship of the given type
// between source and target node
List<AbstractRelationship> rels = finalTargetNode.getRelationships(relType, Direction.BOTH);
for (AbstractRelationship rel : rels)
{
if (rel.getOtherNode(finalTargetNode).equals(sourceNode))
{
deleteRel.execute(rel);
}
}
}
}
return null;
}
};
// execute transaction
Services.command(securityContext, TransactionCommand.class).execute(transaction);
}
else
{
String type = "unknown";
if (sourceNode != null)
{
type = sourceNode.getType();
}
else if (targetNode != null)
{
type = targetNode.getType();
}
throw new FrameworkException(type, new IdNotFoundToken(value));
}
}
public AbstractNode addRelatedNode(final SecurityContext securityContext, final AbstractNode node) throws FrameworkException
{
return (AbstractNode) Services.command(securityContext, TransactionCommand.class).execute(new StructrTransaction()
{
@Override
public Object execute() throws FrameworkException
{
AbstractNode relatedNode = (AbstractNode) Services.command(securityContext,
CreateNodeCommand.class).execute(new NodeAttribute(AbstractNode.Key.type.name(), getDestType().getSimpleName()));
// Create new relationship between facility and location nodes
Command createRel = Services.command(securityContext, CreateRelationshipCommand.class);
AbstractRelationship newRel = (AbstractRelationship) createRel.execute(node, relatedNode, getRelType());
if (cascadeDelete > 0)
{
newRel.setProperty(AbstractRelationship.HiddenKey.cascadeDelete, cascadeDelete);
}
return relatedNode;
}
});
}
//~--- get methods ----------------------------------------------------
public Class getDestType()
{
return destType;
}
public Direction getDirection()
{
return direction;
}
public Cardinality getCardinality()
{
return cardinality;
}
public RelationshipType getRelType()
{
return relType;
}
public Notion getNotion()
{
return notion;
}
// ----- public methods -----
public List<AbstractNode> getRelatedNodes(final SecurityContext securityContext, final AbstractNode node)
{
if (cardinality.equals(Cardinality.OneToMany) || cardinality.equals(Cardinality.ManyToMany))
{
// return getTraversalResults(securityContext, node, StringUtils.toCamelCase(type));
return getTraversalResults(securityContext, node);
}
else
{
logger.log(Level.WARNING, "Requested related nodes with wrong cardinality {0} between {1} and {2}", new Object[]{cardinality.name(), node.getClass().getSimpleName(),
destType});
}
return null;
}
public AbstractNode getRelatedNode(final SecurityContext securityContext, final AbstractNode node)
{
if (cardinality.equals(Cardinality.OneToOne) || cardinality.equals(Cardinality.ManyToOne))
{
List<AbstractNode> nodes = getTraversalResults(securityContext, node);
if ((nodes != null) && nodes.iterator().hasNext())
{
return nodes.iterator().next();
}
}
else
{
logger.log(Level.WARNING, "Requested related node with wrong cardinality {0} between {1} and {2}", new Object[]{cardinality.name(), node.getClass().getSimpleName(),
destType});
}
return null;
}
// ----- private methods -----
private List<AbstractNode> getTraversalResults(final SecurityContext securityContext, final AbstractNode node)
{
// final Class realType = (Class) Services.command(securityContext, GetEntityClassCommand.class).execute(StringUtils.capitalize(destType));
final NodeFactory nodeFactory = new NodeFactory<AbstractNode>(securityContext);
final List<AbstractNode> nodeList = new LinkedList<AbstractNode>();
// use traverser
Iterable<Node> nodes = Traversal.description().uniqueness(Uniqueness.NODE_PATH).breadthFirst().relationships(relType, direction).evaluator(new Evaluator()
{
@Override
public Evaluation evaluate(Path path)
{
int len = path.length();
if (len <= 1)
{
if (len == 0)
{
// do not include start node (which is the
// index node in this case), but continue
// traversal
return Evaluation.EXCLUDE_AND_CONTINUE;
}
else
{
try
{
AbstractNode abstractNode = (AbstractNode) nodeFactory.createNode(securityContext, path.endNode());
// use inheritance
if ((destType != null) && destType.isAssignableFrom(abstractNode.getClass()))
{
nodeList.add(abstractNode);
return Evaluation.INCLUDE_AND_CONTINUE;
}
else
{
return Evaluation.EXCLUDE_AND_CONTINUE;
}
}
catch (FrameworkException fex)
{
logger.log(Level.WARNING, "Unable to instantiate node", fex);
}
}
}
return Evaluation.EXCLUDE_AND_PRUNE;
}
}).traverse(node.getNode()).nodes();
// iterate nodes to evaluate traversal
for (Node n : nodes)
{
}
return nodeList;
}
//~--- set methods ----------------------------------------------------
public void setDestType(Class destType)
{
this.destType = destType;
}
public void setDirection(Direction direction)
{
this.direction = direction;
}
public void setCardinality(Cardinality cardinality)
{
this.cardinality = cardinality;
}
public void setRelType(RelationshipType relType)
{
this.relType = relType;
}
public void setNotion(Notion notion)
{
this.notion = notion;
}
}
/**
* Describes a relation type between two node classes,
* defined by source and destination type (node entity classes) and the
* relationship type.
* <p/>
* Direction is always OUTGOING from source to destination by definition.
* <p/>
* A @see RelationshipMapping is marked with a combined key with name "type" of the form
* "SourceType RELTYPE DestType".
*/
public class RelationshipMapping
{
private static final Logger logger = Logger.getLogger(RelationshipMapping.class.getName());
//~--- fields ---------------------------------------------------------
private Class destType = null;
private String name = null;
private RelationshipType relType = null;
private Class sourceType = null;
//~--- constructors ---------------------------------------------------
public RelationshipMapping(String name, Class sourceType, Class destType, RelationshipType relType)
{
this.sourceType = sourceType;
this.destType = destType;
this.relType = relType;
this.name = name;
}
//~--- methods --------------------------------------------------------
public AbstractRelationship newEntityClass()
{
AbstractRelationship rel = null;
Class type = getEntityClass();
try
{
rel = (AbstractRelationship) type.newInstance();
}
catch (Throwable t)
{
logger.log(Level.WARNING, "Unable to instantiate relationship entity class", t);
}
return rel;
}
//~--- get methods ----------------------------------------------------
public RelationshipType getRelType()
{
return relType;
}
public Class getSourceType()
{
return sourceType;
}
public Class getDestType()
{
return destType;
}
public String getName()
{
return name;
}
public Class getEntityClass()
{
return EntityContext.getNamedRelationClass(sourceType.getSimpleName(), destType.getSimpleName(), relType.name());
}
public List<AbstractRelationship> getRelationships(AbstractNode obj) throws FrameworkException
{
Class combinedRelType = getEntityClass();
List<AbstractRelationship> relsFilteredByType = new LinkedList<AbstractRelationship>();
if (!(obj instanceof AbstractNode))
{
logger.log(Level.SEVERE, "Requested relationships of a non-node object");
throw new FrameworkException(HttpServletResponse.SC_BAD_REQUEST, new ErrorBuffer());
}
AbstractNode node = (AbstractNode) obj;
// filter relationships for correct combined relationship type
for (AbstractRelationship rel : node.getRelationships(relType, getDirectionForType(obj.getStringProperty(AbstractNode.Key.type.name()))))
{
if (rel.getClass().equals(combinedRelType))
{
relsFilteredByType.add(rel);
}
}
return relsFilteredByType;
}
// ----- private methods -----
private Direction getDirectionForType(String type) throws FrameworkException
{
if (type.equals(sourceType.getSimpleName()))
{
return Direction.OUTGOING;
}
if (type.equals(destType.getSimpleName()))
{
return Direction.INCOMING;
}
throw new FrameworkException(HttpServletResponse.SC_BAD_REQUEST, new ErrorBuffer());
}
//~--- set methods ----------------------------------------------------
public void setRelType(RelationshipType relType)
{
this.relType = relType;
}
public void setSourceType(Class sourceType)
{
this.sourceType = sourceType;
}
public void setDestType(Class destType)
{
this.destType = destType;
}
public void setName(String name)
{
this.name = name;
}
}