/*
* 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.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.teiid.core.designer.UserCancelledException;
import org.teiid.designer.compare.DifferenceReport;
import org.teiid.designer.compare.ModelGenerator;
import org.teiid.designer.compare.ModelerComparePlugin;
import org.teiid.designer.core.compare.EObjectMatcherFactory;
/**
* The AbstractModelGenerator class is the abstract base class that can be used to implement
* {@link ModelGenerator}. It provide an implementation of the public methods by defining and using
* a (fewer) number of abstract methods.
*
* @since 8.0
*/
public abstract class AbstractModelGenerator implements ModelGenerator {
private final List matcherFactories;
private String description;
private final List differenceReports;
private Map producedToOutputMapping;
private boolean isNewModelCase = false;
private boolean saveAllBeforeFinish = false;
/**
* Construct an instance of AbstractModelGenerator.
* @param matcherFactories the list of {@link EObjectMatcherFactory mapping adapter}
* instances used during the difference processing; may not be null or empty
*/
public AbstractModelGenerator( final List matcherFactories ) {
super();
this.differenceReports = new LinkedList();
this.matcherFactories = matcherFactories != null ? matcherFactories : Collections.EMPTY_LIST;
this.producedToOutputMapping = new HashMap();
}
public void setProducedToOutputMapping( final Map mapping ) {
this.producedToOutputMapping = mapping != null ? mapping : new HashMap();
}
public Map getProducedToOutputMapping() {
return this.producedToOutputMapping;
}
/**
* Obtain the description for this generator. This method is used to help generate the status messages,
* and therefore should never be null or zero-length. Consequently, if the description is never set
* or is {@link #setDescription(String) set} with a null or zero-length string, a
* {@link #getDefaultDescription() default description} is used.
* @return the description; may not be null
*/
@Override
public String getDescription() {
if ( this.description != null && this.description.trim().length() != 0 ) {
return this.description;
}
final String desc = getDefaultDescription();
if ( desc != null && desc.trim().length() != 0 ) {
return desc;
}
return "the operation"; //$NON-NLS-1$
}
/**
* Set the description for this generator.
* @param desc the description; may be null
*/
@Override
public void setDescription( final String desc ) {
this.description = desc;
}
/**
* 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 progressMonitor the progress monitor; may be null
* @return the status containing the result of the generation and merge process
*/
@Override
public IStatus execute( final IProgressMonitor progressMonitor ) {
final LinkedList problems = new LinkedList();
// Start the progress monitor tasks ...
final IProgressMonitor monitor = progressMonitor != null ? progressMonitor : new NullProgressMonitor();
IStatus diffStatus = null;
// PHASE 1: Generate ...
try {
doClearDifferenceReports();
doGenerateOutput(monitor,problems);
diffStatus = createStatus(problems);
} catch (UserCancelledException e) {
diffStatus = newUserCancelledStatus();
}
if ( diffStatus.getSeverity() == IStatus.ERROR ) {
// There was a catastrophic problem ...
return diffStatus;
}
// Only process/update for differences if it's NOT a new model case;
// PHASE 2: Compute the differences ...
problems.add(diffStatus);
try {
doComputeDifferenceReport(monitor,problems);
if ( this.differenceReports.size() != 0 ) {
doPostProcessDifferenceReports();
}
diffStatus = createStatus(problems);
} catch (UserCancelledException e) {
diffStatus = newUserCancelledStatus();
}
if ( diffStatus.getSeverity() == IStatus.ERROR ) {
// There was a catastrophic problem ...
return diffStatus;
}
// PHASE 3: Merge the differences ...
problems.add(diffStatus);
try {
doMergeOutputIntoOriginal(monitor,problems);
doPostMerge();
} catch (UserCancelledException e1) {
final IStatus mergeStatus = newUserCancelledStatus();
problems.addFirst(mergeStatus);
} finally {
try {
monitor.done();
} catch (RuntimeException e) {
ModelerComparePlugin.Util.log(e);
}
}
return createStatus(problems);
}
/**
* Run the generator. This method invokes the producer to populate the output model, but does not
* performs a difference analysis between the output and original models, nor does it
* merge changes so that the original is a mirror of the output.
* This method should be called before
* {@link #computeDifferenceReport(IProgressMonitor)} and before {@link #mergeOutputIntoOriginal(IProgressMonitor)}.
* @param progressMonitor the progress monitor; may be null
* @return the status containing the result of the generation and merge process
*/
@Override
public IStatus generateOutput( final IProgressMonitor progressMonitor ) {
final IProgressMonitor monitor = progressMonitor != null ? progressMonitor : new NullProgressMonitor();
final LinkedList problems = new LinkedList();
try {
doClearDifferenceReports();
doGenerateOutput(monitor,problems);
} catch ( UserCancelledException e ) {
final IStatus status = newUserCancelledStatus();
problems.addFirst(status);
} finally {
try {
monitor.done();
} catch (RuntimeException e) {
ModelerComparePlugin.Util.log(e);
}
}
return createStatus(problems);
}
/**
* After generating, compute the difference report. This method should be called after
* {@link #generateOutput(IProgressMonitor)} and before {@link #mergeOutputIntoOriginal(IProgressMonitor)}.
* @param progressMonitor the progress monitor; may be null
* @return the status containing the result of the generation and merge process
*/
@Override
public IStatus computeDifferenceReport( final IProgressMonitor progressMonitor ) {
final IProgressMonitor monitor = progressMonitor != null ? progressMonitor : new NullProgressMonitor();
final LinkedList problems = new LinkedList();
try {
doComputeDifferenceReport(monitor,problems);
if ( this.differenceReports.size() != 0 ) {
doPostProcessDifferenceReports();
}
} catch ( UserCancelledException e ) {
final IStatus status = newUserCancelledStatus();
problems.addFirst(status);
} finally {
try {
monitor.done();
} catch (RuntimeException e) {
ModelerComparePlugin.Util.log(e);
}
}
return createStatus(problems);
}
/**
* @see org.teiid.designer.compare.ModelGenerator#getAllDifferenceReports()
*/
@Override
public List getAllDifferenceReports() {
return this.differenceReports;
}
/**
* @see org.teiid.designer.compare.ModelGenerator#getDifferenceReports()
*/
@Override
public List getDifferenceReports() {
return getAllDifferenceReports();
}
protected void addDifferenceReport( final DifferenceReport report ) {
this.differenceReports.add(report);
}
public List getEObjectMatcherFactories() {
return this.matcherFactories;
}
/**
* 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.
* This method should be called after
* {@link #generateOutput(IProgressMonitor)} and after {@link #computeDifferenceReport(IProgressMonitor)}.
* @param progressMonitor the progress monitor; may be null
* @return the status containing the result of the generation and merge process
*/
@Override
public IStatus mergeOutputIntoOriginal( final IProgressMonitor progressMonitor ) {
final IProgressMonitor monitor = progressMonitor != null ? progressMonitor : new NullProgressMonitor();
final LinkedList problems = new LinkedList();
try {
doMergeOutputIntoOriginal(monitor,problems);
doPostMerge();
} catch (UserCancelledException e1) {
final IStatus mergeStatus = newUserCancelledStatus();
problems.addFirst(mergeStatus);
} finally {
try {
monitor.done();
} catch (RuntimeException e) {
ModelerComparePlugin.Util.log(e);
}
}
return createStatus(problems);
}
/**
* Close any resources that were opened by this generator. This method should be called when finished
* with this object. Subclasses should override this method if they have resources that should be closed.
*/
@Override
public void close() {
}
// =========================================================================
// Methods to implement basic behavior
// =========================================================================
protected void doClearDifferenceReports() {
// Call the method so that if it is overridden, this implementation might work without being overridden
this.getAllDifferenceReports().clear();
this.producedToOutputMapping.clear();
}
/**
* 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
*/
protected abstract void doGenerateOutput( final IProgressMonitor monitor,
final LinkedList problems ) throws 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
* @throws UserCancelledException if the user cancelled the operation
*/
protected abstract void doComputeDifferenceReport( final IProgressMonitor monitor,
final LinkedList problems ) throws UserCancelledException;
/**
* Method that can be overridden to post process the difference reports. This implementation merely
* does nothing.
*/
protected abstract void doPostProcessDifferenceReports();
/**
* Method that is executed after the {@link #doMergeOutputIntoOriginal(IProgressMonitor, LinkedList)}
* method.
*/
protected void doPostMerge() {
// do nothing
}
protected abstract void doReresolveAndRebuildImports();
/**
* 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
*/
protected abstract void doMergeOutputIntoOriginal( final IProgressMonitor monitor,
final LinkedList problems ) throws UserCancelledException;
protected String getDefaultDescription() {
return ModelerComparePlugin.Util.getString("AbstractModelGenerator.Default_description"); //$NON-NLS-1$
}
protected IStatus newUserCancelledStatus() {
final Object[] params = new Object[]{this.getDescription()};
final String msg = ModelerComparePlugin.Util.getString("AbstractModelGenerator.User_cancelled_operation",params); //$NON-NLS-1$
final String pluginId = ModelerComparePlugin.PLUGIN_ID;
final int code = USER_CANCELLED;
final IStatus status = new Status(IStatus.WARNING,pluginId,code,msg,null);
return status;
}
protected IStatus newSuccessStatus() {
final Object[] params = new Object[]{this.getDescription()};
final String msg = ModelerComparePlugin.Util.getString("AbstractModelGenerator.Success_msg",params); //$NON-NLS-1$
final String pluginId = ModelerComparePlugin.PLUGIN_ID;
final int code = USER_CANCELLED;
final IStatus status = new Status(IStatus.WARNING,pluginId,code,msg,null);
return status;
}
protected IStatus createStatus( final List problems ) {
// // Put all of the problems into a single IStatus ...
IStatus resultStatus = null;
final String pluginId = ModelerComparePlugin.PLUGIN_ID;
if ( problems == null || problems.isEmpty() ) {
final Object[] params = new Object[]{this.getDescription()};
final String msg = ModelerComparePlugin.Util.getString("AbstractModelGenerator.Completed_generation",params); //$NON-NLS-1$
final IStatus status = new Status(IStatus.OK,pluginId,COMPLETED_WITH_NO_PROBLEMS,msg,null);
resultStatus = status;
} else if ( problems.size() == 1 ) {
resultStatus = (IStatus) problems.get(0);
} else {
// There were problems, so determine whether there were warnings and errors ...
int numErrors = 0;
int numWarnings = 0;
final Iterator iter = problems.iterator();
while (iter.hasNext()) {
final IStatus aStatus = (IStatus)iter.next();
if ( aStatus.getSeverity() == IStatus.WARNING ) {
++numWarnings;
} else if ( aStatus.getSeverity() == IStatus.ERROR ) {
++numErrors;
}
}
// Create the final status ...
final IStatus[] statusArray = (IStatus[]) problems.toArray(new IStatus[problems.size()]);
if ( numWarnings != 0 && numErrors == 0 ) {
final Object[] params = new Object[]{this.getDescription(),new Integer(numWarnings)};
final String msg = ModelerComparePlugin.Util.getString("AbstractModelGenerator.Completed_generation_with_warning(s)",params); //$NON-NLS-1$
resultStatus = new MultiStatus(pluginId,COMPLETED_WITH_WARNINGS,statusArray,msg,null);
} else if ( numWarnings == 0 && numErrors != 0 ) {
final Object[] params = new Object[]{this.getDescription(),new Integer(numErrors)};
final String msg = ModelerComparePlugin.Util.getString("AbstractModelGenerator.Completed_generation_with_error(s)",params); //$NON-NLS-1$
resultStatus = new MultiStatus(pluginId,COMPLETED_WITH_ERRORS,statusArray,msg,null);
} else if ( numWarnings != 0 && numErrors != 0 ) {
final Object[] params = new Object[]{this.getDescription(),new Integer(numErrors),new Integer(numWarnings)};
final String msg = ModelerComparePlugin.Util.getString("AbstractModelGenerator.Completed_generation_with_error(s)_and_warning(s)",params); //$NON-NLS-1$
resultStatus = new MultiStatus(pluginId,COMPLETED_WITH_WARNINGS_AND_ERRORS,statusArray,msg,null);
} else {
final Object[] params = new Object[]{this.getDescription()};
final String msg = ModelerComparePlugin.Util.getString("AbstractModelGenerator.Completed_generation_with_no_errors_or_warnings",params); //$NON-NLS-1$
resultStatus = new MultiStatus(pluginId,COMPLETED_WITH_NO_WARNINGS_AND_ERRORS,statusArray,msg,null);
}
}
return resultStatus;
}
/**
*
* @see org.teiid.designer.compare.ModelGenerator#isNewModelCase()
* @since 5.0.2
*/
@Override
public boolean isNewModelCase() {
return this.isNewModelCase;
}
/**
*
* @see org.teiid.designer.compare.ModelGenerator#setNewModelCase(boolean)
* @since 5.0.2
*/
@Override
public void setNewModelCase(boolean theIsNewModelCase) {
this.isNewModelCase = theIsNewModelCase;
}
/**
*
* @see org.teiid.designer.compare.ModelGenerator#setSaveAllBeforeFinish(boolean)
* @since 5.0.2
*/
@Override
public void setSaveAllBeforeFinish(boolean theDoSave) {
this.saveAllBeforeFinish = theDoSave;
}
/**
*
* @see org.teiid.designer.compare.ModelGenerator#isSaveAllBeforeFinish()
* @since 5.0.2
*/
@Override
public boolean isSaveAllBeforeFinish() {
return this.saveAllBeforeFinish;
}
/**
*
* @see org.teiid.designer.compare.ModelGenerator#saveModel()
* @since 5.0.2
*/
@Override
public void saveModel() {
// No Op
}
}