/** * Store the requested attachment on the filesystem and return a {@code file://} URL where FOP can * access that file. * * @param wiki the name of the owner document's wiki * @param space the name of the owner document's space * @param name the name of the owner document * @param filename the name of the attachment * @param revision an optional attachment version * @param context the current request context * @return a {@code file://} URL where the attachment has been stored * @throws Exception if the attachment can't be retrieved from the database and stored on the * filesystem */ private URL getURL( String wiki, String space, String name, String filename, String revision, XWikiContext context) throws Exception { Map<String, File> usedFiles = getFileMapping(context); String key = getAttachmentKey(space, name, filename, revision); if (!usedFiles.containsKey(key)) { File file = getTemporaryFile(key, context); XWikiDocument doc = context .getWiki() .getDocument( new DocumentReference( StringUtils.defaultString(wiki, context.getDatabase()), space, name), context); XWikiAttachment attachment = doc.getAttachment(filename); if (StringUtils.isNotEmpty(revision)) { attachment = attachment.getAttachmentRevision(revision, context); } FileOutputStream fos = new FileOutputStream(file); IOUtils.copy(attachment.getContentInputStream(context), fos); fos.close(); usedFiles.put(key, file); } return usedFiles.get(key).toURI().toURL(); }
/** * @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); }
/** * @return the archive attachment itself * @throws IOException when an error accessing the Attachment occurs */ public XWikiAttachment getAttachment() throws IOException { if (this.attachment == null) { try { XWikiDocument document = getXWikiContext().getWiki().getDocument(getDocumentReference(), getXWikiContext()); this.attachment = document.getAttachment(this.name); } catch (Exception e) { throw new IOException(String.format("Failed to get Attachment for [%s]", this.uri), e); } } return this.attachment; }
@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; }