@Override
  public String serialize(ResourceReference reference) {
    StringBuilder buffer = new StringBuilder();

    if (reference.getReference() != null) {
      // Make sure we escape special chars: # and ? as they have special meaning in links, but only
      // for
      // links to documents. Also escape \ since it's the escape char.
      String normalizedReference = addEscapesToReferencePart(reference.getReference());
      buffer.append(normalizedReference);

      // Since we don`t have typed references in the 2.0 syntax, we need to reuse the untyped
      // document reference
      // syntax and make it explicit that it's about the WebHome document of the space.
      // This is most useful when converting from 2.1 back to 2.0.
      buffer.append(".WebHome");
    }

    String anchor = reference.getParameter(DocumentResourceReference.ANCHOR);
    if (anchor != null) {
      buffer.append('#');
      buffer.append(addEscapesToExtraParts(anchor));
    }
    String queryString = reference.getParameter(DocumentResourceReference.QUERY_STRING);
    if (queryString != null) {
      buffer.append('?');
      buffer.append(addEscapesToExtraParts(queryString));
    }

    return buffer.toString();
  }
  private XHTMLLinkTypeRenderer getXHTMLLinkTypeRenderer(ResourceReference reference) {
    XHTMLLinkTypeRenderer renderer;

    // TODO: This is probably not very performant since it's called at each begin/endLink.
    try {
      renderer =
          this.componentManagerProvider
              .get()
              .getInstance(XHTMLLinkTypeRenderer.class, reference.getType().getScheme());
    } catch (ComponentLookupException e) {
      // There's no specific XHTML Link Type Renderer for the passed link type, use the default
      // renderer.
      renderer = this.defaultLinkTypeRenderer;
    }
    renderer.setHasLabel(this.hasLabel);
    renderer.setXHTMLWikiPrinter(getXHTMLWikiPrinter());
    return renderer;
  }
  private void updateRelativeLinks(XWikiDocument document, DocumentReference oldDocumentReference)
      throws XWikiException {
    // We support only the syntaxes for which there is an available renderer.
    if (!this.contextComponentManagerProvider
        .get()
        .hasComponent(BlockRenderer.class, document.getSyntax().toIdString())) {
      this.logger.warn(
          "We can't update the relative links from [{}]"
              + " because there is no renderer available for its syntax [{}].",
          document.getDocumentReference(),
          document.getSyntax());
      return;
    }

    DocumentReference newDocumentReference = document.getDocumentReference();

    XDOM xdom = document.getXDOM();
    List<Block> blocks = linkedResourceHelper.getBlocks(xdom);

    boolean modified = false;
    for (Block block : blocks) {
      ResourceReference resourceReference = linkedResourceHelper.getResourceReference(block);
      if (resourceReference == null) {
        // Skip invalid blocks.
        continue;
      }

      ResourceType resourceType = resourceReference.getType();

      // TODO: support ATTACHMENT as well.
      if (!ResourceType.DOCUMENT.equals(resourceType) && !ResourceType.SPACE.equals(resourceType)) {
        // We are currently only interested in Document or Space references.
        continue;
      }

      // current link, use the old document's reference to fill in blanks.
      EntityReference oldLinkReference =
          this.resourceReferenceResolver.resolve(resourceReference, null, oldDocumentReference);
      // new link, use the new document's reference to fill in blanks.
      EntityReference newLinkReference =
          this.resourceReferenceResolver.resolve(resourceReference, null, newDocumentReference);

      // If the new and old link references don`t match, then we must update the relative link.
      if (!newLinkReference.equals(oldLinkReference)) {
        modified = true;

        // Serialize the old (original) link relative to the new document's location, in compact
        // form.
        String serializedLinkReference =
            this.compactEntityReferenceSerializer.serialize(oldLinkReference, newDocumentReference);

        // Update the reference in the XDOM.
        linkedResourceHelper.setResourceReferenceString(block, serializedLinkReference);
      }
    }

    if (modified) {
      document.setContent(xdom);
      saveDocumentPreservingContentAuthor(document, "Updated the relative links.", true);
      this.logger.info("Updated the relative links from [{}].", document.getDocumentReference());
    } else {
      this.logger.info("No relative links to update in [{}].", document.getDocumentReference());
    }
  }
  private boolean renameLink(
      Block block,
      DocumentReference currentDocumentReference,
      DocumentReference oldTarget,
      DocumentReference newTarget)
      throws InvalidArgumentException {
    boolean modified = false;

    ResourceReference resourceReference = linkedResourceHelper.getResourceReference(block);
    if (resourceReference == null) {
      // Skip invalid blocks.
      throw new InvalidArgumentException();
    }

    ResourceType resourceType = resourceReference.getType();

    // TODO: support ATTACHMENT as well.
    if (!ResourceType.DOCUMENT.equals(resourceType) && !ResourceType.SPACE.equals(resourceType)) {
      // We are currently only interested in Document or Space references.
      throw new InvalidArgumentException();
    }

    // Resolve the resource reference.
    EntityReference linkEntityReference =
        resourceReferenceResolver.resolve(resourceReference, null, currentDocumentReference);
    // Resolve the document of the reference.
    DocumentReference linkTargetDocumentReference =
        defaultReferenceDocumentReferenceResolver.resolve(linkEntityReference);
    EntityReference newTargetReference = newTarget;
    ResourceType newResourceType = resourceType;

    // If the link was resolved to a space...
    if (EntityType.SPACE.equals(linkEntityReference.getType())) {
      if (XWiki.DEFAULT_SPACE_HOMEPAGE.equals(newTarget.getName())) {
        // If the new document reference is also a space (non-terminal doc), be careful to keep it
        // serialized as a space still (i.e. without ".WebHome") and not serialize it as a doc by
        // mistake
        // (i.e. with ".WebHome").
        newTargetReference = newTarget.getLastSpaceReference();
      } else {
        // If the new target is a non-terminal document, we can not use a "space:" resource type to
        // access
        // it anymore. To fix it, we need to change the resource type of the link reference "doc:".
        newResourceType = ResourceType.DOCUMENT;
      }
    }

    // If the link targets the old (renamed) document reference, we must update it.
    if (linkTargetDocumentReference.equals(oldTarget)) {
      modified = true;
      String newReferenceString =
          this.compactEntityReferenceSerializer.serialize(
              newTargetReference, currentDocumentReference);

      // Update the reference in the XDOM.
      linkedResourceHelper.setResourceReferenceString(block, newReferenceString);
      linkedResourceHelper.setResourceType(block, newResourceType);
    }

    return modified;
  }
  @Test
  public void testParseWhenInWikiMode() throws Exception {
    // Create a Mock WikiModel implementation so that the link parser works in wiki mode
    this.componentManager.registerMockComponent(WikiModel.class);

    ResourceReference reference = parser.parse("");
    Assert.assertEquals("", reference.getReference());
    Assert.assertFalse(reference.isTyped());
    Assert.assertEquals(ResourceType.DOCUMENT, reference.getType());
    Assert.assertEquals("Typed = [false] Type = [doc] Reference = []", reference.toString());

    reference = parser.parse("Hello World");
    Assert.assertEquals("Hello World", reference.getReference());
    Assert.assertFalse(reference.isTyped());
    Assert.assertEquals(ResourceType.DOCUMENT, reference.getType());
    Assert.assertEquals(
        "Typed = [false] Type = [doc] Reference = [Hello World]", reference.toString());

    reference = parser.parse("http://xwiki.org");
    Assert.assertEquals("http://xwiki.org", reference.getReference());
    Assert.assertFalse(reference.isTyped());
    Assert.assertEquals(ResourceType.URL, reference.getType());
    Assert.assertEquals(
        "Typed = [false] Type = [url] Reference = [http://xwiki.org]", reference.toString());

    // Verify mailto: URI is recognized
    reference = parser.parse("mailto:[email protected]?subject=test");
    Assert.assertEquals("[email protected]?subject=test", reference.getReference());
    Assert.assertTrue(reference.isTyped());
    Assert.assertEquals(ResourceType.MAILTO, reference.getType());
    Assert.assertEquals(
        "Typed = [true] Type = [mailto] Reference = [[email protected]?subject=test]",
        reference.toString());

    // Verify attach: URI is recognized
    reference = parser.parse("attach:some:content");
    Assert.assertEquals("some:content", reference.getReference());
    Assert.assertTrue(reference.isTyped());
    Assert.assertEquals(ResourceType.ATTACHMENT, reference.getType());
    Assert.assertEquals(
        "Typed = [true] Type = [attach] Reference = [some:content]", reference.toString());

    // Verify that unknown URIs are ignored
    // Note: In this example we point to a document and we consider that myxwiki is the wiki name
    // and
    // http://xwiki.org is the page name
    reference = parser.parse("mywiki:http://xwiki.org");
    Assert.assertEquals("mywiki:http://xwiki.org", reference.getReference());
    Assert.assertFalse(reference.isTyped());
    Assert.assertEquals(ResourceType.DOCUMENT, reference.getType());
    Assert.assertEquals(
        "Typed = [false] Type = [doc] Reference = [mywiki:http://xwiki.org]", reference.toString());

    // Verify doc links work
    reference = parser.parse("doc:wiki:space.page");
    Assert.assertEquals(ResourceType.DOCUMENT, reference.getType());
    Assert.assertEquals("wiki:space.page", reference.getReference());
    Assert.assertEquals(
        "Typed = [true] Type = [doc] Reference = [wiki:space.page]", reference.toString());
    Assert.assertTrue(reference.isTyped());

    // Verify InterWiki links work
    reference = parser.parse("interwiki:alias:content");
    Assert.assertEquals(ResourceType.INTERWIKI, reference.getType());
    Assert.assertEquals("content", reference.getReference());
    Assert.assertTrue(reference.isTyped());
    Assert.assertEquals("alias", ((InterWikiResourceReference) reference).getInterWikiAlias());
    Assert.assertEquals(
        "Typed = [true] Type = [interwiki] Reference = [content] "
            + "Parameters = [[interWikiAlias] = [alias]]",
        reference.toString());

    // Verify that an invalid InterWiki link is considered as Document link
    reference = parser.parse("interwiki:invalid_since_doesnt_have_colon");
    Assert.assertEquals(ResourceType.DOCUMENT, reference.getType());
    Assert.assertEquals("interwiki:invalid_since_doesnt_have_colon", reference.getReference());
    Assert.assertFalse(reference.isTyped());
    Assert.assertEquals(
        "Typed = [false] Type = [doc] Reference = [interwiki:invalid_since_doesnt_have_colon]",
        reference.toString());

    // Verify typed URLs
    reference = parser.parse("url:http://xwiki.org");
    Assert.assertEquals(ResourceType.URL, reference.getType());
    Assert.assertTrue(reference.isTyped());
    Assert.assertEquals("http://xwiki.org", reference.getReference());
    Assert.assertEquals(
        "Typed = [true] Type = [url] Reference = [http://xwiki.org]", reference.toString());

    // Verify query string and anchors have no meaning in link reference to documents.
    reference = parser.parse("Hello World?no=queryString#notAnAnchor");
    Assert.assertEquals(ResourceType.DOCUMENT, reference.getType());
    Assert.assertEquals("Hello World?no=queryString#notAnAnchor", reference.getReference());
    Assert.assertFalse(reference.isTyped());
    Assert.assertNull(((DocumentResourceReference) reference).getAnchor());
    Assert.assertNull(((DocumentResourceReference) reference).getQueryString());
    Assert.assertEquals(
        "Typed = [false] Type = [doc] Reference = [Hello World?no=queryString#notAnAnchor]",
        reference.toString());

    // Verify that the interwiki separator from XWiki Syntax 2.0 has not meaning in link references
    // to documents
    reference = parser.parse("page@alias");
    Assert.assertEquals(ResourceType.DOCUMENT, reference.getType());
    Assert.assertFalse(reference.isTyped());
    Assert.assertEquals("page@alias", reference.getReference());
    Assert.assertEquals(
        "Typed = [false] Type = [doc] Reference = [page@alias]", reference.toString());

    // Verify path link types
    reference = parser.parse("path:/some/path");
    Assert.assertEquals(ResourceType.PATH, reference.getType());
    Assert.assertTrue(reference.isTyped());
    Assert.assertEquals("/some/path", reference.getReference());
    Assert.assertEquals(
        "Typed = [true] Type = [path] Reference = [/some/path]", reference.toString());

    // Verify UNC link types
    reference = parser.parse("unc:\\\\myserver\\myshare\\mydoc.txt");
    Assert.assertEquals(ResourceType.UNC, reference.getType());
    Assert.assertTrue(reference.isTyped());
    Assert.assertEquals("\\\\myserver\\myshare\\mydoc.txt", reference.getReference());
    Assert.assertEquals(
        "Typed = [true] Type = [unc] Reference = [\\\\myserver\\myshare\\mydoc.txt]",
        reference.toString());

    // Verify that reference escapes are left as is by the link parser
    reference = this.parser.parse("pa\\.ge");
    Assert.assertEquals(ResourceType.DOCUMENT, reference.getType());
    Assert.assertEquals("pa\\.ge", reference.getReference());
  }
  @Test
  public void testParseWhenNotInWikiMode() throws Exception {
    // Verify that mailto: links are treated normally even when in non wiki mode
    ResourceReference reference = parser.parse("mailto:something");
    Assert.assertEquals("something", reference.getReference());
    Assert.assertTrue(reference.isTyped());
    Assert.assertEquals(ResourceType.MAILTO, reference.getType());
    Assert.assertEquals(
        "Typed = [true] Type = [mailto] Reference = [something]", reference.toString());

    // Verify that non typed links are treated as URLs
    reference = parser.parse("something");
    Assert.assertEquals("something", reference.getReference());
    Assert.assertFalse(reference.isTyped());
    Assert.assertEquals(ResourceType.URL, reference.getType());
    Assert.assertEquals(
        "Typed = [false] Type = [url] Reference = [something]", reference.toString());

    // Verify that doc: links are treated as URLs
    reference = parser.parse("doc:something");
    Assert.assertEquals("doc:something", reference.getReference());
    Assert.assertFalse(reference.isTyped());
    Assert.assertEquals(ResourceType.URL, reference.getType());
    Assert.assertEquals(
        "Typed = [false] Type = [url] Reference = [doc:something]", reference.toString());

    // Verify that attach: links are treated as URLs
    reference = parser.parse("attach:something");
    Assert.assertEquals("attach:something", reference.getReference());
    Assert.assertFalse(reference.isTyped());
    Assert.assertEquals(ResourceType.URL, reference.getType());
    Assert.assertEquals(
        "Typed = [false] Type = [url] Reference = [attach:something]", reference.toString());
  }
