/*******************************************************************************
* Copyright (c) 2004, 2010 BREDEX GmbH.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* BREDEX GmbH - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.jubula.client.core.businessprocess;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.PersistenceException;
import javax.persistence.Query;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jubula.client.core.businessprocess.db.TestSuiteBP;
import org.eclipse.jubula.client.core.i18n.Messages;
import org.eclipse.jubula.client.core.model.IAUTMainPO;
import org.eclipse.jubula.client.core.model.ICapPO;
import org.eclipse.jubula.client.core.model.ICategoryPO;
import org.eclipse.jubula.client.core.model.IExecTestCasePO;
import org.eclipse.jubula.client.core.model.INodePO;
import org.eclipse.jubula.client.core.model.IProjectPO;
import org.eclipse.jubula.client.core.model.IReusedProjectPO;
import org.eclipse.jubula.client.core.model.ISpecTestCasePO;
import org.eclipse.jubula.client.core.model.IUsedToolkitPO;
import org.eclipse.jubula.client.core.model.PoMaker;
import org.eclipse.jubula.client.core.persistence.GeneralStorage;
import org.eclipse.jubula.client.core.persistence.NodePM;
import org.eclipse.jubula.client.core.persistence.PMException;
import org.eclipse.jubula.client.core.persistence.PersistenceManager;
import org.eclipse.jubula.client.core.persistence.Persistor;
import org.eclipse.jubula.client.core.persistence.ProjectPM;
import org.eclipse.jubula.client.core.utils.AbstractNonPostOperatingTreeNodeOperation;
import org.eclipse.jubula.client.core.utils.ITreeNodeOperation;
import org.eclipse.jubula.client.core.utils.ITreeTraverserContext;
import org.eclipse.jubula.client.core.utils.SpecTreeTraverser;
import org.eclipse.jubula.client.core.utils.TreeTraverser;
import org.eclipse.jubula.toolkit.common.utils.ToolkitUtils;
import org.eclipse.jubula.toolkit.common.xml.businessprocess.ComponentBuilder;
import org.eclipse.jubula.tools.internal.constants.StringConstants;
import org.eclipse.jubula.tools.internal.constants.ToolkitConstants;
import org.eclipse.jubula.tools.internal.exception.JBException;
import org.eclipse.jubula.tools.internal.exception.ProjectDeletedException;
import org.eclipse.jubula.tools.internal.messagehandling.MessageIDs;
import org.eclipse.jubula.tools.internal.xml.businessmodell.CompSystem;
import org.eclipse.jubula.tools.internal.xml.businessmodell.Component;
import org.eclipse.jubula.tools.internal.xml.businessmodell.ToolkitDescriptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Business processes for the used toolkits information.
*
* @author BREDEX GmbH
* @created 25.05.2007
*/
public class UsedToolkitBP {
/** standard logging */
private static Logger log = LoggerFactory.getLogger(UsedToolkitBP.class);
/**
* The singleton instance.
*/
private static UsedToolkitBP instance = null;
/**
* The Set of used Toolkits.
*/
private Set<IUsedToolkitPO> m_usedToolkits = new HashSet<IUsedToolkitPO>();
/**
* private utility constructor
*/
private UsedToolkitBP() {
// private
}
/**
* Adds the used toolkits of the given {@link ISpecTestCasePO} to the list
* of used toolkits.
* @param specTC The {@link ISpecTestCasePO} whose toolkits are to add.
* @param project the project of the {@link ISpecTestCasePO}
* @throws PMException in case of DB error.
* @throws ProjectDeletedException if the project was deleted in another
* session.
*/
public void addToolkit(ISpecTestCasePO specTC, IProjectPO project)
throws PMException, ProjectDeletedException {
final Iterator<INodePO> childs = specTC.getAllNodeIter();
final Set<IUsedToolkitPO> addedToolkits =
new HashSet<IUsedToolkitPO>();
final Set<IUsedToolkitPO> currentToolkits =
readUsedToolkitsFromDB(project);
while (childs.hasNext()) {
INodePO child = childs.next();
if (child instanceof ICapPO) {
IUsedToolkitPO usedToolkit = addToolkit((ICapPO)child, project);
if (usedToolkit != null
&& !currentToolkits.contains(usedToolkit)) {
addedToolkits.add(usedToolkit);
}
}
}
insertIntoDB(addedToolkits);
}
/**
* Adds the toolkit of the given {@link ICapPO} to the internal Set of
* used toolkits.
* @param capPO A {@link ICapPO}.
* @param project the project depending to the given {@link ICapPO}.
* @return A new used IUsedToolkitPO or null if the toolkit was already used.
*/
private IUsedToolkitPO addToolkit(ICapPO capPO, IProjectPO project) {
final String compType = capPO.getComponentType();
final CompSystem compSystem = ComponentBuilder.getInstance()
.getCompSystem();
final Component component = compSystem.findComponent(compType);
final ToolkitDescriptor descr = component.getToolkitDesriptor();
final Long projectID = project.getId();
final IUsedToolkitPO usedToolkit = PoMaker.createUsedToolkitsPO(
descr.getToolkitID(),
descr.getMajorVersion(),
descr.getMinorVersion(),
projectID);
final boolean isAdded = m_usedToolkits.add(usedToolkit);
if (isAdded) {
return usedToolkit;
}
return null;
}
/**
* Inserts the given List of used toolkits into the DB.
*
* @param usedToolkits
* the used toolkits to insert into DB.
* @throws PMException
* in case of DB error.
* @throws ProjectDeletedException
* if the project was deleted in another session.
*/
private void insertIntoDB(Set<IUsedToolkitPO> usedToolkits)
throws PMException, ProjectDeletedException {
if (usedToolkits.isEmpty()) {
return;
}
final EntityManager session = Persistor.instance().openSession();
IUsedToolkitPO currToolkit = null;
try {
final EntityTransaction tx =
Persistor.instance().getTransaction(session);
for (IUsedToolkitPO toolkit : usedToolkits) {
currToolkit = toolkit;
session.persist(toolkit);
}
Persistor.instance().commitTransaction(session, tx);
} catch (PersistenceException e) {
PersistenceManager.handleDBExceptionForAnySession(currToolkit,
e, session);
} finally {
Persistor.instance().dropSession(session);
}
}
/**
* Gets all used toolkits of the given Project from the DB.
* @param project the current Project.
* @return set of used toolkits
* @throws PMException in case of DB error.
*/
@SuppressWarnings("unchecked")
public synchronized Set<IUsedToolkitPO> readUsedToolkitsFromDB(
IProjectPO project) throws PMException {
if (project == null) {
m_usedToolkits = new HashSet<IUsedToolkitPO>(0);
return new HashSet<IUsedToolkitPO>(m_usedToolkits);
}
final EntityManager session = Persistor.instance().openSession();
try {
final Query q = session.createQuery(
"select USEDTOOLKITS from UsedToolkitPO as USEDTOOLKITS where USEDTOOLKITS.hbmParentProjectId = :projectID"); //$NON-NLS-1$
q.setParameter("projectID", project.getId()); //$NON-NLS-1$
final List<IUsedToolkitPO> toolkits = q.getResultList();
m_usedToolkits = new HashSet<IUsedToolkitPO>(toolkits);
} catch (PersistenceException e) {
PersistenceManager.handleDBExceptionForAnySession(null, e, session);
} finally {
Persistor.instance().dropSessionWithoutLockRelease(session);
}
return new HashSet<IUsedToolkitPO>(m_usedToolkits);
}
/**
* Refreshes the ToolkitInfo of the given Project.<br>
* <b>Note: This is an expensive operation!</b><br>
* @param project the Project
*/
public void refreshToolkitInfo(final IProjectPO project)
throws PMException, ProjectDeletedException {
refreshToolkitInfo(project, null);
}
/**
* Refreshes the ToolkitInfo of the given Project.<br>
* <b>Note: This is an expensive operation!</b><br>
* @param project the Project
* @param monitor The progress monitor for this operation.
* <code>null</code> is allowed, and indicates that
* there is no need to check for cancelation or report
* progress.
*/
public void refreshToolkitInfo(final IProjectPO project,
final IProgressMonitor monitor)
throws PMException, ProjectDeletedException {
EntityManager s = Persistor.instance().openSession();
try {
deleteToolkitsFromDB(s, project.getId(), true);
} finally {
Persistor.instance().dropSession(s);
}
m_usedToolkits.clear();
final ITreeNodeOperation<INodePO> addToolkitOP =
new AbstractNonPostOperatingTreeNodeOperation<INodePO>() {
@SuppressWarnings("synthetic-access")
public boolean operate(ITreeTraverserContext<INodePO> ctx,
INodePO parent, INodePO node, boolean alreadyVisited) {
if (node instanceof ICapPO) {
if (monitor != null && monitor.isCanceled()) {
ctx.setContinued(false);
return true;
}
addToolkit((ICapPO)node, project);
}
return true;
}
};
SpecTreeTraverser traverser = new SpecTreeTraverser(project,
addToolkitOP);
traverser.traverse();
if (monitor != null && monitor.isCanceled()) {
return;
}
insertIntoDB(m_usedToolkits);
}
/**
*
* @param s session to use for delete operation
* @param parentProjectId id of root project
* @param commit flag for commitment of delete statement
* @throws PMException in case of failed delete statement
*/
public void deleteToolkitsFromDB(EntityManager s, Long parentProjectId,
boolean commit) throws PMException, ProjectDeletedException {
try {
if (commit) {
EntityTransaction tx = Persistor
.instance().getTransaction(s);
executeDeleteStatement(s, parentProjectId);
Persistor.instance().commitTransaction(s, tx);
} else {
executeDeleteStatement(s, parentProjectId);
}
} catch (PersistenceException e) {
String msg = Messages.DeletionOfToolkitsFailed
+ StringConstants.DOT;
log.error(msg, e);
throw new PMException(msg, MessageIDs.E_DB_SAVE);
}
}
/**
* @param s session to use
* @param parentProjectId id of parent project
*/
private synchronized void executeDeleteStatement(
EntityManager s, Long parentProjectId) {
Query q = s.createQuery(
"delete from UsedToolkitPO u where u.hbmParentProjectId = :parentProjId"); //$NON-NLS-1$
q.setParameter("parentProjId", parentProjectId); //$NON-NLS-1$
q.executeUpdate();
}
/**
* @return the singleton instance
*/
public static UsedToolkitBP getInstance() {
if (instance == null) {
instance = new UsedToolkitBP();
}
return instance;
}
/**
* @return A Set of currently used toolkits.
*/
public Set<IUsedToolkitPO> getUsedToolkits() {
return new HashSet<IUsedToolkitPO>(m_usedToolkits);
}
/**
* Gets the toolkit level of the given node.
* @param node an InodePO
* @return the toolkit level.
*/
public String getToolkitLevel(INodePO node) {
// FIXME (AT) : Aufteilen fuer TC- und TS-Browser!!!
String level = ToolkitConstants.LEVEL_ABSTRACT;
node.setToolkitLevel(ToolkitConstants.LEVEL_ABSTRACT);
if (node instanceof ICapPO) {
ICapPO cap = (ICapPO)node;
final String compType = cap.getComponentType();
final Component comp = ComponentBuilder.getInstance()
.getCompSystem().findComponent(compType);
level = comp.getToolkitDesriptor().getLevel();
node.setToolkitLevel(level);
return level;
}
Iterator< ? extends INodePO> iter = node.getNodeListIterator();
if (node instanceof IProjectPO) {
iter = TestSuiteBP.getListOfTestSuites().iterator();
}
String mainLevel = ToolkitConstants.LEVEL_ABSTRACT;
while (iter.hasNext()) {
level = getToolkitLevel(iter.next());
if (ToolkitUtils.isToolkitMoreConcrete(level, mainLevel)) {
mainLevel = level;
}
}
node.setToolkitLevel(mainLevel);
return mainLevel;
}
/**
* Updates the toolkit level in the hierarchy.
* @param node the changed node.
* @param oldLevel the old toolkit level of the given node.
*/
public void updateToolkitLevel(INodePO node, String oldLevel) {
String oldTkLevel = oldLevel;
final String newLevel = getToolkitLevel(node);
if (oldTkLevel.length() == 0) {
oldTkLevel = newLevel;
}
if (newLevel.equals(oldTkLevel)) {
return;
}
final boolean moreConcrete = ToolkitUtils.isToolkitMoreConcrete(
newLevel, oldTkLevel);
if (node instanceof ISpecTestCasePO) {
ISpecTestCasePO specTC = (ISpecTestCasePO)node;
final List<IExecTestCasePO> execs =
NodePM.getInternalExecTestCases(specTC.getGuid(),
specTC.getParentProjectId());
for (IExecTestCasePO exec : execs) {
final INodePO execParent = exec.getSpecAncestor();
final String parentLevel = execParent.getToolkitLevel();
if (ToolkitUtils.isToolkitMoreConcrete(parentLevel, oldTkLevel)
|| (!moreConcrete && existsCapWithLevel(oldTkLevel,
execParent))) {
continue;
}
final String oldLev = execParent.getToolkitLevel();
execParent.setToolkitLevel(newLevel);
updateToolkitLevel(execParent, oldLev);
}
}
INodePO parent = node.getParentNode();
if (parent instanceof ICategoryPO) {
parent = parent.getParentNode();
while ((parent instanceof ICategoryPO) && parent != null) {
parent = parent.getParentNode();
}
}
if (parent == null) {
parent = GeneralStorage.getInstance().getProject();
}
if (parent == null) {
return;
}
final String parentLevel = parent.getToolkitLevel();
if (moreConcrete) {
if (parentLevel.equals(newLevel) || ToolkitUtils
.isToolkitMoreConcrete(parentLevel, newLevel)) {
return;
}
} else if (existsCapWithLevel(oldTkLevel, parent)) {
return;
}
parent.setToolkitLevel(newLevel);
if (parent.getParentNode() == null) {
return;
}
updateToolkitLevel(parent.getParentNode(), parentLevel);
}
/**
* Checks if there are version conflicts of the toolkit plugins.
* @param usedToolkits toolkits used in given project
* @return A List of {@link ToolkitPluginError.ERROR}, or an empty List
* if there are no errors.
*/
public List<ToolkitPluginError> checkUsedToolkitPluginVersions(
Set<IUsedToolkitPO> usedToolkits) {
final List<ToolkitPluginError> errors =
new ArrayList<ToolkitPluginError>(0);
final List<ToolkitDescriptor> toolkitPluginDescriptors =
ComponentBuilder.getInstance().getCompSystem()
.getAllToolkitDescriptors();
for (IUsedToolkitPO usedTk : usedToolkits) {
final int usedTkMajVers = usedTk.getMajorVersion();
final int usedTkMinVers = usedTk.getMinorVersion();
for (ToolkitDescriptor plDescr : toolkitPluginDescriptors) {
if (usedTk.getToolkitId().equals(plDescr.getToolkitID())) {
final int pluginMajVers = plDescr.getMajorVersion();
final int pluginMinVers = plDescr.getMinorVersion();
if (usedTkMajVers != pluginMajVers) {
errors.add(new ToolkitPluginError(
ToolkitPluginError.ERROR.MAJOR_VERSION_ERROR,
usedTk.getToolkitId(), pluginMajVers,
usedTkMajVers));
}
if (usedTkMinVers < pluginMinVers) {
errors.add(new ToolkitPluginError(
ToolkitPluginError.ERROR.MINOR_VERSION_LOWER,
usedTk.getToolkitId(), pluginMinVers,
usedTkMinVers));
}
if (usedTkMinVers > pluginMinVers) {
errors.add(new ToolkitPluginError(
ToolkitPluginError.ERROR.MINOR_VERSION_HIGHER,
usedTk.getToolkitId(), pluginMinVers,
usedTkMinVers));
}
}
}
}
return errors;
}
/**
* @author BREDEX GmbH
* @created 31.07.2007
*/
public static class ToolkitPluginError {
/**
* The errors.
*/
public static enum ERROR {
/***/
MAJOR_VERSION_ERROR,
/***/
MINOR_VERSION_LOWER,
/***/
MINOR_VERSION_HIGHER
}
/**
* The error.
*/
private ToolkitPluginError.ERROR m_error = null;
/**
* The id of the toolkit.
*/
private String m_toolkitId = null;
/**
* The version of the toolkit.
*/
private int m_pluginToolkitVersion = 0;
/**
* The version of the used plugin.
*/
private int m_usedToolkitVerison = 0;
/**
* Constructor.
* @param error the error.
* @param toolkitId the id of the toolkit.
* @param pluginToolkitVersion the version of the plugin.
* @param usedToolkitVerison the version of the used toolkit.
*/
public ToolkitPluginError(ToolkitPluginError.ERROR error,
String toolkitId, int pluginToolkitVersion,
int usedToolkitVerison) {
m_error = error;
m_toolkitId = toolkitId;
m_pluginToolkitVersion = pluginToolkitVersion;
m_usedToolkitVerison = usedToolkitVerison;
}
/**
* @return the error.
*/
public ToolkitPluginError.ERROR getError() {
return m_error;
}
/**
* @return the version of the plugin.
*/
public int getPluginToolkitVersion() {
return m_pluginToolkitVersion;
}
/**
* @return the version of the used toolkit.
*/
public int getUsedToolkitVerison() {
return m_usedToolkitVerison;
}
/**
* @return the id of the toolkit.
*/
public String getToolkitId() {
return m_toolkitId;
}
}
/**
* Checks, if a Cap with the given toolkit level exists under the given
* root.
* @param level the level to check.
* @param root the root
* @return true if a cap with the given toolkit level exists,
* false otherwise.
*/
private boolean existsCapWithLevel(final String level, INodePO root) {
/**
* Helper class to get the result out of the ITreeNodeOperation.
*/
final class BooleanHolder {
private boolean m_bool = false;
/**
* @return the boolean
*/
public boolean getBool() {
return m_bool;
}
/**
* @param bool a boolean
*/
public void setBool(boolean bool) {
m_bool = bool;
}
}
final BooleanHolder treeOpResult = new BooleanHolder();
final ITreeNodeOperation<INodePO> levelSearchOp =
new AbstractNonPostOperatingTreeNodeOperation<INodePO>() {
public boolean operate(
ITreeTraverserContext<INodePO> ctx, INodePO parent,
INodePO node, boolean alreadyVisited) {
if (node instanceof ICapPO) {
final ICapPO cap = (ICapPO)node;
if (level.equals(cap.getToolkitLevel())) {
treeOpResult.setBool(true);
ctx.setContinued(false);
}
}
return true;
}
};
final TreeTraverser traverser = new SpecTreeTraverser(root,
levelSearchOp);
traverser.traverse();
return treeOpResult.getBool();
}
/**
* Calculates and returns the path from the root node of the toolkit
* hierarchy to the node representing the given toolkit. For example:
*
* Swing inherits from Concrete; Concrete inherits from Abstract.
* Abstract is the root of the toolkit hierarchy.
*
* The path for Swing would be [Abstract, Concrete, Swing].
*
* @param toolkit The toolkit for which to find the path to the root
* toolkit.
* @return the tree path for the given toolkit.
*/
private List<ToolkitDescriptor> getPathToRoot(
ToolkitDescriptor toolkit) {
List<ToolkitDescriptor> path =
new LinkedList<ToolkitDescriptor>();
ToolkitDescriptor currentToolkit = toolkit;
while (currentToolkit != null) {
path.add(0, currentToolkit);
ToolkitDescriptor included =
ComponentBuilder.getInstance().getCompSystem()
.getToolkitDescriptor(currentToolkit.getIncludes());
currentToolkit = included != null ? included
: ComponentBuilder.getInstance().getCompSystem()
.getToolkitDescriptor(
currentToolkit.getDepends());
}
return path;
}
/**
* @param project the Project
* @return A List of the allowed toolkits for the given project.
*/
public List<ToolkitDescriptor> getAllowedProjectToolkits(
IProjectPO project) {
List<ToolkitDescriptor> allowedToolkits =
new ArrayList<ToolkitDescriptor>();
try {
refreshToolkitInfo(project);
} catch (PMException e) {
// nothing
} catch (ProjectDeletedException e) {
// nothing
}
Set<ToolkitDescriptor> allowedByAuts =
getAllowedProjectToolkitsAut(project.getAutMainList());
Set<ToolkitDescriptor> allowedByReusedProjects =
getAllowedProjectToolkitsReused(project.getUsedProjects());
Set<ToolkitDescriptor> allowedBySteps =
getAllowedProjectToolkitsStep(getUsedToolkits());
// Take intersection of allowed toolkits
allowedToolkits.addAll(ComponentBuilder.getInstance().getCompSystem()
.getAllToolkitDescriptors());
allowedToolkits.retainAll(allowedByAuts);
allowedToolkits.retainAll(allowedByReusedProjects);
allowedToolkits.retainAll(allowedBySteps);
return allowedToolkits;
}
/**
* Computes and returns the set of possible toolkits for a project
* that uses <code>usedToolkits</code>.
*
* @param usedToolkits Set of toolkits within a project. This is deterimined
* by the test steps / components used within the
* project.
* @return allowed toolkits.
*/
private Set<ToolkitDescriptor> getAllowedProjectToolkitsStep(
Set<IUsedToolkitPO> usedToolkits) {
Set<ToolkitDescriptor> stepToolkits =
new HashSet<ToolkitDescriptor>();
for (IUsedToolkitPO usedTk : usedToolkits) {
stepToolkits.add(ComponentBuilder.getInstance().getCompSystem()
.getToolkitDescriptor(usedTk.getToolkitId()));
}
return getMostConcreteAllowed(stepToolkits);
}
/**
* Computes and returns the path to root for the toolkit in
* <code>toolkits</code> that is furthest from the root node of the
* toolkit hierarchy. The toolkit described by this path can be considered
* to be the most concrete toolkit from <code>toolkits</code>.
*
* @param toolkits The toolkits to check.
* @return The path to root for the most concrete element in
* <code>toolkits</code>.
*/
private List<ToolkitDescriptor> getLongestPathToRoot(
Set<ToolkitDescriptor> toolkits) {
List<ToolkitDescriptor> longestPath =
new ArrayList<ToolkitDescriptor>();
for (ToolkitDescriptor toolkit : toolkits) {
List<ToolkitDescriptor> pathToRoot = getPathToRoot(toolkit);
if (pathToRoot.size() > longestPath.size()) {
longestPath = pathToRoot;
}
}
return longestPath;
}
/**
* Computes and returns the set of possible toolkits for a project
* that reuses <code>reusedProjects</code>.
*
* @param reusedProjects Set of projects reused by a project.
* @return allowed toolkits.
*/
private Set<ToolkitDescriptor> getAllowedProjectToolkitsReused(
Set<IReusedProjectPO> reusedProjects) {
Set<ToolkitDescriptor> reusedToolkits =
new HashSet<ToolkitDescriptor>();
for (IReusedProjectPO reused : reusedProjects) {
IProjectPO reusedProject;
try {
reusedProject = ProjectPM.loadProjectFromMaster(reused);
// If the project cannot be found in the db, then we cannot consider
// it in our computations.
if (reusedProject != null) {
reusedToolkits.add(
ComponentBuilder.getInstance().getCompSystem()
.getToolkitDescriptor(
reusedProject.getToolkit()));
}
} catch (JBException e) {
// Do nothing.
// If the project cannot be found in the db, then we cannot consider
// it in our computations.
}
}
return getMostConcreteAllowed(reusedToolkits);
}
/**
* Computes and returns the set of toolkits allowed based on the following
* criteria:
* The most concrete (least abstract) toolkit in <code>toolkits</code>
* is selected. This toolkit and all descendants of this toolkit are
* returned.
*
* @param toolkits Set of toolkits from which to choose.
* @return A set of allowed toolkits containing the most concrete instance
* in <code>toolkits</code> and all of its descendants.
*/
private Set<ToolkitDescriptor> getMostConcreteAllowed(
Set<ToolkitDescriptor> toolkits) {
Set<ToolkitDescriptor> allowedToolkits =
new HashSet<ToolkitDescriptor>();
allowedToolkits.addAll(ComponentBuilder.getInstance()
.getCompSystem().getAllToolkitDescriptors());
List<ToolkitDescriptor> longestPathToRoot =
getLongestPathToRoot(toolkits);
if (longestPathToRoot.size() > 0) {
ToolkitDescriptor mostConcreteToolkit =
longestPathToRoot.get(longestPathToRoot.size() - 1);
mostConcreteToolkit =
getMostConcreteIndependentToolkit(mostConcreteToolkit);
allowedToolkits.retainAll(getDescendants(mostConcreteToolkit));
}
return allowedToolkits;
}
/**
* Searches up the Toolkit hierarchy for an independent Toolkit
* (that is, a Toolkit that includes another toolkit and is
* thus available as a specification Toolkit).
*
* @param baseToolkit The Toolkit from which the search is started.
* May be <code>null</code>.
* @return The first independent Toolkit encountered during the search.
* Will be <code>baseToolkit</code> if <code>baseToolkit</code> is
* independent. Will be <code>null</code> if no independent Toolkit
* can be found among <code>baseToolkit</code>'s ancestor Toolkits.
*/
private ToolkitDescriptor getMostConcreteIndependentToolkit(
ToolkitDescriptor baseToolkit) {
ToolkitDescriptor currentToolkit = baseToolkit;
CompSystem compSystem = ComponentBuilder.getInstance().getCompSystem();
while (currentToolkit != null
&& compSystem.getToolkitDescriptor(
currentToolkit.getIncludes()) == null
&& compSystem.getToolkitDescriptor(
currentToolkit.getDepends()) != null) {
currentToolkit = compSystem.getToolkitDescriptor(
currentToolkit.getDepends());
}
return currentToolkit;
}
/**
* Computes and returns the set of possible toolkits for a project
* that contains <code>projectAuts</code>.
*
* @param projectAuts Set of AUTs contained in a project.
* @return allowed toolkits.
*/
private Set<ToolkitDescriptor> getAllowedProjectToolkitsAut(
Set<IAUTMainPO> projectAuts) {
final CompSystem compSys =
ComponentBuilder.getInstance().getCompSystem();
Set<ToolkitDescriptor> allowedToolkits =
new HashSet<ToolkitDescriptor>();
final Set<ToolkitDescriptor> autToolkits =
new HashSet<ToolkitDescriptor>();
if (projectAuts.isEmpty()) {
// If no AUT is defined, then the project toolkit is not
// restricted based on defined AUTs.
allowedToolkits.addAll(compSys.getAllToolkitDescriptors());
}
for (IAUTMainPO autMain : projectAuts) {
final String autToolkit = autMain.getToolkit();
autToolkits.add(compSys.getToolkitDescriptor(autToolkit));
}
// Determine paths to root for all aut toolkits
List<List<ToolkitDescriptor>> pathsToRoot =
new LinkedList<List<ToolkitDescriptor>>();
for (ToolkitDescriptor toolkit : autToolkits) {
List<ToolkitDescriptor> path = getPathToRoot(toolkit);
pathsToRoot.add(path);
}
// Add all common ancestors
if (!pathsToRoot.isEmpty()) {
// The path to which all other paths can be compared
List<ToolkitDescriptor> refPath = pathsToRoot.get(0);
for (int i = 0; i < refPath.size(); i++) {
ToolkitDescriptor toolkit = refPath.get(i);
boolean isCommon = true;
for (int j = 1; j < pathsToRoot.size() && isCommon; j++) {
List<ToolkitDescriptor> otherPath =
pathsToRoot.get(j);
isCommon = otherPath.size() > i
&& otherPath.get(i).equals(toolkit);
}
if (isCommon) {
allowedToolkits.add(toolkit);
}
}
}
return allowedToolkits;
}
/**
*
* @param toolkit The toolkit for which to find all descendants.
* @return all descendants of <code>toolkit</code> within the toolkit
* hierarchy. This <em>includes</em> the given toolkit.
*/
private Set<ToolkitDescriptor> getDescendants(
ToolkitDescriptor toolkit) {
Set<ToolkitDescriptor> descendants =
new HashSet<ToolkitDescriptor>();
descendants.add(toolkit);
List<ToolkitDescriptor> allToolkits =
ComponentBuilder.getInstance().getCompSystem()
.getAllToolkitDescriptors();
for (ToolkitDescriptor toolkitDesc : allToolkits) {
if (ToolkitUtils.doesToolkitInclude(toolkitDesc.getToolkitID(),
toolkit.getToolkitID())) {
descendants.add(toolkitDesc);
}
}
return descendants;
}
}