public XWikiPageClassLoader(String jarWikiPage, ClassLoader parent, XWikiContext context)
      throws XWikiException {
    super(new URL[0], parent);

    XWikiDocument doc = context.getWiki().getDocument(jarWikiPage, context);
    if (!doc.isNew()) {
      List attachList = doc.getAttachmentList();
      for (int i = 0; i < attachList.size(); i++) {
        XWikiAttachment attach = (XWikiAttachment) attachList.get(i);
        String filename = attach.getFilename();
        if (filename.endsWith(".jar")) {
          String downloadURL = doc.getExternalAttachmentURL(filename, "download", context);
          try {
            addURL(new URL(downloadURL));
            if (LOGGER.isDebugEnabled()) {
              LOGGER.debug(
                  "Adding ["
                      + downloadURL
                      + "] JAR from page ["
                      + jarWikiPage
                      + "] to Groovy classloader");
            }
          } catch (Exception e) {
            LOGGER.warn(
                "Failed to add ["
                    + downloadURL
                    + "] JAR from page ["
                    + jarWikiPage
                    + "], ignoring it.");
          }
        }
      }
    }
  }
  /**
   * @see "XWIKI-9399: Attachment version is incremented when a document is rolled back even if the
   *     attachment did not change"
   */
  @Test
  public void rollbackDoesNotSaveUnchangedAttachment() throws Exception {
    String version = "1.1";
    String fileName = "logo.png";
    Date date = new Date();
    XWikiAttachment currentAttachment = mock(XWikiAttachment.class);
    when(currentAttachment.getAttachmentRevision(version, context)).thenReturn(currentAttachment);
    when(currentAttachment.getDate()).thenReturn(new Timestamp(date.getTime()));
    when(currentAttachment.getVersion()).thenReturn(version);
    when(currentAttachment.getFilename()).thenReturn(fileName);

    XWikiAttachment oldAttachment = mock(XWikiAttachment.class);
    when(oldAttachment.getFilename()).thenReturn(fileName);
    when(oldAttachment.getVersion()).thenReturn(version);
    when(oldAttachment.getDate()).thenReturn(date);

    DocumentReference documentReference = new DocumentReference("wiki", "Space", "Page");
    XWikiDocument document = mock(XWikiDocument.class);
    when(document.getDocumentReference()).thenReturn(documentReference);
    when(document.getAttachmentList()).thenReturn(Arrays.asList(currentAttachment));
    when(document.getAttachment(fileName)).thenReturn(currentAttachment);

    XWikiDocument result = mock(XWikiDocument.class);
    when(result.clone()).thenReturn(result);
    when(result.getDocumentReference()).thenReturn(documentReference);
    when(result.getAttachmentList()).thenReturn(Arrays.asList(oldAttachment));
    when(result.getAttachment(fileName)).thenReturn(oldAttachment);

    String revision = "3.5";
    when(xwiki.getVersioningStore().loadXWikiDoc(document, revision, context)).thenReturn(result);

    AttachmentRecycleBinStore attachmentRecycleBinStore = mock(AttachmentRecycleBinStore.class);
    xwiki.setAttachmentRecycleBinStore(attachmentRecycleBinStore);

    DocumentReference reference = document.getDocumentReference();
    this.mocker.registerMockComponent(ContextualLocalizationManager.class);
    when(xwiki.getStore().loadXWikiDoc(any(XWikiDocument.class), same(context)))
        .thenReturn(new XWikiDocument(reference));

    xwiki.rollback(document, revision, context);

    verify(attachmentRecycleBinStore, never())
        .saveToRecycleBin(
            same(currentAttachment), any(String.class), any(Date.class), same(context), eq(true));
    verify(oldAttachment, never()).setMetaDataDirty(true);
  }
