/*******************************************************************************
* Copyright (c) 2012 VMware, 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:
* VMware, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.internal.bestpractices.quickfix;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.core.JarPackageFragmentRoot;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.wizards.NewClassCreationWizard;
import org.eclipse.jdt.ui.wizards.NewTypeWizardPage;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IMarkerResolution2;
import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
import org.springframework.ide.eclipse.core.java.JdtUtils;
import org.springsource.ide.eclipse.commons.core.StatusHandler;
import org.w3c.dom.Element;
/**
* Resolution for class not found markers. Opens a dialog so that the user can
* create the class that wasn't found.
* @author Wesley Coelho
* @author Leo Dos Santos
* @author Christian Dupuis
*/
public class CreateNewClassMarkerResolution implements IMarkerResolution2 {
private static final String MESSAGE_ATTRIBUTE_KEY = "message";
private String descriptionClassName = "";
public CreateNewClassMarkerResolution(IMarker marker) {
String markerMessage = marker.getAttribute(MESSAGE_ATTRIBUTE_KEY, "");
descriptionClassName = extractQualifiedClassName(markerMessage);
}
private String extractClassNameFromMessage(String message) {
String qualifiedClassName = extractQualifiedClassName(message);
return qualifiedClassName.substring(qualifiedClassName.lastIndexOf(".") + 1, qualifiedClassName.length());
}
private String extractPackageNameFromMessage(String message) {
if (message.length() == 0) {
return "";
}
String qualifiedClassName = extractQualifiedClassName(message);
int endPos = qualifiedClassName.lastIndexOf(".");
if (endPos < 0) {
return "";
}
return qualifiedClassName.substring(0, endPos);
}
private String extractQualifiedClassName(String message) {
final String startTag = "class '";
int startPos = message.indexOf(startTag) + startTag.length() + 1;
int endPos = message.indexOf("'", startPos);
return message.substring(startPos, endPos);
}
public String getDescription() {
return "Create class " + descriptionClassName + " declared in the bean definition";
}
public Image getImage() {
return null;
}
public String getLabel() {
return "Create class " + descriptionClassName;
}
/**
* Create a package fragment for the given package name. This currently
* guesses the package root from the available package roots. It currently
* selects the first package root that isn't for a jar'ed package.
*/
private IPackageFragmentRoot inferPackageFragmentRoot(IJavaProject javaProject, String packageName)
throws CoreException {
try {
IPackageFragmentRoot[] packageFragmentRoots = javaProject.getPackageFragmentRoots();
for (int i = 0; i < packageFragmentRoots.length; i++) {
if (!(packageFragmentRoots[i] instanceof JarPackageFragmentRoot)) {
return packageFragmentRoots[i];
}
}
}
catch (JavaModelException e) {
throw new CoreException(e.getStatus());
}
return null;
}
public void run(IMarker marker) {
NewClassCreationWizard wizard = new NewClassCreationWizard();
wizard.init(JavaPlugin.getDefault().getWorkbench(), null);
Shell shell = JavaPlugin.getActiveWorkbenchShell();
WizardDialog dialog = new WizardDialog(shell, wizard);
dialog.create();
dialog.getShell().setText("New");
IWizardPage[] pages = wizard.getPages();
NewTypeWizardPage page = (NewTypeWizardPage) pages[0];
String markerMessage = marker.getAttribute(MESSAGE_ATTRIBUTE_KEY, "");
IJavaProject javaProject = JdtUtils.getJavaProject(marker.getResource());
IPackageFragmentRoot sourcePackageFragmentRoot = null;
String packageName = extractPackageNameFromMessage(markerMessage);
try {
sourcePackageFragmentRoot = inferPackageFragmentRoot(javaProject, packageName);
if (sourcePackageFragmentRoot != null) {
page.setPackageFragmentRoot(sourcePackageFragmentRoot, true);
IPackageFragment packageFragment = sourcePackageFragmentRoot.getPackageFragment(packageName);
if (packageFragment != null) {
page.setPackageFragment(packageFragment, true);
}
}
}
catch (CoreException e) {
StatusHandler.log(e.getStatus());
}
page.setTypeName(extractClassNameFromMessage(markerMessage), true);
if (dialog.open() == Window.OK) {
IType createdType = (IType) wizard.getCreatedElement();
String fullyQualifiedClassName = createdType.getFullyQualifiedName();
updateXmlBeanClass(marker, fullyQualifiedClassName);
}
}
private void updateXmlBeanClass(IMarker marker, String fullyQualifiedClassName) {
IStructuredModel model = null;
try {
model = XmlQuickFixUtil.getModel(marker);
Element beanElement = XmlQuickFixUtil.getMarkerElement(model, marker);
beanElement.setAttribute("class", fullyQualifiedClassName);
XmlQuickFixUtil.saveMarkedFile(marker);
}
catch (CoreException e) {
StatusHandler.log(e.getStatus());
}
finally {
if (model != null) {
model.releaseFromEdit();
model = null;
}
}
}
}