/** * @param document the document * @param result the list to add reference to */ private void addAttachmentsReferences(XWikiDocument document, List<EntityReference> result) { List<XWikiAttachment> attachments = document.getAttachmentList(); for (XWikiAttachment attachment : attachments) { AttachmentReference attachmentReference = attachment.getReference(); try { Iterables.addAll(result, this.attachmentResolverProvider.get().getReferences(attachmentReference)); } catch (Exception e) { this.logger.error("Failed to resolve references for attachment [" + attachmentReference + "]", e); } } }
@Override public XWikiAttachment next() { Object[] item = this.data.next(); try { XWikiDocument doc = new XWikiDocument(HibernateAttachmentsReader.this.resolver.resolve(String.valueOf(item[0]))); XWikiAttachment att = new XWikiAttachment(doc, String.valueOf(item[1])); HibernateAttachmentsReader.this.store.loadAttachmentContent(att, HibernateAttachmentsReader.this.context.get(), true); HibernateAttachmentsReader.this.archiveStore.loadArchive(att, HibernateAttachmentsReader.this.context.get(), true); HibernateAttachmentsReader.this.logger.debug("Loaded [{}] from the database", att.getReference()); return att; } catch (Exception ex) { HibernateAttachmentsReader.this.logger.error("Failed to read attachment from the database store: {}", ex.getMessage(), ex); } return null; }
@Override public XWikiAttachment next() { Object[] item = this.data.next(); try { XWikiDocument doc = new XWikiDocument(HibernateAttachmentsReader.this.resolver.resolve(String.valueOf(item[0]))); XWikiAttachment att = new XWikiAttachment(doc, String.valueOf(item[1])); HibernateAttachmentsReader.this.store.loadAttachmentContent(att, HibernateAttachmentsReader.this.context.get(), true); HibernateAttachmentsReader.this.archiveStore.loadArchive(att, HibernateAttachmentsReader.this.context.get(), true); HibernateAttachmentsReader.this.logger.debug("Loaded [{}] from the database", att.getReference()); return att; } catch (Exception ex) { HibernateAttachmentsReader.this.logger.error("Failed to read attachment from the database store: {}", ex.getMessage(), ex); } return null; }
/** * Get a StartableTransactionRunnable to save an attachment in the recycle-bin. * * @param deleted the attachment to save. * @param index the index of the deleted attachment * @param context the legacy XWikiContext which might be needed to get the content from the attachment, or to load * the attachment versioning store. * @return a TransactionRunnable for storing the deleted attachment. * @throws XWikiException if one is thrown trying to get data from the attachment or loading the attachment archive * in order to save it in the deleted section. */ private StartableTransactionRunnable getSaveTrashAttachmentRunnable(final XWikiAttachment deleted, long index, final XWikiContext context) throws XWikiException { final DeletedAttachmentFileProvider provider = this.fileTools.getDeletedAttachmentFileProvider(deleted.getReference(), index); return new SaveDeletedAttachmentContentRunnable(deleted, provider, this.fileTools, this.metaSerializer, this.versionSerializer, context); } }
@Override public boolean discardEntity(XWikiAttachment entity) { boolean transaction = false; try { transaction = ((XWikiHibernateBaseStore) this.store).beginTransaction(this.context.get()); Session session = ((XWikiHibernateBaseStore) this.store).getSession(this.context.get()); session.delete(entity.getAttachment_content()); session.delete(entity.getAttachment_archive()); this.logger.debug("Deleted attachment [{}] from the database", entity.getReference()); } catch (XWikiException ex) { this.logger.warn("Failed to cleanup attachment from the database: {}", ex.getMessage()); return false; } finally { if (transaction) { ((XWikiHibernateBaseStore) this.store).endTransaction(this.context.get(), transaction); } } return true; }
@Override public boolean discardEntity(XWikiAttachment entity) { boolean transaction = false; try { transaction = ((XWikiHibernateBaseStore) this.store).beginTransaction(this.context.get()); Session session = ((XWikiHibernateBaseStore) this.store).getSession(this.context.get()); session.delete(entity.getAttachment_content()); session.delete(entity.getAttachment_archive()); this.logger.debug("Deleted attachment [{}] from the database", entity.getReference()); } catch (XWikiException ex) { this.logger.warn("Failed to cleanup attachment from the database: {}", ex.getMessage()); return false; } finally { if (transaction) { ((XWikiHibernateBaseStore) this.store).endTransaction(this.context.get(), transaction); } } return true; }
@Override public boolean storeEntity(XWikiAttachment entity) { if (entity == null) { return true; } XWikiAttachment existing = new XWikiAttachment(entity.getDoc(), entity.getFilename()); try { this.store.loadAttachmentContent(existing, this.context.get(), false); // If loading succeeded, then the attachment already exists on the filesystem; // keep using the existing attachment version and discard the database one this.logger.debug("Skipped importing already existing attachment [{}]", entity.getReference()); return true; } catch (XWikiException e) { // No such attachment on the filesystem, continue storing it } try { this.store.saveAttachmentContent(entity, false, this.context.get(), false); // The archive is also automatically stored by the call above, no need to explicitly store the archive this.logger.debug("Imported attachment [{}] into the filesystem store", entity.getReference()); return true; } catch (XWikiException ex) { this.logger.error("Failed to store attachment into the filesystem store: {}", ex.getMessage(), ex); return false; } } }
/** * Get a TransactionRunnable for deleting an attachment archive. this runnable can be run with any transaction * including a VoidTransaction. * * @param archive The attachment archive to delete. * @return a StartableTransactionRunnable for deleting the attachment archive. */ public StartableTransactionRunnable getArchiveDeleteRunnable(final XWikiAttachmentArchive archive) { if (archive == null) { throw new NullPointerException("The archive to delete cannot be null."); } if (archive.getAttachment() == null) { throw new IllegalArgumentException("Cannot delete an archive unless it is associated with an attachment."); } return new AttachmentArchiveDeleteRunnable(archive, this.fileTools, this.fileTools.getAttachmentFileProvider(archive.getAttachment().getReference())); } }
@Override public boolean storeEntity(XWikiAttachment entity) { if (entity == null) { return true; } XWikiAttachment existing = new XWikiAttachment(entity.getDoc(), entity.getFilename()); try { this.store.loadAttachmentContent(existing, this.context.get(), false); // If loading succeeded, then the attachment already exists on the filesystem; // keep using the existing attachment version and discard the database one this.logger.debug("Skipped importing already existing attachment [{}]", entity.getReference()); return true; } catch (XWikiException e) { // No such attachment on the filesystem, continue storing it } try { this.store.saveAttachmentContent(entity, false, this.context.get(), false); // The archive is also automatically stored by the call above, no need to explicitly store the archive this.logger.debug("Imported attachment [{}] into the filesystem store", entity.getReference()); return true; } catch (XWikiException ex) { this.logger.error("Failed to store attachment into the filesystem store: {}", ex.getMessage(), ex); return false; } } }
/** * Get a TransactionRunnable for saving or updating the current attachment. this runnable can be run with any * transaction including a VoidTransaction. * * @param archive The attachment archive to save. * @param context An XWikiContext used for getting the attachments from the archive with getRevision() and for * getting the content from the attachments with getContentInputStream(). * @return a new StartableTransactionRunnable for saving this attachment archive. * @throws XWikiException if versions of the attachment cannot be loaded form the archive. */ public StartableTransactionRunnable getArchiveSaveRunnable(final XWikiAttachmentArchive archive, final XWikiContext context) throws XWikiException { return new AttachmentArchiveSaveRunnable(archive, this.fileTools, this.fileTools.getAttachmentFileProvider(archive.getAttachment().getReference()), this.metaSerializer, context); }
/** * Tries to extract text indexable content from a generic attachment. * * @param attachment the attachment to extract the content from * @return the text representation of the attachment's content * @throws SolrIndexerException if problems occur */ protected String getContentAsText(XWikiAttachment attachment) { try { Metadata metadata = new Metadata(); metadata.set(TikaMetadataKeys.RESOURCE_NAME_KEY, attachment.getFilename()); InputStream in = attachment.getContentInputStream(this.xcontextProvider.get()); try { return TikaUtils.parseToString(in, metadata); } finally { in.close(); } } catch (Exception e) { this.logger.error("Failed to retrieve the content of attachment [{}]", attachment.getReference(), e); return null; } }
@Override public void save(XWikiAttachment attachment, Date deleteDate, long index, boolean bTransaction) throws XWikiException { XWikiContext xcontext = this.xcontextProvider.get(); final StartableTransactionRunnable tr = getSaveTrashAttachmentRunnable(attachment, index, xcontext); new StartableTransactionRunnable().runIn(tr); try { tr.start(); } catch (Exception e) { throw new XWikiException(XWikiException.MODULE_XWIKI_STORE, XWikiException.MODULE_XWIKI, "Failed to store deleted attachment [" + attachment.getReference() + "]", e); } }
@Override public void loadAttachmentContent(final XWikiAttachment attachment, final XWikiContext context, final boolean bTransaction) throws XWikiException { final File attachFile = this.fileTools.getAttachmentFileProvider(attachment.getReference()).getAttachmentContentFile(); if (!attachFile.exists()) { throw new XWikiException(XWikiException.MODULE_XWIKI_STORE, XWikiException.ERROR_XWIKI_STORE_FILENOTFOUND, String.format("The attachment [%s] could not be found in the filesystem attachment store.", attachFile)); } FilesystemAttachmentContent content = new FilesystemAttachmentContent(attachFile); content.setContentDirty(false); attachment.setAttachment_content(content); attachment.setContentStore(FileSystemStoreUtils.HINT); }
/** * Get a TransactionRunnable for deleting an attachment. * * @param attachment the XWikiAttachment to delete. * @param updateDocument whether or not to update the document at the same time. * @param context the XWikiContext for the request. * @return a TransactionRunnable for deleting the attachment which must be run inside of an * XWikiHibernateTransaction * @throws XWikiException if unable to load the attachment archive to delete. */ private TransactionRunnable<XWikiHibernateTransaction> getAttachmentDeleteRunnable(final XWikiAttachment attachment, final boolean updateDocument, final XWikiContext context) throws XWikiException { final File attachFile = this.fileTools.getAttachmentFileProvider(attachment.getReference()).getAttachmentContentFile(); return new AttachmentDeleteTransactionRunnable(attachment, updateDocument, context, attachFile, this.fileTools.getBackupFile(attachFile), this.fileTools.getLockForFile(attachFile)); }
this.logger.error("Attachment [{}] has malformed history", attachment.getReference(), e); size = Long.valueOf(attachment.getFilesize()); } catch (XWikiException e) { this.logger.error("Failed to get content of attachment [{}]", attachment.getReference(), e);
@Override public XWikiAttachmentArchive loadArchive(final XWikiAttachment attachment, final XWikiContext context, final boolean bTransaction) throws XWikiException { try { return this.loadArchive(attachment, this.fileTools.getAttachmentFileProvider(attachment.getReference())); } catch (Exception e) { if (e instanceof XWikiException) { throw (XWikiException) e; } final Object[] args = { attachment.getFilename(), UNKNOWN_NAME }; if (attachment.getDoc() != null) { args[1] = attachment.getDoc().getFullName(); } throw new XWikiException(XWikiException.MODULE_XWIKI_STORE, XWikiException.ERROR_XWIKI_UNKNOWN, "Exception while loading attachment archive {0} for document {1}", e, args); } }
/** * Get a TransactionRunnable for saving the attachment content. If {@link XWikiAttachment#getAttachment_content()} * yields null, this runnable will do nothing. * * @param attachment the XWikiAttachment whose content should be saved. * @param updateDocument whether or not to update the document at the same time. * @param context the XWikiContext for the request. * @return a TransactionRunnable for saving the attachment content in an XWikiHibernateTransaction. * @throws XWikiException if thrown by AttachmentSaveTransactionRunnable() */ private TransactionRunnable<XWikiHibernateTransaction> getAttachmentContentSaveRunnable( final XWikiAttachment attachment, final boolean updateDocument, final XWikiContext context) throws XWikiException { final XWikiAttachmentContent content = attachment.getAttachment_content(); if (content == null) { // If content does not exist we should not blank the attachment. return new TransactionRunnable<>(); } // This is the permanent location where the attachment content will go. final File attachFile = this.fileTools.getAttachmentFileProvider(attachment.getReference()).getAttachmentContentFile(); return new AttachmentSaveTransactionRunnable(attachment, updateDocument, context, attachFile, this.fileTools.getTempFile(attachFile), this.fileTools.getBackupFile(attachFile), this.fileTools.getLockForFile(attachFile)); }
solrDocument.addField(FieldUtils.ATTACHMENT_AUTHOR_DISPLAY, authorDisplayName); } catch (Exception e) { this.logger.error("Failed to get author display name for attachment [{}]", attachment.getReference(), e);
solrDocument.setField(FieldUtils.ATTACHMENT_AUTHOR_DISPLAY_SORT, authorDisplayName); } catch (Exception e) { this.logger.error("Failed to get author display name for attachment [{}]", attachment.getReference(), e);
@Override public XWikiAttachment restoreAttachment(final XWikiAttachment attachment, final XWikiContext context) throws XWikiException { XWikiAttachment result = attachment; if (result != null) { // TODO Add XWikiAttachment#clone(XWikiAttachment) // this toXML does not copy content. result.fromXML(this.attachment.toXML(context)); if (this.attachment.getAttachment_content() != null) { attachment.setAttachment_content((XWikiAttachmentContent) this.attachment.getAttachment_content() .clone()); attachment.getAttachment_content().setAttachment(attachment); } if (this.attachment.getAttachment_archive() != null) { result.setAttachment_archive((XWikiAttachmentArchive) this.attachment.getAttachment_archive().clone()); result.getAttachment_archive().setAttachment(result); } } else { result = (XWikiAttachment) this.attachment.clone(); } result.setDoc(context.getWiki().getDocument(this.attachment.getReference().getDocumentReference(), context)); return result; }