示例#3
0
  private int installDocument(
      DocumentInfo doc, boolean isAdmin, boolean backup, XWikiContext context)
      throws XWikiException {
    if (this.preserveVersion && this.withVersions) {
      // Right now importing an archive and the history revisions it contains
      // without overriding the existing document is not supported.
      // We fallback on adding a new version to the existing history without importing the
      // archive's revisions.
      this.withVersions = false;
    }

    int result = DocumentInfo.INSTALL_OK;

    if (LOGGER.isDebugEnabled()) {
      LOGGER.debug("Package installing document " + doc.getFullName() + " " + doc.getLanguage());
    }

    if (doc.getAction() == DocumentInfo.ACTION_SKIP) {
      addToSkipped(doc.getFullName() + ":" + doc.getLanguage(), context);
      return DocumentInfo.INSTALL_OK;
    }

    int status = doc.testInstall(isAdmin, context);
    if (status == DocumentInfo.INSTALL_IMPOSSIBLE) {
      addToErrors(doc.getFullName() + ":" + doc.getLanguage(), context);
      return DocumentInfo.INSTALL_IMPOSSIBLE;
    }
    if (status == DocumentInfo.INSTALL_OK
        || status == DocumentInfo.INSTALL_ALREADY_EXIST
            && doc.getAction() == DocumentInfo.ACTION_OVERWRITE) {
      XWikiDocument previousdoc = null;
      if (status == DocumentInfo.INSTALL_ALREADY_EXIST) {
        previousdoc = context.getWiki().getDocument(doc.getFullName(), context);
        // if this document is a translation: we should only delete the translation
        if (doc.getDoc().getTranslation() != 0) {
          previousdoc = previousdoc.getTranslatedDocument(doc.getLanguage(), context);
        }
        // we should only delete the previous document
        // if we are overridding the versions and/or if this is a backup pack
        if (!this.preserveVersion || this.withVersions) {
          try {
            // This is not a real document delete, it's a upgrade. To be sure to not
            // generate DELETE notification we directly use {@link XWikiStoreInterface}
            context.getWiki().getStore().deleteXWikiDoc(previousdoc, context);
          } catch (Exception e) {
            // let's log the error but not stop
            result = DocumentInfo.INSTALL_ERROR;
            addToErrors(doc.getFullName() + ":" + doc.getLanguage(), context);
            if (LOGGER.isErrorEnabled()) {
              LOGGER.error("Failed to delete document " + previousdoc.getDocumentReference());
            }
            if (LOGGER.isDebugEnabled()) {
              LOGGER.debug("Failed to delete document " + previousdoc.getDocumentReference(), e);
            }
          }
        } else if (previousdoc.hasElement(XWikiDocument.HAS_ATTACHMENTS)) {
          // We conserve the old attachments in the new documents
          List<XWikiAttachment> newDocAttachments = doc.getDoc().getAttachmentList();
          for (XWikiAttachment att : previousdoc.getAttachmentList()) {
            if (doc.getDoc().getAttachment(att.getFilename()) == null) {
              // We add the attachment to new document
              newDocAttachments.add(att);
              // But then we add it in the "to remove list" of the document
              // So the attachment will be removed from the database when XWiki#saveDocument
              // will be called
              doc.getDoc().removeAttachment(att);
            }
          }
        }
        doc.getDoc().addXObjectsToRemoveFromVersion(previousdoc);
        doc.getDoc().setOriginalDocument(previousdoc);
      }
      try {
        if (!backup) {
          doc.getDoc().setAuthorReference(context.getUserReference());
          doc.getDoc().setContentAuthorReference(context.getUserReference());
          // if the import is not a backup pack we set the date to now
          Date date = new Date();
          doc.getDoc().setDate(date);
          doc.getDoc().setContentUpdateDate(date);
        }

        if (!this.withVersions) {
          doc.getDoc().setVersion("1.1");
        }

        // Does the document to be imported already exists in the wiki ?
        boolean isNewDocument = previousdoc == null;

        // Conserve existing history only if asked for it and if this history exists
        boolean conserveExistingHistory = this.preserveVersion && !isNewDocument;

        // Does the document from the package contains history revisions ?
        boolean packageHasHistory = this.documentContainsHistory(doc);

        // Reset to initial (1.1) version when we don't want to conserve existing history and either
        // we don't
        // want the package history or this latter one is empty
        boolean shouldResetToInitialVersion =
            !conserveExistingHistory && (!this.withVersions || !packageHasHistory);

        if (conserveExistingHistory) {
          // Insert the archive from the existing document
          doc.getDoc().setDocumentArchive(previousdoc.getDocumentArchive(context));
        } else {
          // Reset or replace history
          // if there was not history in the source package then we should reset the version number
          // to 1.1
          if (shouldResetToInitialVersion) {
            // Make sure the save will not increment the version to 2.1
            doc.getDoc().setContentDirty(false);
            doc.getDoc().setMetaDataDirty(false);
          }
        }

        String saveMessage = context.getMessageTool().get("core.importer.saveDocumentComment");
        context.getWiki().saveDocument(doc.getDoc(), saveMessage, context);
        addToInstalled(doc.getFullName() + ":" + doc.getLanguage(), context);

        if ((this.withVersions && packageHasHistory) || conserveExistingHistory) {
          // we need to force the saving the document archive.
          if (doc.getDoc().getDocumentArchive() != null) {
            context
                .getWiki()
                .getVersioningStore()
                .saveXWikiDocArchive(doc.getDoc().getDocumentArchive(context), true, context);
          }
        }

        if (shouldResetToInitialVersion) {
          // If we override and do not import version, (meaning reset document to 1.1)
          // We need manually reset possible existing revision for the document
          // This means making the history empty (it does not affect the version number)
          doc.getDoc().resetArchive(context);
        }

      } catch (XWikiException e) {
        addToErrors(doc.getFullName() + ":" + doc.getLanguage(), context);
        if (LOGGER.isErrorEnabled()) {
          LOGGER.error("Failed to save document " + doc.getFullName(), e);
        }
        result = DocumentInfo.INSTALL_ERROR;
      }
    }
    return result;
  }
  @Override
  public String render(XWikiContext context) throws XWikiException {
    XWikiRequest request = context.getRequest();
    XWikiResponse response = context.getResponse();
    XWikiDocument doc = context.getDoc();
    String path = request.getRequestURI();
    String filename = Util.decodeURI(getFileName(path, ACTION_NAME), context);
    XWikiAttachment attachment = null;

    final String idStr = request.getParameter("id");
    if (StringUtils.isNumeric(idStr)) {
      int id = Integer.parseInt(idStr);
      if (doc.getAttachmentList().size() > id) {
        attachment = doc.getAttachmentList().get(id);
      }
    } else {
      attachment = doc.getAttachment(filename);
    }

    if (attachment == null) {
      Object[] args = {filename};
      throw new XWikiException(
          XWikiException.MODULE_XWIKI_APP,
          XWikiException.ERROR_XWIKI_APP_ATTACHMENT_NOT_FOUND,
          "Attachment {0} not found",
          null,
          args);
    }

    XWikiPluginManager plugins = context.getWiki().getPluginManager();
    attachment = plugins.downloadAttachment(attachment, context);

    // Try to load the attachment content just to make sure that the attachment really exists
    // This will throw an exception if the attachment content isn't available
    try {
      attachment.getContentSize(context);
    } catch (XWikiException e) {
      Object[] args = {filename};
      throw new XWikiException(
          XWikiException.MODULE_XWIKI_APP,
          XWikiException.ERROR_XWIKI_APP_ATTACHMENT_NOT_FOUND,
          "Attachment content {0} not found",
          null,
          args);
    }

    long lastModifiedOnClient = request.getDateHeader("If-Modified-Since");
    long lastModifiedOnServer = attachment.getDate().getTime();
    if (lastModifiedOnClient != -1 && lastModifiedOnClient >= lastModifiedOnServer) {
      response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
      return null;
    }

    // Sending the content of the attachment
    if (request.getHeader(RANGE_HEADER_NAME) != null) {
      try {
        if (sendPartialContent(attachment, request, response, context)) {
          return null;
        }
      } catch (IOException ex) {
        // Broken response...
      }
    }
    sendContent(attachment, request, response, filename, context);
    return null;
  }