1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package org.xwiki.extension.xar.internal.job.diff

File AttachmentUnifiedDiffBuilder.java

 

Coverage histogram

../../../../../../../img/srcFileCovDistChart0.png
83% of files have more coverage

Code metrics

24
37
5
1
163
107
28
0.76
7.4
5
5.6

Classes

Class Line # Actions
AttachmentUnifiedDiffBuilder 50 37 0% 28 66
0.00%
 

Contributing tests

No tests hitting this source file were found.

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.extension.xar.internal.job.diff;
21   
22    import java.io.IOException;
23    import java.io.InputStream;
24    import java.util.Arrays;
25    import java.util.Collections;
26    import java.util.List;
27   
28    import javax.inject.Singleton;
29   
30    import org.apache.commons.io.IOUtils;
31    import org.apache.commons.lang3.exception.ExceptionUtils;
32    import org.xwiki.component.annotation.Component;
33    import org.xwiki.diff.display.UnifiedDiffBlock;
34    import org.xwiki.extension.xar.job.diff.DocumentUnifiedDiff;
35    import org.xwiki.extension.xar.job.diff.DocumentVersionReference;
36    import org.xwiki.extension.xar.job.diff.EntityUnifiedDiff;
37    import org.xwiki.model.reference.AttachmentReference;
38   
39    import com.xpn.xwiki.XWikiContext;
40    import com.xpn.xwiki.doc.XWikiAttachment;
41   
42    /**
43    * Computes the differences, in unified format, between two versions of an attachment.
44    *
45    * @version $Id: 45bd00c351e09454cded7b73fdceeef6b3358075 $
46    * @since 7.0RC1
47    */
48    @Component(roles = AttachmentUnifiedDiffBuilder.class)
49    @Singleton
 
50    public class AttachmentUnifiedDiffBuilder extends AbstractUnifiedDiffBuilder
51    {
52    /**
53    * The list of media type patterns that match text files.
54    */
55    private static final List<String> TEXT_MEDIA_TYPE_PATTERNS = Arrays.asList("text/", "application/xml",
56    "application/javascript", "application/ecmascript", "application/json", "application/x-sh", "+xml");
57   
58    /**
59    * Show content differences only for text files under 50KB.
60    */
61    private static final int TEXT_FILE_SIZE_LIMIT = 50000;
62   
63    /**
64    * Computes the differences, in unified format, between two versions of an attachment and adds the result to the
65    * given {@link DocumentUnifiedDiff}.
66    *
67    * @param previousAttachment the previous version of the attachment
68    * @param nextAttachment the next version of the attachment
69    * @param documentDiff where to add the differences
70    */
 
71  0 toggle public void addAttachmentDiff(XWikiAttachment previousAttachment, XWikiAttachment nextAttachment,
72    DocumentUnifiedDiff documentDiff)
73    {
74  0 AttachmentReference previousReference =
75    getAttachmentVersionReference(previousAttachment, documentDiff.getPreviousReference());
76  0 AttachmentReference nextReference =
77    getAttachmentVersionReference(nextAttachment, documentDiff.getNextReference());
78  0 EntityUnifiedDiff<AttachmentReference> attachmentDiff =
79    new EntityUnifiedDiff<>(previousReference, nextReference);
80   
81  0 if ((previousAttachment == null || isSmallTextFile(previousAttachment))
82    && (nextAttachment == null || isSmallTextFile(nextAttachment))) {
83    // Compute content differences.
84  0 maybeAddDiff(attachmentDiff, CONTENT, getContentAsString(previousAttachment),
85    getContentAsString(nextAttachment));
86    } else {
87    // The size difference is useful when the content difference is not shown.
88  0 maybeAddDiff(attachmentDiff, "size", previousAttachment == null ? null : previousAttachment.getFilesize(),
89  0 nextAttachment == null ? null : nextAttachment.getFilesize());
90  0 if (attachmentDiff.isEmpty() && !contentEquals(previousAttachment, nextAttachment)) {
91    // If the files have the same size but the content is different then show an empty list.
92  0 attachmentDiff.put(CONTENT, Collections.<UnifiedDiffBlock<String, Character>>emptyList());
93    }
94    }
95   
96  0 if (attachmentDiff.size() > 0) {
97  0 documentDiff.getAttachmentDiffs().add(attachmentDiff);
98    }
99    }
100   
 
101  0 toggle private AttachmentReference getAttachmentVersionReference(XWikiAttachment attachment,
102    DocumentVersionReference documentVersionReference)
103    {
104  0 return attachment == null ? null : new AttachmentReference(attachment.getFilename(), documentVersionReference);
105    }
106   
 
107  0 toggle private boolean isSmallTextFile(XWikiAttachment attachment)
108    {
109  0 if (attachment != null && attachment.getFilesize() < TEXT_FILE_SIZE_LIMIT) {
110  0 String mediaType = attachment.getMimeType(xcontextProvider.get());
111  0 for (String mediaTypePattern : TEXT_MEDIA_TYPE_PATTERNS) {
112  0 if (mediaType.equals(mediaTypePattern) || mediaType.startsWith(mediaTypePattern)
113    || mediaType.endsWith(mediaTypePattern)) {
114  0 return true;
115    }
116    }
117    }
118  0 return false;
119    }
120   
 
121  0 toggle private boolean contentEquals(XWikiAttachment previousAttachment, XWikiAttachment nextAttachment)
122    {
123  0 if (previousAttachment == null || nextAttachment == null) {
124  0 return previousAttachment == nextAttachment;
125    } else {
126  0 XWikiContext xcontext = this.xcontextProvider.get();
127  0 InputStream previousContent = null;
128  0 InputStream nextContent = null;
129  0 try {
130  0 previousContent = previousAttachment.getContentInputStream(xcontext);
131  0 nextContent = nextAttachment.getContentInputStream(xcontext);
132  0 return IOUtils.contentEquals(previousContent, nextContent);
133    } catch (Exception e) {
134  0 this.logger.warn("Failed to compare the content of attachment [{}]. Root cause: {}",
135    previousAttachment.getFilename(), ExceptionUtils.getRootCauseMessage(e));
136  0 return false;
137    } finally {
138  0 try {
139  0 if (previousContent != null) {
140  0 previousContent.close();
141    }
142  0 if (nextContent != null) {
143  0 nextContent.close();
144    }
145    } catch (IOException e) {
146    // Ignore.
147    }
148    }
149    }
150    }
151   
 
152  0 toggle private String getContentAsString(XWikiAttachment attachment)
153    {
154  0 try {
155  0 return attachment == null ? null : IOUtils.toString(attachment.getContentInputStream(this.xcontextProvider
156    .get()));
157    } catch (Exception e) {
158  0 this.logger.warn("Failed to read the content of attachment [{}]. Root cause: {}", attachment.getFilename(),
159    ExceptionUtils.getRootCauseMessage(e));
160  0 return null;
161    }
162    }
163    }