org.jboss.tools.seam.ui.refactoring.SeamRefactorContributionFactory.java Source code

Java tutorial

Introduction

Here is the source code for org.jboss.tools.seam.ui.refactoring.SeamRefactorContributionFactory.java

Source

/*******************************************************************************
 * Copyright (c) 2009 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.seam.ui.refactoring;

import java.io.IOException;
import java.util.Set;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jdt.core.IAnnotation;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.internal.ui.text.FastJavaPartitionScanner;
import org.eclipse.jdt.ui.text.IJavaPartitions;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.TextSelection;
import org.eclipse.jface.text.rules.IToken;
import org.eclipse.jface.text.rules.Token;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.internal.services.IWorkbenchLocationService;
import org.eclipse.ui.menus.AbstractContributionFactory;
import org.eclipse.ui.menus.IContributionRoot;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.services.IServiceLocator;
import org.eclipse.wst.sse.core.StructuredModelManager;
import org.eclipse.wst.sse.core.internal.provisional.IModelManager;
import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion;
import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion;
import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionList;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMDocument;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode;
import org.eclipse.wst.xml.core.internal.regions.DOMRegionContext;
import org.jboss.tools.common.el.core.model.ELInstance;
import org.jboss.tools.common.el.core.model.ELInvocationExpression;
import org.jboss.tools.common.el.core.model.ELModel;
import org.jboss.tools.common.el.core.model.ELPropertyInvocation;
import org.jboss.tools.common.el.core.parser.ELParser;
import org.jboss.tools.common.el.core.parser.ELParserUtil;
import org.jboss.tools.common.model.ui.editor.EditorPartWrapper;
import org.jboss.tools.common.model.util.EclipseJavaUtil;
import org.jboss.tools.common.model.util.EclipseResourceUtil;
import org.jboss.tools.common.propertieseditor.PropertiesCompoundEditor;
import org.jboss.tools.common.util.FileUtil;
import org.jboss.tools.jst.web.ui.editors.WebCompoundEditor;
import org.jboss.tools.seam.core.ISeamComponent;
import org.jboss.tools.seam.core.ISeamJavaComponentDeclaration;
import org.jboss.tools.seam.core.ISeamProject;
import org.jboss.tools.seam.core.SeamCorePlugin;
import org.jboss.tools.seam.core.SeamCoreMessages;
import org.jboss.tools.seam.internal.core.refactoring.RenameComponentProcessor;
import org.jboss.tools.seam.internal.core.refactoring.RenameComponentRefactoring;
import org.jboss.tools.seam.internal.core.refactoring.RenameSeamContextVariableProcessor;
import org.jboss.tools.seam.ui.SeamGuiPlugin;
import org.jboss.tools.seam.ui.wizard.RenameComponentWizard;
import org.jboss.tools.seam.ui.wizard.RenameSeamContextVariableWizard;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * @author Daniel Azarov
 */
public class SeamRefactorContributionFactory extends AbstractContributionFactory {
    private static final String ANNOTATION_NAME = "org.jboss.seam.annotations.Name"; //$NON-NLS-1$
    private static final String JAVA_EXT = "java"; //$NON-NLS-1$
    private static final String XML_EXT = "xml"; //$NON-NLS-1$
    private static final String XHTML_EXT = "xhtml"; //$NON-NLS-1$
    private static final String JSP_EXT = "jsp"; //$NON-NLS-1$
    private static final String PROPERTIES_EXT = "properties"; //$NON-NLS-1$
    private static final String GET = "get"; //$NON-NLS-1$
    private static final String SET = "set"; //$NON-NLS-1$
    private static final String IS = "is"; //$NON-NLS-1$

    static private String selectedText;
    static private IFile editorFile;
    private String fileContent;
    private IEditorPart editor;
    private Shell shell;

    public SeamRefactorContributionFactory() {
        super("", "");
    }

    public SeamRefactorContributionFactory(String location, String namespace) {
        super(location, namespace);
    }

