org.dozer.eclipse.plugin.sourcepage.hyperlink.DozerClassHyperlinkDetector.java Source code

Java tutorial

Introduction

Here is the source code for org.dozer.eclipse.plugin.sourcepage.hyperlink.DozerClassHyperlinkDetector.java

Source

/**
 * Copyright 2005-2013 Dozer Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.dozer.eclipse.plugin.sourcepage.hyperlink;

import org.dozer.eclipse.plugin.sourcepage.util.DozerPluginUtils;
import org.eclipse.core.resources.IFile;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.hyperlink.AbstractHyperlinkDetector;
import org.eclipse.jface.text.hyperlink.IHyperlink;
import org.eclipse.wst.xml.core.internal.Logger;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMAttr;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMElement;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode;
import org.springframework.ide.eclipse.beans.core.internal.model.BeansMapEntry;
import org.springframework.ide.eclipse.beans.core.model.IBean;
import org.springframework.ide.eclipse.beans.ui.editor.hyperlink.JavaElementHyperlink;
import org.springframework.ide.eclipse.beans.ui.editor.util.BeansEditorUtils;
import org.springframework.ide.eclipse.core.StringUtils;
import org.springframework.ide.eclipse.core.java.Introspector;
import org.springframework.ide.eclipse.core.java.JdtUtils;
import org.springframework.ide.eclipse.core.model.ISourceModelElement;
import org.w3c.dom.Attr;
import org.w3c.dom.Node;

import java.util.Set;

public class DozerClassHyperlinkDetector extends AbstractHyperlinkDetector {

    @SuppressWarnings("restriction")
    public final IHyperlink[] detectHyperlinks(ITextViewer textViewer, IRegion region,
            boolean canShowMultipleHyperlinks) {
        if (region == null || textViewer == null) {
            return null;
        }

        IDocument document = textViewer.getDocument();

        Node currentNode = BeansEditorUtils.getNodeByOffset(document, region.getOffset());
        if (currentNode != null) {
            switch (currentNode.getNodeType()) {
            case Node.ELEMENT_NODE:
                // at first try to handle selected attribute value
                Attr currentAttr = BeansEditorUtils.getAttrByOffset(currentNode, region.getOffset());
                IDOMAttr attr = (IDOMAttr) currentAttr;
                if (currentAttr != null && region.getOffset() >= attr.getValueRegionStartOffset()) {
                    if (isLinkableAttr(currentAttr)) {
                        IRegion hyperlinkRegion = getHyperlinkRegion(currentAttr);
                        IHyperlink hyperLink = createHyperlink(currentAttr.getName(), currentAttr.getNodeValue(),
                                currentNode, currentNode.getParentNode(), document, textViewer, hyperlinkRegion,
                                region);
                        if (hyperLink != null) {
                            return new IHyperlink[] { hyperLink };
                        }
                    }
                }
                break;

            case Node.TEXT_NODE:
                IRegion hyperlinkRegion = getHyperlinkRegion(currentNode);
                Node parentNode = currentNode.getParentNode();
                if (parentNode != null) {
                    IHyperlink hyperLink = createHyperlink(parentNode.getNodeName(), currentNode.getNodeValue(),
                            currentNode, parentNode, document, textViewer, hyperlinkRegion, region);
                    if (hyperLink != null) {
                        return new IHyperlink[] { hyperLink };
                    }
                }
                break;
            }
        }
        return null;
    }

    public IHyperlink createHyperlink(String attrName, String target, Node node, Node parentNode,
            IDocument document, ITextViewer textViewer, IRegion hyperlinkRegion, IRegion cursor) {
        String nodeName = parentNode.getNodeName();
        IFile file = BeansEditorUtils.getFile(document);
        IType type = JdtUtils.getJavaType(file.getProject(), target);

        if ("class-a".equals(nodeName) || "class-b".equals(nodeName) || "a-hint".equals(attrName)
                || "b-hint".equals(attrName) || "a-deep-index-hint".equals(attrName)
                || "b-deep-index-hint".equals(attrName)) {
            //make a simple hyperlink to the class
            if (type != null) {
                return new JavaElementHyperlink(hyperlinkRegion, type);
            }
        } else if ("set-method".equals(attrName) || "get-method".equals(attrName)
                || "map-set-method".equals(attrName) || "map-get-method".equals(attrName)) {
            if ("field".equals(nodeName)) {
                String targetClassName = DozerPluginUtils.getMappingClassName(node);

                //get the first method that matches and make a hyperlink to that
                if (targetClassName != null) {
                    IType targetClass = JdtUtils.getJavaType(file.getProject(), targetClassName);
                    IMethod method = getMethodFromType(targetClass, target);
                    if (method != null) {
                        return new JavaElementHyperlink(hyperlinkRegion, method);
                    }
                }
            }
        } else if ("a-hint".equals(attrName) || "b-hint".equals(attrName)) {
            //make a simple hyperlink to the class
            if (parentNode.getParentNode() != null && "mapping".equals(parentNode.getParentNode().getNodeName())) {
                if (type != null) {
                    return new JavaElementHyperlink(hyperlinkRegion, type);
                }
            }
        } else if ("custom-converter".equals(attrName)) {
            //make a simple hyperlink to the class
            if (type != null) {
                return new JavaElementHyperlink(hyperlinkRegion, type);
            }
        } else if ("custom-converter-id".equals(attrName)) {
            //search spring-bean that uses our mapping file and return the mapping
            //for the customconverter-id map-property
            ISourceModelElement modelElement = getModelElementForCustomConverter(BeansEditorUtils.getFile(document),
                    target);

            if (modelElement != null) {
                return new SourceModelHyperlink(modelElement, hyperlinkRegion);
            }
        } else if ("a".equals(nodeName) || "b".equals(nodeName)) {
            String targetClassName = DozerPluginUtils.getMappingClassName(node.getParentNode());
            String property = node.getNodeValue();

            if (targetClassName != null) {
                IType targetClass = JdtUtils.getJavaType(file.getProject(), targetClassName);

                try {
                    //if we are doing indexed property mapping, we remove the []
                    property = property.replaceAll("\\[\\]", "");

                    IMethod method = Introspector.getReadableProperty(targetClass, property);

                    if (method != null)
                        return new JavaElementHyperlink(hyperlinkRegion, method);
                } catch (Throwable e) {
                    Logger.logException(e);
                }
            }
        } else if ("bean-factory".equals(attrName)) {
            //make a simple hyperlink to the class
            if (type != null) {
                return new JavaElementHyperlink(hyperlinkRegion, type);
            }
        }

        return null;
    }

    /**
     * Get First Method by name
     * 
     * @param type
     * @param methodName
     * @return
     */
    private IMethod getMethodFromType(IType type, String methodName) {
        try {
            Set<IMethod> methods = Introspector.getAllMethods(type);
            for (IMethod method : methods) {
                if (method.getElementName().equals(methodName)) {
                    return method;
                }
            }
        } catch (Exception e) {
        }

        return null;
    }

    private ISourceModelElement getModelElementForCustomConverter(IFile file, String customConverterId) {
        IBean bean = DozerPluginUtils.getDozerBeanForMappingFile(file);
        BeansMapEntry modelElement = DozerPluginUtils.getCCIModelElementForMappingFile(bean, customConverterId);

        if (modelElement != null)
            return modelElement;

        //exact property not found, at least return bean
        return bean;
    }

    public boolean isLinkableAttr(Attr attr) {
        String attrName = attr.getName();
        String ownerName = attr.getOwnerElement().getNodeName();
        String parentName = attr.getOwnerElement().getParentNode().getNodeName();

        if ("bean-factory".equals(attrName))
            return true;
        else if ("field".equals(ownerName)) {
            if ("custom-converter".equals(attrName) || "custom-converter-id".equals(attrName))
                return true;
        } else if ("field".equals(parentName)) {
            if ("set-method".equals(attrName) || "get-method".equals(attrName) || "map-set-method".equals(attrName)
                    || "map-get-method".equals(attrName))
                return true;
        }

        return false;
    }

    @SuppressWarnings("restriction")
    protected final IRegion getHyperlinkRegion(Node node) {
        if (node != null) {
            switch (node.getNodeType()) {
            case Node.DOCUMENT_TYPE_NODE:
            case Node.TEXT_NODE:
                IDOMNode docNode = (IDOMNode) node;
                return new Region(docNode.getStartOffset(), docNode.getEndOffset() - docNode.getStartOffset());

            case Node.ELEMENT_NODE:
                IDOMElement element = (IDOMElement) node;
                int endOffset;
                if (element.hasEndTag() && element.isClosed()) {
                    endOffset = element.getStartEndOffset();
                } else {
                    endOffset = element.getEndOffset();
                }
                return new Region(element.getStartOffset(), endOffset - element.getStartOffset());

            case Node.ATTRIBUTE_NODE:
                IDOMAttr att = (IDOMAttr) node;
                // do not include quotes in attribute value region
                int regOffset = att.getValueRegionStartOffset();
                int regLength = att.getValueRegionText().length();
                String attValue = att.getValueRegionText();
                if (StringUtils.isQuoted(attValue)) {
                    regOffset += 1;
                    regLength = regLength - 2;
                }
                return new Region(regOffset, regLength);
            }
        }
        return null;
    }

}