Package org.springframework.ide.eclipse.beans.ui.editor.hyperlink

Source Code of org.springframework.ide.eclipse.beans.ui.editor.hyperlink.NamespaceHyperlinkDetectorSupport$NoOpProblemReporter

/*******************************************************************************
* Copyright (c) 2007, 2010 Spring IDE Developers
* 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:
*     Spring IDE Developers - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.beans.ui.editor.hyperlink;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.core.resources.IFile;
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.IHyperlink;
import org.eclipse.jface.text.hyperlink.IHyperlinkDetector;
import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;
import org.springframework.beans.factory.parsing.Problem;
import org.springframework.beans.factory.parsing.ProblemReporter;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate;
import org.springframework.beans.factory.xml.NamespaceHandler;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.beans.factory.xml.XmlReaderContext;
import org.springframework.core.io.Resource;
import org.springframework.ide.eclipse.beans.core.BeansCorePlugin;
import org.springframework.ide.eclipse.beans.core.DefaultBeanDefinitionRegistry;
import org.springframework.ide.eclipse.beans.core.internal.model.namespaces.DelegatingNamespaceHandlerResolver;
import org.springframework.ide.eclipse.beans.core.model.IBeansConfig;
import org.springframework.ide.eclipse.beans.core.namespaces.NamespaceUtils;
import org.springframework.ide.eclipse.beans.ui.editor.contentassist.IContentAssistCalculator;
import org.springframework.ide.eclipse.beans.ui.editor.util.BeansEditorUtils;
import org.springframework.ide.eclipse.core.java.JdtUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

/**
* Support class for implementing custom {@link IHyperlinkDetector}s. Calculation of individual hyperlinks is done via
* {@link IHyperlinkCalculator} strategy interfaces respectively.
* <p>
* Provides the {@link #registerHyperlinkCalculator} methods for registering a {@link IHyperlinkCalculator} to handle a
* specific element.
* @author Christian Dupuis
* @since 2.0.2
*/
@SuppressWarnings("restriction")
public class NamespaceHyperlinkDetectorSupport extends AbstractHyperlinkDetector {

  private static final Method FIND_PARSER_FOR_ELEMENT_METHOD;

  static {
    Method method = null;
    try {
      method = NamespaceHandlerSupport.class.getDeclaredMethod("findParserForElement", Element.class,
          ParserContext.class);
      method.setAccessible(true);
    }
    catch (Exception e) {
    }

    FIND_PARSER_FOR_ELEMENT_METHOD = method;
  }

  /**
   * Stores the {@link IHyperlinkCalculator} keyed the return value of a call to
   * {@link #createRegisteredName(String, String)}.
   */
  private Map<String, IHyperlinkCalculator> calculators = new HashMap<String, IHyperlinkCalculator>();

  /**
   * Calculates hyperlink for the given request by delegating the request to a located {@link IHyperlinkCalculator}
   * returned by {@link #locateHyperlinkCalculator(String, String)}.
   */
  public IHyperlink createHyperlink(String name, String target, Node node, Node parentNode, IDocument document,
      ITextViewer textViewer, IRegion hyperlinkRegion, IRegion cursor) {

    String parentNodeName = null;
    String parentNamespaceUri = null;
    if (parentNode != null) {
      parentNodeName = parentNode.getLocalName();
      parentNamespaceUri = parentNode.getNamespaceURI();
    }

    IHyperlinkCalculator calculator = locateHyperlinkCalculator(parentNamespaceUri, parentNodeName,
        node.getLocalName(), name);
    if (calculator != null) {
      return calculator.createHyperlink(name, target, node, parentNode, document, textViewer, hyperlinkRegion,
          cursor);
    }
    return null;
  }

