1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package org.xwiki.store.legacy.store.internal

File FilesystemAttachmentVersioningStore.java

 

Coverage histogram

../../../../../../img/srcFileCovDistChart5.png
74% of files have more coverage

Code metrics

22
55
8
1
272
164
22
0.4
6.88
8
2.75

Classes

Class Line # Actions
FilesystemAttachmentVersioningStore 54 55 0% 22 43
0.4941176549.4%
 

Contributing tests

This file is covered by 3 tests. .

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package org.xwiki.store.legacy.store.internal;
21   
22    import java.io.File;
23    import java.io.FileInputStream;
24    import java.io.IOException;
25    import java.io.InputStream;
26    import java.util.List;
27    import java.util.concurrent.locks.ReadWriteLock;
28   
29    import com.xpn.xwiki.doc.XWikiAttachment;
30    import com.xpn.xwiki.doc.XWikiAttachmentArchive;
31    import com.xpn.xwiki.store.AttachmentVersioningStore;
32    import com.xpn.xwiki.XWikiContext;
33    import com.xpn.xwiki.XWikiException;
34    import javax.inject.Inject;
35    import javax.inject.Named;
36    import javax.inject.Singleton;
37    import org.xwiki.component.annotation.Component;
38    import org.xwiki.store.legacy.doc.internal.FilesystemAttachmentContent;
39    import org.xwiki.store.legacy.doc.internal.ListAttachmentArchive;
40    import org.xwiki.store.filesystem.internal.AttachmentFileProvider;
41    import org.xwiki.store.filesystem.internal.FilesystemStoreTools;
42    import org.xwiki.store.serialization.Serializer;
43    import org.xwiki.store.StartableTransactionRunnable;
44   
45    /**
46    * Filesystem based AttachmentVersioningStore implementation.
47    *
48    * @version $Id: 03ba65151ffd7efab47787ce60d85a24d7ba6f3a $
49    * @since 3.0M2
50    */
51    @Component
52    @Named("file")
53    @Singleton
 
