Java tutorial
/******************************************************************************* * Copyright (c) 2006, 2011 Obeo. * 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: * Obeo - initial API and implementation *******************************************************************************/ package org.eclipse.emf.compare.ui.internal; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import org.eclipse.compare.CompareConfiguration; import org.eclipse.compare.CompareEditorInput; import org.eclipse.compare.CompareUI; import org.eclipse.compare.IResourceProvider; import org.eclipse.compare.IStreamContentAccessor; import org.eclipse.compare.ITypedElement; import org.eclipse.compare.ResourceNode; import org.eclipse.compare.structuremergeviewer.ICompareInput; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.mapping.IModelProviderDescriptor; import org.eclipse.core.resources.mapping.ModelProvider; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtension; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.compare.EMFCompareException; import org.eclipse.emf.compare.EMFComparePlugin; import org.eclipse.emf.compare.diff.metamodel.ComparisonResourceSetSnapshot; import org.eclipse.emf.compare.diff.metamodel.ComparisonResourceSnapshot; import org.eclipse.emf.compare.diff.metamodel.ComparisonSnapshot; import org.eclipse.emf.compare.diff.metamodel.DiffFactory; import org.eclipse.emf.compare.diff.metamodel.DiffModel; import org.eclipse.emf.compare.diff.metamodel.DiffResourceSet; import org.eclipse.emf.compare.diff.service.DiffService; import org.eclipse.emf.compare.match.MatchOptions; import org.eclipse.emf.compare.match.engine.GenericMatchScopeProvider; import org.eclipse.emf.compare.match.metamodel.MatchFactory; import org.eclipse.emf.compare.match.metamodel.MatchModel; import org.eclipse.emf.compare.match.metamodel.MatchResourceSet; import org.eclipse.emf.compare.match.service.MatchService; import org.eclipse.emf.compare.ui.EMFCompareUIMessages; import org.eclipse.emf.compare.ui.EMFCompareUIPlugin; import org.eclipse.emf.compare.ui.ICompareInputDetailsProvider; import org.eclipse.emf.compare.ui.ModelCompareInput; import org.eclipse.emf.compare.ui.team.AbstractTeamHandler; import org.eclipse.emf.compare.ui.util.EMFCompareConstants; import org.eclipse.emf.compare.util.EMFCompareMap; import org.eclipse.emf.compare.util.EclipseModelUtils; import org.eclipse.emf.compare.util.ModelUtils; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Shell; import org.eclipse.team.core.mapping.ISynchronizationContext; import org.eclipse.team.ui.mapping.ISynchronizationCompareAdapter; import org.eclipse.ui.PlatformUI; /** * This class will allow model comparison given a CompareConfiguration while allowing specific handling of * resource loading when team providers require it. * * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a> */ public final class ModelComparator implements ICompareInputDetailsProvider { /** * This will be initialized to <code>false</code> in eclipse 3.5M6 and above, <code>true</code> otherwise. */ protected static final boolean IS_LESS_GANYMEDE; /** Keeps track of the team handlers declared for the extension point. */ private static final Set<TeamHandlerDescriptor> CACHED_HANDLERS = new LinkedHashSet<TeamHandlerDescriptor>(); /** * This will contain instances of comparators associated to given CompareConfiguration. */ private static final Map<CompareConfiguration, ModelComparator> INSTANCES = new HashMap<CompareConfiguration, ModelComparator>(); /** Name of the extension point to parse for team handlers. */ private static final String TEAM_HANDLERS_EXTENSION_POINT = "org.eclipse.emf.compare.ui.team.handler"; //$NON-NLS-1$ /** This will hold the result of these resources' comparison. */ protected ComparisonSnapshot comparisonResult; /** Keeps a reference to the last "ancestor" element of the input. */ private ITypedElement ancestorElement; /** Resource of the ancestor model used in this comparison. */ private Resource ancestorResource; /** Keeps a reference to the root CompareConfiguration. */ private final CompareConfiguration compareConfiguration; /** This will keep track of the handler used by this comparison. */ private AbstractTeamHandler comparisonHandler; /** Keeps a reference to the last "left" element of the input. */ private ITypedElement leftElement; /** * Indicates that the left compared model is remote and shouldn't be modified. */ private boolean leftIsRemote; /** Resource of the left model used in this comparison. */ private Resource leftResource; /** Keeps a reference to the last "right" element of the input. */ private ITypedElement rightElement; /** * Indicates that the right compared model is remote and shouldn't be modified. This will only happen if * we couldn't load a local resource when comparing with repository. */ private boolean rightIsRemote; /** Resource of the right model used in this comparison. */ private Resource rightResource; /** The compare input we were initially fed. */ private final ICompareInput compareInput; /** * This will be set to <code>true</code> if we managed to load the resources, <code>false</code> if an * error occured. */ private boolean loadingSucceeded; static { parseExtensionMetaData(); boolean temp = false; try { Class.forName("org.eclipse.compare.internal.ICompareAsText"); //$NON-NLS-1$ temp = true; } catch (ClassNotFoundException e) { // Will be thrown in Eclipse 3.5M6 or above } IS_LESS_GANYMEDE = temp; } /** * Instantiates a ModelComparator given its root CompareConfiguration. * * @param configuration * CompareConfiguration of this comparator. * @param input * The previous compare input. */ private ModelComparator(CompareConfiguration configuration, ICompareInput input) { compareConfiguration = configuration; compareInput = input; } /** * This will return the ModelComparator associated to the given CompareConfiguration. * * @param configuration * CompareConfiguration of this comparator. * @param input * The previous compare input. * @return The comparator for this configuration. */ public static ModelComparator getComparator(CompareConfiguration configuration, ICompareInput input) { if (!INSTANCES.containsKey(configuration)) { INSTANCES.put(configuration, new ModelComparator(configuration, input)); } return INSTANCES.get(configuration); } /** * This will return the ModelComparator associated to the given CompareConfiguration. * * @param configuration * CompareConfiguration of this comparator. * @return The comparator for this configuration. */ public static ModelComparator getComparator(CompareConfiguration configuration) { return INSTANCES.get(configuration); } /** * Removes the comparator corresponding to a no longer used configuration. * * @param configuration * CompareConfiguration which comparator should be removed. */ public static void removeComparator(CompareConfiguration configuration) { // In eclipse 3.5M6 and above, viewers can be switched. We cannot remove the comparator then if (IS_LESS_GANYMEDE) { INSTANCES.remove(configuration); } } /** * This will parse {@link #TEAM_HANDLERS_EXTENSION_POINT} for team handlers. */ private static void parseExtensionMetaData() { final IExtension[] extensions = Platform.getExtensionRegistry() .getExtensionPoint(TEAM_HANDLERS_EXTENSION_POINT).getExtensions(); // The RevisionComparisonHandler will be added last in the registry to allow clients override TeamHandlerDescriptor revisionHandler = null; for (final IExtension extension : extensions) { for (final IConfigurationElement configElement : extension.getConfigurationElements()) { final TeamHandlerDescriptor descriptor = new TeamHandlerDescriptor(configElement); if (RevisionComparisonHandler.class.getName().equals(descriptor.getHandlerClass())) { revisionHandler = descriptor; } else { CACHED_HANDLERS.add(descriptor); } } } CACHED_HANDLERS.add(revisionHandler); } /** * This will run the comparison process and return the resulting {@link ComparisonSnapshot snapshot}. * * @param configuration * Compared configuration of this comparison. Properties will be set on this to hold comparison * data. * @return Result of the comparison of the loaded resources. */ public ComparisonSnapshot compare(CompareConfiguration configuration) { if (!loadingSucceeded) { // We couldn't load the resource. It's useless to carry on. comparisonResult = DiffFactory.eINSTANCE.createComparisonResourceSetSnapshot(); } if (comparisonResult == null) { final Date start = Calendar.getInstance().getTime(); MatchService.setMatchEngineSelector(new VisualEngineSelector()); DiffService.setDiffEngineSelector(new VisualEngineSelector()); // show prompt to select the match scope final MessageDialog queryMatchScopeDialog = new MessageDialog( PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), EMFCompareUIMessages.getString("ModelComparator.MatchModeSelectionDialogTitle"), null, //$NON-NLS-1$ EMFCompareUIMessages.getString("ModelComparator.MatchModeSelectionDialogMessage"), //$NON-NLS-1$ MessageDialog.NONE, new String[] { EMFCompareUIMessages .getString("ModelComparator.MatchModelSelectionDialogResourceOption"), //$NON-NLS-1$ EMFCompareUIMessages .getString("ModelComparator.MatchModelSelectionDialogResourceSetOption") }, //$NON-NLS-1$ 0); final boolean doResourceMatchOnly = queryMatchScopeDialog.open() == 0; if (doResourceMatchOnly) { comparisonResult = doResourceCompare(); } else { comparisonResult = doResourceSetCompare(); } // set date of comparison final Date end = Calendar.getInstance().getTime(); comparisonResult.setDate(end); configuration.setLeftEditable(configuration.isLeftEditable() && !isLeftRemote()); configuration.setRightEditable(configuration.isRightEditable() && !isRightRemote()); configuration.setProperty(EMFCompareConstants.PROPERTY_COMPARISON_TIME, end.getTime() - start.getTime()); if (isLeftRemote()) { if (doResourceMatchOnly) { configuration.setLeftLabel(EMFCompareUIMessages.getString( EMFCompareUIMessages.getString("ModelComparator.remoteResourceCompareLabel"))); //$NON-NLS-1$ configuration.setRightLabel(EMFCompareUIMessages.getString( EMFCompareUIMessages.getString("ModelComparator.localResourceCompareLabel"))); //$NON-NLS-1$ } else { configuration.setLeftLabel(EMFCompareUIMessages.getString( EMFCompareUIMessages.getString("ModelComparator.remoteResourceSetCompareLabel"))); //$NON-NLS-1$ configuration.setRightLabel(EMFCompareUIMessages.getString( EMFCompareUIMessages.getString("ModelComparator.localResourceSetCompareLabel"))); //$NON-NLS-1$ } } } return comparisonResult; } /** * Perform a comparison of the left and right (and if specified ancestor resource). * * @return the {@link ComparisonResourceSnapshot} that contains the comparison result. */ protected ComparisonResourceSnapshot doResourceCompare() { // create snapshot final ComparisonResourceSnapshot snapshot = DiffFactory.eINSTANCE.createComparisonResourceSnapshot(); snapshot.setDiff(DiffFactory.eINSTANCE.createDiffModel()); snapshot.setMatch(MatchFactory.eINSTANCE.createMatchModel()); try { PlatformUI.getWorkbench().getProgressService().busyCursorWhile(new IRunnableWithProgress() { public void run(IProgressMonitor monitor) throws InterruptedException { final Map<String, Object> options = new EMFCompareMap<String, Object>(); options.put(MatchOptions.OPTION_PROGRESS_MONITOR, monitor); // do comparison final MatchModel match; if (getAncestorResource() == null) { options.put(MatchOptions.OPTION_MATCH_SCOPE_PROVIDER, new GenericMatchScopeProvider(getLeftResource(), getRightResource())); match = MatchService.doResourceMatch(getLeftResource(), getRightResource(), options); } else { options.put(MatchOptions.OPTION_MATCH_SCOPE_PROVIDER, new GenericMatchScopeProvider( getLeftResource(), getRightResource(), getAncestorResource())); match = MatchService.doResourceMatch(getLeftResource(), getRightResource(), getAncestorResource(), options); } final DiffModel diff = DiffService.doDiff(match, getAncestorResource() != null); snapshot.setDiff(diff); snapshot.setMatch(match); } }); } catch (final InterruptedException e) { EMFComparePlugin.log(e, false); } catch (final EMFCompareException e) { EMFComparePlugin.log(e, false); } catch (final InvocationTargetException e) { EMFComparePlugin.log(e, true); } return snapshot; } /** * /** Perform a comparison of the left and right (and if specified ancestor resource), as well as all * other resources, included in their respective resource sets. * * @return the {@link ComparisonResourceSetSnapshot} that contains the comparison result. */ protected ComparisonResourceSetSnapshot doResourceSetCompare() { final ComparisonResourceSetSnapshot snapshot = DiffFactory.eINSTANCE.createComparisonResourceSetSnapshot(); snapshot.setDiffResourceSet(DiffFactory.eINSTANCE.createDiffResourceSet()); snapshot.setMatchResourceSet(MatchFactory.eINSTANCE.createMatchResourceSet()); try { PlatformUI.getWorkbench().getProgressService().busyCursorWhile(new IRunnableWithProgress() { public void run(IProgressMonitor monitor) throws InterruptedException { final Map<String, Object> options = new EMFCompareMap<String, Object>(); options.put(MatchOptions.OPTION_PROGRESS_MONITOR, monitor); // do comparison final MatchResourceSet match; if (getAncestorResource() == null) { options.put(MatchOptions.OPTION_MATCH_SCOPE_PROVIDER, new GenericMatchScopeProvider( getLeftResource().getResourceSet(), getRightResource().getResourceSet())); match = MatchService.doResourceSetMatch(getLeftResource().getResourceSet(), getRightResource().getResourceSet(), options); } else { options.put(MatchOptions.OPTION_MATCH_SCOPE_PROVIDER, new GenericMatchScopeProvider(getLeftResource().getResourceSet(), getRightResource().getResourceSet(), getAncestorResource().getResourceSet())); match = MatchService.doResourceSetMatch(getLeftResource().getResourceSet(), getRightResource().getResourceSet(), getAncestorResource().getResourceSet(), options); } final DiffResourceSet diff = DiffService.doDiff(match, getAncestorResource() != null); snapshot.setDiffResourceSet(diff); snapshot.setMatchResourceSet(match); } }); } catch (final InterruptedException e) { EMFComparePlugin.log(e, false); } catch (final EMFCompareException e) { EMFComparePlugin.log(e, false); } catch (final InvocationTargetException e) { EMFComparePlugin.log(e, true); } return snapshot; } /** * Returns the compared resources ancestor. * * @return The compared resources ancestor. */ public Resource getAncestorResource() { if (comparisonHandler != null) return comparisonHandler.getAncestorResource(); return ancestorResource; } /** * This will return the comparison result. * * @return The comparison result. <code>null</code> if no comparison has been done since last loading * resources. */ public ComparisonSnapshot getComparisonResult() { return comparisonResult; } /** * Returns the left compared resource. * * @return The left compared resource. */ public Resource getLeftResource() { if (comparisonHandler != null) return comparisonHandler.getLeftResource(); return leftResource; } /** * Returns the right compared resource. * * @return The right compared resource. */ public Resource getRightResource() { if (comparisonHandler != null) return comparisonHandler.getRightResource(); return rightResource; } /** * Indicates that the left resource is remote and shouldn't be modified. * * @return <code>true</code> if the left compared resource is remote, <code>false</code> otherwise. */ public boolean isLeftRemote() { if (comparisonHandler != null) return comparisonHandler.isLeftRemote(); return leftIsRemote; } /** * Indicates that the right resource is remote and shouldn't be modified. Note that this will never return * <code>true</code> unless we failed to load a local resource for comparison. * * @return <code>true</code> if the right compared resource is remote, <code>false</code> otherwise. */ public boolean isRightRemote() { if (comparisonHandler != null) return comparisonHandler.isRightRemote(); return rightIsRemote; } /** * Returns the compare input we've initially been fed. * * @return The initial compare input. */ public ICompareInput getCompareInput() { return compareInput; } /** * This will load the resources held by <code>input</code>. * * @param input * CompareInput which holds the resources to be loaded. * @return <code>true</code> if the given models have been successfully loaded, <code>false</code> * otherwise. */ public boolean loadResources(ICompareInput input) { if (ancestorElement != input.getAncestor() || leftElement != input.getLeft() || rightElement != input.getRight()) { clear(); leftElement = input.getLeft(); rightElement = input.getRight(); ancestorElement = input.getAncestor(); // check whether this comparison hasn't already been played (workaround for #345415) if (handleResourceMapping(input)) { loadingSucceeded = true; return loadingSucceeded; } try { // This will be sufficient when comparing local resources loadingSucceeded = handleLocalResources(leftElement, rightElement, ancestorElement); // If resources weren't local, iterates through the registry to find // a proper team handler if (!loadingSucceeded) { final Iterator<TeamHandlerDescriptor> handlerDescriptorIterator = CACHED_HANDLERS.iterator(); while (handlerDescriptorIterator.hasNext()) { final AbstractTeamHandler handler = handlerDescriptorIterator.next().getHandlerInstance(); loadingSucceeded |= handler.loadResources(input); if (loadingSucceeded) { comparisonHandler = handler; break; } } } // We didn't find a proper handler, use a generic one if (!loadingSucceeded) { loadingSucceeded |= handleGenericResources(leftElement, rightElement, ancestorElement); } /* * The generic handler should work for any EMF resources. If we're here, no exception has been * thrown and loading ended accurately */ loadingSucceeded = true; } catch (final IOException e) { final String dialogMessage; if (IS_LESS_GANYMEDE) { dialogMessage = EMFCompareUIMessages.getString("ModelComparator.ResourceLoadingFailure"); //$NON-NLS-1$ } else { dialogMessage = EMFCompareUIMessages .getString("ModelComparator.ResourceLoadingFailureGanymede"); //$NON-NLS-1$ } final Dialog dialog = new CompareErrorDialog( PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), "Comparison failed", //$NON-NLS-1$ dialogMessage, new Status(IStatus.ERROR, EMFCompareUIPlugin.PLUGIN_ID, e.getMessage(), e)); final int buttonPressed = dialog.open(); if (buttonPressed == CompareErrorDialog.COMPARE_AS_TEXT_ID) { final Set<Object> set = new HashSet<Object>(); final CompareEditorInput editorInput = (CompareEditorInput) compareConfiguration.getContainer(); // value of the 3.3 and 3.4 "ICompareAsText.PROP_TEXT_INPUT" compareConfiguration.setProperty("org.eclipse.compare.TextInputs", set); //$NON-NLS-1$ set.add(editorInput); set.add(editorInput.getCompareResult()); CompareUI.openCompareEditorOnPage(editorInput, null); } } catch (final CoreException e) { EMFComparePlugin.log(e.getStatus()); } } else { // input was the same as the last } return loadingSucceeded; } /** * This is a workaround for bug 345415 and needs to be removed ASAP when this bug is fixed. Basically, * Platform/Compare does not call our ModelProvider when using the action * "right-click > Open In Compare Editor". We then do the work ourselves here... but with insufficient * information. We'll need to access non-API fields along the way. * * @param input * The input we've been fed by Platform/Compare. * @return <code>true</code> if we managed to find a ResourceMapping with a {@link ModelCompareInput} * corresponding to <em>input</em>, <code>false</code> otherwise. */ private boolean handleResourceMapping(ICompareInput input) { final IResourceProvider resourceProvider = (IResourceProvider) Platform.getAdapterManager() .getAdapter(leftElement, IResourceProvider.class); if (resourceProvider != null) { final IResource localResource = resourceProvider.getResource(); final IModelProviderDescriptor[] descriptors = ModelProvider.getModelProviderDescriptors(); for (int i = 0; i < descriptors.length; i++) { final IModelProviderDescriptor descriptor = descriptors[i]; try { final IResource[] resources = descriptor .getMatchingResources(new IResource[] { localResource, }); if (resources.length > 0) { final ModelProvider modelProvider = descriptor.getModelProvider(); final ISynchronizationCompareAdapter compareAdapter = (ISynchronizationCompareAdapter) Platform .getAdapterManager() .getAdapter(modelProvider, ISynchronizationCompareAdapter.class); // FIXME until 345415 is fixed, we need to find the proper model provider from here... // ... which requires access to non-API things. final Field contextField = input.getClass().getDeclaredField("context"); //$NON-NLS-1$ contextField.setAccessible(true); final ISynchronizationContext context = (ISynchronizationContext) contextField.get(input); final ICompareInput actualInput = compareAdapter.asCompareInput(context, localResource); if (actualInput instanceof ModelCompareInput) { comparisonResult = ((ModelCompareInput) actualInput).getComparisonSnapshot(); return true; } } } catch (CoreException e) { // FIXME log } catch (SecurityException e) { // FIXME remove when 345415 is fixed } catch (NoSuchFieldException e) { // FIXME remove when 345415 is fixed } catch (IllegalArgumentException e) { // FIXME remove when 345415 is fixed } catch (IllegalAccessException e) { // FIXME remove when 345415 is fixed } } } return false; } /** * We might want to create an editor for an already compared configuration. This enables us to do so. * * @param snapshot * The expected result of this comparison. */ public void setComparisonResult(ComparisonSnapshot snapshot) { if (snapshot instanceof ComparisonResourceSnapshot) { comparisonResult = DiffFactory.eINSTANCE.createComparisonResourceSetSnapshot(); comparisonResult.setDate(snapshot.getDate()); final DiffResourceSet diffRS = DiffFactory.eINSTANCE.createDiffResourceSet(); diffRS.getDiffModels().add(((ComparisonResourceSnapshot) snapshot).getDiff()); ((ComparisonResourceSetSnapshot) comparisonResult).setDiffResourceSet(diffRS); final MatchResourceSet matchRS = MatchFactory.eINSTANCE.createMatchResourceSet(); matchRS.getMatchModels().add(((ComparisonResourceSnapshot) snapshot).getMatch()); ((ComparisonResourceSetSnapshot) comparisonResult).setMatchResourceSet(matchRS); } else { comparisonResult = snapshot; } } /** * Clears all loaded resources from the resource set. */ private void clear() { clearResourceSet(leftResource, rightResource, ancestorResource); leftResource = null; rightResource = null; ancestorResource = null; comparisonResult = null; comparisonHandler = null; } /** * This will empty the resourceSet of the given <tt>resource</tt>. * * @param resource * Resource that is to be cleared. */ private void clearResourceSet(Resource... resource) { for (int i = 0; i < resource.length; i++) { if (resource[i] == null) { continue; } final ResourceSet resourceSet = resource[i].getResourceSet(); final Iterator<Resource> resourcesIterator = resourceSet.getResources().iterator(); while (resourcesIterator.hasNext()) { resourcesIterator.next().unload(); } resourceSet.getResources().clear(); } } /** * This generic handler should be able to load resources passed by any team plug-in. Using this handler * instead of the subversive specific handler in plugin org.eclipse.emf.compare.team.subversive will * result in unsaveable merge operations for example. Users of specific team plugins should write their * own handler to avoid going through this method in order for their files to be saveable (thus * mergeable). * * @param left * Handler of the left compared model. * @param right * Handler of the right compared model. * @param ancestor * Handler of these two models' common ancestor. * @return <code>true</code> If all resources have been loaded by this handler, <code>false</code> * otherwise. * @throws IOException * Thrown if the right resource cannot be loaded. * @throws CoreException * Thrown if exceptions occur when loading the remote resources (left and ancestor). */ private boolean handleGenericResources(ITypedElement left, ITypedElement right, ITypedElement ancestor) throws IOException, CoreException { if (left instanceof ResourceNode && right instanceof IStreamContentAccessor) { if (((ResourceNode) left).getResource().isAccessible()) { leftResource = EclipseModelUtils .load(((ResourceNode) left).getResource().getFullPath(), new ResourceSetImpl()).eResource(); } else { leftResource = ModelUtils.createResource(URI.createPlatformResourceURI( ((ResourceNode) left).getResource().getFullPath().toOSString(), true)); // resource has been deleted. We set it as "remote" to disable merge facilities leftIsRemote = true; } try { rightResource = ModelUtils.load(((IStreamContentAccessor) right).getContents(), right.getName(), new ResourceSetImpl()).eResource(); } catch (final IOException e) { // We couldn't load the remote resource. Considers it has been added to the repository rightResource = ModelUtils.createResource(URI.createURI(right.getName())); // Set the left as remote to disable merge facilities leftIsRemote = true; } rightIsRemote = true; if (ancestor != null) { try { ancestorResource = ModelUtils.load(((IStreamContentAccessor) ancestor).getContents(), ancestor.getName(), new ResourceSetImpl()).eResource(); } catch (final IOException e) { // Couldn't load ancestor resource, create an empty one ancestorResource = ModelUtils.createResource(URI.createURI(ancestor.getName())); } } return true; } /* * We should never be here. There always is a local resource when comparing with CVS. this code will * be executed if we couldn't manage to handle this local resource as such. Though the resource will * be loaded thanks to this generic handler, note that it will not be saveable. */ boolean result = false; if (left instanceof IStreamContentAccessor && right instanceof IStreamContentAccessor) { leftResource = ModelUtils .load(((IStreamContentAccessor) left).getContents(), left.getName(), new ResourceSetImpl()) .eResource(); rightResource = ModelUtils .load(((IStreamContentAccessor) right).getContents(), right.getName(), new ResourceSetImpl()) .eResource(); rightIsRemote = true; leftIsRemote = true; if (ancestor != null) { ancestorResource = ModelUtils.load(((IStreamContentAccessor) ancestor).getContents(), ancestor.getName(), new ResourceSetImpl()).eResource(); } result = true; } return result; } /** * This will try and load the given element as being local resources. * * @param left * Handler of the left compared model. * @param right * Handler of the right compared model. * @param ancestor * Handler of these two models' common ancestor. * @return <code>true</code> If all resources have been loaded by this handler, <code>false</code> * otherwise. * @throws IOException * Thrown if resources cannot be loaded. */ private boolean handleLocalResources(ITypedElement left, ITypedElement right, ITypedElement ancestor) throws IOException { if (left instanceof ResourceNode && right instanceof ResourceNode) { leftResource = EclipseModelUtils .load(((ResourceNode) left).getResource().getFullPath(), new ResourceSetImpl()).eResource(); rightResource = EclipseModelUtils .load(((ResourceNode) right).getResource().getFullPath(), new ResourceSetImpl()).eResource(); if (ancestor != null) { ancestorResource = EclipseModelUtils .load(((ResourceNode) ancestor).getResource().getFullPath(), new ResourceSetImpl()) .eResource(); } return true; } return false; } /** * Describes a team handler registered from a plug-in's extension point. * * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a> */ private static final class TeamHandlerDescriptor { /** * Name of the extension point attribute corresponding to the handler's class. */ private static final String ATTRIBUTE_HANDLER_CLASS = "class"; //$NON-NLS-1$ /** * Keeps a reference to the configuration element that describes this handler. */ private final IConfigurationElement element; /** This descriptor's wrapped {@link AbstractTeamHandler handler}. */ private AbstractTeamHandler handler; /** * Constructs a new descriptor from an IConfigurationElement. * * @param configuration * Configuration of the team handler. */ public TeamHandlerDescriptor(IConfigurationElement configuration) { element = configuration; } /** * Returns an instance of the described handler. * * @return Instance of the handler. */ public AbstractTeamHandler getHandlerInstance() { if (handler == null) { try { handler = (AbstractTeamHandler) element.createExecutableExtension(ATTRIBUTE_HANDLER_CLASS); } catch (final CoreException e) { EMFComparePlugin.log(e, true); } } return handler; } /** * Returns the class of the wrapped AbstractTeamHandler. This is only used internally to set the * RevisionComparisonHandler last. * * @return The class of the wrapped AbstractTeamHandler. */ String getHandlerClass() { return element.getAttribute(ATTRIBUTE_HANDLER_CLASS); } } /** * This implementation of an ErrorDialog allows us to display comparison failures to the user along with a * way for them to force a text comparison of the offending files. * * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a> */ final class CompareErrorDialog extends ErrorDialog { /** ID of the "Compare As Text" button. Not intended to be either subclassed or accessed externally. */ static final int COMPARE_AS_TEXT_ID = IDialogConstants.CLIENT_ID + 1; /** * Delegates to the super constructor. * * @param parentShell * Parent Shell of this viewer. * @param dialogTitle * Title of this error dialog. * @param dialogMessage * Message to display to the user. * @param status * The error to show to the user. */ public CompareErrorDialog(Shell parentShell, String dialogTitle, String dialogMessage, IStatus status) { super(parentShell, dialogTitle, dialogMessage, status, IStatus.OK | IStatus.INFO | IStatus.WARNING | IStatus.ERROR); } /** * {@inheritDoc} * * @see org.eclipse.jface.dialogs.ErrorDialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite) */ @Override protected void createButtonsForButtonBar(Composite parent) { /* * Using the CANCEL_ID for an "OK" button in order to inherit the cancel behavior but be coherent * with the error message. */ createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.OK_LABEL, true); if (IS_LESS_GANYMEDE) { createButton(parent, COMPARE_AS_TEXT_ID, "Compare As Text", false); //$NON-NLS-1$ } createDetailsButton(parent); } /** * {@inheritDoc} * * @see org.eclipse.jface.dialogs.ErrorDialog#buttonPressed(int) */ @Override protected void buttonPressed(int id) { if (id == COMPARE_AS_TEXT_ID) { setReturnCode(COMPARE_AS_TEXT_ID); close(); } else { super.buttonPressed(id); } } } }