PcmRepositoryWriter.java

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

import de.uka.ipd.sdq.beagle.core.Blackboard;
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.failurehandling.FailureHandler;
import de.uka.ipd.sdq.beagle.core.failurehandling.FailureReport;

import org.palladiosimulator.pcm.repository.impl.RepositoryImpl;

import java.io.File;
import java.io.IOException;

/**
 * Writes Beagle’s findings back to a PCM repository. This class is meant to be used for
 * Blackboard instances created by {@link PcmRepositoryBlackboardFactoryAdder} and may not
 * be useable with other blackboards.
 *
 * @author Joshua Gleitze
 * @author Ansgar Spiegler
 */
public class PcmRepositoryWriter {

	/**
	 * The FailureHandler for this class.
	 */
	private static final FailureHandler FAILURE_HANDLER = FailureHandler.getHandler("BlackboardStorer");

	/**
	 * Blackboard to get Mapping from.
	 */
	private final Blackboard blackboard;

	/**
	 * The Mappings of Seffs to Ids.
	 */
	private final PcmBeagleMappings pcmMappings;

	/**
	 * FileLoader to load a repository for a given file.
	 */
	private final PcmRepositoryFileLoader fileLoader;

	/**
	 * The annotator that writes all final EvaluableExpression of a given Blackboard to
	 * the Repository.
	 */
	private final PcmRepositoryWriterAnnotator annotator;

	/**
	 * Creates a writer to write the results written on {@code blackboard} back to a PCM
	 * repository.
	 *
	 * @param blackboard The blackboard containing results.
	 */
	public PcmRepositoryWriter(final Blackboard blackboard) {
		this.blackboard = blackboard;
		this.pcmMappings = this.blackboard.readFor(PcmRepositoryBlackboardFactoryAdder.class);
		this.fileLoader = new PcmRepositoryFileLoader();
		this.annotator = new PcmRepositoryWriterAnnotator(blackboard, this.pcmMappings);
	}

	/**
	 * Writes the Beagle’s findings to the {@code repositoryFile}. For each
	 * {@linkplain ResourceDemandingInternalAction}, {@linkplain SeffBranch} and
	 * {@linkplain SeffLoop}, the method will look up the identifier of the element in the
	 * source repository file the object was created for. If {@code repositoryFile}
	 * contains an element with this identifier that is of the appropriate type, the
	 * object’s result will appropriately written to {@code repositoryFile}. Nothing will
	 * be written otherwise.
	 *
	 *
	 * <p>If the element Id with final EvaluableExpression from the Blackboard can not be
	 * found in the repository file.
	 *
	 * <p>If the Blackboard elements (e.g. SeffBranch) from the elements with final
	 * EvaluableExpression from the Blackboard do not Correspond to the repository PCM
	 * elements (e.g. BranchAction).
	 *
	 * @param repositoryFile A PCM repository file to write Beagle’s results to. It should
	 *            use the same identifiers for elements as the repository file Beagle’s
	 *            blackboard was initially created for.
	 */
	public void writeTo(final File repositoryFile) {
		final RepositoryImpl repository = this.fileLoader.loadRepositoryFromFile(repositoryFile);

		this.annotator.annotateAll(repository);
		this.saveRepository(repository, repositoryFile);
	}

	/**
	 * Method should be called after annotating changes on the {@link RepositoryImpl}. It
	 * will store the repository at the given File-path.
	 *
	 * @param repository modified Repository to store
	 * @param repositoryFile storing repository as this file
	 */
	private void saveRepository(final RepositoryImpl repository, final File repositoryFile) {
		try {
			EmfHelper.saveToXMIFile(repository, repositoryFile.getAbsolutePath());
		} catch (final IOException ioException) {
			final FailureReport<Void> failure = new FailureReport<Void>()
				.message("The modified repository can not be saved to %s!", repositoryFile.getAbsolutePath())
				.cause(ioException)
				.recoverable()
				.retryWith(() -> this.saveRepository(repository, repositoryFile));
			FAILURE_HANDLER.handle(failure);
		}
	}

}