blob: 7d653279f2a1781abcef46d084f048805e2e6de7 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2012 Oracle. 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:
* Oracle - initial API and implementation
******************************************************************************/
package org.eclipse.jpt.jpa.core.internal.refactoring;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.resources.mapping.IResourceChangeDescriptionFactory;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jpt.common.utility.internal.CollectionTools;
import org.eclipse.jpt.common.utility.internal.iterables.EmptyIterable;
import org.eclipse.jpt.jpa.core.JpaProject;
import org.eclipse.jpt.jpa.core.JpaProjectManager;
import org.eclipse.jpt.jpa.core.JptJpaCorePlugin;
import org.eclipse.jpt.jpa.core.context.persistence.MappingFileRef;
import org.eclipse.jpt.jpa.core.context.persistence.Persistence;
import org.eclipse.jpt.jpa.core.context.persistence.PersistenceUnit;
import org.eclipse.jpt.jpa.core.context.persistence.PersistenceXml;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.CompositeChange;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.core.refactoring.TextChange;
import org.eclipse.ltk.core.refactoring.TextFileChange;
import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
import org.eclipse.ltk.core.refactoring.participants.RenameParticipant;
import org.eclipse.ltk.core.refactoring.participants.ResourceChangeChecker;
import org.eclipse.text.edits.MalformedTreeException;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.ReplaceEdit;
import org.eclipse.text.edits.TextEdit;
public abstract class AbstractJpaRenameJavaElementParticipant
extends RenameParticipant {
protected IJavaElement originalJavaElement;
/**
* Store the persistence.xml ReplaceEdits in the checkConditions() call
* to avoid duplicated effort in createChange().
*/
protected final Map<IFile, Iterable<ReplaceEdit>> persistenceXmlReplaceEdits;
/**
* Store the mapping file ReplaceEdits in the checkConditions() call
* to avoid duplicated effort in createChange().
*/
protected final Map<IFile, Iterable<ReplaceEdit>> mappingFileReplaceEdits;
protected AbstractJpaRenameJavaElementParticipant() {
super();
this.persistenceXmlReplaceEdits = new HashMap<IFile, Iterable<ReplaceEdit>>();
this.mappingFileReplaceEdits = new HashMap<IFile, Iterable<ReplaceEdit>>();
}
@Override
protected boolean initialize(Object element) {
if (!getArguments().getUpdateReferences()) {
//we do not want to do any refactoring if the user chooses not to update references
return false;
}
this.originalJavaElement = (IJavaElement) element;
return true;
}
protected IJavaElement getOriginalJavaElement() {
return this.originalJavaElement;
}
//**************** RefactoringParticipant implementation *****************
/**
* Inform the refactoring processor of any files that are going to change. In the process of determining
* this go ahead and build up the appropriate ReplaceEdits to be used in the createChange()
*/
@Override
public RefactoringStatus checkConditions(IProgressMonitor monitor, CheckConditionsContext context) throws OperationCanceledException {
monitor.subTask(JpaCoreRefactoringMessages.JPA_REFACORING_PARTICIPANT_LOADING_JPA_PROJECTS_SUB_TASK_NAME);
Iterable<JpaProject> jpaProjects = this.getJpaProjects();
int size = CollectionTools.size(jpaProjects);
if (size == 0) {
return null;
}
SubMonitor sm = SubMonitor.convert(monitor, size*10 + 2);
sm.subTask(this.getCheckConditionsSubTaskName());
ResourceChangeChecker checker = (ResourceChangeChecker) context.getChecker(ResourceChangeChecker.class);
IResourceChangeDescriptionFactory deltaFactory = checker.getDeltaFactory();
for (JpaProject jpaProject : jpaProjects) {
this.createReplaceEdits(sm.newChild(10), jpaProject);
}
if (sm.isCanceled()) {
throw new OperationCanceledException();
}
for (IFile file : this.persistenceXmlReplaceEdits.keySet()) {
deltaFactory.change(file);
}
sm.worked(1);
for (IFile file : this.mappingFileReplaceEdits.keySet()) {
deltaFactory.change(file);
}
sm.worked(1);
return null;
}
protected Iterable<JpaProject> getJpaProjects() throws OperationCanceledException {
try {
return this.getJpaProjectManager().waitToGetJpaProjects();
} catch (InterruptedException ex) {
throw new OperationCanceledException(ex.getMessage());
}
}
protected JpaProjectManager getJpaProjectManager() {
return (JpaProjectManager) ResourcesPlugin.getWorkspace().getAdapter(JpaProjectManager.class);
}
protected abstract String getCompositeChangeName();
/**
* This will be appended to the main refactoring task named : 'Checking preconditions...'
*/
protected abstract String getCheckConditionsSubTaskName();
@Override
public Change createChange(IProgressMonitor monitor) throws CoreException, OperationCanceledException {
if (this.persistenceXmlReplaceEdits.isEmpty() && this.mappingFileReplaceEdits.isEmpty()) {
return null;
}
SubMonitor sm = SubMonitor.convert(monitor, this.persistenceXmlReplaceEdits.size() + this.mappingFileReplaceEdits.size());
sm.subTask(this.getCreateChangeSubTaskName());
CompositeChange compositeChange = new CompositeChange(this.getCompositeChangeName());
for (IFile persistenceXmlFile : this.persistenceXmlReplaceEdits.keySet()) {
this.addPersistenceXmlRenameEdits(persistenceXmlFile, compositeChange);
sm.worked(1);
}
for (IFile mappingFile : this.mappingFileReplaceEdits.keySet()) {
if (sm.isCanceled()) {
throw new OperationCanceledException();
}
this.addMappingFileRenameEdits(mappingFile, compositeChange);
sm.worked(1);
}
//must check for children in case all changes were made in other participant's TextChanges,
//want to return null so our node does not appear in the preview tree
return compositeChange.getChildren().length == 0 ? null : compositeChange;
}
/**
* This will be appended to the main refactoring task named : 'Creating workspace modifications...'
*/
protected abstract String getCreateChangeSubTaskName();
protected void createReplaceEdits(IProgressMonitor monitor, JpaProject jpaProject) throws OperationCanceledException {
PersistenceUnit persistenceUnit = getPersistenceUnit(jpaProject);
if (persistenceUnit == null) {
return;
}
SubMonitor sm = SubMonitor.convert(monitor, 1 + persistenceUnit.getMappingFileRefsSize());
Iterable<ReplaceEdit> classRefDeleteEdits = this.createPersistenceXmlReplaceEditsCheckClasspath(persistenceUnit);
sm.worked(1);
if (!CollectionTools.isEmpty(classRefDeleteEdits)) {
this.persistenceXmlReplaceEdits.put(jpaProject.getPersistenceXmlResource().getFile(), classRefDeleteEdits);
}
for (MappingFileRef mappingFileRef : persistenceUnit.getMappingFileRefs()) {
if (sm.isCanceled()) {
throw new OperationCanceledException();
}
Iterable<ReplaceEdit> edits = this.createMappingFileReplaceEditsCheckClasspath(mappingFileRef);
if (!CollectionTools.isEmpty(edits)) {
IFile file = (IFile) mappingFileRef.getMappingFile().getResource();
this.mappingFileReplaceEdits.put(file, edits);
}
sm.worked(1);
}
}
protected Iterable<ReplaceEdit> createPersistenceXmlReplaceEditsCheckClasspath(PersistenceUnit persistenceUnit) {
//check isOnClassPath since there could be types with the same name in different projects
if (persistenceUnit.getJpaProject().getJavaProject().isOnClasspath(this.originalJavaElement)) {
return createPersistenceXmlReplaceEdits(persistenceUnit);
}
return EmptyIterable.instance();
}
protected abstract Iterable<ReplaceEdit> createPersistenceXmlReplaceEdits(PersistenceUnit persistenceUnit);
protected void addPersistenceXmlRenameEdits(IFile persistenceXmlFile, CompositeChange compositeChange) {
Iterable<ReplaceEdit> replacePackageEdits = this.persistenceXmlReplaceEdits.get(persistenceXmlFile);
TextChange textChange = getTextChange(persistenceXmlFile);
if (textChange == null) {
textChange = new TextFileChange(this.getPersistenceXmlChangeName(), persistenceXmlFile);
//TODO probably need to figure out TextEditGroups since these can be used to show check boxes under the file in the preview dialog
//also used to add edits to existing changes??
MultiTextEdit multiTextEdit = new MultiTextEdit();
textChange.setEdit(multiTextEdit);
// textChange.addTextEditGroup(new TextEditGroup("edit persistence unit", multiTextEdit));???
compositeChange.add(textChange);
}
this.addEdits(textChange, replacePackageEdits);
}
protected abstract String getPersistenceXmlChangeName();
protected Iterable<ReplaceEdit> createMappingFileReplaceEditsCheckClasspath(MappingFileRef mappingFileRef) {
//check isOnClassPath since there could be types with the same name in different projects
if (mappingFileRef.getJpaProject().getJavaProject().isOnClasspath(this.originalJavaElement)) {
return this.createMappingFileReplaceEdits(mappingFileRef);
}
return EmptyIterable.instance();
}
protected abstract Iterable<ReplaceEdit> createMappingFileReplaceEdits(MappingFileRef mappingFileRef);
protected void addMappingFileRenameEdits(IFile mappingFile, CompositeChange compositeChange) {
Iterable<ReplaceEdit> replacedTypeEdits = this.mappingFileReplaceEdits.get(mappingFile);
TextChange textChange = getTextChange(mappingFile);
if (textChange == null) {
textChange = new TextFileChange(this.getMappingFileChangeName(), mappingFile);
MultiTextEdit multiTextEdit = new MultiTextEdit();
textChange.setEdit(multiTextEdit);
compositeChange.add(textChange);
}
this.addEdits(textChange, replacedTypeEdits);
}
protected abstract String getMappingFileChangeName();
private PersistenceUnit getPersistenceUnit(JpaProject jpaProject) {
PersistenceXml persistenceXml = jpaProject.getRootContextNode().getPersistenceXml();
if (persistenceXml == null) {
return null;
}
Persistence persistence = persistenceXml.getPersistence();
if (persistence == null) {
return null;
}
if (persistence.getPersistenceUnitsSize() != 1) {
return null; // the context model currently only supports 1 persistence unit
}
return persistence.getPersistenceUnits().iterator().next();
}
private void addEdits(TextChange textChange, Iterable<? extends TextEdit> textEdits) {
for (TextEdit textEdit : textEdits) {
try {
textChange.addEdit(textEdit);
}
catch (MalformedTreeException ex) {
//log exception and don't add this persistence.xml type deletion to the conflicting change object
JptJpaCorePlugin.log(ex);
}
}
}
}