/* * 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.core; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.isA; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import org.eclipse.core.resources.IResource; import org.eclipse.emf.common.command.Command; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.emf.edit.command.CommandParameter; import org.eclipse.emf.edit.domain.EditingDomain; import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.teiid.core.designer.ModelerCoreException; import org.teiid.core.designer.ModelerCoreRuntimeException; import org.teiid.core.designer.util.CoreArgCheck; import org.teiid.designer.core.ModelEditorImpl.AddCommandFactory; import org.teiid.designer.core.container.Container; import org.teiid.designer.core.metamodel.MetamodelDescriptor; import org.teiid.designer.core.resource.MMXmiResource; import org.teiid.designer.core.resource.xmi.MtkXmiResourceImpl; import org.teiid.designer.core.spi.RegistrySPI; import org.teiid.designer.core.transaction.UnitOfWork; import org.teiid.designer.core.util.ModelContents; import org.teiid.designer.core.util.ModelResourceContainerFactory; import org.teiid.designer.core.workspace.ModelResource; import org.teiid.designer.core.workspace.ModelUtil; import org.teiid.designer.core.workspace.ModelWorkspaceManager; import org.teiid.designer.metamodels.core.Annotation; import org.teiid.designer.metamodels.core.ModelAnnotation; /** * Mock the model editor */ public class ModelEditorMock { private ModelWorkspaceMock modelWkspMock; private ModelEditor modelEditor; /** * Create instance * @param modelWorkspaceMock * @throws Exception */ public ModelEditorMock(ModelWorkspaceMock modelWorkspaceMock) throws Exception { this.modelWkspMock = modelWorkspaceMock; modelEditor = mock(ModelEditor.class); // // Registers itself to ModelerCore // ((RegistrySPI) ModelerCore.getRegistry()).register(ModelerCore.MODEL_EDITOR_KEY, modelEditor); when(modelEditor.getName(isA(EObject.class))).thenAnswer(new Answer<String>() { @Override public String answer(InvocationOnMock invocation) throws Throwable { Object[] args = invocation.getArguments(); return ModelUtil.getName((EObject)args[0]); } }); when(modelEditor.getNameFeature(isA(EObject.class))).thenAnswer(new Answer<EStructuralFeature>() { @Override public EStructuralFeature answer(InvocationOnMock invocation) throws Throwable { Object[] args = invocation.getArguments(); return ModelUtil.getNameFeature((EObject)args[0]); } }); when(modelEditor.findModelResource(isA(Resource.class))).thenAnswer(new Answer<ModelResource>() { @Override public ModelResource answer(InvocationOnMock invocation) throws Throwable { Object[] args = invocation.getArguments(); Resource resource = (Resource) args[0]; return ModelerCore.getModelWorkspace().findModelResource(resource); } }); when(modelEditor.findModelResource(isA(EObject.class))).thenAnswer(new Answer<ModelResource>() { @Override public ModelResource answer(InvocationOnMock invocation) throws Throwable { Object[] args = invocation.getArguments(); EObject eObject = (EObject) args[0]; ModelResource modelResource = ModelerCore.getModelWorkspace().findModelResource(eObject); return modelResource; } }); when(modelEditor.findModelResource(isA(IResource.class))).thenAnswer(new Answer<ModelResource>() { @Override public ModelResource answer(InvocationOnMock invocation) throws Throwable { Object[] args = invocation.getArguments(); IResource resource = (IResource) args[0]; return (ModelResource)ModelWorkspaceManager.getModelWorkspaceManager().findModelWorkspaceItem(resource); } }); when(modelEditor.getUri(isA(EObject.class))).then(new Answer<URI>() { @Override public URI answer(InvocationOnMock invocation) throws Throwable { Object[] args = invocation.getArguments(); EObject object = (EObject) args[0]; if (object instanceof EClass) { Resource eResource = object.eResource(); // Do this only if we are in the Eclipse plugin environment since the metamodel // registry will not be loaded otherwise. if (eResource != null && ModelerCore.getPlugin() != null) { URI eResourceUri = eResource.getURI(); MetamodelDescriptor descriptor = ModelerCore.getMetamodelRegistry().getMetamodelDescriptor(eResourceUri); if (descriptor != null) { String logicalUri = URI.decode(descriptor.getNamespaceURI()); return URI.createURI(logicalUri).appendFragment(eResource.getURIFragment(object)); } } } // Otherwise return the URI based on the EObject's resource URI and // it's location within that resource return EcoreUtil.getURI(object); } }); when(modelEditor.getModelContents(isA(ModelResource.class))).thenAnswer(new Answer<ModelContents>() { @Override public ModelContents answer(InvocationOnMock invocation) throws Throwable { Object[] args = invocation.getArguments(); ModelResource resource = (ModelResource) args[0]; return ModelContents.getModelContents(resource); } }); when(modelEditor.getModelContents(isA(EObject.class))).thenAnswer(new Answer<ModelContents>() { @Override public ModelContents answer(InvocationOnMock invocation) throws Throwable { Object[] args = invocation.getArguments(); EObject eObject = (EObject) args[0]; return modelEditor.getModelContents(eObject.eResource()); } }); when(modelEditor.getModelContents(isA(Resource.class))).thenAnswer(new Answer<ModelContents>() { @Override public ModelContents answer(InvocationOnMock invocation) throws Throwable { Object[] args = invocation.getArguments(); Resource resource = (Resource) args[0]; if (resource instanceof MtkXmiResourceImpl) { return ((MtkXmiResourceImpl)resource).getModelContents(); } final ModelResource modelResource = modelEditor.findModelResource(resource); return modelEditor.getModelContents(modelResource); } }); when(modelEditor.getModelAnnotation(isA(EObject.class))).thenAnswer(new Answer<ModelAnnotation>() { @Override public ModelAnnotation answer(InvocationOnMock invocation) throws Throwable { Object[] args = invocation.getArguments(); EObject eObject = (EObject) args[0]; final Resource resource = eObject.eResource(); if (resource instanceof MMXmiResource) { return ((MMXmiResource)resource).getModelAnnotation(); } final ModelResource modelResource = resource == null ? null : modelEditor.findModelResource(resource); return modelResource == null ? null : modelResource.getModelAnnotation(); } }); when(modelEditor.getAnnotation(isA(EObject.class), anyBoolean())).thenAnswer(new Answer<Annotation>() { @Override public Annotation answer(InvocationOnMock invocation) throws Throwable { Object[] args = invocation.getArguments(); EObject eObject = (EObject) args[0]; Boolean forceCreate = (Boolean) args[1]; final Resource eObjectResource = eObject.eResource(); if (eObjectResource instanceof MMXmiResource) { // Just look up the annotations right off the resource ... final MMXmiResource emfResource = (MMXmiResource)eObjectResource; Annotation annotation = emfResource.getAnnotation(eObject); if (annotation == null && forceCreate) { annotation = ModelResourceContainerFactory.createNewAnnotation(eObject, emfResource.getAnnotationContainer(true)); } return annotation; } return null; } }); doAnswer(new Answer() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { Object[] args = invocation.getArguments(); addValue(args[0], args[1], (EList) args[2], CommandParameter.NO_INDEX); return null; } }).when(modelEditor).addValue(any(), any(), isA(EList.class)); } public void dispose() { Mockito.reset(modelEditor); ((RegistrySPI) ModelerCore.getRegistry()).unregister(ModelerCore.MODEL_EDITOR_KEY); modelEditor = null; modelWkspMock = null; } /** * @return the modelEditor */ public ModelEditor getModelEditor() { return this.modelEditor; } private Container getContainer() { return modelWkspMock.getContainer(); } protected void executeCommandInTransaction( final UnitOfWork uow, final Object owner, final Command cmd ) throws ModelerCoreException { CoreArgCheck.isNotNull(uow); if (cmd == null) fail("Command was null"); //$NON-NLS-1$ if (!cmd.canExecute()) { fail("Command cannot execute"); //$NON-NLS-1$ } // Execute the command ... uow.executeCommand(cmd); } protected Object executeAsTransaction( final TransactionRunnable runnable, Container container, final String operationDescription, final boolean isSignificant, final boolean undoable, final Object source ) throws ModelerCoreException { // Use default container if not specified if (container == null) { container = getContainer(); } // Get the current transaction (this may create one) ... final UnitOfWork uow = container.getEmfTransactionProvider().getCurrent(); boolean startedTxn = false; // If the current transaction is new, it must be started ... if (uow.requiresStart()) { uow.begin(); startedTxn = true; uow.setSignificant(isSignificant); uow.setSource(source); uow.setUndoable(undoable); // Set the description ... if (operationDescription != null) { uow.setDescription(operationDescription); } } boolean failed = false; Object result = null; try { // Perform the requested work result = runnable.run(uow); } catch (ModelerCoreException t) { // There was a runtime exception while performing the work failed = true; throw t; } catch (RuntimeException t) { // There was a runtime exception while performing the work failed = true; throw new ModelerCoreRuntimeException(t); } finally { if (startedTxn) { // We started the current transaction ... if (!failed) { // Commit the transaction ... try { uow.commit(); } catch (Throwable e) { ModelerCore.Util.log(e); failed = true; } } if (failed) { // Rollback the transaction ... // (which may have failed while performing the work or when committing) try { uow.rollback(); } catch (ModelerCoreException e1) { ModelerCore.Util.log(e1); } } } } return result; } private String getPresentationValue( final Object obj ) { if (obj == null) { return ""; //$NON-NLS-1$ } if (obj instanceof EObject) { for (Iterator iter = ((EObject)obj).eClass().getEAllStructuralFeatures().iterator(); iter.hasNext();) { final EStructuralFeature feature = (EStructuralFeature)iter.next(); if (ModelEditor.NAME_FEATURE_NAME.equalsIgnoreCase(feature.getName())) { Object val = ((EObject)obj).eGet(feature); if (val == null) { return ((EObject)obj).eClass().getName(); } return val.toString(); } } return ((EObject)obj).eClass().getName(); } else if (obj instanceof Resource) { return URI.decode(((Resource)obj).getURI().toString()); } else if (obj instanceof Collection) { if (((Collection)obj).size() > 1) { return ModelerCore.Util.getString("ModelEditorImpl.many_1"); //$NON-NLS-1$ } else if (((Collection)obj).size() == 0) { return ModelerCore.Util.getString("ModelEditorImpl.empty_list_2"); //$NON-NLS-1$ } Object first = ((Collection)obj).iterator().next(); return getPresentationValue(first); } return obj.toString(); } protected void addValue( final Object owner, final Object value, final EList feature, final int index ) throws ModelerCoreException { CoreArgCheck.isNotNull(owner); CoreArgCheck.isNotNull(value); CoreArgCheck.isNotNull(feature); // convert the value into a collection final Collection values = new ArrayList(); if (value instanceof Collection) { values.addAll((Collection)value); } else { values.add(value); } final Container cntr = getContainer(); if (cntr == null) { feature.add(index, values); } else { final boolean isSignificant = true; final String operationDescription = ModelerCore.Util.getString("ModelEditorImpl.Add_values_to_{0}_1", getPresentationValue(owner)); //$NON-NLS-1$ final TransactionRunnable runnable = new TransactionRunnable() { @Override public Object run( final UnitOfWork uow ) throws ModelerCoreException { final EditingDomain ed = modelWkspMock.getEditingDomain(); Command command = AddCommandFactory.create(owner, ed, feature, values, index); executeCommandInTransaction(uow, owner, command); return null; } }; executeAsTransaction(runnable, cntr, operationDescription, isSignificant, true, this); } } }