54    public class FilesystemAttachmentVersioningStore implements AttachmentVersioningStore
55    {
56    /**
57    * To put in an exception message if the document name or filename cannot be determined.
58    */
59    private static final String UNKNOWN_NAME = "UNKNOWN";
60   
61    /**
62    * Tools for getting files to store given content in.
63    */
64    @Inject
65    private FilesystemStoreTools fileTools;
66   
67    /**
68    * A serializer for the list of attachment metdata.
69    */
70    @Inject
71    @Named("attachment-list-meta/1.0")
72    private Serializer<List<XWikiAttachment>, List<XWikiAttachment>> metaSerializer;
73   
74    /**
75    * Testing Constructor.
76    *
77    * @param fileTools the means of getting files and locks.
78    * @param metaSerializer a serializer for attachment versioning metadata.
79    */
 
80  3 toggle public FilesystemAttachmentVersioningStore(final FilesystemStoreTools fileTools,
81    final Serializer<List<XWikiAttachment>,
82    List<XWikiAttachment>> metaSerializer)
83    {
84  3 this.fileTools = fileTools;
85  3 this.metaSerializer = metaSerializer;
86    }
87   
88    /**
89    * Constructor for dependency injection.
90    */
 
91  0 toggle public FilesystemAttachmentVersioningStore()
92    {
93    }
94   
 
95  2 toggle @Override
96    public XWikiAttachmentArchive loadArchive(final XWikiAttachment attachment,
97    final XWikiContext context,
98    final boolean bTransaction)
99    throws XWikiException
100    {
101   
102  2 try {
103  2 return this.loadArchive(attachment, this.fileTools.getAttachmentFileProvider(attachment));
104    } catch (Exception e) {
105  0 if (e instanceof XWikiException) {
106  0 throw (XWikiException) e;
107    }
108  0 final Object[] args = {attachment.getFilename(), UNKNOWN_NAME};
109  0 if (attachment.getDoc() != null) {
110  0 args[1] = attachment.getDoc().getFullName();
111    }
112  0 throw new XWikiException(XWikiException.MODULE_XWIKI_STORE,
113    XWikiException.ERROR_XWIKI_UNKNOWN,
114    "Exception while loading attachment archive {0} for document {1}",
115    e, args);
116    }
117    }
118   
119    /**
120    * Load an attachment archive from a specified location.
121    *
122    * @param attachment the attachment to load the archive for.
123    * @param provider a means of gaining access to the location where the archive is stored.
124    * @return an XWikiAttachmentArchive for the given attachment.
125    * @throws IOException if the metadata cannot be found or there is a failure while parsing it.
126    */
 
127  2 toggle XWikiAttachmentArchive loadArchive(final XWikiAttachment attachment,
128    final AttachmentFileProvider provider)
129    throws IOException
130    {
131  2 final File metaFile = provider.getAttachmentVersioningMetaFile();
132   
133    // If no meta file then assume no archive and return an empty archive.
134  2 if (!metaFile.exists()) {
135  0 return new ListAttachmentArchive(attachment);
136    }
137   
138  2 final ReadWriteLock lock = this.fileTools.getLockForFile(metaFile);
139  2 final List<XWikiAttachment> attachList;
140  2 lock.readLock().lock();
141  2 try {
142  2 final InputStream is = new FileInputStream(metaFile);
143  2 attachList = this.metaSerializer.parse(is);
144  2 is.close();
145    } finally {
146  2 lock.readLock().unlock();
147    }
148   
149    // Get the content file and lock for each revision.
150  2 for (XWikiAttachment attach : attachList) {
151  6 final File contentFile = provider.getAttachmentVersionContentFile(attach.getVersion());
152  6 attach.setAttachment_content(new FilesystemAttachmentContent(contentFile, attach));
153    // Pass the document since it will be lost in the serialize/deserialize.
154  6 attach.setDoc(attachment.getDoc());
155    }
156   
157  2 final ListAttachmentArchive out = new ListAttachmentArchive(attachList);
158  2 out.setAttachment(attachment);
159  2 return out;
160    }
161   
162    /**
163    * {@inheritDoc}
164    * <p>
165    * bTransaction cannot be used in this case, in order to have transaction atomicity,
166    * please use getArchiveSaveRunnable() instead.
167    * </p>
168    *
169    * @see AttachmentVersioningStore#saveArchive(XWikiAttachmentArchive, XWikiContext, boolean)
170    */
 
171  3 toggle @Override
172    public void saveArchive(final XWikiAttachmentArchive archive,
173    final XWikiContext context,
174    final boolean bTransaction)
175    throws XWikiException
176    {
177  3 try {
178  3 this.getArchiveSaveRunnable(archive, context).start();
179    } catch (Exception e) {
180  0 if (e instanceof XWikiException) {
181  0 throw (XWikiException) e;
182    }
183  0 final Object[] args = {UNKNOWN_NAME, UNKNOWN_NAME};
184  0 if (archive.getAttachment() != null) {
185  0 args[0] = archive.getAttachment().getFilename();
186  0 if (archive.getAttachment().getDoc() != null) {
187  0 args[1] = archive.getAttachment().getDoc().getFullName();
188    }
189    }
190  0 throw new XWikiException(XWikiException.MODULE_XWIKI_STORE,
191    XWikiException.ERROR_XWIKI_UNKNOWN,
192    "Exception while saving attachment archive {0} of document {1}",
193    e, args);
194    }
195    }
196   
197    /**
198    * Get a TransactionRunnable for saving or updating the current attachment.
199    * this runnable can be run with any transaction including a VoidTransaction.
200    *
201    * @param archive The attachment archive to save.
202    * @param context An XWikiContext used for getting the attachments from the archive with getRevision()
203    * and for getting the content from the attachments with getContentInputStream().
204    * @return a new StartableTransactionRunnable for saving this attachment archive.
205    * @throws XWikiException if versions of the arrachment cannot be loaded form the archive.
206    */
 
207  3 toggle public StartableTransactionRunnable getArchiveSaveRunnable(final XWikiAttachmentArchive archive,
208    final XWikiContext context)
209    throws XWikiException
210    {
211  3 return new AttachmentArchiveSaveRunnable(
212    archive, this.fileTools, this.fileTools.getAttachmentFileProvider(archive.getAttachment()),
213    this.metaSerializer, context);
214    }
215   
216    /**
217    * {@inheritDoc}
218    * <p>
219    * bTransaction is ignored by this implementation.
220    * If you need to delete an archive inside of a larger transaction,
221    * please use getArchiveDeleteRunnable()
222    * </p>
223    *
224    * @see AttachmentVersioningStore#deleteArchive(XWikiAttachment, XWikiContext, boolean)
225    */
 
226  1 toggle @Override
227    public void deleteArchive(final XWikiAttachment attachment,
228    final XWikiContext context,
229    final boolean bTransaction)
230    throws XWikiException
231    {
232  1 if (attachment == null) {
233  0 throw new NullPointerException("The attachment to delete cannot be null");
234    }
235  1 try {
236  1 final XWikiAttachmentArchive archive = this.loadArchive(attachment, context, bTransaction);
237  1 this.getArchiveDeleteRunnable(archive).start();
238    } catch (Exception e) {
239  0 if (e instanceof XWikiException) {
240  0 throw (XWikiException) e;
241    }
242  0 final Object[] args = {attachment.getFilename(), UNKNOWN_NAME};
243  0 if (attachment.getDoc() != null) {
244  0 args[1] = attachment.getDoc().getFullName();
245    }
246  0 throw new XWikiException(XWikiException.MODULE_XWIKI_STORE,
247    XWikiException.ERROR_XWIKI_UNKNOWN,
248    "Exception while deleting attachment archive {0} from document {1}",
249    e, args);
250    }
251    }
252   
253    /**
254    * Get a TransactionRunnable for deleting an attachment archive.
255    * this runnable can be run with any transaction including a VoidTransaction.
256    *
257    * @param archive The attachment archive to delete.
258    * @return a StartableTransactionRunnable for deleting the attachment archive.
259    */
 
260  1 toggle public StartableTransactionRunnable getArchiveDeleteRunnable(final XWikiAttachmentArchive archive)
261    {
262  1 if (archive == null) {
263  0 throw new NullPointerException("The archive to delete cannot be null.");
264    }
265  1 if (archive.getAttachment() == null) {
266  0 throw new IllegalArgumentException(
267    "Cannot delete an archive unless it is associated with an attachment.");
268    }
269  1 return new AttachmentArchiveDeleteRunnable(
270    archive, this.fileTools, this.fileTools.getAttachmentFileProvider(archive.getAttachment()));
271    }
272    }