    @Override
    public void createContributionItems(IServiceLocator serviceLocator, IContributionRoot additions) {

        if (serviceLocator.hasService(IWorkbenchLocationService.class)) {
            IWorkbenchLocationService service = (IWorkbenchLocationService) serviceLocator
                    .getService(IWorkbenchLocationService.class);
            editor = service.getWorkbenchWindow().getActivePage().getActiveEditor();
            shell = service.getWorkbench().getActiveWorkbenchWindow().getShell();

            if (!(editor.getEditorInput() instanceof FileEditorInput))
                return;

            FileEditorInput input = (FileEditorInput) editor.getEditorInput();

            editorFile = input.getFile();
            String ext = editorFile.getFileExtension();

            if (!JAVA_EXT.equalsIgnoreCase(ext) && !XML_EXT.equalsIgnoreCase(ext)
                    && !XHTML_EXT.equalsIgnoreCase(ext) && !JSP_EXT.equalsIgnoreCase(ext)
                    && !PROPERTIES_EXT.equalsIgnoreCase(ext))
                return;

            ISeamProject seamProject = SeamCorePlugin.getSeamProject(editorFile.getProject(), true);
            if (seamProject == null)
                return;

            MenuManager mm = new MenuManager(SeamCoreMessages.SEAM_REFACTOR);
            mm.setVisible(true);

            boolean separatorIsAdded = false;

            if (JAVA_EXT.equalsIgnoreCase(ext)) {
                ISeamComponent component = getComponent(editorFile);
                if (component != null) {
                    mm.add(new RenameSeamComponentAction());

                    additions.addContributionItem(new Separator(), null);
                    additions.addContributionItem(mm, null);
                    separatorIsAdded = true;
                }
            }

            ISelection sel = editor.getEditorSite().getSelectionProvider().getSelection();

            if (sel == null || sel.isEmpty())
                return;

            if (sel instanceof StructuredSelection) {
                if (editor instanceof PropertiesCompoundEditor) {
                    sel = ((PropertiesCompoundEditor) editor).getActiveEditor().getSite().getSelectionProvider()
                            .getSelection();
                } else if (editor instanceof EditorPartWrapper) {
                    EditorPartWrapper wrapperEditor = (EditorPartWrapper) editor;
                    if (wrapperEditor.getEditor() instanceof WebCompoundEditor) {
                        WebCompoundEditor xmlEditor = (WebCompoundEditor) wrapperEditor.getEditor();
                        sel = xmlEditor.getActiveEditor().getSite().getSelectionProvider().getSelection();
                    }
                } else if (editor instanceof WebCompoundEditor)
                    sel = ((WebCompoundEditor) editor).getActiveEditor().getSite().getSelectionProvider()
                            .getSelection();
            }

            if (sel instanceof TextSelection) {
                TextSelection selection = (TextSelection) sel;

                selectedText = selection.getText();

                try {
                    fileContent = FileUtil.readStream(editorFile);
                } catch (CoreException e) {
                    SeamGuiPlugin.getDefault().logError(e);
                }

                boolean status = false;

                if (JAVA_EXT.equalsIgnoreCase(ext)) {
                    // check - whether selected component's name or not
                    //               if(checkNameAnnotation(selection)){
                    //                  mm.add(new RenameSeamComponentAction());
                    //                  
                    //                  additions.addContributionItem(mm, null);
                    //               }
                    //checkPropertyName(selection, mm, additions);
                    status = checkContextVariableInJava(editorFile, fileContent, selection);
                } else if (XML_EXT.equalsIgnoreCase(ext) || XHTML_EXT.equalsIgnoreCase(ext)
                        || JSP_EXT.equalsIgnoreCase(ext))
                    status = checkContextVariableInDOM(editorFile, fileContent, selection);
                else if (PROPERTIES_EXT.equalsIgnoreCase(ext))
                    status = checkContextVariableInProperties(editorFile, fileContent, selection);

                if (status) {
                    mm.add(new RenameSeamContextVariableAction());

                    if (!separatorIsAdded)
                        additions.addContributionItem(new Separator(), null);
                    additions.addContributionItem(mm, null);
                }
            }
        }
    }

    private boolean checkContextVariableInJava(IFile file, String content, TextSelection selection) {
        try {
            FastJavaPartitionScanner scaner = new FastJavaPartitionScanner();
            Document document = new Document(content);
            scaner.setRange(document, 0, document.getLength());
            IToken token = scaner.nextToken();
            while (token != null && token != Token.EOF) {
                if (IJavaPartitions.JAVA_STRING.equals(token.getData())) {
                    int length = scaner.getTokenLength();
                    int offset = scaner.getTokenOffset();
                    if (offset <= selection.getOffset()
                            && (offset + length) >= (selection.getOffset() + selection.getLength())) {
                        String value = document.get(offset, length);
                        if (value.indexOf('{') > -1) {
                            return scanString(file, value, offset, selection);
                        }
                    }
                }
                token = scaner.nextToken();
            }
        } catch (BadLocationException e) {
            SeamCorePlugin.getDefault().logError(e);
        }
        return false;
    }