Example #7
0
  @Override
  public void filter(Document htmlDocument, Map<String, String> cleaningParams) {
    String targetDocument = cleaningParams.get("targetDocument");
    DocumentReference targetDocumentReference = null;

    List<Element> images =
        filterDescendants(htmlDocument.getDocumentElement(), new String[] {TAG_IMG});
    for (Element image : images) {
      if (targetDocumentReference == null && !StringUtils.isBlank(targetDocument)) {
        targetDocumentReference = this.documentStringReferenceResolver.resolve(targetDocument);
      }

      String src = image.getAttribute(ATTRIBUTE_SRC);
      // If it's a Data URI scheme don't touch it
      if (!src.startsWith("data:")) {
        if (!StringUtils.isBlank(src) && targetDocumentReference != null) {
          // OpenOffice 3.2 server generates relative image paths, extract image name.
          int separator = src.lastIndexOf("/");
          if (-1 != separator) {
            src = src.substring(separator + 1);
          }
          try {
            // We have to decode the image file name in case it contains URL special characters.
            src = URLDecoder.decode(src, "UTF-8");
          } catch (UnsupportedEncodingException e) {
            // This should never happen.
          }

          // Set image source attribute relative to the reference document.
          AttachmentReference attachmentReference =
              new AttachmentReference(src, targetDocumentReference);
          image.setAttribute(
              ATTRIBUTE_SRC,
              this.documentAccessBridge.getAttachmentURL(attachmentReference, false));

          // The 'align' attribute of images creates a lot of problems. First,the office server has
          // a problem
          // with
          // center aligning images (it aligns them to left). Next, the office server uses <br
          // clear"xxx"> for
          // avoiding content wrapping around images which is not valid XHTML. There for, to be
          // consistent and
          // simple we will remove the 'align' attribute of all the images so that they are all left
          // aligned.
          image.removeAttribute(ATTRIBUTE_ALIGN);
        } else if (src.startsWith("file://")) {
          src = "Missing.png";
          image.setAttribute(ATTRIBUTE_SRC, src);
          image.setAttribute(ATTRIBUTE_ALT, src);
        }

        ResourceReference imageReference = new ResourceReference(src, ResourceType.ATTACHMENT);
        imageReference.setTyped(false);
        Comment beforeComment =
            htmlDocument.createComment(
                XMLUtils.escapeXMLComment(
                    "startimage:" + this.xhtmlMarkerSerializer.serialize(imageReference)));
        Comment afterComment = htmlDocument.createComment("stopimage");
        image.getParentNode().insertBefore(beforeComment, image);
        image.getParentNode().insertBefore(afterComment, image.getNextSibling());
      }
    }
  }