Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'web/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/hyperlink/TaglibHyperlinkDetector.java')
-rw-r--r--web/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/hyperlink/TaglibHyperlinkDetector.java451
1 files changed, 451 insertions, 0 deletions
diff --git a/web/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/hyperlink/TaglibHyperlinkDetector.java b/web/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/hyperlink/TaglibHyperlinkDetector.java
new file mode 100644
index 0000000000..50dc904e57
--- /dev/null
+++ b/web/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/hyperlink/TaglibHyperlinkDetector.java
@@ -0,0 +1,451 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2017 IBM Corporation and others.
+ * 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:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jst.jsp.ui.internal.hyperlink;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.List;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.ITypedRegion;
+import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.TextUtilities;
+import org.eclipse.jface.text.hyperlink.AbstractHyperlinkDetector;
+import org.eclipse.jface.text.hyperlink.IHyperlink;
+import org.eclipse.jface.text.hyperlink.URLHyperlink;
+import org.eclipse.jst.jsp.core.internal.contentmodel.TaglibController;
+import org.eclipse.jst.jsp.core.internal.contentmodel.tld.CMElementDeclarationImpl;
+import org.eclipse.jst.jsp.core.internal.contentmodel.tld.TLDCMDocumentManager;
+import org.eclipse.jst.jsp.core.internal.contentmodel.tld.TaglibTracker;
+import org.eclipse.jst.jsp.core.internal.contentmodel.tld.provisional.JSP11TLDNames;
+import org.eclipse.jst.jsp.core.internal.provisional.JSP11Namespace;
+import org.eclipse.jst.jsp.core.internal.provisional.JSP12Namespace;
+import org.eclipse.jst.jsp.core.taglib.ITLDRecord;
+import org.eclipse.jst.jsp.core.taglib.ITaglibRecord;
+import org.eclipse.jst.jsp.core.taglib.TaglibIndex;
+import org.eclipse.jst.jsp.core.text.IJSPPartitions;
+import org.eclipse.jst.jsp.ui.internal.JSPUIMessages;
+import org.eclipse.jst.jsp.ui.internal.Logger;
+import org.eclipse.wst.sse.core.StructuredModelManager;
+import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
+import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;
+import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredPartitioning;
+import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion;
+import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionCollection;
+import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionList;
+import org.eclipse.wst.sse.core.utils.StringUtils;
+import org.eclipse.wst.xml.core.internal.contentmodel.CMElementDeclaration;
+import org.eclipse.wst.xml.core.internal.provisional.contentmodel.CMNodeWrapper;
+import org.eclipse.wst.xml.core.internal.provisional.document.IDOMAttr;
+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.w3c.dom.Attr;
+import org.w3c.dom.Element;
+import org.w3c.dom.EntityReference;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * Detects hyperlinks for taglibs.
+ */
+public class TaglibHyperlinkDetector extends AbstractHyperlinkDetector {
+ private final String HTTP_PROTOCOL = "http://";//$NON-NLS-1$
+ private final String JAR_PROTOCOL = "jar:file:";//$NON-NLS-1$
+ // private String URN_TAGDIR = "urn:jsptagdir:";
+ private String URN_TLD = "urn:jsptld:";
+ private String XMLNS = "xmlns:"; //$NON-NLS-1$
+
+ static final int TAG = 1;
+ static final int ATTRIBUTE = 2;
+
+ static IRegion findDefinition(IDOMModel model, String searchName, int searchType) {
+ NodeList declarations = null;
+ if (searchType == TAG)
+ declarations = model.getDocument().getElementsByTagNameNS("*", JSP11TLDNames.TAG);
+ else if (searchType == ATTRIBUTE)
+ declarations = model.getDocument().getElementsByTagNameNS("*", JSP11TLDNames.ATTRIBUTE);
+ if (declarations == null || declarations.getLength() == 0) {
+ if (searchType == TAG)
+ declarations = model.getDocument().getElementsByTagName(JSP11TLDNames.TAG);
+ else if (searchType == ATTRIBUTE)
+ declarations = model.getDocument().getElementsByTagName(JSP11TLDNames.ATTRIBUTE);
+ }
+ if (declarations != null) {
+ for (int i = 0; i < declarations.getLength(); i++) {
+ NodeList names = model.getDocument().getElementsByTagName(JSP11TLDNames.NAME);
+ for (int j = 0; j < names.getLength(); j++) {
+ String name = getContainedText(names.item(j));
+ if (searchName.compareTo(name) == 0) {
+ int start = -1;
+ int end = -1;
+ Node caret = names.item(j).getFirstChild();
+ if (caret != null) {
+ start = ((IDOMNode) caret).getStartOffset();
+ }
+ while (caret != null) {
+ end = ((IDOMNode) caret).getEndOffset();
+ caret = caret.getNextSibling();
+ }
+ if (start > 0) {
+ return new Region(start, end - start);
+ }
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private static String getContainedText(Node parent) {
+ NodeList children = parent.getChildNodes();
+ if (children.getLength() == 1) {
+ return children.item(0).getNodeValue().trim();
+ }
+ StringBuffer s = new StringBuffer();
+ Node child = parent.getFirstChild();
+ while (child != null) {
+ if (child.getNodeType() == Node.ENTITY_REFERENCE_NODE) {
+ String reference = ((EntityReference) child).getNodeValue();
+ if (reference == null && child.getNodeName() != null) {
+ reference = "&" + child.getNodeName() + ";"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if (reference != null) {
+ s.append(reference.trim());
+ }
+ }
+ else {
+ s.append(child.getNodeValue().trim());
+ }
+ child = child.getNextSibling();
+ }
+ return s.toString().trim();
+ }
+
+ public IHyperlink[] detectHyperlinks(ITextViewer textViewer, IRegion region, boolean canShowMultipleHyperlinks) {
+ IHyperlink hyperlink = null;
+
+ if (textViewer != null && region != null) {
+ IDocument doc = textViewer.getDocument();
+ if (doc != null) {
+ try {
+ // check if jsp tag/directive first
+ ITypedRegion partition = TextUtilities.getPartition(doc, IStructuredPartitioning.DEFAULT_STRUCTURED_PARTITIONING, region.getOffset(), false);
+ if (partition != null && partition.getType() == IJSPPartitions.JSP_DIRECTIVE) {
+ IStructuredModel sModel = null;
+ try {
+ sModel = StructuredModelManager.getModelManager().getExistingModelForRead(doc);
+ // check if jsp taglib directive
+ Node currentNode = getCurrentNode(sModel, region.getOffset());
+ if (currentNode != null && currentNode.getNodeType() == Node.ELEMENT_NODE) {
+ String baseLocationForTaglib = getBaseLocationForTaglib(doc);
+ if (baseLocationForTaglib != null && JSP11Namespace.ElementName.DIRECTIVE_TAGLIB.equalsIgnoreCase(currentNode.getNodeName())) {
+ /**
+ * The taglib directive itself
+ */
+ // get the uri attribute
+ Attr taglibURINode = ((Element) currentNode).getAttributeNode(JSP11Namespace.ATTR_NAME_URI);
+ if (taglibURINode != null) {
+ ITaglibRecord reference = TaglibIndex.resolve(baseLocationForTaglib, taglibURINode.getValue(), false);
+ // when using a tagdir
+ // (ITaglibRecord.TAGDIR),
+ // there's nothing to link to
+ if (reference != null) {
+ // handle taglibs
+ switch (reference.getRecordType()) {
+ case (ITaglibRecord.TLD) : {
+ ITLDRecord record = (ITLDRecord) reference;
+ String uriString = record.getPath().toString();
+ IRegion hyperlinkRegion = getHyperlinkRegion(taglibURINode, region);
+ if (hyperlinkRegion != null) {
+ hyperlink = createHyperlink(uriString, hyperlinkRegion, doc, null);
+ }
+ }
+ break;
+ case (ITaglibRecord.JAR) :
+ case (ITaglibRecord.URL) : {
+ IRegion hyperlinkRegion = getHyperlinkRegion(taglibURINode, region);
+ if (hyperlinkRegion != null) {
+ hyperlink = new TaglibJarUriHyperlink(hyperlinkRegion, reference);
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (baseLocationForTaglib != null && JSP12Namespace.ElementName.ROOT.equalsIgnoreCase(currentNode.getNodeName())) {
+ /**
+ * The jsp:root element
+ */
+ NamedNodeMap attrs = currentNode.getAttributes();
+ for (int i = 0; i < attrs.getLength(); i++) {
+ Attr attr = (Attr) attrs.item(i);
+ if (attr.getNodeName().startsWith(XMLNS)) {
+ String uri = StringUtils.strip(attr.getNodeValue());
+ if (uri.startsWith(URN_TLD)) {
+ uri = uri.substring(URN_TLD.length());
+ }
+ ITaglibRecord reference = TaglibIndex.resolve(baseLocationForTaglib, uri, false);
+ // when using a tagdir
+ // (ITaglibRecord.TAGDIR),
+ // there's nothing to link to
+ if (reference != null) {
+ // handle taglibs
+ switch (reference.getRecordType()) {
+ case (ITaglibRecord.TLD) : {
+ ITLDRecord record = (ITLDRecord) reference;
+ String uriString = record.getPath().toString();
+ IRegion hyperlinkRegion = getHyperlinkRegion(attr, region);
+ if (hyperlinkRegion != null) {
+ hyperlink = createHyperlink(uriString, hyperlinkRegion, doc, null);
+ }
+ }
+ break;
+ case (ITaglibRecord.JAR) :
+ case (ITaglibRecord.URL) : {
+ IRegion hyperlinkRegion = getHyperlinkRegion(attr, region);
+ if (hyperlinkRegion != null) {
+ hyperlink = new TaglibJarUriHyperlink(hyperlinkRegion, reference);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else {
+ /**
+ * Hyperlink custom tag to its TLD or tag file
+ */
+ TLDCMDocumentManager documentManager = TaglibController.getTLDCMDocumentManager(doc);
+ if (documentManager != null) {
+ List documentTrackers = documentManager.getCMDocumentTrackers(currentNode.getPrefix(), region.getOffset());
+ for (int i = 0; i < documentTrackers.size(); i++) {
+ TaglibTracker tracker = (TaglibTracker) documentTrackers.get(i);
+ CMElementDeclaration decl = (CMElementDeclaration) tracker.getElements().getNamedItem(currentNode.getNodeName());
+ if (decl != null) {
+ decl = (CMElementDeclaration) ((CMNodeWrapper) decl).getOriginNode();
+ if (decl instanceof CMElementDeclarationImpl) {
+ String base = ((CMElementDeclarationImpl) decl).getLocationString();
+ IRegion hyperlinkRegion = getHyperlinkRegion(currentNode, region);
+ if (hyperlinkRegion != null) {
+ hyperlink = createHyperlink(base, hyperlinkRegion, doc, currentNode);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ finally {
+ if (sModel != null)
+ sModel.releaseFromRead();
+ }
+ }
+ }
+ catch (BadLocationException e) {
+ Logger.log(Logger.WARNING_DEBUG, e.getMessage(), e);
+ }
+ }
+ }
+ if (hyperlink != null)
+ return new IHyperlink[]{hyperlink};
+ return null;
+ }
+
+ /**
+ * Get the base location from the current model (if within workspace,
+ * location is relative to workspace, otherwise, file system path)
+ */
+ private String getBaseLocationForTaglib(IDocument document) {
+ String baseLoc = null;
+
+ // get the base location from the current model
+ IStructuredModel sModel = null;
+ try {
+ sModel = StructuredModelManager.getModelManager().getExistingModelForRead(document);
+ if (sModel != null) {
+ baseLoc = sModel.getBaseLocation();
+ }
+ }
+ finally {
+ if (sModel != null) {
+ sModel.releaseFromRead();
+ }
+ }
+ return baseLoc;
+ }
+
+ // the below methods were copied from URIHyperlinkDetector
+
+ private IRegion getHyperlinkRegion(Node node, IRegion boundingRegion) {
+ IRegion hyperRegion = null;
+
+ if (node != null) {
+ short nodeType = node.getNodeType();
+ if (nodeType == Node.DOCUMENT_TYPE_NODE) {
+ // handle doc type node
+ IDOMNode docNode = (IDOMNode) node;
+ hyperRegion = new Region(docNode.getStartOffset(), docNode.getEndOffset() - docNode.getStartOffset());
+ }
+ else if (nodeType == Node.ATTRIBUTE_NODE) {
+ // handle attribute nodes
+ IDOMAttr att = (IDOMAttr) node;
+ // do not include quotes in attribute value region
+ int regOffset = att.getValueRegionStartOffset();
+ ITextRegion valueRegion = att.getValueRegion();
+ if (valueRegion != null) {
+ int regLength = valueRegion.getTextLength();
+ String attValue = att.getValueRegionText();
+ if (StringUtils.isQuoted(attValue)) {
+ ++regOffset;
+ regLength = regLength - 2;
+ }
+ hyperRegion = new Region(regOffset, regLength);
+ }
+ }
+ if (nodeType == Node.ELEMENT_NODE) {
+ // Handle doc type node
+ IDOMNode docNode = (IDOMNode) node;
+ hyperRegion = getNameRegion(docNode.getFirstStructuredDocumentRegion());
+ if (hyperRegion == null) {
+ hyperRegion = new Region(docNode.getStartOffset(), docNode.getFirstStructuredDocumentRegion().getTextLength());
+ }
+ }
+ }
+ /**
+ * Only return a hyperlink region that overlaps the search region.
+ * This will help us to not underline areas not under the cursor.
+ */
+ if (hyperRegion != null && intersects(hyperRegion, boundingRegion))
+ return hyperRegion;
+ return null;
+ }
+
+ private boolean intersects(IRegion hyperlinkRegion, IRegion detectionRegion) {
+ int hyperLinkStart = hyperlinkRegion.getOffset();
+ int hyperLinkEnd = hyperlinkRegion.getOffset() + hyperlinkRegion.getLength();
+ int detectionStart = detectionRegion.getOffset();
+ int detectionEnd = detectionRegion.getOffset() + detectionRegion.getLength();
+ return (hyperLinkStart <= detectionStart && detectionStart < hyperLinkEnd) || (hyperLinkStart <= detectionEnd && detectionEnd <= hyperLinkEnd);// ||
+ }
+
+ private IRegion getNameRegion(ITextRegionCollection containerRegion) {
+ ITextRegionList regions = containerRegion.getRegions();
+ ITextRegion nameRegion = null;
+ for (int i = 0; i < regions.size(); i++) {
+ ITextRegion r = regions.get(i);
+ if (r.getType() == DOMRegionContext.XML_TAG_NAME) {
+ nameRegion = r;
+ break;
+ }
+ }
+ if (nameRegion != null)
+ return new Region(containerRegion.getStartOffset(nameRegion), nameRegion.getTextLength());
+ return null;
+ }
+
+ /**
+ * Create the appropriate hyperlink
+ *
+ * @param uriString
+ * @param hyperlinkRegion
+ * @return IHyperlink
+ */
+ private IHyperlink createHyperlink(String uriString, IRegion hyperlinkRegion, IDocument document, Node node) {
+ IHyperlink link = null;
+
+ if (uriString != null) {
+ String temp = uriString.toLowerCase();
+ if (temp.startsWith(HTTP_PROTOCOL)) {
+ // this is a URLHyperlink since this is a web address
+ link = new URLHyperlink(hyperlinkRegion, uriString);
+ }
+ else if (temp.startsWith(JAR_PROTOCOL)) {
+ // this is a URLFileHyperlink since this is a local address
+ try {
+ link = new URLFileRegionHyperlink(hyperlinkRegion, TAG, node.getLocalName(), new URL(uriString)) {
+ public String getHyperlinkText() {
+ return JSPUIMessages.CustomTagHyperlink_hyperlinkText;
+ }
+ };
+ }
+ catch (MalformedURLException e) {
+ Logger.log(Logger.WARNING_DEBUG, e.getMessage(), e);
+ }
+ }
+ else {
+ // try to locate the file in the workspace
+ IPath path = new Path(uriString);
+ if (path.segmentCount() > 1) {
+ IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(path);
+ if (file.getType() == IResource.FILE && file.isAccessible()) {
+ if (node != null) {
+ link = new TLDFileHyperlink(file, TAG, node.getLocalName(), hyperlinkRegion) {
+ public String getHyperlinkText() {
+ return JSPUIMessages.TLDHyperlink_hyperlinkText;
+ }
+ };
+ }
+ else {
+ link = new WorkspaceFileHyperlink(hyperlinkRegion, file) {
+ public String getHyperlinkText() {
+ return JSPUIMessages.TLDHyperlink_hyperlinkText;
+ }
+ };
+ }
+ }
+ }
+ }
+ if (link == null) {
+ // this is an ExternalFileHyperlink since file does not exist
+ // in workspace
+ File externalFile = new File(uriString);
+ link = new ExternalFileHyperlink(hyperlinkRegion, externalFile) {
+ public String getHyperlinkText() {
+ return JSPUIMessages.TLDHyperlink_hyperlinkText;
+ }
+ };
+ }
+ }
+
+ return link;
+ }
+
+ private Node getCurrentNode(IStructuredModel model, int offset) {
+ // get the current node at the offset (returns either: element,
+ // doctype, text)
+ IndexedRegion inode = null;
+ if (model != null) {
+ inode = model.getIndexedRegion(offset);
+ if (inode == null) {
+ inode = model.getIndexedRegion(offset - 1);
+ }
+ }
+
+ if (inode instanceof Node) {
+ return (Node) inode;
+ }
+ return null;
+ }
+}

Back to the top