/*
* JBoss, Home of Professional Open Source.
*
* See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
*
* See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
*/
package org.teiid.designer.jdbc.metadata.impl;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.teiid.core.designer.util.CoreArgCheck;
import org.teiid.designer.jdbc.JdbcImportSettings;
import org.teiid.designer.jdbc.metadata.JdbcNode;
/**
* JdbcNodeSelections
*
* @since 8.0
*/
public class JdbcNodeSelections {
public static final int SELECTED = JdbcNode.SELECTED;
public static final int UNSELECTED = JdbcNode.UNSELECTED;
public static final int PARTIALLY_SELECTED = JdbcNode.PARTIALLY_SELECTED;
public static final int UNKNOWN = -1;
private final Set selecteds;
private final Set unselecteds;
private final Set partiallySelected;
/**
* Construct an instance of JdbcNodeSelections.
*
*/
public JdbcNodeSelections() {
super();
this.selecteds = new HashSet();
this.unselecteds = new HashSet();
this.partiallySelected = new HashSet();
}
/**
* Initialize the node selections with the supplied settings, which record
* the included catalogs and schemas and excluded leaf nodes.
* <p>
* This method follows the following logic:
* <ol>
* <li>Step 1: First go through all the excluded leaf nodes. If a leaf node is excluded,
* then there is at least one sibling that is selected, and the parent is
* thus known to be partially selected.</li>
* <li>Step 2: Go through the included schemas and catalogs. Any schema or catalog
* that is included but that has not yet been marked as partially
* selected means that there were no <i>excluded</i> nodes below that
* schema/catalog, so the schema/catalog is completely selected.</li>
* </ol>
* </p>
* @param settings the settings; may not be null
*/
public void initialize( final JdbcImportSettings settings ) {
CoreArgCheck.isNotNull(settings);
//-------------------------------------------------------------------------
// Step 1: Go through the excluded objects
//-------------------------------------------------------------------------
final Iterator iter = settings.getExcludedObjectPaths().iterator();
while (iter.hasNext()) {
final String pathStr = (String)iter.next();
IPath path = new Path(pathStr);
this.unselecteds.add(path);
// Go up the path and add all ancestors as partially selected
while ( path.segmentCount() > 1 ) {
final IPath parentPath = path.removeLastSegments(1);
this.partiallySelected.add(parentPath);
path = parentPath;
}
}
//-------------------------------------------------------------------------
// Step 2: Go through the included schemas and catalogs
//-------------------------------------------------------------------------
// Note that if a database has both schemas and catalogs, then the schemas
// should be below the catalogs. Consequently, in that case, we only want
// to mark the schemas (and not mark any catalogs above those schemas).
// When those schema nodes are materialized, they will get their correct
// selection mode, and they will cause the selection mode of their parent
// catalog to be property calculated.
final Set ignoreCatalogsAboveSchemas = new HashSet();
final Iterator schemaIter = settings.getIncludedSchemaPaths().iterator();
while (schemaIter.hasNext()) {
final String pathStr = (String)schemaIter.next();
final IPath path = new Path(pathStr);
// See if the path is already partially selected
if ( !this.partiallySelected.contains(path) ) {
// it is not, so that means the whole schema was selected ...
this.selecteds.add(path);
// and plan to ignore anything above the selected schema ...
IPath tempPath = path;
while ( tempPath.segmentCount() > 1 ) {
tempPath = tempPath.removeLastSegments(1);
ignoreCatalogsAboveSchemas.add(tempPath);
}
}
}
final Iterator catalogIter = settings.getIncludedCatalogPaths().iterator();
while (catalogIter.hasNext()) {
final String pathStr = (String)catalogIter.next();
final IPath path = new Path(pathStr);
// Ignore any catalog that was above a SELECTED schema ...
if ( ignoreCatalogsAboveSchemas.contains(path) ) {
// This catalog is above a SELECTED schema, so mark it as partially selected ...
this.partiallySelected.add(path);
continue; // skip this one
}
// See if the path is already partially selected
if ( !this.partiallySelected.contains(path) ) {
// it is not, so that means the whole schema was selected ...
this.selecteds.add(path);
}
}
}
/**
* Return whether there are any paths that are known to be selected, unselected or partially selected.
* @return true if there are at least some paths known to be selected, unselected or partially selected,
* or false if there no known selection modes for any path
*/
public boolean hasSelectionModes() {
return this.selecteds.size() != 0 || this.partiallySelected.size() != 0 || this.unselecteds.size() != 0;
}
public int getSelectionMode( final IPath path ) {
CoreArgCheck.isNotNull(path);
if ( this.selecteds.contains(path) ) {
return SELECTED;
}
if ( this.unselecteds.contains(path) ) {
return UNSELECTED;
}
if ( this.partiallySelected.contains(path) ) {
return PARTIALLY_SELECTED;
}
// -------------------------------------------------------------------
// The path is not known. However, the "default" can be determined by
// looking at the ancestors.
// -------------------------------------------------------------------
// If this is the JdbcDatabase path ...
if ( path.segmentCount() == 0 ) {
// The default for the JdbcDatabase path should be to be PARTIALLY_SELECTED
// so that children are figured out
this.unselecteds.add(path);
return UNSELECTED;
}
// If this path is for a root object ...
if ( path.segmentCount() == 1 ) {
// so the default should be to be UNSELECTED
this.unselecteds.add(path);
return UNSELECTED;
}
// Get the parent path and see what it's selection mode is ...
final IPath parentPath = path.removeLastSegments(1);
final int parentMode = getSelectionMode(parentPath); // recursive!!!
if ( parentMode == SELECTED ) {
// The parent is fully selected, so should this node ...
this.selecteds.add(path);
return SELECTED;
}
if ( parentMode == PARTIALLY_SELECTED ) {
// The parent is partially selected, so we don't know what to assume
return UNKNOWN;
// // The parent is partially selected, so we'll assume nodes underneath a partially-selected
// // node should be fully selected
// this.selecteds.add(path);
// return SELECTED;
}
// Parent is unselected, so this node should be as well ...
return UNSELECTED;
}
public void setSelected( final IPath path, final int selectionMode ) {
CoreArgCheck.isNotNull(path);
if ( selectionMode == SELECTED ) {
this.selecteds.add(path);
this.unselecteds.remove(path);
this.partiallySelected.remove(path);
} else if ( selectionMode == UNSELECTED ) {
this.selecteds.remove(path);
this.unselecteds.add(path);
this.partiallySelected.remove(path);
} else if ( selectionMode == PARTIALLY_SELECTED ) {
this.selecteds.remove(path);
this.unselecteds.remove(path);
this.partiallySelected.add(path);
}
}
}