    private boolean scanString(IFile file, String string, int offset, TextSelection selection) {
        int startEl = string.indexOf("#{"); //$NON-NLS-1$
        if (startEl > -1) {
            ELParser parser = ELParserUtil.getJbossFactory().createParser();
            ELModel model = parser.parse(string);
            for (ELInstance instance : model.getInstances()) {
                for (ELInvocationExpression ie : instance.getExpression().getInvocations()) {
                    ELPropertyInvocation pi = findSeamContextVariable(ie);
                    if (pi != null) {
                        if (offset + pi.getStartPosition() == selection.getOffset()
                                && pi.getLength() == selection.getLength())
                            return true;
                    }
                }
            }
        }
        return false;
    }

    private ELPropertyInvocation findSeamContextVariable(ELInvocationExpression invocationExpression) {
        ELInvocationExpression invExp = invocationExpression;
        while (invExp != null) {
            if (invExp instanceof ELPropertyInvocation) {
                if (((ELPropertyInvocation) invExp).getQualifiedName() != null
                        && ((ELPropertyInvocation) invExp).getQualifiedName().equals(selectedText))
                    return (ELPropertyInvocation) invExp;
                else
                    invExp = invExp.getLeft();

            } else {
                invExp = invExp.getLeft();
            }
        }
        return null;
    }

    private boolean checkContextVariableInDOM(IFile file, String content, TextSelection selection) {
        IModelManager manager = StructuredModelManager.getModelManager();
        if (manager == null) {
            return false;
        }
        IStructuredModel model = null;
        try {
            model = manager.getModelForRead(file);
            if (model instanceof IDOMModel) {
                IDOMModel domModel = (IDOMModel) model;
                IDOMDocument document = domModel.getDocument();
                return scanChildNodes(file, document, selection);
            }
        } catch (CoreException e) {
            SeamCorePlugin.getDefault().logError(e);
        } catch (IOException e) {
            SeamCorePlugin.getDefault().logError(e);
        } finally {
            if (model != null) {
                model.releaseFromRead();
            }
        }
        return false;
    }

    private boolean scanChildNodes(IFile file, Node parent, TextSelection selection) {
        boolean status = false;

        if (parent == null)
            return false;

        NodeList children = parent.getChildNodes();
        for (int i = 0; i < children.getLength(); i++) {
            Node curentValidatedNode = children.item(i);
            if (Node.ELEMENT_NODE == curentValidatedNode.getNodeType()) {
                status = scanNodeContent(file, ((IDOMNode) curentValidatedNode).getFirstStructuredDocumentRegion(),
                        DOMRegionContext.XML_TAG_ATTRIBUTE_VALUE, selection);
                if (status)
                    return status;
            } else if (Node.TEXT_NODE == curentValidatedNode.getNodeType()) {
                status = scanNodeContent(file, ((IDOMNode) curentValidatedNode).getFirstStructuredDocumentRegion(),
                        DOMRegionContext.XML_CONTENT, selection);
                if (status)
                    return status;
            }
            status = scanChildNodes(file, curentValidatedNode, selection);
            if (status)
                return status;
        }
        return false;
    }

    private boolean scanNodeContent(IFile file, IStructuredDocumentRegion node, String regionType,
            TextSelection selection) {
        boolean status = false;

        if (node == null)
            return false;

        ITextRegionList regions = node.getRegions();
        for (int i = 0; i < regions.size(); i++) {
            ITextRegion region = regions.get(i);
            if (region.getType() == regionType) {
                String text = node.getFullText(region);
                if (text.indexOf("{") > -1) { //$NON-NLS-1$
                    int offset = node.getStartOffset() + region.getStart();
                    status = scanString(file, text, offset, selection);
                    if (status)
                        return status;
                }
            }
        }
        return false;
    }

    private boolean checkContextVariableInProperties(IFile file, String content, TextSelection selection) {
        return scanString(file, content, 0, selection);
    }

    private ISeamComponent getComponent(IFile file) {
        IProject project = file.getProject();
        ISeamProject seamProject = SeamCorePlugin.getSeamProject(project, true);
        if (seamProject != null) {
            Set<ISeamComponent> components = seamProject.getComponentsByPath(editorFile.getFullPath());
            for (ISeamComponent component : components) {
                ISeamJavaComponentDeclaration declaration = component.getJavaDeclaration();
                if (declaration != null) {
                    IResource resource = declaration.getResource();
                    if (resource != null && resource.getFullPath().equals(editorFile.getFullPath())) {
                        if (declaration.getName().equals(component.getName())) {
                            return component;
                        }
                    }
                }
            }
        }
        return null;
    }

