All Downloads are FREE. Search and download functionalities are using the official Maven repository.

xdev.vt.EntityRelationship Maven / Gradle / Ivy

package xdev.vt;

/*-
 * #%L
 * XDEV Application Framework
 * %%
 * Copyright (C) 2003 - 2020 XDEV Software
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program 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 Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */


import java.io.Serializable;

import xdev.db.sql.Condition;
import xdev.lang.Copyable;
import xdev.util.ArrayUtils;
import xdev.util.MathUtils;
import xdev.util.StringUtils;


/**
 * This class describes the relationship between two {@link Entity} objects.
 * 
 * @author XDEV Software Corp.
 * @see Entity
 * 
 */
public class EntityRelationship implements Copyable, Serializable
{
	private static final long	serialVersionUID	= -8619356395478812452L;
	
	private final Entity		firstEntity;
	private final Entity		secondEntity;
	private final boolean		loop;
	private final int			hash;
	

	/**
	 * Creates a new relationship containing the given tables, columns and
	 * cardinalities.
	 * 

* Note that the column count of both entities must match, otherwise a * {@link IllegalArgumentException} is thrown. * * @param tableName1 * @param columnName1 * @param cardinality1 * @param tableName2 * @param columnName2 * @param cardinality2 * @throws IllegalArgumentException * if the column count of both entities doesn't match */ public EntityRelationship(String tableName1, String columnName1, Cardinality cardinality1, String tableName2, String columnName2, Cardinality cardinality2) throws IllegalArgumentException { this(new Entity(tableName1,columnName1,cardinality1),new Entity(tableName2,columnName2, cardinality2)); } /** * Creates a new relationship containing the given tables, columns and * cardinalities. *

* Note that the column count of both entities must match, otherwise a * {@link IllegalArgumentException} is thrown. * * @param tableName1 * @param columnNames1 * @param cardinality1 * @param tableName2 * @param columnNames2 * @param cardinality2 * @throws IllegalArgumentException * if the column count of both entities doesn't match * * @since 3.2 */ public EntityRelationship(String tableName1, String[] columnNames1, Cardinality cardinality1, String tableName2, String[] columnNames2, Cardinality cardinality2) throws IllegalArgumentException { this(new Entity(tableName1,columnNames1,cardinality1),new Entity(tableName2,columnNames2, cardinality2)); } /** * Initializes a new instance of {@link EntityRelationship}. *

* Note that the column count of both entities must match, otherwise a * {@link IllegalArgumentException} is thrown. * * @param firstEntity * the first entity of the relationship. * @param secondEntity * the second entity of the relationship. * @throws IllegalArgumentException * if the column count of both entities doesn't match */ public EntityRelationship(Entity firstEntity, Entity secondEntity) throws IllegalArgumentException { if(firstEntity.columnNames.length != secondEntity.columnNames.length) { throw new IllegalArgumentException("entities must have same number of columns"); } this.firstEntity = firstEntity; this.secondEntity = secondEntity; this.loop = firstEntity.getTableName().equals(secondEntity.getTableName()); int hash1 = firstEntity.hashCode(); int hash2 = secondEntity.hashCode(); if(hash1 > hash2) { int tmp = hash1; hash1 = hash2; hash2 = tmp; } this.hash = MathUtils.computeHash(hash1,hash2); } /** * Returns the first entity of this relationship. * * @return a {@link Entity} */ public Entity getFirstEntity() { return firstEntity; } /** * Returns the second entity of this relationship. * * @return a {@link Entity} */ public Entity getSecondEntity() { return secondEntity; } /** * Returns the {@link Entity} on the other side of the relationship. * * @param entity * the {@link Entity}, which related {@link Entity} should be * returned * @return the other {@link Entity} or null if none found. */ public Entity getOther(Entity entity) { if(firstEntity == entity) { return secondEntity; } else if(secondEntity == entity) { return firstEntity; } return null; } /** * Returns the {@link Entity} for a specified tableName. * * @param tableName * to get the {@link Entity} for. * @return an {@link Entity}, or null if none found. */ public Entity getReferrer(String tableName) { if(firstEntity.refersTo(tableName)) { return firstEntity; } if(secondEntity.refersTo(tableName)) { return secondEntity; } return null; } /** * Returns the {@link Entity} for a specified tableName and columnName. * * @param tableName * to get the {@link Entity} for. * @param columnName * to get the {@link Entity} for * @return an {@link Entity}, or null if none found. * @see #getReferrer(String, String[]) */ public Entity getReferrer(String tableName, String columnName) { return getReferrer(tableName,new String[]{columnName}); } /** * Returns the {@link Entity} for a specified tableName and columnNames. * * @param tableName * to get the {@link Entity} for. * @param columnNames * to get the {@link Entity} for * @return an {@link Entity}, or null if none found. * @since 3.2 */ public Entity getReferrer(String tableName, String[] columnNames) { if(firstEntity.refersTo(tableName,columnNames)) { return firstEntity; } if(secondEntity.refersTo(tableName,columnNames)) { return secondEntity; } return null; } /** * Checks if this relation is a loop, meaning it starts and ends at the same * table. * * @return true if the start end the end of this relation * points to the same table, false otherwise */ public boolean isLoop() { return loop; } /** * Returns, if this {@link EntityRelationship} refers to the combination of * the specified tablename and columnname. * * @param tableName * the name of the table to check. * @param columnName * the name of the column to check. * @return true, if this {@link EntityRelationship} refers to the specified * parameters. * @deprecated since multiple columns are supported, use * {@link #refersTo(String, String[])} */ @Deprecated public boolean refersTo(String tableName, String columnName) { return firstEntity.refersTo(tableName,columnName) || secondEntity.refersTo(tableName,columnName); } /** * Returns, if this {@link EntityRelationship} refers to the combination of * the specified tablename and columnname. * * @param tableName * the name of the table to check. * @param columnNames * the names of the column to check. * @return true, if this {@link EntityRelationship} refers to the specified * parameters. * @since 3.2 */ public boolean refersTo(String tableName, String[] columnNames) { return firstEntity.refersTo(tableName,columnNames) || secondEntity.refersTo(tableName,columnNames); } /** * Returns, if this {@link EntityRelationship} refers to the specified * virtual table name. * * @param tableName * the name of the virtual table to check. * @return true, if this {@link EntityRelationship} refers to the specified * table name. */ public boolean refersTo(String tableName) { return firstEntity.refersTo(tableName) || secondEntity.refersTo(tableName); } /** * Returns a copy of this {@link EntityRelationship}. * * @return a copied {@link EntityRelationship}. */ public String getConnectedTable(String tableName) { Entity entity = getReferrer(tableName); if(entity != null) { return getOther(entity).getTableName(); } return null; } /** * @since 3.2 */ public int getColumnCount() { return firstEntity.getColumnCount(); } @Override public EntityRelationship clone() { return new EntityRelationship(firstEntity.clone(),secondEntity.clone()); } /** * Checks this {@link EntityRelationship} with another * {@link EntityRelationship} for equality. *

* Two {@link EntityRelationship} objects are considered equal, if its * entities are equal. *

* * @param obj * the other Entity * @return true if this Entity equals the other one. */ @Override public boolean equals(Object obj) { if(obj == this) { return true; } if(obj instanceof EntityRelationship) { return hash == ((EntityRelationship)obj).hash; } return false; } /** * Determines if this relationship refers to the same tables and columns as * the other relationship. * * @param other * the relationship to check * @return true if this relationship refers to the same tables * and columns as the other relationship, * false otherwise. */ public boolean equalsTablesAndColumns(EntityRelationship other) { Entity otherFirst = other.firstEntity; Entity otherSecond = other.secondEntity; return (firstEntity.equals(otherFirst) && secondEntity.equals(otherSecond)) || (firstEntity.equals(otherSecond) && secondEntity.equals(otherFirst)); } /** * Returns a hashcode built from the hashcodes of the related entities. * * @return a hashcode */ @Override public int hashCode() { return hash; } /** * Returns a {@link String} representation of this * {@link EntityRelationship} containing both entities. * * @return the relationship as {@link String}. */ @Override public String toString() { return new StringBuilder().append(firstEntity.tableName).append("(") .append(StringUtils.concat(",",(Object[])firstEntity.columnNames)).append(") [ ") .append(firstEntity.cardinality.toString()).append(" - ") .append(secondEntity.cardinality.toString()).append(" ] ") .append(secondEntity.tableName).append("(") .append(StringUtils.concat(",",(Object[])secondEntity.columnNames)).append(")") .toString(); } /** * Creates a {@link Condition} that can be used for joining the entities of * this {@link EntityRelationship} within SQL queries. * * @return a {@link Condition}. */ public Condition getCondition() { Condition condition = null; int cc = firstEntity.getColumnCount(); for(int i = 0; i < cc; i++) { VirtualTableColumn col1 = firstEntity.getVirtualTableColumn(i); VirtualTableColumn col2 = secondEntity.getVirtualTableColumn(i); if(col1 == null || col2 == null) { return null; } Condition part = col1.eq(col2); if(condition == null) { condition = part; } else { condition = condition.AND(part); } } return condition; } /** * This class provides an abstraction for an entity within a * {@link EntityRelationship}. * * @author XDEV Software Corp. * @see EntityRelationship */ public static class Entity implements Copyable, Serializable { private static final long serialVersionUID = -4394075785300688603L; private final String tableName; private final String[] columnNames; private final int hash; private Cardinality cardinality; private VirtualTable virtualTable; private VirtualTableColumn[] virtualTableColumns; /** * Initializes a new {@link Entity}. * * @param tableName * the table name of the entity. * @param columnName * the column name used for the relationship to the other * entity. * @param cardinality * the {@link Cardinality} of the entity. */ public Entity(String tableName, String columnName, Cardinality cardinality) { this(tableName,new String[]{columnName},cardinality); } /** * Initializes a new {@link Entity}. * * @param tableName * the table name of the entity. * @param columnNames * the column names used for the relationship to the other * entity. * @param cardinality * the {@link Cardinality} of the entity. * @since 3.2 */ public Entity(String tableName, String[] columnNames, Cardinality cardinality) { this.tableName = tableName; this.columnNames = columnNames; this.hash = MathUtils.computeHashDeep(tableName,columnNames); this.cardinality = cardinality; } /** * Returns the table name. * * @return the table name */ public String getTableName() { return tableName; } /** * Returns the first column name (name of the join column of the * relationship). * * @return the first column name * @see #getColumnCount() * @see #getColumnNames() */ public String getColumnName() { return columnNames[0]; } /** * Returns the number of columns of this entity. * * @return the number of columns of this entity * @since 3.2 */ public int getColumnCount() { return columnNames.length; } /** * Returns the column name at the specified index. * * @since 3.2 * @see #getColumnCount() * @see #getColumnNames() */ public String getColumnName(int index) { return columnNames[index]; } /** * Returns all column names of this entity * * @since 3.2 * * @see #getColumnCount() * @see #getColumnName(int) */ public String[] getColumnNames() { return columnNames; } /** * Determines if this {@link Entity} refers to the specified table name. * * @param tableName * name of the table to be checked. * @return true, if this {@link Entity} refers to the specified * tableName, false otherwise. */ public boolean refersTo(String tableName) { return this.tableName.equals(tableName); } /** * Determines if this {@link Entity} refers to the specified table and * column name. * * @param tableName * name of the table to be checked. * @param columnName * name of the column to be checked. * @return true, if this {@link Entity} refers to the specified * tableName and columnName, * false otherwise. * @deprecated since multiple columns are supported, use * {@link #refersTo(String, String[])} */ @Deprecated public boolean refersTo(String tableName, String columnName) { return refersTo(tableName,new String[]{columnName}); } /** * Determines if this {@link Entity} refers to the specified table and * column name. * * @param tableName * name of the table to be checked. * @param columnNames * names of the column to be checked. * @return true, if this {@link Entity} refers to the specified * tableName and columnName, * false otherwise. * @since 3.2 */ public boolean refersTo(String tableName, String[] columnNames) { return this.tableName.equals(tableName) && ArrayUtils.equals(this.columnNames,columnNames); } /** * Determines if this {@link Entity} refers to the same table and column * as entity. * * @param entity * the {@link Entity} to check * @return true, if this {@link Entity} refers to the same table and * column as entity, false otherwise. */ public boolean refersTo(Entity entity) { return refersTo(entity.tableName,entity.columnNames); } /** * Returns the fully qualified column name (of the first column). * * @return the fully qualified column name * @deprecated not particularly useful since multiple columns are * supported */ @Deprecated public String getFullQualifiedName() { return tableName + "." + columnNames[0]; } /** * Returns the {@link Cardinality} of the {@link Entity}. * * @return a {@link Cardinality} */ public Cardinality getCardinality() { return cardinality; } /** * Sets the {@link Cardinality} of the {@link Entity}. * * @param cardinality * {@link Cardinality} to be set. */ public void setCardinality(Cardinality cardinality) { this.cardinality = cardinality; } /** * Returns the referred {@link VirtualTable}. *

* This is a shortcut for * *

		 * VirtualTables.getVirtualTable(entity.getTableName());
		 * 
* * @return the referred {@link VirtualTable} of this entity, or * null if the virtual table cannot be found * @since 3.2 * @see #getVirtualTableColumn() */ public VirtualTable getVirtualTable() { if(virtualTable == null) { virtualTable = VirtualTables.getVirtualTable(tableName); } return virtualTable; } /** * Returns a referred {@link VirtualTableColumn}. * * @param columnIndex * the index of the column to ask for * @return a referred {@link VirtualTableColumn} of this entity, or * null if the column cannot be found * @since 3.2 * @see #getVirtualTable() */ public VirtualTableColumn getVirtualTableColumn(int columnIndex) { if(virtualTableColumns == null) { virtualTableColumns = new VirtualTableColumn[columnNames.length]; } VirtualTable vt; if(virtualTableColumns[columnIndex] == null && (vt = getVirtualTable()) != null) { virtualTableColumns[columnIndex] = vt.getColumn(columnNames[columnIndex]); } return virtualTableColumns[columnIndex]; } /** * Returns a copy of this {@link Entity}. * * @return the copied {@link Entity}. */ @Override public Entity clone() { return new Entity(tableName,columnNames,cardinality); } /** * Checks this {@link Entity} with another {@link Entity} for equality. *

* The table name and the column name have to be equal to be considered * equal. *

* * @param obj * the other Entity * @return true if this Entity equals the other one. */ @Override public boolean equals(Object obj) { if(obj == this) { return true; } if(obj != null && obj instanceof Entity) { return ((Entity)obj).hash == hash; } return false; } /** * Returns the hashcode of this {@link Entity} built from the name of * the table and the name of the column. * * @return a hashcode */ @Override public int hashCode() { return hash; } /** * Returns an {@link String} representation for this {@link Entity} * consisting of tablename, columnname and cardinality. * * @return the entity as a String */ @Override public String toString() { return new StringBuilder().append(tableName).append("(") .append(StringUtils.concat(",",(Object[])columnNames)).append(") [") .append(cardinality.toString()).append("]").toString(); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy