PcmRepositoryExtractor.java

package de.uka.ipd.sdq.beagle.core.pcmconnection;

import de.uka.ipd.sdq.beagle.core.Blackboard;
import de.uka.ipd.sdq.beagle.core.ExternalCallParameter;
import de.uka.ipd.sdq.beagle.core.ResourceDemandingInternalAction;
import de.uka.ipd.sdq.beagle.core.SeffBranch;
import de.uka.ipd.sdq.beagle.core.SeffLoop;
import de.uka.ipd.sdq.beagle.core.facade.BlackboardCreator;
import de.uka.ipd.sdq.beagle.core.facade.SourceCodeFileProvider;
import de.uka.ipd.sdq.beagle.core.pcmsourcestatementlink.PcmSourceStatementLinkRepository;

import de.uka.ipd.sdq.identifier.Identifier;

import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.palladiosimulator.pcm.repository.RepositoryComponent;
import org.palladiosimulator.pcm.repository.impl.BasicComponentImpl;
import org.palladiosimulator.pcm.repository.impl.RepositoryImpl;
import org.palladiosimulator.pcm.seff.AbstractBranchTransition;
import org.palladiosimulator.pcm.seff.ServiceEffectSpecification;
import org.palladiosimulator.pcm.seff.impl.ResourceDemandingBehaviourImpl;
import org.palladiosimulator.pcm.seff.impl.ResourceDemandingSEFFImpl;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

/**
 * Extracting a given Pcm repository. Offering 2 methods:
 * {@link #getBlackboardForAllElements(RepositoryImpl, BlackboardCreator)} and
 * {@link #getBlackboardForIds(RepositoryImpl, Collection, BlackboardCreator)}
 *
 * @author Ansgar Spiegler
 * @author Roman Langrehr
 */
public class PcmRepositoryExtractor {

	/**
	 * Temporary storage for all extracted {@link SeffLoop SeffLoops} that should be
	 * written on the {@link Blackboard}.
	 */
	private Set<SeffLoop> seffLoopSet;

	/**
	 * Temporary storage for all extracted {@link SeffBranch SeffBranches} that should be
	 * written on the {@link Blackboard}.
	 */
	private Set<SeffBranch> seffBranchSet;

	/**
	 * Temporary storage for all extracted {@link ResourceDemandingInternalAction rdSeffs}
	 * that should be written on the {@link Blackboard}.
	 */
	private Set<ResourceDemandingInternalAction> rdiaSet;

	/**
	 * Temporary storage for all extracted {@link ExternalCallParameter} that should be
	 * written on the {@link Blackboard}.
	 */
	private Set<ExternalCallParameter> externalCallParameterSet;

	/**
	 * Helping class instance for extracting, creating and adding SEFF elements to Sets.
	 */
	private PcmRepositorySeffExtractor pcmSeffExtractor;

	/**
	 * The {@link SourceCodeFileProvider} for the project under analysis.
	 */
	private final SourceCodeFileProvider sourceCodeFileProvider;

	/**
	 * The {@link PcmSourceStatementLinkRepository} for the project under analysis.
	 */
	private final PcmSourceStatementLinkRepository sourceStatementLinkRepository;

	/**
	 * Creates a new name parser for a specific project to analyse.
	 *
	 * @param sourceCodeFileProvider The {@link SourceCodeFileProvider} for the project
	 *            under analysis.
	 * @param sourceStatementLinkRepository The repository containing the linking of
	 *            seffElements to SourceCode
	 */
	public PcmRepositoryExtractor(final SourceCodeFileProvider sourceCodeFileProvider,
		final PcmSourceStatementLinkRepository sourceStatementLinkRepository) {
		this.sourceCodeFileProvider = sourceCodeFileProvider;
		this.sourceStatementLinkRepository = sourceStatementLinkRepository;
	}

	/**
	 * Builds a new blackboard and writes the Beagle objects representing all found
	 * <em>PCM elements</em> to it. Only <em>PCM elements</em> that fulfil the
	 * restrictions described in the class description will be written.
	 *
	 * @param repository The repository to look up.
	 * @param blackboardFactory all translated <em>PCM elements</em> will be written on
	 *            it. The rdias, seffLoops, seffBranches and externalCallPAramerts will
	 *            never be {@code null} afterwards.
	 */
	public void getBlackboardForAllElements(final RepositoryImpl repository,
		final BlackboardCreator blackboardFactory) {
		final PcmBeagleMappings pcmMappings = new PcmBeagleMappings();
		this.seffLoopSet = new HashSet<SeffLoop>();
		this.seffBranchSet = new HashSet<SeffBranch>();
		this.rdiaSet = new HashSet<ResourceDemandingInternalAction>();
		this.externalCallParameterSet = new HashSet<ExternalCallParameter>();
		this.pcmSeffExtractor = new PcmRepositorySeffExtractor(this.seffLoopSet, this.seffBranchSet, this.rdiaSet,
			this.externalCallParameterSet, pcmMappings, this.sourceCodeFileProvider,
			this.sourceStatementLinkRepository);

		this.scanRepository(repository);

		blackboardFactory.setRdias(this.rdiaSet);
		blackboardFactory.setBranches(this.seffBranchSet);
		blackboardFactory.setLoops(this.seffLoopSet);
		blackboardFactory.setExternalCalls(this.externalCallParameterSet);
		blackboardFactory.setPcmMappings(pcmMappings);
	}

	/**
	 * Builds a new blackboard and writes the Beagle objects representing <em>PCM
	 * elements</em> related to {@code ids} to it. Only <em>PCM elements</em> that fulfil
	 * the restrictions described in the class description will be written.
	 *
	 * <p>For any provided ID {@code id}, <em>PCM elements</em> will be selected to be
	 * written on the blackboard as follows:
	 *
	 * <ul>
	 *
	 * <li>If {@code id} describes a component, all <em>PCM elements</em> that are part of
	 * the component’s service effect specification will be selected. Nested components
	 * will be inspected recursively.
	 *
	 * <li>If {@code id} describes a repository, all contained components will be
	 * inspected as if their ID had been provided.
	 *
	 * <li>If {@code id} describes a <em>PCM element</em>, it will be selected.
	 *
	 * <li>Any other ID will be silently ignored.
	 *
	 * </ul>
	 *
	 *
	 * @param repository The repository to look up.
	 * @param identifiers Identifiers of elements in the repository files that shall be
	 *            written to the Blackboard.
	 * @param blackboardFactory all translated <em>PCM elements</em> will be written on
	 *            it. The rdias, seffLoops, seffBranches and externalCallPAramerts will
	 *            never be {@code null} afterwards.
	 */
	public void getBlackboardForIds(final RepositoryImpl repository, final Collection<String> identifiers,
		final BlackboardCreator blackboardFactory) {
		final PcmBeagleMappings pcmMappings = new PcmBeagleMappings();
		final Set<EObject> setOfIdentifiedObjects = new HashSet<EObject>();

		this.seffLoopSet = new HashSet<SeffLoop>();
		this.seffBranchSet = new HashSet<SeffBranch>();
		this.rdiaSet = new HashSet<ResourceDemandingInternalAction>();
		this.externalCallParameterSet = new HashSet<ExternalCallParameter>();
		this.pcmSeffExtractor = new PcmRepositorySeffExtractor(this.seffLoopSet, this.seffBranchSet, this.rdiaSet,
			this.externalCallParameterSet, pcmMappings, this.sourceCodeFileProvider,
			this.sourceStatementLinkRepository);

		if (identifiers.contains(repository.getId())) {
			this.scanRepository(repository);

			blackboardFactory.setRdias(this.rdiaSet);
			blackboardFactory.setBranches(this.seffBranchSet);
			blackboardFactory.setLoops(this.seffLoopSet);
			blackboardFactory.setExternalCalls(this.externalCallParameterSet);
			blackboardFactory.setPcmMappings(pcmMappings);

		}

		// Look up for each Repository-object ID if its found in the
		// identifiers-Collection
		// If so, the Object is added to a Set named "setOfIdentifiedObjects"
		final TreeIterator<EObject> contentIterator = repository.eAllContents();
		while (contentIterator.hasNext()) {
			final EObject content = contentIterator.next();

			Identifier contentIdentifier = null;
			if (content instanceof Identifier) {
				contentIdentifier = (Identifier) content;
				if (identifiers.contains(contentIdentifier.getId())) {
					setOfIdentifiedObjects.add(content);
				}
			}
		}

		this.extractMeaningfulElements(setOfIdentifiedObjects);

		// Add the sets to the blackboard and return

		blackboardFactory.setRdias(this.rdiaSet);
		blackboardFactory.setBranches(this.seffBranchSet);
		blackboardFactory.setLoops(this.seffLoopSet);
		blackboardFactory.setExternalCalls(this.externalCallParameterSet);
		blackboardFactory.setPcmMappings(pcmMappings);
	}

	/**
	 * Finds all PCM elements that are meaningful to Beagle in the provided set of
	 * {@code contentObjects}. Populates {@link #rdiaSet}, {@link #seffBranchSet},
	 * {@link #seffLoopSet} and {@link #externalCallParameterSet}.
	 *
	 * @param contentObjects The objects to check for meanigfulness.
	 */
	private void extractMeaningfulElements(final Set<EObject> contentObjects) {
		for (final EObject object : contentObjects) {
			if (object.getClass() == BasicComponentImpl.class) {
				this.extractBasicComponentAndAddContentsToSet((BasicComponentImpl) object);
			} else if (object.getClass() == ResourceDemandingSEFFImpl.class) {
				this.extractResourceDemandingSEFFImplAndAddContentsToSet((ResourceDemandingSEFFImpl) object);
			} else if (object instanceof AbstractBranchTransition) {
				final EList<EObject> specificBranchContentList = object.eContents();
				for (final EObject specificBranchContent : specificBranchContentList) {
					if (specificBranchContent.getClass() == ResourceDemandingBehaviourImpl.class) {
						for (final EObject stepBehaviour : ((ResourceDemandingBehaviourImpl) specificBranchContent)
							.eContents()) {
							this.pcmSeffExtractor.extractBehaviourAndAddToSet(stepBehaviour);
						}
					}
				}
			} else {
				this.pcmSeffExtractor.extractBehaviourAndAddToSet(object);
			}
		}
	}

	/**
	 * This method takes the whole {@link PcmRepositoryBlackboardFactoryAdder#repository}
	 * and extracts all needed content into the storing sets.
	 *
	 * @param repositoryToScan The repository to read from.
	 */
	private void scanRepository(final RepositoryImpl repositoryToScan) {
		final EList<RepositoryComponent> componentList = repositoryToScan.getComponents__Repository();
		for (final RepositoryComponent component : componentList) {
			if (component.getClass() == BasicComponentImpl.class) {
				this.extractBasicComponentAndAddContentsToSet((BasicComponentImpl) component);
			}
		}
	}

	/**
	 * BasicComponent extracting method. Looking for all included SEFFs. Recursive calls
	 * to methods that save all needed SEFF-elements into the sets.
	 *
	 * @param basicComponent Component of the Repository.
	 */
	private void extractBasicComponentAndAddContentsToSet(final BasicComponentImpl basicComponent) {
		final EList<ServiceEffectSpecification> seffList =
			basicComponent.getServiceEffectSpecifications__BasicComponent();
		for (final ServiceEffectSpecification seff : seffList) {
			if (seff.getClass() == ResourceDemandingSEFFImpl.class) {
				this.extractResourceDemandingSEFFImplAndAddContentsToSet((ResourceDemandingSEFFImpl) seff);
			}
		}
	}

	/**
	 * ResourceDemandingSEFF extracting method. Looking for all including Contents.
	 * Recursive calls to methods that save all needed SEFF-elements into the sets.
	 *
	 * @param rdSeff rdSeff of the Repository.
	 */
	private void extractResourceDemandingSEFFImplAndAddContentsToSet(final ResourceDemandingSEFFImpl rdSeff) {
		final EList<EObject> rdSeffContentList = rdSeff.eContents();
		for (final EObject rdSeffContent : rdSeffContentList) {
			this.pcmSeffExtractor.extractBehaviourAndAddToSet(rdSeffContent);
		}
	}

}