    private IAnnotation getNameAnnotation(IFile file) {
        try {
            ICompilationUnit unit = getCompilationUnit(file);
            for (IType type : unit.getAllTypes()) {
                for (IAnnotation annotation : type.getAnnotations()) {
                    if (EclipseJavaUtil.resolveType(type, annotation.getElementName()).equals(ANNOTATION_NAME))
                        return annotation;
                }
            }
        } catch (CoreException ex) {
            SeamCorePlugin.getDefault().logError(ex);
        }
        return null;
    }

    private ICompilationUnit getCompilationUnit(IFile file) throws CoreException {
        IProject project = file.getProject();
        IJavaProject javaProject = (IJavaProject) project.getNature(JavaCore.NATURE_ID);
        for (IResource resource : EclipseResourceUtil.getJavaSourceRoots(project)) {
            if (resource.getFullPath().isPrefixOf(file.getFullPath())) {
                IPath path = file.getFullPath().removeFirstSegments(resource.getFullPath().segmentCount());
                IJavaElement element = javaProject.findElement(path);
                if (element instanceof ICompilationUnit) {
                    return (ICompilationUnit) element;
                }
            }
        }
        return null;
    }

    private String getPropertyName(IMethod method) {
        String name = method.getElementName();

        if (name.startsWith(GET) || name.startsWith(SET))
            return name.substring(3).toLowerCase();

        if (name.startsWith(IS))
            return name.substring(2).toLowerCase();

        return name.toLowerCase();
    }

    private static void saveAndBuild() {
        if (!SeamGuiPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getActivePage()
                .saveAllEditors(true))
            return;

        try {
            Job.getJobManager().join(ResourcesPlugin.FAMILY_AUTO_BUILD, null);
        } catch (InterruptedException e) {
            // do nothing
        }
    }

    public static void invokeRenameComponentWizard(ISeamComponent component, Shell activeShell) {
        saveAndBuild();

        RenameComponentProcessor processor = new RenameComponentProcessor(component);
        RenameComponentRefactoring refactoring = new RenameComponentRefactoring(processor);
        RenameComponentWizard wizard = new RenameComponentWizard(refactoring, component);
        RefactoringWizardOpenOperation op = new RefactoringWizardOpenOperation(wizard);
        try {
            String titleForFailedChecks = SeamCoreMessages.SEAM_COMPONENT_RENAME_HANDLER_ERROR;
            op.run(activeShell, titleForFailedChecks);
        } catch (final InterruptedException irex) {
            // operation was canceled
        }
        //SeamUIUtil.waiteForBuild();
        //SeamUIUtil.refreshSeamComponentView();
    }

    public static void invokeRenameSeamContextVariableWizard(String oldName, Shell activeShell) {
        saveAndBuild();

        RenameSeamContextVariableProcessor processor = new RenameSeamContextVariableProcessor(editorFile,
                selectedText);
        RenameComponentRefactoring refactoring = new RenameComponentRefactoring(processor);
        RenameSeamContextVariableWizard wizard = new RenameSeamContextVariableWizard(refactoring, editorFile);
        RefactoringWizardOpenOperation op = new RefactoringWizardOpenOperation(wizard);
        try {
            String titleForFailedChecks = SeamCoreMessages.SEAM_COMPONENT_RENAME_HANDLER_ERROR;
            op.run(activeShell, titleForFailedChecks);
        } catch (final InterruptedException irex) {
            // operation was canceled
        }
        //SeamUIUtil.waiteForBuild();
        //SeamUIUtil.refreshSeamComponentView();
    }

    class RenameSeamComponentAction extends Action {
        public RenameSeamComponentAction() {
            super(SeamCoreMessages.RENAME_SEAM_COMPONENT);
        }

        public void run() {
            saveAndBuild();

            ISeamComponent component = getComponent(editorFile);
            invokeRenameComponentWizard(component, shell);
        }
    }

    class RenameSeamContextVariableAction extends Action {
        public RenameSeamContextVariableAction() {
            super(SeamCoreMessages.RENAME_SEAM_CONTEXT_VARIABLE);
        }

        public void run() {
            saveAndBuild();

            invokeRenameSeamContextVariableWizard(selectedText, shell);
        }
    }

}