/** * Copyright (C) 2010-2017 Structr GmbH * * This file is part of Structr <http://structr.org>. * * Structr is free software: you can redistribute it and/or modify * it under the terms of the GNU 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 General Public License * along with Structr. If not, see <http://www.gnu.org/licenses/>. */ package org.structr.core.entity; import org.structr.api.graph.Direction; import org.structr.common.SecurityContext; import org.structr.common.error.FrameworkException; import org.structr.core.app.App; import org.structr.core.app.StructrApp; import org.structr.core.graph.NodeInterface; import org.structr.core.graph.search.SearchCommand; import org.structr.core.notion.Notion; import org.structr.core.notion.RelationshipNotion; /** * * */ public abstract class OneToMany<S extends NodeInterface, T extends NodeInterface> extends AbstractRelationship<S, T> implements Relation<S, T, OneStartpoint<S>, ManyEndpoint<T>> { @Override public Multiplicity getSourceMultiplicity() { return Multiplicity.One; } @Override public Multiplicity getTargetMultiplicity() { return Multiplicity.Many; } @Override public OneStartpoint<S> getSource() { return new OneStartpoint<>(this); } @Override public ManyEndpoint<T> getTarget() { return new ManyEndpoint<>(this); } @Override public int getCascadingDeleteFlag() { return Relation.NONE; } @Override public int getAutocreationFlag() { return Relation.NONE; } @Override public void ensureCardinality(final SecurityContext securityContext, final NodeInterface sourceNode, final NodeInterface targetNode) throws FrameworkException { final App app = StructrApp.getInstance(); final Class<? extends OneToMany> clazz = this.getClass(); final Class<S> sourceType = getSourceType(); if (targetNode != null) { // check existing relationships final Relation<?, T, ?, ?> incomingRel = targetNode.getIncomingRelationship(clazz); // if (incomingRel != null && sourceType.isAssignableFrom(incomingRel.getSourceType())) { // if (incomingRel != null && sourceType.isInstance(incomingRel.getSourceNode())) { if (incomingRel != null && SearchCommand.isTypeAssignableFromOtherType(sourceType, incomingRel.getSourceType())) { app.delete(incomingRel); } } } @Override public Notion getEndNodeNotion() { return new RelationshipNotion(getTargetIdProperty()); } @Override public Notion getStartNodeNotion() { return new RelationshipNotion(getSourceIdProperty()); } @Override public Direction getDirectionForType(final Class<? extends NodeInterface> type) { return super.getDirectionForType(getSourceType(), getTargetType(), type); } @Override public Class getOtherType(final Class type) { switch (getDirectionForType(type)) { case INCOMING: return getSourceType(); case OUTGOING: return getTargetType(); case BOTH: return getSourceType(); // don't know... } return null; } @Override public boolean isHidden() { return false; } @Override public boolean isInternal() { return false; } }