protected IRegion getRegion(IDocument document, final int offset) {
    StructuredModelWrapper smw = new StructuredModelWrapper();
    smw.init(document);
    try {
      Document xmlDocument = smw.getDocument();
      if (xmlDocument == null) return null;

      Node n = Utils.findNodeForOffset(xmlDocument, offset);

      if (n == null || !(n instanceof IDOMElement)) return null;

      IDOMElement elem = (IDOMElement) n;
      String tagName = elem.getTagName();
      int start = Utils.getValueStart(elem);
      final int nameStart =
          start + (elem.isEndTag() ? "</" : "<").length(); // $NON-NLS-1$ //$NON-NLS-2$
      final int nameEnd = nameStart + tagName.length();

      if (nameStart > offset || nameEnd <= offset) return null;

      return new Region(nameStart, nameEnd - nameStart);
    } finally {
      smw.dispose();
    }
  }
  /**
   * @param offset
   * @return
   */
  protected IRegion getRegion(IDocument document, int offset) {
    StructuredModelWrapper smw = new StructuredModelWrapper();
    try {
      smw.init(document);
      Document xmlDocument = smw.getDocument();
      if (xmlDocument == null) return null;

      Node n = Utils.findNodeForOffset(xmlDocument, offset);

      if (n == null || !(n instanceof Attr)) return null;
      int start = Utils.getValueStart(n);
      int end = Utils.getValueEnd(n);
      if (start > offset) return null;

      String attrText = document.get(start, end - start);

      StringBuffer sb = new StringBuffer(attrText);
      // find start of css class
      int bStart = offset - start;
      while (bStart >= 0) {
        if (!Character.isJavaIdentifierPart(sb.charAt(bStart))
            && sb.charAt(bStart) != '_'
            && sb.charAt(bStart) != '-'
            && sb.charAt(bStart) != '.') {
          bStart++;
          break;
        }

        if (bStart == 0) break;
        bStart--;
      }
      // find end of css class
      int bEnd = offset - start;
      while (bEnd < sb.length()) {
        if (!Character.isJavaIdentifierPart(sb.charAt(bEnd))
            && sb.charAt(bEnd) != '_'
            && sb.charAt(bEnd) != '-'
            && sb.charAt(bEnd) != '.') break;
        bEnd++;
      }

      final int propStart = bStart + start;
      final int propLength = bEnd - bStart;

      if (propStart > offset || propStart + propLength < offset) return null;
      return new Region(propStart, propLength);
    } catch (BadLocationException x) {
      // ignore
      return null;
    } finally {
      smw.dispose();
    }
  }
  public static IHyperlinkRegion getRegion(IDocument document, final int offset) {
    StructuredModelWrapper smw = new StructuredModelWrapper();
    try {
      smw.init(document);
      Document xmlDocument = smw.getDocument();
      if (xmlDocument == null) return null;

      Node n = Utils.findNodeForOffset(xmlDocument, offset);

      if (n == null || !(n instanceof Attr)) return null;

      int start = Utils.getValueStart(n);
      int end = Utils.getValueEnd(n);

      if (start < 0 || start > offset) return null;

      String attrText = document.get(start, end - start);
      StringBuffer sb = new StringBuffer(attrText);

      // find start of bean property
      int bStart = offset - start;
      while (bStart >= 0) {
        if (!Character.isJavaIdentifierPart(sb.charAt(bStart)) && sb.charAt(bStart) != '.') {
          bStart++;
          break;
        }

        if (bStart == 0) break;
        bStart--;
      }
      // find end of bean property
      int bEnd = offset - start;
      while (bEnd < sb.length()) {
        if (!Character.isJavaIdentifierPart(sb.charAt(bEnd)) && sb.charAt(bEnd) != '.') break;
        bEnd++;
      }

      int propStart = bStart + start;
      int propLength = bEnd - bStart;

      if (propStart > offset || propStart + propLength < offset) return null;

      IHyperlinkRegion region = new HyperlinkRegion(propStart, propLength, null, null, null);
      return region;
    } catch (BadLocationException x) {
      JSFExtensionsPlugin.log("", x); // $NON-NLS-1$
      return null;
    } finally {
      smw.dispose();
    }
  }
 protected String getAttributeValue(IDocument document, Node node, String attrName) {
   if (document == null || node == null || attrName == null) return null;
   try {
     Attr attr = (Attr) node.getAttributes().getNamedItem(attrName);
     return Utils.getTrimmedValue(document, attr);
   } catch (BadLocationException x) {
     StrutsExtensionsPlugin.getPluginLog().logError(x);
     return null;
   }
 }
  /**
   * @see
   *     com.ibm.sse.editor.extensions.hyperlink.IHyperlinkPartitionRecognizer#recognize(org.eclipse.jface.text.IDocument,
   *     com.ibm.sse.editor.extensions.hyperlink.IHyperlinkRegion)
   */
  public boolean recognize(IDocument document, int offset, IHyperlinkRegion region) {
    StructuredModelWrapper smw = new StructuredModelWrapper();
    smw.init(document);
    try {
      Document xmlDocument = smw.getDocument();
      if (xmlDocument == null) return false;

      Node n = Utils.findNodeForOffset(xmlDocument, offset);
      if (!(n instanceof Attr)) return false;

      IHyperlinkRegion r = getRegion(document, offset);
      if (r == null) return false;

      Attr attr = (Attr) n;
      String attrName = attr.getNodeName();
      if (!"var".equals(attrName) && !"basename".equals(attrName))
        return false; //$NON-NLS-1$ //$NON-NLS-2$

      Element lbTag = attr.getOwnerElement();
      String name = lbTag.getTagName();
      int column = name.indexOf(":"); // $NON-NLS-1$
      if (column == -1) return false;
      String usedPrefix = name.substring(0, column);
      if (usedPrefix == null || usedPrefix.trim().length() == 0) return false;

      String[] prefixes = getLoadBundleTagPrefixes(document, offset);
      if (prefixes == null) return true; // xhtml

      boolean prefixIsAbleToBeUsed = false;
      for (String prefix : prefixes) {
        if (usedPrefix.equals(prefix)) {
          prefixIsAbleToBeUsed = true;
          break;
        }
      }
      if (!prefixIsAbleToBeUsed) return false;

      Attr lbTagVar = lbTag.getAttributeNode("var"); // $NON-NLS-1$
      Attr lbTagBasename = lbTag.getAttributeNode("basename"); // $NON-NLS-1$

      if (lbTagVar == null
          || lbTagVar.getNodeValue() == null
          || lbTagVar.getNodeValue().trim().length() == 0) return false;
      if (lbTagBasename == null
          || lbTagBasename.getNodeValue() == null
          || lbTagBasename.getNodeValue().trim().length() == 0) return false;

      return true;
    } finally {
      smw.dispose();
    }
  }
  /**
   * @see
   *     com.ibm.sse.editor.hyperlink.AbstractHyperlinkPartitioner#parse(org.eclipse.jface.text.IDocument,
   *     com.ibm.sse.editor.extensions.hyperlink.IHyperlinkRegion)
   */
  protected IHyperlinkRegion parse(IDocument document, int offset, IHyperlinkRegion superRegion) {
    StructuredModelWrapper smw = new StructuredModelWrapper();
    smw.init(document);
    try {
      Document xmlDocument = smw.getDocument();
      if (xmlDocument == null) return null;

      Utils.findNodeForOffset(xmlDocument, offset);
      IRegion r = getRegion(document, offset);
      if (r == null) return null;

      String axis = getAxis(document, offset);
      String contentType = superRegion.getContentType();
      String type = JSF_JSP_TAG_NAME_PARTITION;

      return new HyperlinkRegion(r.getOffset(), r.getLength(), axis, contentType, type);
    } finally {
      smw.dispose();
    }
  }
  /**
   * @see
   *     com.ibm.sse.editor.extensions.hyperlink.IHyperlinkPartitionRecognizer#recognize(org.eclipse.jface.text.IDocument,
   *     com.ibm.sse.editor.extensions.hyperlink.IHyperlinkRegion)
   */
  public boolean recognize(IDocument document, int offset, IHyperlinkRegion region) {
    if (!super.recognize(document, offset, region)) return false;

    StructuredModelWrapper smw = new StructuredModelWrapper();
    smw.init(document);
    try {
      Document xmlDocument = smw.getDocument();
      if (xmlDocument == null) return false;

      Node n = Utils.findNodeForOffset(xmlDocument, offset);
      if (!(n instanceof Attr)) return false;
      Node parentNode = ((Attr) n).getOwnerElement();

      String resourceAttrValue = getAttributeValue(document, parentNode, RESOURCE_ATTRNAME);
      if (resourceAttrValue != null && FALSE_ATTRVALUE.equals(resourceAttrValue)) return false;

      return true;
    } finally {
      smw.dispose();
    }
  }
  /**
   * @see
   *     com.ibm.sse.editor.hyperlink.AbstractHyperlinkPartitioner#parse(org.eclipse.jface.text.IDocument,
   *     com.ibm.sse.editor.extensions.hyperlink.IHyperlinkRegion)
   */
  protected IHyperlinkRegion parse(IDocument document, int offset, IHyperlinkRegion superRegion) {
    StructuredModelWrapper smw = new StructuredModelWrapper();
    try {
      smw.init(document);
      Document xmlDocument = smw.getDocument();
      if (xmlDocument == null) return null;

      Node n = Utils.findNodeForOffset(xmlDocument, offset);
      if (n == null || !(n instanceof Attr)) return null;

      String axis = getAxis(document, offset);
      String contentType = superRegion.getContentType();
      String type = getPartitionType(axis);

      IRegion r = getRegion(document, offset);
      if (r == null) return null;

      return new HyperlinkRegion(r.getOffset(), r.getLength(), axis, contentType, type);
    } finally {
      smw.dispose();
    }
  }