/*******************************************************************************
* Copyright (c) 2016 Pivotal, Inc.
* 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:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.quickfix.jdt.processors.imports;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.internal.ui.text.correction.ContributedProcessorDescriptor;
import org.eclipse.jdt.internal.ui.text.correction.JavaCorrectionProcessor;
import org.eclipse.jdt.internal.ui.text.correction.QuickFixProcessor;
import org.eclipse.jdt.ui.text.java.IQuickFixProcessor;
import org.osgi.framework.Bundle;
import org.springframework.ide.eclipse.quickfix.Activator;
/**
* Helper that adds/removes the JDT {@link QuickFixProcessor} from the
* {@link JavaCorrectionProcessor} registry in JDT.
* <p/>
* This is NOT a utility class. It holds state as it keeps track of the removed
* JDT quickfix processor, therefore only ONE helper should be created per STS
* session.
*
*/
public class JDTQuickFixProcessorHelper {
/**
* This disables the STS quickfix for organising imports and retains the
* default JDT quickfix processor in the JDT registry. To do so, the
* following needs to be passed as a VM arg to STS/Eclipse:
* -Denable.sts.quickfix.imports=false
*/
public static final String ENABLE_STS_QUICKFIX_IMPORTS = "enable.sts.quickfix.imports";
private ContributedProcessorDescriptor jdtProcessorDescriptor = null;
private Boolean removeJDTQuickFixProcessor = null;
private static JDTQuickFixProcessorHelper instance;
private JDTQuickFixProcessorHelper() {
// Only one helper should ever exist in workbench
}
public static JDTQuickFixProcessorHelper getInstance() {
if (instance == null) {
instance = new JDTQuickFixProcessorHelper();
}
return instance;
}
/**
* Removes the JDT QuickFixProcessor from the
* {@link JavaCorrectionProcessor} registry
* @param cu
* @return true if JDT QuickFix Processor was removed on this call. False if
* no action or changes are performed on the JDT quickfix processor registry
* (e.g. JDT quickfix processor was already disabled from a previous run)
*/
public synchronized boolean removeJDTQuickFixProcessor(ICompilationUnit cu) throws Exception {
// No further action if processor was already removed or there is no cu,
// or JDT processor should not be removed
if (this.jdtProcessorDescriptor != null || cu == null || !shouldRemoveJDTQuickfixProcessor()) {
return false;
}
Class<?> quickFixProcessor = getJavaCorrectionProcessor();
if (quickFixProcessor != null) {
try {
Field correctionProcessor = quickFixProcessor.getDeclaredField("fgContributedCorrectionProcessors");
if (correctionProcessor != null) {
correctionProcessor.setAccessible(true);
Object corrProcessorObj = correctionProcessor.get(null);
if (corrProcessorObj instanceof ContributedProcessorDescriptor[]) {
ContributedProcessorDescriptor[] descriptors = (ContributedProcessorDescriptor[]) corrProcessorObj;
if (descriptors != null) {
List<ContributedProcessorDescriptor> edited = new ArrayList<ContributedProcessorDescriptor>(
descriptors.length);
ContributedProcessorDescriptor foundJDTProcessorToRemove = null;
for (ContributedProcessorDescriptor desc : descriptors) {
IQuickFixProcessor processor = (IQuickFixProcessor) desc.getProcessor(cu,
IQuickFixProcessor.class);
if (processor != null) {
if (!processor.getClass().getName()
.equals("org.eclipse.jdt.internal.ui.text.correction.QuickFixProcessor")) {
edited.add(desc);
}
else {
foundJDTProcessorToRemove = desc;
}
}
}
if (foundJDTProcessorToRemove != null) {
this.jdtProcessorDescriptor = foundJDTProcessorToRemove;
correctionProcessor.set(null, edited.toArray(new ContributedProcessorDescriptor[0]));
return true;
}
}
}
}
}
catch (SecurityException e) {
Activator.log(e);
}
catch (IllegalAccessException e) {
Activator.log(e);
}
catch (IllegalArgumentException e) {
Activator.log(e);
}
catch (NoSuchFieldException e) {
Activator.log(e);
}
}
return false;
}
public synchronized boolean isJDTProcessorRemoved() {
return jdtProcessorDescriptor != null;
}
/**
* Adds the JDT QuickFixProcessor back into the
* {@link JavaCorrectionProcessor} registry
* @param cu
* @return true if the processor was successfully restored. False if no
* action was performed on the registry
*/
public synchronized boolean addJDTQuickFixProcessor(ICompilationUnit cu) {
// This restores the JDT Quickfix processor into JDT quickfix processor
// registry.
// No action needs to be peformed if there is no JDT processor to
// restore
if (jdtProcessorDescriptor == null) {
return false;
}
Class<?> quickFixProcessor = getJavaCorrectionProcessor();
if (quickFixProcessor != null) {
try {
Field correctionProcessor = quickFixProcessor.getDeclaredField("fgContributedCorrectionProcessors");
if (correctionProcessor != null) {
correctionProcessor.setAccessible(true);
Object corrProcessorObj = correctionProcessor.get(null);
if (corrProcessorObj instanceof ContributedProcessorDescriptor[]) {
ContributedProcessorDescriptor[] descriptors = (ContributedProcessorDescriptor[]) corrProcessorObj;
if (descriptors != null) {
List<ContributedProcessorDescriptor> toEdit = Arrays.asList(descriptors);
boolean exists = false;
for (ContributedProcessorDescriptor desc : toEdit) {
IQuickFixProcessor curr = (IQuickFixProcessor) desc.getProcessor(cu,
IQuickFixProcessor.class);
if (desc == jdtProcessorDescriptor || curr.getClass().getName()
.equals("org.eclipse.jdt.internal.ui.text.correction.QuickFixProcessor")) {
exists = true;
break;
}
}
if (!exists && jdtProcessorDescriptor != null) {
toEdit.add(jdtProcessorDescriptor);
correctionProcessor.set(null, toEdit.toArray(new ContributedProcessorDescriptor[0]));
return true;
}
}
}
}
}
catch (SecurityException e) {
Activator.log(e);
}
catch (IllegalAccessException e) {
Activator.log(e);
}
catch (IllegalArgumentException e) {
Activator.log(e);
}
catch (NoSuchFieldException e) {
Activator.log(e);
}
}
return false;
}
protected Class<?> getJavaCorrectionProcessor() {
Class<?> processor = null;
Bundle bundle = getBundle();
if (bundle != null) {
try {
processor = bundle.loadClass("org.eclipse.jdt.internal.ui.text.correction.JavaCorrectionProcessor");
}
catch (Throwable e) {
Activator.logInfo(
"Unable to find the JDT 'JavaCorrectionProcessor' registry. The STS 'Add Imports' quickfix processor may not be available as access to the registry is required to enable this feature.");
}
}
return processor;
}
/**
*
* @return true if JDT UI bundle is found. False otherwise
*/
protected Bundle getBundle() {
Bundle bundle = null;
try {
bundle = Platform.getBundle("org.eclipse.jdt.ui");
}
catch (Throwable e) {
Activator.log(e);
}
return bundle;
}
/**
*
* @return true if the JDT quickfix processor should be removed. False
* otherwise, meaning that the JDT quickfix processor will remained
* registered in JDT.
*/
public synchronized boolean shouldRemoveJDTQuickfixProcessor() {
if (removeJDTQuickFixProcessor == null) {
Properties properties = System.getProperties();
removeJDTQuickFixProcessor = properties == null || !properties.containsKey(ENABLE_STS_QUICKFIX_IMPORTS)
|| !"false".equals(properties.getProperty(ENABLE_STS_QUICKFIX_IMPORTS));
}
return removeJDTQuickFixProcessor;
}
}