  /**
   * Calculates multiple hyperlinks for the given request by delegating the request to a located
   * {@link IHyperlinkCalculator} returned by {@link #locateHyperlinkCalculator(String, String)}.
   */
  public IHyperlink[] createHyperlinks(String name, String target, Node node, Node parentNode, IDocument document,
      ITextViewer textViewer, IRegion hyperlinkRegion, IRegion cursor) {

    String parentNodeName = null;
    String parentNamespaceUri = null;
    if (parentNode != null) {
      parentNodeName = parentNode.getLocalName();
      parentNamespaceUri = parentNode.getNamespaceURI();
    }

    IHyperlinkCalculator calculator = locateHyperlinkCalculator(parentNamespaceUri, parentNodeName,
        node.getLocalName(), name);

    if (calculator instanceof IMultiHyperlinkCalculator) {
      return ((IMultiHyperlinkCalculator) calculator).createHyperlinks(name, target, node, parentNode, document,
          textViewer, hyperlinkRegion, cursor);
    }
    else if (calculator != null) {
      return new IHyperlink[] { calculator.createHyperlink(name, target, node, parentNode, document, textViewer,
          hyperlinkRegion, cursor) };
    }
    return null;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public IHyperlink[] detectHyperlinks(ITextViewer textViewer, IRegion region, boolean canShowMultipleHyperlinks) {
    IHyperlink[] hyperlinks = super.detectHyperlinks(textViewer, region, canShowMultipleHyperlinks);
    if (hyperlinks == null) {
      hyperlinks = new IHyperlink[0];
    }

    // Special support opening NamespaceHandlers
    IDocument document = textViewer.getDocument();
    Node currentNode = BeansEditorUtils.getNodeByOffset(document, region.getOffset());

    if ((canShowMultipleHyperlinks || hyperlinks.length == 0)
        && BeansEditorUtils.isElementAtOffset(currentNode, region.getOffset())
        && currentNode instanceof Element) {

      hyperlinks = createBeanDefinitionParserHyperlink(hyperlinks, document, currentNode);
    }

    return hyperlinks;
  }

  /**
   * Empty implementation. To be overridden by subclasses.
   */
  public void init() {
  }

  /**
   * Checks if a {@link IHyperlinkCalculator} for the given attribute has been registered.
   */
  public boolean isLinkableAttr(Attr attr) {

    Node parentNode = attr.getOwnerElement().getParentNode();
    String parentNodeName = null;
    String parentNamespaceUri = null;
    if (parentNode != null) {
      parentNodeName = parentNode.getLocalName();
      parentNamespaceUri = parentNode.getNamespaceURI();
    }

    return locateHyperlinkCalculator(parentNamespaceUri, parentNodeName, attr.getOwnerElement().getLocalName(),
        attr.getLocalName()) != null;
  }

  /**
   * Locates {@link IHyperlink} instances of open up {@link BeanDefinitionParser}s for selected namespace elements.
   */
  private IHyperlink[] createBeanDefinitionParserHyperlink(IHyperlink[] hyperlinks, IDocument document,
      Node currentNode) {
   
    String namespaceUri = currentNode.getNamespaceURI();
    IFile file = BeansEditorUtils.getFile(document);
    IBeansConfig config = BeansCorePlugin.getModel().getConfig(file, true);
   
    // Only search for non-default namespace handlers
    if (config != null && namespaceUri != null && !namespaceUri.equals(NamespaceUtils.DEFAULT_NAMESPACE_URI)) {
     
      ClassLoader cl = BeansCorePlugin.getClassLoader();
      if (NamespaceUtils.useNamespacesFromClasspath(file.getProject())) {
        cl = JdtUtils.getClassLoader(file.getProject(), cl);
      }
     
      // Construct NamespaceHandlerResolver using the project's classpath if configured
      DelegatingNamespaceHandlerResolver resolver = new DelegatingNamespaceHandlerResolver(cl, config);
      NamespaceHandler handler = resolver.resolve(namespaceUri);
      if (handler instanceof NamespaceHandlerSupport) {
       
        XmlReaderContext readerContext = new XmlReaderContext((Resource) config.getAdapter(Resource.class),
            new NoOpProblemReporter(), null, null, new XmlBeanDefinitionReader(
                new DefaultBeanDefinitionRegistry()), resolver);
       
        Object parser = ReflectionUtils.invokeMethod(FIND_PARSER_FOR_ELEMENT_METHOD, handler,
            (Element) currentNode, new ParserContext(readerContext, new BeanDefinitionParserDelegate(
                readerContext)));

        if (parser != null) {
          IType type = JdtUtils.getJavaType(file.getProject(), parser.getClass().getName());
          if (type != null) {

            List<IHyperlink> links = new ArrayList<IHyperlink>(Arrays.asList(hyperlinks));
            links.add(new JavaElementHyperlink(
                new Region(((IndexedRegion) currentNode).getStartOffset() + 1, currentNode
                    .getNodeName().length()), type));
            hyperlinks = links.toArray(new IHyperlink[links.size()]);
          }
        }
      }
    }
    return hyperlinks;
  }

  /**
   * Locates a {@link IContentAssistCalculator} in the {@link #calculators} store for the given <code>nodeName</code>
   * and <code>attributeName</code>.
   */
  private IHyperlinkCalculator locateHyperlinkCalculator(String parentNamespaceUri, String parentNodeName,
      String nodeName, String attributeName) {
    String key = createRegisteredName(parentNamespaceUri, parentNodeName, nodeName, attributeName);
    if (this.calculators.containsKey(key)) {
      return this.calculators.get(key);
    }
    key = createRegisteredName(null, null, nodeName, attributeName);
    if (this.calculators.containsKey(key)) {
      return this.calculators.get(key);
    }
    key = createRegisteredName(null, null, null, attributeName);
    if (this.calculators.containsKey(key)) {
      return this.calculators.get(key);
    }
    return null;
  }

  /**
   * Creates a name from the <code>nodeName</code> and <code>attributeName</code>.
   * @param nodeName the local (non-namespace qualified) name of the element
   * @param attributeName the local (non-namespace qualified) name of the attribute
   */
  protected String createRegisteredName(String parentNamespaceUri, String parentNodeName, String nodeName,
      String attributeName) {
    StringBuilder builder = new StringBuilder();
    if (StringUtils.hasText(parentNamespaceUri)) {
      builder.append("/parentNamespaceUri=");
      builder.append(parentNamespaceUri);
    }
    else {
      builder.append("/parentNamespaceUri=");
      builder.append("*");
    }
    if (StringUtils.hasText(parentNodeName)) {
      builder.append("/parentNodeName=");
      builder.append(parentNodeName);
    }
    else {
      builder.append("/parentNodeName=");
      builder.append("*");
    }
    if (StringUtils.hasText(nodeName)) {
      builder.append("/nodeName=");
      builder.append(nodeName);
    }
    else {
      builder.append("/nodeName=");
      builder.append("*");
    }
    if (StringUtils.hasText(attributeName)) {
      builder.append("/attribute=");
      builder.append(attributeName);
    }
    return builder.toString();

  }

  /**
   * Subclasses can call this to register the supplied {@link IHyperlinkCalculator} to handle the specified attribute.
   * The attribute name is the local (non-namespace qualified) name.
   */
  protected void registerHyperlinkCalculator(String attributeName, IHyperlinkCalculator calculator) {
    registerHyperlinkCalculator(null, attributeName, calculator);
  }

  /**
   * Subclasses can call this to register the supplied {@link IHyperlinkCalculator} to handle the specified attribute
   * <b>only</b> for a given element. The attribute name is the local (non-namespace qualified) name.
   */
  protected void registerHyperlinkCalculator(String nodeName, String attributeName, IHyperlinkCalculator calculator) {
    registerHyperlinkCalculator(null, null, nodeName, attributeName, calculator);
  }

  /**
   * Subclasses can call this to register the supplied {@link IHyperlinkCalculator} to handle the specified attribute
   * <b>only</b> for a given element. The attribute name is the local (non-namespace qualified) name.
   */
  protected void registerHyperlinkCalculator(String parentNamespaceUri, String parentNodeName, String nodeName,
      String attributeName, IHyperlinkCalculator calculator) {
    this.calculators.put(createRegisteredName(parentNamespaceUri, parentNodeName, nodeName, attributeName),
        calculator);
  }

  private static final class NoOpProblemReporter implements ProblemReporter {

    public void fatal(Problem problem) {
    }

    public void error(Problem problem) {
    }

    public void warning(Problem problem) {
    }
  }
}
TOP

Related Classes of org.springframework.ide.eclipse.beans.ui.editor.hyperlink.NamespaceHyperlinkDetectorSupport$NoOpProblemReporter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.