/*
* 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.compare.generator;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.ecore.EObject;
import org.teiid.core.designer.ModelerCoreException;
import org.teiid.core.designer.ModelerCoreRuntimeException;
import org.teiid.core.designer.UserCancelledException;
import org.teiid.core.designer.util.CoreArgCheck;
import org.teiid.designer.compare.DifferenceProcessor;
import org.teiid.designer.compare.DifferenceReport;
import org.teiid.designer.compare.ModelProducer;
import org.teiid.designer.compare.ModelerComparePlugin;
import org.teiid.designer.compare.processor.DifferenceProcessorImpl;
import org.teiid.designer.compare.processor.MergeProcessorImpl;
import org.teiid.designer.compare.selector.ModelResourceSelector;
import org.teiid.designer.compare.selector.ModelSelector;
import org.teiid.designer.core.ModelerCore;
import org.teiid.designer.core.TransactionRunnable;
import org.teiid.designer.core.compare.EObjectMatcherFactory;
import org.teiid.designer.core.transaction.UnitOfWork;
import org.teiid.designer.core.workspace.ModelWorkspaceException;
/**
* @since 8.0
*/
public class BasicModelGenerator extends AbstractModelGenerator {
private static final int UNITS_GENERATION = 10000;
private static final int UNITS_DIFFERENCE = 100;
private static final int UNITS_DIFFERENCE_POST_PROCESS = 100;
private static final int UNITS_MERGE = 1000;
public static final boolean DEFAULT_USE_TRANSACTION_DURING_MERGE = true;
private final ModelSelector original;
final ModelProducer producer;
private MergeProcessorImpl mergeProcessor;
private boolean useTransactionDuringMerge = DEFAULT_USE_TRANSACTION_DURING_MERGE;
/**
* Construct an instance of ModelGenerator.
*
* @param output the ModelSelector where the <code>outputProducer</code> will put the generated objects; may not be null
* @param original the ModelSelector defining the original model into which the <code>output</code> objects are to be merged;
* may not be null
* @param outputProducer the component that produces the <code>output</code> contents; may not be null
* @param mappingAdapters the list of {@link EObjectMatcherFactory mapping adapter} instances
* used during the difference processing; may not be null or empty
* @throws IllegalArgumentException if any of the above requirements are not satisfied, or if the <code>output</code> and
* <code>original</code> objects are the same object
*/
public BasicModelGenerator( final ModelSelector original,
final ModelProducer outputProducer,
final List mappingAdapters ) {
super(mappingAdapters);
CoreArgCheck.isNotNull(original);
CoreArgCheck.isNotNull(outputProducer);
this.original = original;
this.producer = outputProducer;
}
/**
* Close any resources that were opened by this generator. This method should be called when finished with this object.
*/
@Override
public void close() {
super.close();
this.producer.getOutputSelector().close();
}
public ModelSelector getOriginalModelSelector() {
return this.original;
}
/**
* Execute the generator. This method invokes the producer to populate the output model, performs a difference analysis
* between the output and original models, and merges all changes so that the original is a mirror of the output.
*
* @param monitor the progress monitor; may be null
* @param problems the list into which {@link IStatus} problems should be placed
*/
@Override
protected void doGenerateOutput( final IProgressMonitor monitor,
final LinkedList problems ) throws UserCancelledException {
CoreArgCheck.isNotNull(monitor);
// Set up the progress monitor
final Object[] taskParams = new Object[] {this.getDescription()};
final String taskName = ModelerComparePlugin.Util.getString("ModelGenerator.Performing_{0}", taskParams); //$NON-NLS-1$
final int numUnits = UNITS_GENERATION;
monitor.beginTask(null, numUnits);
monitor.setTaskName(taskName);
// First check if cancelled
if (monitor.isCanceled()) {
throw new UserCancelledException();
}
// -------------------------------------------------------------
// Populate the output model ...
// -------------------------------------------------------------
try {
// Open the model selector ...
this.producer.getOutputSelector().open();
final TransactionRunnable op = new TransactionRunnable() {
@Override
public Object run( UnitOfWork uow ) throws ModelerCoreException {
try {
producer.execute(monitor, problems);
} catch (Exception e) {
throw new WrappedModelerCoreException(e);
}
return null;
}
};
// Perform the runnable ...
if (this.useTransactionDuringMerge) {
final boolean significant = true;
final String desc = this.getDescription();
ModelerCore.getModelEditor().executeAsTransaction(op, desc, significant, this);
} else {
op.run(null);
}
// Record work performed ...
monitor.worked(UNITS_GENERATION);
} catch (WrappedModelerCoreException we) {
final Throwable e = we.getException();
if (e instanceof ModelerCoreRuntimeException
&& ((ModelerCoreRuntimeException)e).getChild() instanceof UserCancelledException) {
final UserCancelledException cancellation = (UserCancelledException)((ModelerCoreRuntimeException)e).getChild();
throw cancellation;
// do nothing - the user cancelled
}
final Object[] params = new Object[] {this.getDescription(), e.getLocalizedMessage()};
final String msg = ModelerComparePlugin.Util.getString("ModelGenerator.Error_during_generation", params); //$NON-NLS-1$
final String pluginId = ModelerComparePlugin.PLUGIN_ID;
final int code = ERROR_PRODUCING_OUTPUT_MODEL;
final IStatus status = new Status(IStatus.ERROR, pluginId, code, msg, e);
problems.addFirst(status);
} catch (ModelerCoreRuntimeException e) {
if (e.getChild() instanceof UserCancelledException) {
// do nothing - the user cancelled
} else {
final Object[] params = new Object[] {this.getDescription(), e.getLocalizedMessage()};
final String msg = ModelerComparePlugin.Util.getString("ModelGenerator.Error_during_generation", params); //$NON-NLS-1$
final String pluginId = ModelerComparePlugin.PLUGIN_ID;
final int code = ERROR_PRODUCING_OUTPUT_MODEL;
final IStatus status = new Status(IStatus.ERROR, pluginId, code, msg, e);
problems.addFirst(status);
}
} catch (Exception e) {
final Object[] params = new Object[] {this.getDescription(), e.getLocalizedMessage()};
final String msg = ModelerComparePlugin.Util.getString("ModelGenerator.Error_during_generation", params); //$NON-NLS-1$
final String pluginId = ModelerComparePlugin.PLUGIN_ID;
final int code = ERROR_PRODUCING_OUTPUT_MODEL;
final IStatus status = new Status(IStatus.ERROR, pluginId, code, msg, e);
problems.addFirst(status);
} catch (Throwable e) {
final Object[] params = new Object[] {this.getDescription(), e.getLocalizedMessage()};
final String msg = ModelerComparePlugin.Util.getString("ModelGenerator.Unexpected_runtime_error_during_generation", params); //$NON-NLS-1$
final String pluginId = ModelerComparePlugin.PLUGIN_ID;
final int code = RUNTIME_ERROR_PRODUCING_OUTPUT_MODEL;
final IStatus status = new Status(IStatus.ERROR, pluginId, code, msg, e);
problems.addFirst(status);
}
// See if cancelled ...
if (monitor.isCanceled()) {
throw new UserCancelledException();
}
}
/**
* Execute the generator. This method invokes the producer to populate the output model, performs a difference analysis
* between the output and original models, and merges all changes so that the original is a mirror of the output.
*
* @param monitor the progress monitor; may be null
* @param problems the list into which {@link IStatus} problems should be placed
*/
@Override
protected void doComputeDifferenceReport( final IProgressMonitor monitor,
final LinkedList problems ) throws UserCancelledException {
CoreArgCheck.isNotNull(monitor);
// Set up the progress monitor
final Object[] taskParams = new Object[] {this.getDescription()};
final String taskName = ModelerComparePlugin.Util.getString("ModelGenerator.Performing_{0}", taskParams); //$NON-NLS-1$
final int numUnits = UNITS_DIFFERENCE + UNITS_DIFFERENCE_POST_PROCESS;
monitor.beginTask(null, numUnits);
monitor.setTaskName(taskName);
// First check if cancelled
if (monitor.isCanceled()) {
throw new UserCancelledException();
}
// --------------------------------------------------------------
// Compute the difference between the output and the original ...
// --------------------------------------------------------------
final List matcherFactories = getEObjectMatcherFactories();
final ModelSelector output = this.producer.getOutputSelector();
final DifferenceProcessor diffProcessor = new DifferenceProcessorImpl(this.original, output);
if (matcherFactories.size() != 0) {
diffProcessor.addEObjectMatcherFactories(matcherFactories);
}
final IStatus diffStatus = diffProcessor.execute(monitor);
// Record work performed ...
monitor.worked(UNITS_DIFFERENCE);
// Let the subclass do something with the difference report ...
final DifferenceReport differenceReport = diffProcessor.getDifferenceReport();
addDifferenceReport(differenceReport);
if (diffStatus.getSeverity() == IStatus.ERROR) {
problems.addFirst(diffStatus);
} else {
problems.add(diffStatus);
}
}
protected class WrappedModelerCoreException extends ModelerCoreException {
public WrappedModelerCoreException( Exception exception ) {
super(exception);
}
}
/**
* @see org.teiid.designer.compare.generator.AbstractModelGenerator#doPostProcessDifferenceReports()
*/
@Override
protected void doPostProcessDifferenceReports() {
// do nothing by default
}
/**
* Execute the generator. This method invokes the producer to populate the output model, performs a difference analysis
* between the output and original models, and merges all changes so that the original is a mirror of the output.
*
* @param monitor the progress monitor; may be null
* @param problems the list into which {@link IStatus} problems should be placed
* @throws UserCancelledException if the user cancelled the operation
*/
@Override
protected void doMergeOutputIntoOriginal( final IProgressMonitor monitor,
final LinkedList problems ) throws UserCancelledException {
CoreArgCheck.isNotNull(monitor);
// Set up the progress monitor
final Object[] taskParams = new Object[] {this.getDescription()};
final String taskName = ModelerComparePlugin.Util.getString("ModelGenerator.Performing_{0}", taskParams); //$NON-NLS-1$
final int numUnits = UNITS_MERGE;
monitor.beginTask(null, numUnits);
monitor.setTaskName(taskName);
// See if cancelled ...
if (monitor.isCanceled()) {
throw new UserCancelledException();
}
// ------------------------------------------------------------------
// Merge the differences (make the original look like the output) ...
// ------------------------------------------------------------------
if (getAllDifferenceReports().size() != 0) {
final DifferenceReport diffReport = (DifferenceReport)getDifferenceReports().get(0);
final ModelSelector output = this.producer.getOutputSelector();
boolean moveRatherThanCopyAdds = isNewModelCase();
EObject[] dummyArray = null;
this.mergeProcessor = new MergeProcessorImpl(diffReport, this.original, output, dummyArray, moveRatherThanCopyAdds);
this.mergeProcessor.setEndingToSourceMapping(this.getProducedToOutputMapping());
final IStatus mergeStatus = mergeProcessor.execute(monitor);
if (mergeStatus.getSeverity() == IStatus.ERROR) {
// There was a catastrophic problem ...
problems.add(mergeStatus);
}
// Close the processor's temporary resource ...
output.close();
}
// Record work performed ...
monitor.worked(UNITS_MERGE);
}
/**
* @see org.teiid.designer.compare.generator.AbstractModelGenerator#doReresolveAndRebuildImports()
* @since 4.2
*/
@Override
protected void doReresolveAndRebuildImports() {
if (this.mergeProcessor != null) {
this.mergeProcessor.reresolve(null);
}
}
/**
* @see org.teiid.designer.compare.ModelGenerator#saveModel()
* @since 5.0.2
*/
@Override
public void saveModel() {
super.saveModel();
final ModelSelector selector = getOriginalModelSelector();
if (selector instanceof ModelResourceSelector) {
try {
// System.out.println(" - - - - - - - BasicModelGenerator.saveModel() Saving Resource = " +
// ((ModelResourceSelector)selector).getModelResource().getItemName());
((ModelResourceSelector)selector).getModelResource().save(null, true);
} catch (ModelWorkspaceException err) {
ModelerComparePlugin.Util.log(err);
}
}
}
}