/* This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 Servoy BV This program 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. 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program; if not, see http://www.gnu.org/licenses or write to the Free Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 */ package com.servoy.j2db.persistence; import java.rmi.RemoteException; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import com.servoy.base.query.IBaseSQLCondition; import com.servoy.base.scripting.annotations.ServoyClientSupport; import com.servoy.base.util.DataSourceUtilsBase; import com.servoy.j2db.J2DBGlobals; import com.servoy.j2db.Messages; import com.servoy.j2db.dataprocessing.IFoundSetManagerInternal; import com.servoy.j2db.documentation.ServoyDocumented; import com.servoy.j2db.query.ISQLJoin; import com.servoy.j2db.query.ISQLTableJoin; import com.servoy.j2db.util.DataSourceUtils; import com.servoy.j2db.util.Debug; import com.servoy.j2db.util.Pair; import com.servoy.j2db.util.ScopesUtils; import com.servoy.j2db.util.UUID; /** * A relation (between 2 tables on one or more key column pairs) * * @author jblok */ @ServoyDocumented(category = ServoyDocumented.DESIGNTIME, typeCode = IRepository.RELATIONS) @ServoyClientSupport(mc = true, wc = true, sc = true) public class Relation extends AbstractBase implements ISupportChilds, ISupportUpdateableName, ISupportHTMLToolTipText, ISupportContentEquals, ISupportEncapsulation, ICloneable, IRelation, ISupportDeprecated { private static final long serialVersionUID = 1L; public static final String INTERNAL_PREFIX = "-int-"; public static RuntimeProperty<ISQLTableJoin> RELATION_JOIN = new RuntimeProperty<ISQLTableJoin>() { }; /* * All 1-n providers for this class */ private transient IDataProvider[] primary; private transient Column[] foreign; private transient int[] operators; /** * Constructor I */ Relation(ISupportChilds parent, int element_id, UUID uuid) { super(IRepository.RELATIONS, parent, element_id, uuid); } /* * _____________________________________________________________ Methods from IPersist */ /* * _____________________________________________________________ Methods for relation column handling */ public boolean checkIfRelationItemsValid(IDataProvider[] primaryDataProvider, Column[] foreignColumns) throws RepositoryException { if (primaryDataProvider == null || primaryDataProvider.length == 0 || foreignColumns == null || foreignColumns.length == 0) { throw new RepositoryException("one of the arguments is null or is an empty array"); //$NON-NLS-1$ } for (Column column : foreignColumns) { if (!column.getTable().getName().equalsIgnoreCase(getForeignTableName())) { throw new RepositoryException("one of the arguments has another tablename than the ones defined on creation of the relations"); //$NON-NLS-1$ } } return true; } public void createNewRelationItems(IDataProvider[] primaryDataProvider, int[] ops, Column[] foreignColumns) throws RepositoryException { if (!isParentRef()) checkIfRelationItemsValid(primaryDataProvider, foreignColumns); List<IPersist> allobjects = getAllObjectsAsList(); int i = 0; if (primaryDataProvider != null) { for (; i < primaryDataProvider.length; i++) { RelationItem obj = null; if (i < allobjects.size()) { obj = (RelationItem)allobjects.get(i); } else { obj = (RelationItem)getRootObject().getChangeHandler().createNewObject(this, IRepository.RELATION_ITEMS); addChild(obj); } //set all the required properties obj.setPrimaryDataProviderID(primaryDataProvider[i].getDataProviderID()); obj.setOperator(ops[i]); obj.setForeignColumnName(foreignColumns[i].getDataProviderID()); } } //delete the once which are not used anymore if (i < allobjects.size()) { IPersist[] remainder = allobjects.subList(i, allobjects.size()).toArray(new IPersist[allobjects.size() - i]); for (IPersist p : remainder) { ((IDeveloperRepository)p.getRootObject().getRepository()).deleteObject(p); } } flushCashedItems(); primary = primaryDataProvider; //faster foreign = foreignColumns; //faster operators = ops; //faster } public RelationItem createNewRelationItem(IFoundSetManagerInternal foundSetManager, IDataProvider primaryDataProvider, int ops, Column foreignColumn) throws RepositoryException { if (!foreignColumn.getTable().equals(foundSetManager.getTable(getForeignDataSource()))) { throw new RepositoryException("one of the arguments has another tablename than the ones defined on creation of the relations"); //$NON-NLS-1$ } RelationItem obj = null; if (primaryDataProvider != null) { obj = (RelationItem)getRootObject().getChangeHandler().createNewObject(this, IRepository.RELATION_ITEMS); //set all the required properties obj.setPrimaryDataProviderID(primaryDataProvider.getDataProviderID()); obj.setOperator(ops); obj.setForeignColumnName(foreignColumn.getName()); addChild(obj); } flushCashedItems(); return obj; } /* * _____________________________________________________________ Methods from this class */ //the repository element id can differ! public boolean contentEquals(Object obj) { if (obj instanceof Relation) { Relation other = (Relation)obj; try { List<IPersist> allobjects = getAllObjectsAsList(); if (other.getAllObjectsAsList().size() != allobjects.size()) return false; for (int pos = 0; pos < allobjects.size(); pos++) { RelationItem ri = (RelationItem)allobjects.get(pos); RelationItem ori = (RelationItem)other.getAllObjectsAsList().get(pos); if (!ri.contentEquals(ori)) { return false; } } if (!isGlobal() && (!getPrimaryTableName().equals(other.getPrimaryTableName()) || !getForeignTableName().equals(other.getForeignTableName()))) { return false; } return (getName().equals(other.getName()) && getDeleteRelatedRecords() == other.getDeleteRelatedRecords() && getAllowCreationRelatedRecords() == other.getAllowCreationRelatedRecords()); } catch (Exception e) { Debug.error(e); } } return false; } @Override public String toString() { return getName(); } public void updateName(IValidateName validator, String name) throws RepositoryException { validator.checkName(name, getID(), new ValidatorSearchContext(IRepository.RELATIONS), true); setTypedProperty(StaticContentSpecLoader.PROPERTY_NAME, name); getRootObject().getChangeHandler().fireIPersistChanged(this); } /** * Set the name * * @param arg the name */ public void setName(String arg) { setTypedProperty(StaticContentSpecLoader.PROPERTY_NAME, arg); } /** * The name of the relation. */ public String getName() { return getTypedProperty(StaticContentSpecLoader.PROPERTY_NAME); } /** * Set the primary data source */ public void setPrimaryDataSource(String arg) { setTypedProperty(StaticContentSpecLoader.PROPERTY_PRIMARYDATASOURCE, arg); } /** * Qualified name of the primary data source. Contains both the name of the primary server * and the name of the primary table. */ public String getPrimaryDataSource() { return getTypedProperty(StaticContentSpecLoader.PROPERTY_PRIMARYDATASOURCE); } /** * Set the foreign data source */ public void setForeignDataSource(String arg) { setTypedProperty(StaticContentSpecLoader.PROPERTY_FOREIGNDATASOURCE, arg); } /** * Qualified name of the foreign data source. Contains both the name of the foreign * server and the name of the foreign table. */ public String getForeignDataSource() { return getTypedProperty(StaticContentSpecLoader.PROPERTY_FOREIGNDATASOURCE); } /** * Set the serverName1 * * @param arg the serverName1 */ public void setPrimaryServerName(String arg) { setPrimaryDataSource(DataSourceUtils.createDBTableDataSource(arg, getPrimaryTableName())); } public String getPrimaryServerName() { String primaryDataSource = getPrimaryDataSource(); if (primaryDataSource == null) { return null; } String[] stn = DataSourceUtilsBase.getDBServernameTablename(primaryDataSource); if (stn != null) { return stn[0]; } // data source is not a server/table combi Table primaryTable = null; try { primaryTable = getPrimaryTable(); } catch (RepositoryException e) { Debug.error(e); } return primaryTable == null ? null : primaryTable.getServerName(); } /** * Set the foreignServerName * * @param arg the foreignServerName */ public void setForeignServerName(String arg) { setForeignDataSource(DataSourceUtils.createDBTableDataSource(arg, getForeignTableName())); } public String getForeignServerName() { String foreignDataSource = getForeignDataSource(); if (foreignDataSource == null) { return null; } String[] stn = DataSourceUtilsBase.getDBServernameTablename(foreignDataSource); if (stn != null) { return stn[0]; } // data source is not a server/table combi Table foreignTable = null; try { foreignTable = getForeignTable(); } catch (RepositoryException e) { Debug.error(e); } return foreignTable == null ? null : foreignTable.getServerName(); } /** * Set the tableName1 * * @param arg the tableName1 */ public void setPrimaryTableName(String arg) { setPrimaryDataSource(DataSourceUtils.createDBTableDataSource(getPrimaryServerName(), arg)); } public String getPrimaryTableName() { String primaryDataSource = getPrimaryDataSource(); if (primaryDataSource == null) { return null; } String[] stn = DataSourceUtilsBase.getDBServernameTablename(primaryDataSource); if (stn != null) { return stn[1]; } // data source is not a server/table combi Table primaryTable = null; try { primaryTable = getPrimaryTable(); } catch (RepositoryException e) { Debug.error(e); } return primaryTable == null ? null : primaryTable.getName(); } public Table getPrimaryTable() throws RepositoryException { return getTable(getPrimaryDataSource()); } public IServer getPrimaryServer() throws RepositoryException, RemoteException { String primaryDataSource = getPrimaryDataSource(); if (primaryDataSource == null) { return null; } String[] stn = DataSourceUtilsBase.getDBServernameTablename(primaryDataSource); if (stn != null) { return getRootObject().getServer(stn[0]); } ITable primaryTable = getPrimaryTable(); if (primaryTable != null) { return getRootObject().getServer(primaryTable.getServerName()); } return null; } /** * Set the foreignTableName * * @param arg the foreignTableName */ public void setForeignTableName(String arg) { setForeignDataSource(DataSourceUtils.createDBTableDataSource(getForeignServerName(), arg)); } public String getForeignTableName() { String foreignDataSource = getForeignDataSource(); if (foreignDataSource == null) { return null; } String[] stn = DataSourceUtilsBase.getDBServernameTablename(foreignDataSource); if (stn != null) { return stn[1]; } // data source is not a server/table combi Table foreignTable = null; try { foreignTable = getForeignTable(); } catch (RepositoryException e) { Debug.error(e); } return foreignTable == null ? null : foreignTable.getName(); } /** * A String which specified a set of sort options for the initial sorting of data * retrieved through this relation. * * Has the form "column_name asc, another_column_name desc, ...". */ public String getInitialSort() { return getTypedProperty(StaticContentSpecLoader.PROPERTY_INITIALSORT); } /** * Sets the sortOptions. * * @param initialSort The sortOptions to set */ public void setInitialSort(String arg) { setTypedProperty(StaticContentSpecLoader.PROPERTY_INITIALSORT, arg); } /** * Gets the duplicateRelatedRecords. * * @return Returns a boolean */ public boolean getDuplicateRelatedRecords() { return getTypedProperty(StaticContentSpecLoader.PROPERTY_DUPLICATERELATEDRECORDS).booleanValue(); } /** * Sets the duplicateRelatedRecords. * * @param duplicateRelatedRecords The options to set */ public void setDuplicateRelatedRecords(boolean arg) { setTypedProperty(StaticContentSpecLoader.PROPERTY_DUPLICATERELATEDRECORDS, arg); } /** * Set the deleteRelatedRecords * * @param arg the deleteRelatedRecords */ public void setDeleteRelatedRecords(boolean arg) { setTypedProperty(StaticContentSpecLoader.PROPERTY_DELETERELATEDRECORDS, arg); } /** * Flag that tells if related records should be deleted or not when a parent record is deleted. * * The default value of this flag is "false". */ public boolean getDeleteRelatedRecords() { return getTypedProperty(StaticContentSpecLoader.PROPERTY_DELETERELATEDRECORDS).booleanValue(); } /** * Set the existsInDB * * @param arg the existsInDB */ public void setExistsInDB(boolean arg) { setTypedProperty(StaticContentSpecLoader.PROPERTY_EXISTSINDB, arg); } /** * Get the existsInDB * * @return the existsInDB */ public boolean getExistsInDB() { return getTypedProperty(StaticContentSpecLoader.PROPERTY_EXISTSINDB).booleanValue(); } public void setAllowCreationRelatedRecords(boolean arg) { setTypedProperty(StaticContentSpecLoader.PROPERTY_ALLOWCREATIONRELATEDRECORDS, arg); } /** * Flag that tells if related records can be created through this relation. * * The default value of this flag is "false". */ public boolean getAllowCreationRelatedRecords() { return getTypedProperty(StaticContentSpecLoader.PROPERTY_ALLOWCREATIONRELATEDRECORDS).booleanValue(); } public void setAllowParentDeleteWhenHavingRelatedRecords(boolean arg) { setTypedProperty(StaticContentSpecLoader.PROPERTY_ALLOWPARENTDELETEWHENHAVINGRELATEDRECORDS, arg); } /** * Flag that tells if the parent record can be deleted while it has related records. * * The default value of this flag is "true". */ public boolean getAllowParentDeleteWhenHavingRelatedRecords() { return getTypedProperty(StaticContentSpecLoader.PROPERTY_ALLOWPARENTDELETEWHENHAVINGRELATEDRECORDS).booleanValue(); } public int getItemCount() { return getAllObjectsAsList().size(); } public IDataProvider[] getPrimaryDataProviders(IDataProviderHandler dataProviderHandler) throws RepositoryException { if (primary == null) { makePrimaryDataProviders(dataProviderHandler); } return primary; } public Column[] getForeignColumns() throws RepositoryException { if (foreign == null) { makeForeignColumns(); } return foreign; } private Table getTable(String dataSource) throws RepositoryException { if (dataSource == null) { return null; } String[] stn = DataSourceUtilsBase.getDBServernameTablename(dataSource); if (stn != null) { try { IServer server = getRootObject().getServer(stn[0]); if (server == null) { valid = Boolean.FALSE; throw new RepositoryException(Messages.getString("servoy.exception.serverNotFound", new Object[] { stn[0] })); //$NON-NLS-1$ } return (Table)server.getTable(stn[1]); } catch (RemoteException e) { Debug.error(e); return null; } } // not a server/table combi, ask the current clients foundset manager if (J2DBGlobals.getServiceProvider() != null) { return (Table)J2DBGlobals.getServiceProvider().getFoundSetManager().getTable(dataSource); } // developer return null; } public Table getForeignTable() throws RepositoryException { return getTable(getForeignDataSource()); } public IServer getForeignServer() throws RepositoryException, RemoteException { String foreignDataSource = getForeignDataSource(); if (foreignDataSource == null) { return null; } String[] stn = DataSourceUtilsBase.getDBServernameTablename(foreignDataSource); if (stn != null) { return getRootObject().getServer(stn[0]); } ITable foreignTable = getForeignTable(); if (foreignTable != null) { return getRootObject().getServer(foreignTable.getServerName()); } return null; } public boolean isUsableInSort() { if (!isUsableInSearch()) { return false; } if (getJoinType() != ISQLJoin.INNER_JOIN) { // outer joins icw or-null modifiers do not work (oracle) or looses outer join (ansi) for (int operator : getOperators()) { if ((operator & IBaseSQLCondition.ORNULL_MODIFIER) != 0) { return false; } } } return true; } public boolean isUsableInSearch() { return isValid() && !isMultiServer() && !isGlobal(); } public boolean isMultiServer() { String primaryServerName = getPrimaryServerName(); return (primaryServerName == null || !primaryServerName.equals(getForeignServerName())); } //creates real object relations also does some checks private void makePrimaryDataProviders(IDataProviderHandler dataProviderHandler) throws RepositoryException { if (primary != null) return; List<IPersist> allobjects = getAllObjectsAsList(); IDataProvider[] p = new IDataProvider[allobjects.size()]; Table pt = null; RepositoryException exception = null; for (int pos = 0; pos < allobjects.size(); pos++) { RelationItem ri = (RelationItem)allobjects.get(pos); String pdp = ri.getPrimaryDataProviderID(); if (ScopesUtils.isVariableScope(pdp)) { IDataProvider pc = dataProviderHandler.getGlobalDataProvider(pdp); if (pc != null) { p[pos] = pc; } else if (exception == null) { exception = new RepositoryException(Messages.getString("servoy.relation.error.dataproviderDoesntExist", //$NON-NLS-1$ new Object[] { ri.getPrimaryDataProviderID(), ri.getForeignColumnName(), getName() })); } } else if (pdp != null && pdp.startsWith(LiteralDataprovider.LITERAL_PREFIX)) { p[pos] = new LiteralDataprovider(pdp); } else { if (pt == null) { pt = getPrimaryTable(); } if (pt != null) { IDataProvider pc = dataProviderHandler.getDataProviderForTable(pt, pdp); if (pc != null) { p[pos] = pc; } else if (exception == null) { exception = new RepositoryException(Messages.getString("servoy.relation.error.dataproviderDoesntExist", //$NON-NLS-1$ new Object[] { ri.getPrimaryDataProviderID(), ri.getForeignColumnName(), getName() })); } } else if (exception == null) { exception = new RepositoryException( Messages.getString("servoy.relation.error.tableDoesntExist", new Object[] { getPrimaryTableName(), getForeignTableName(), getName() })); //$NON-NLS-1$ } } } primary = p; if (exception != null) { valid = Boolean.FALSE; throw exception; } } private void makeForeignColumns() throws RepositoryException { if (foreign != null) return; List<IPersist> allobjects = getAllObjectsAsList(); Column[] f = new Column[allobjects.size()]; Table ft = null; RepositoryException exception = null; for (int pos = 0; pos < allobjects.size(); pos++) { RelationItem ri = (RelationItem)allobjects.get(pos); if (ft == null) { ft = getTable(getForeignDataSource()); } if (ft != null) { Column fc = ft.getColumn(ri.getForeignColumnName()); if (fc != null) { f[pos] = fc; } else { if (exception == null) exception = new RepositoryException(Messages.getString("servoy.relation.error.dataproviderDoesntExist", //$NON-NLS-1$ new Object[] { ri.getPrimaryDataProviderID(), ri.getForeignColumnName(), getName() })); } } else { if (exception == null) exception = new RepositoryException(Messages.getString("servoy.relation.error.tableDoesntExist", //$NON-NLS-1$ new Object[] { getPrimaryTableName(), getForeignTableName(), getName() })); } } foreign = f; if (exception != null) { valid = Boolean.FALSE; throw exception; } } public boolean isValid() { if (valid == null && getForeignDataSource() != null) { try { IServer server = getForeignServer(); valid = Boolean.valueOf(server != null && server.isValid() && getForeignTable() != null); } catch (Exception e) { valid = Boolean.FALSE; } } // default to true return valid == null || valid.booleanValue(); } public Boolean valid = null; public void setValid(boolean b) { if (b) //clear so they are checked again { flushCashedItems(); } valid = Boolean.valueOf(b); } public void flushCashedItems() { primary = null; foreign = null; operators = null; isGlobal = null; usedScopes = null; isLiteral = null; valid = null; } public int[] getOperators() { if (operators == null) { List<IPersist> allobjects = getAllObjectsAsList(); int size = 0; if (primary != null) { size = primary.length; } else { size = allobjects.size(); } operators = new int[size]; if (allobjects != null) { for (int pos = 0; pos < allobjects.size(); pos++) { RelationItem ri = (RelationItem)allobjects.get(pos); operators[pos] = ri.getOperator(); } } } return operators; } public boolean isParentRef() { String primaryDataSource = getPrimaryDataSource(); return primaryDataSource != null && primaryDataSource.equals(getForeignDataSource()) && getAllObjectsAsList().size() == 0; } /** * Does the relation always relate to the same record? * * @return true if the relation is a FK->PK relation on the same data source. * @throws RepositoryException */ public boolean isExactPKRef(IDataProviderHandler dataProviderHandler) throws RepositoryException { String primaryDataSource = getPrimaryDataSource(); return primaryDataSource != null && primaryDataSource.equals(getForeignDataSource()) // same data source && isFKPKRef() // FK to itself && Arrays.equals(getPrimaryDataProviders(dataProviderHandler), getForeignColumns()); } /** * Does the relation define a FK->PK relation? * * @throws RepositoryException */ public boolean isFKPKRef() throws RepositoryException { getForeignColumns(); if (foreign == null || foreign.length == 0) { return false; } getOperators(); for (int element : operators) { if (element != IBaseSQLCondition.EQUALS_OPERATOR) { return false; } } return Arrays.equals(foreign[0].getTable().getRowIdentColumns().toArray(), foreign); } public String checkKeyTypes(IDataProviderHandler dataProviderHandler) throws RepositoryException { if (primary == null) { //make sure they are loaded getPrimaryDataProviders(dataProviderHandler); getForeignColumns(); } if (primary != null && foreign != null) { for (int i = 0; i < primary.length; i++) { if (primary[i] == null || foreign[i] == null) { return Messages.getString("servoy.relation.error"); //$NON-NLS-1$ } if (primary[i] instanceof LiteralDataprovider) { Object value = ((LiteralDataprovider)primary[i]).getValue(foreign[i].getDataProviderType()); try { if (value != null) { Column.getAsRightType(foreign[i].getDataProviderType(), foreign[i].getFlags(), value, foreign[i].getLength(), true); continue; } } catch (Exception e) { } return Messages.getString("servoy.relation.error.literalInvalidForColumn", //$NON-NLS-1$ new Object[] { ((LiteralDataprovider)primary[i]).getLiteral(), foreign[i].getDataProviderID() }); } int primaryType = Column.mapToDefaultType(primary[i].getDataProviderType()); int foreignType = Column.mapToDefaultType(foreign[i].getDataProviderType()); if (primaryType == IColumnTypes.INTEGER && foreignType == IColumnTypes.NUMBER) { continue; //allow integer to number mappings } if (primaryType == IColumnTypes.NUMBER && foreignType == IColumnTypes.INTEGER) { continue; //allow number to integer mappings } if (foreignType == IColumnTypes.INTEGER && primary[i] instanceof AbstractBase && "Boolean".equals(((AbstractBase)primary[i]).getSerializableRuntimeProperty(IScriptProvider.TYPE))) //$NON-NLS-1$ { continue; //allow boolean var to number mappings } if (primaryType != foreignType) { return Messages.getString("servoy.relation.error.typeDoesntMatch", //$NON-NLS-1$ new Object[] { primary[i].getDataProviderID(), foreign[i].getDataProviderID() }); } } } return null; } private transient Boolean isGlobal; private transient Boolean isLiteral; public boolean isGlobal() { if (isGlobal == null) { isGlobal = Boolean.valueOf(isGlobalEx()); } return isGlobal.booleanValue(); } /** * @return true if entirely global */ private boolean isGlobalEx() { if (!isValid()) return false;//don't know List<IPersist> allobjects = getAllObjectsAsList(); if (allobjects.size() == 0) return false; for (IPersist ri : allobjects) { String primaryDataProviderID = ((RelationItem)ri).getPrimaryDataProviderID(); if (primaryDataProviderID != null) { if (!ScopesUtils.isVariableScope(primaryDataProviderID) && !primaryDataProviderID.startsWith(LiteralDataprovider.LITERAL_PREFIX)) { return false; } } else { Debug.error("Relation '" + getName() + "' has NULL primary dataprovider in a relation item. Solution: " + getRootObject()); //$NON-NLS-1$//$NON-NLS-2$ throw new NullPointerException(); } } return true; } public boolean isLiteral() { if (isLiteral == null) { isLiteral = Boolean.valueOf(isLiteralEx()); } return isLiteral.booleanValue(); } private boolean isLiteralEx() { if (!isValid()) return false;//don't know List<IPersist> allobjects = getAllObjectsAsList(); if (allobjects.size() == 0) return false; for (IPersist ri : allobjects) { String primaryDataProviderID = ((RelationItem)ri).getPrimaryDataProviderID(); if (!primaryDataProviderID.startsWith(LiteralDataprovider.LITERAL_PREFIX)) { return false; } } return true; } public boolean isInternal() { String name = getName(); return name != null && name.startsWith(INTERNAL_PREFIX); } private transient Set<String> usedScopes; public boolean usesScope(String scopeName) { if (!isGlobal()) { // scopes are only for global relations return false; } Set<String> tmp = usedScopes; if (tmp == null) { List<IPersist> allobjects = getAllObjectsAsList(); if (allobjects.size() == 0) return false; tmp = new HashSet<String>(); for (IPersist ri : allobjects) { Pair<String, String> scope = ScopesUtils.getVariableScope(((RelationItem)ri).getPrimaryDataProviderID()); if (scope.getLeft() != null) { tmp.add(scope.getLeft()); } } usedScopes = tmp; } return tmp.contains(scopeName); } public String toHTML() { StringBuilder sb = new StringBuilder(); sb.append("<html>Name(solution): <b>"); //$NON-NLS-1$ sb.append(getName()); sb.append(" ("); //$NON-NLS-1$ sb.append(getRootObject().getName()); sb.append(')'); if (isGlobal()) { sb.append("</b><br>Global relation <b>"); //$NON-NLS-1$ } sb.append("</b><br><br>From: <b>"); //$NON-NLS-1$ sb.append(getPrimaryServerName()); sb.append(" - "); //$NON-NLS-1$ sb.append(getPrimaryTableName()); sb.append("</b><br>To: <b>"); //$NON-NLS-1$ sb.append(getForeignServerName()); sb.append(" - "); //$NON-NLS-1$ sb.append(getForeignTableName()); sb.append("</b><br>"); //$NON-NLS-1$ sb.append("<br>"); //$NON-NLS-1$ List<IPersist> allobjects = getAllObjectsAsList(); int size = allobjects.size(); for (int i = 0; i < size; i++) { RelationItem ri = (RelationItem)allobjects.get(i); sb.append(ri.getPrimaryDataProviderID()); sb.append(" <font color=\"red\">"); //$NON-NLS-1$ sb.append(RelationItem.getOperatorAsString(ri.getOperator()).replaceAll("<", "<")); //$NON-NLS-1$ //$NON-NLS-2$ sb.append("</font> "); //$NON-NLS-1$ sb.append(ri.getForeignColumnName()); if (i < size - 1) sb.append("<br>"); //$NON-NLS-1$ } sb.append("</html>"); //$NON-NLS-1$ return sb.toString(); } /** * The join type that is performed between the primary table and the foreign table. * Can be "inner join" or "left outer join". */ public int getJoinType() { return getTypedProperty(StaticContentSpecLoader.PROPERTY_JOINTYPE).intValue(); } public void setJoinType(int JoinType) { setTypedProperty(StaticContentSpecLoader.PROPERTY_JOINTYPE, JoinType); } @Override public void setEncapsulation(int arg) { int newAccess = arg; int access = getEncapsulation(); if ((newAccess & PersistEncapsulation.MODULE_SCOPE) == PersistEncapsulation.MODULE_SCOPE && (newAccess & PersistEncapsulation.HIDE_IN_SCRIPTING_MODULE_SCOPE) == PersistEncapsulation.HIDE_IN_SCRIPTING_MODULE_SCOPE) { if ((access & PersistEncapsulation.MODULE_SCOPE) == PersistEncapsulation.MODULE_SCOPE) newAccess = newAccess ^ PersistEncapsulation.MODULE_SCOPE; else newAccess = newAccess ^ PersistEncapsulation.HIDE_IN_SCRIPTING_MODULE_SCOPE; } setTypedProperty(StaticContentSpecLoader.PROPERTY_ENCAPSULATION, newAccess); } /** * The encapsulation mode of this Relation. The following can be used/checked: * * - Public (not a separate option - if none of the below options are selected) * - Hide in scripting; Module Scope - not available in scripting from any other context except the form itself. Available in designer for the same module. * - Module Scope - available in both scripting and designer but only in the same module. * * @return the encapsulation mode/level of the persist. */ @Override public int getEncapsulation() { return getTypedProperty(StaticContentSpecLoader.PROPERTY_ENCAPSULATION).intValue(); } /* * @see com.servoy.j2db.persistence.ISupportDeprecated#getDeprecated() */ @Override public String getDeprecated() { return getTypedProperty(StaticContentSpecLoader.PROPERTY_DEPRECATED); } /* * @see com.servoy.j2db.persistence.ISupportDeprecated#setDeprecated(String) */ @Override public void setDeprecated(String deprecatedInfo) { setTypedProperty(StaticContentSpecLoader.PROPERTY_DEPRECATED, "".equals(deprecatedInfo) ? null : deprecatedInfo); } }