/*******************************************************************************
* Copyright (c) 2015 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is 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:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.batch.ui.participants;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IType;
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.TextFileChange;
import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
import org.eclipse.ltk.core.refactoring.participants.RenameParticipant;
import org.eclipse.osgi.util.NLS;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.ReplaceEdit;
import org.eclipse.text.edits.TextEdit;
import org.jboss.tools.batch.core.BatchConstants;
import org.jboss.tools.batch.core.IBatchArtifact;
import org.jboss.tools.batch.core.IBatchProject;
import org.jboss.tools.batch.core.IBatchProperty;
import org.jboss.tools.batch.internal.core.impl.BatchProject;
import org.jboss.tools.batch.internal.core.impl.BatchProjectFactory;
import org.jboss.tools.batch.internal.core.impl.BatchUtil;
import org.jboss.tools.batch.ui.BatchUIPlugin;
import org.jboss.tools.common.java.IAnnotationDeclaration;
import org.jboss.tools.common.refactoring.FileChangeFactory;
import org.jboss.tools.common.text.ITextSourceReference;
import org.jboss.tools.common.util.BeanUtil;
public class BatchArtifactRenameParticipant extends RenameParticipant {
private IType type;
private IField field;
private String newName;
private RefactoringStatus status;
private CompositeChange rootChange;
private TextFileChange lastChange;
private ArrayList<String> keys = new ArrayList<String>();
@Override
protected boolean initialize(Object element) {
if (element instanceof IType) {
type = (IType) element;
status = new RefactoringStatus();
rootChange = new CompositeChange(BatchParticipantMessages.Updating_Batch_Artifacts_References);
return true;
}else if(element instanceof IField){
field = (IField) element;
type = field.getDeclaringType();
status = new RefactoringStatus();
rootChange = new CompositeChange(BatchParticipantMessages.Updating_Batch_Artifacts_References);
return true;
}
return false;
}
@Override
public String getName() {
return null;
}
@Override
public RefactoringStatus checkConditions(IProgressMonitor pm, CheckConditionsContext context)
throws OperationCanceledException {
IProject project = type.getJavaProject().getProject();
BatchProject batchProject = (BatchProject) BatchProjectFactory.getBatchProjectWithProgress(project);
if (batchProject == null) {
return status;
}
IBatchArtifact artifact = batchProject.getArtifact(type);
IBatchProperty property = null;
if (artifact != null) { // rename within Batch Artifact
if(field != null){ // field rename
for (IBatchProperty prop : artifact.getProperties()) {
if (prop.getField().equals(field)) {
IAnnotationDeclaration declaration = prop.getBatchPropertyDeclaration();
if (declaration == null || declaration.getMemberValue(BatchConstants.ATTR_NAME) != null) { // Annotation @Named has a value
return status;
}
newName = getArguments().getNewName();
property = prop;
}
}
}else{ // class rename
IAnnotationDeclaration declaration = artifact.getNamedDeclaration();
if (declaration == null || declaration.getMemberValue(null) != null) { // Annotation @Named has a value
return status;
}
newName = BeanUtil.getDefaultBeanName(getArguments().getNewName());
}
} else { // rename exception
String fullyQualifiedName = type.getFullyQualifiedName();
StringBuilder b = new StringBuilder(fullyQualifiedName);
b.replace(fullyQualifiedName.lastIndexOf(type.getElementName()), fullyQualifiedName.lastIndexOf(type.getElementName()) + type.getElementName().length(), getArguments().getNewName() );
newName = b.toString();
}
searchInProject(batchProject, artifact, property, pm);
BatchProject[] projects = batchProject.getAllDependentProjects(true);
for (BatchProject p : projects) {
searchInProject(p, artifact, property, pm);
}
return status;
}
private void searchInProject(IBatchProject batchProject, IBatchArtifact artifact, IBatchProperty property, IProgressMonitor monitor) {
monitor.beginTask(BatchParticipantMessages.Searching_For_Batch_Artifacts_References, batchProject
.getDeclaredBatchJobs().size());
Collection<ITextSourceReference> references = new HashSet<ITextSourceReference>();
if (!batchProject.getProject().isSynchronized(IResource.DEPTH_ZERO)) {
Exception exception = new Exception(NLS.bind(
BatchParticipantMessages.Cannot_Read_Out_Of_Sync_Resource, batchProject.getProject()
.getFullPath().toString()));
exception.setStackTrace(Thread.currentThread().getStackTrace());
BatchUIPlugin.getDefault().logError(exception);
return;
}
if (artifact != null) {
if(property != null){
references.addAll(searchForPropertyReferences(batchProject, artifact.getName(), property.getPropertyName(),
monitor));
}else{
references.addAll(searchForReferences(batchProject, BatchConstants.ATTR_REF, artifact.getName(),
monitor));
}
} else {
references.addAll(searchForReferences(batchProject, BatchConstants.ATTR_CLASS,
type.getFullyQualifiedName(), monitor));
}
for (ITextSourceReference reference : references) {
if (((IFile) reference.getResource()).isReadOnly()) {
Exception exception = new Exception(NLS.bind(
BatchParticipantMessages.Cannot_Change_Read_Only_File, ((IFile) reference.getResource())
.getFullPath().toString()));
exception.setStackTrace(Thread.currentThread().getStackTrace());
BatchUIPlugin.getDefault().logError(exception);
} else {
change((IFile) reference.getResource(), reference.getStartPosition(), reference.getLength(),
newName);
}
}
monitor.done();
}
private Collection<ITextSourceReference> searchForReferences(IBatchProject batchProject,
String attributeName, String attributeValue, IProgressMonitor monitor) {
int worked = 0;
Collection<ITextSourceReference> references = new HashSet<ITextSourceReference>();
for (IFile file : batchProject.getDeclaredBatchJobs()) {
if (monitor.isCanceled()) {
return references;
}
if (file.isPhantom()) {
continue;
}
if (!file.isSynchronized(IResource.DEPTH_ZERO)) {
Exception exception = new Exception(
NLS.bind(BatchParticipantMessages.Cannot_Read_Out_Of_Sync_Resource, file.getFullPath()
.toString()));
exception.setStackTrace(Thread.currentThread().getStackTrace());
BatchUIPlugin.getDefault().logError(exception);
return references;
}
references.addAll(BatchUtil.getAttributeReferences(file, attributeName, attributeValue));
monitor.worked(++worked);
}
return references;
}
private Collection<ITextSourceReference> searchForPropertyReferences(IBatchProject batchProject,
String artifactName, String propertyName, IProgressMonitor monitor) {
int worked = 0;
Collection<ITextSourceReference> references = new HashSet<ITextSourceReference>();
for (IFile file : batchProject.getDeclaredBatchJobs()) {
if (monitor.isCanceled()) {
return references;
}
if (file.isPhantom()) {
continue;
}
if (!file.isSynchronized(IResource.DEPTH_ZERO)) {
Exception exception = new Exception(
NLS.bind(BatchParticipantMessages.Cannot_Read_Out_Of_Sync_Resource, file.getFullPath()
.toString()));
exception.setStackTrace(Thread.currentThread().getStackTrace());
BatchUIPlugin.getDefault().logError(exception);
return references;
}
references.addAll(BatchUtil.getPropertyAttributeReferences(file, artifactName, propertyName));
monitor.worked(++worked);
}
return references;
}
protected TextFileChange getChange(IFile file) {
if (lastChange != null && lastChange.getFile().equals(file))
return lastChange;
for (int i = 0; i < rootChange.getChildren().length; i++) {
TextFileChange change = (TextFileChange) rootChange.getChildren()[i];
if (change.getFile().equals(file)) {
lastChange = change;
return lastChange;
}
}
lastChange = FileChangeFactory.getFileChange(file);
MultiTextEdit root = new MultiTextEdit();
lastChange.setEdit(root);
rootChange.add(lastChange);
return lastChange;
}
private void change(IFile file, int offset, int length, String text) {
String key = file.getFullPath().toString() + " " + offset;
if (!keys.contains(key)) {
TextFileChange change = getChange(file);
TextEdit edit = new ReplaceEdit(offset, length, text);
change.addEdit(edit);
keys.add(key);
}
}
@Override
public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
if (rootChange.getChildren().length > 0) {
return rootChange;
}
return null;
}
}