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

File DiffXarJob.java

 

Coverage histogram

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

Code metrics

28
73
9
1
261
188
33
0.45
8.11
9
3.67

Classes

Class Line # Actions
DiffXarJob 63 73 0% 33 110
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;
21   
22    import java.io.File;
23    import java.io.IOException;
24    import java.util.Collection;
25    import java.util.HashSet;
26    import java.util.Set;
27   
28    import javax.inject.Inject;
29    import javax.inject.Named;
30    import javax.inject.Provider;
31   
32    import org.xwiki.component.annotation.Component;
33    import org.xwiki.extension.ExtensionDependency;
34    import org.xwiki.extension.ExtensionId;
35    import org.xwiki.extension.InstalledExtension;
36    import org.xwiki.extension.job.InstallRequest;
37    import org.xwiki.extension.job.internal.AbstractExtensionJob;
38    import org.xwiki.extension.xar.internal.handler.UnsupportedNamespaceException;
39    import org.xwiki.extension.xar.internal.handler.XarExtensionHandler;
40    import org.xwiki.extension.xar.internal.handler.XarHandlerUtils;
41    import org.xwiki.extension.xar.internal.handler.packager.Packager;
42    import org.xwiki.extension.xar.internal.job.diff.DocumentUnifiedDiffBuilder;
43    import org.xwiki.extension.xar.job.diff.DiffXarJobStatus;
44    import org.xwiki.extension.xar.job.diff.DocumentUnifiedDiff;
45    import org.xwiki.extension.xar.job.diff.DocumentVersionReference;
46    import org.xwiki.model.reference.WikiReference;
47    import org.xwiki.xar.XarEntry;
48    import org.xwiki.xar.XarException;
49    import org.xwiki.xar.XarFile;
50   
51    import com.xpn.xwiki.XWikiContext;
52    import com.xpn.xwiki.XWikiException;
53    import com.xpn.xwiki.doc.XWikiDocument;
54   
55    /**
56    * Computes the differences between the documents provided by a XAR extension and the documents from the database.
57    *
58    * @version $Id: 23b959e7c0b6d19435d87ac6b49a827735d35a3a $
59    * @since 7.0RC1
60    */
61    @Component
62    @Named(DiffXarJob.JOB_TYPE)
 
63    public class DiffXarJob extends AbstractExtensionJob<InstallRequest, DiffXarJobStatus>
64    {
65    /**
66    * The id of the job.
67    */
68    public static final String JOB_TYPE = "diffXar";
69   
70    /**
71    * Used to get the documents from the XAR.
72    */
73    @Inject
74    private Packager packager;
75   
76    /**
77    * Used to get the documents from the database.
78    */
79    @Inject
80    private Provider<XWikiContext> xcontextProvider;
81   
82    /**
83    * Used to compute the differences.
84    */
85    @Inject
86    private DocumentUnifiedDiffBuilder documentDiffBuilder;
87   
88    /**
89    * The set of features that have been compared. We try to avoid comparing the same feature twice. We assume all the
90    * features are compared on the same namespace.
91    */
92    private Set<String> comparedFeatures = new HashSet<>();
93   
 
94  0 toggle @Override
95    public String getType()
96    {
97  0 return JOB_TYPE;
98    }
99   
 
100  0 toggle @Override
101    protected DiffXarJobStatus createNewStatus(InstallRequest request)
102    {
103  0 return new DiffXarJobStatus(request, this.observationManager, this.loggerManager);
104    }
105   
 
106  0 toggle @Override
107    protected void runInternal() throws Exception
108    {
109  0 InstallRequest request = getRequest();
110    // There must be only one namespace specified because we compute the differences for only one wiki.
111  0 if (!request.hasNamespaces() || request.getNamespaces().size() != 1) {
112  0 return;
113    }
114   
115  0 String namespace = request.getNamespaces().iterator().next();
116   
117  0 Collection<ExtensionId> extensionIds = request.getExtensions();
118  0 this.progressManager.pushLevelProgress(extensionIds.size(), this);
119  0 try {
120  0 for (ExtensionId extensionId : extensionIds) {
121  0 this.progressManager.startStep(this);
122   
123  0 InstalledExtension installedExtension = getInstalledExtension(extensionId, namespace);
124    // Make sure the specified extension is installed on the specified namespace.
125  0 if (installedExtension != null && installedExtension.isInstalled(namespace)) {
126  0 diff(extensionId.getId(), namespace);
127    }
128    }
129    } finally {
130  0 this.progressManager.popLevelProgress(this);
131    }
132    }
133   
 
134  0 toggle private InstalledExtension getInstalledExtension(ExtensionId extensionId, String namespace)
135    {
136  0 if (extensionId.getVersion() != null) {
137  0 return this.installedExtensionRepository.getInstalledExtension(extensionId);
138    } else {
139  0 return this.installedExtensionRepository.getInstalledExtension(extensionId.getId(), namespace);
140    }
141    }
142   
 
143  0 toggle private void diff(String feature, String namespace)
144    {
145  0 if (this.comparedFeatures.contains(feature)) {
146    // We already looked at this feature.
147  0 return;
148    }
149  0 this.comparedFeatures.add(feature);
150   
151  0 InstalledExtension installedExtension =
152    this.installedExtensionRepository.getInstalledExtension(feature, namespace);
153  0 if (installedExtension != null) {
154  0 diff(installedExtension, namespace);
155   
156  0 Collection<? extends ExtensionDependency> dependencies = installedExtension.getDependencies();
157   
158  0 this.progressManager.pushLevelProgress(dependencies.size(), this);
159  0 try {
160  0 for (ExtensionDependency dependency : dependencies) {
161  0 this.progressManager.startStep(this);
162   
163  0 diff(dependency.getId(), namespace);
164    }
165    } finally {
166  0 this.progressManager.popLevelProgress(this);
167    }
168    }
169    }
170   
 
171  0 toggle private void diff(InstalledExtension installedExtension, String namespace)
172    {
173  0 Collection<ExtensionId> excludedExtensions = getRequest().getExcludedExtensions();
174  0 if (XarExtensionHandler.TYPE.equals(installedExtension.getType())
175    && (excludedExtensions == null || !excludedExtensions.contains(installedExtension.getId()))) {
176  0 if (getRequest().isVerbose()) {
177  0 this.logger.info("Computing differences for [{}] on namespace [{}]", installedExtension.getId(),
178    namespace);
179    }
180  0 try {
181  0 WikiReference wikiReference = new WikiReference(XarHandlerUtils.getWikiFromNamespace(namespace));
182  0 diff(new XarFile(new File(installedExtension.getFile().getAbsolutePath())), wikiReference,
183    installedExtension.getId());
184    } catch (UnsupportedNamespaceException e) {
185  0 this.logger.error("Failed to extract the wiki id from the namespace [{}].", namespace, e);
186    } catch (IOException e) {
187  0 this.logger.error("Failed to read the XAR file of the extension [{}].", installedExtension.getId(), e);
188    } catch (XarException e) {
189  0 this.logger.error("Failed to parse the XAR file of the extension [{}].", installedExtension.getId(), e);
190    }
191    }
192    }
193   
 
194  0 toggle private void diff(XarFile xarFile, WikiReference wikiReference, ExtensionId extensionId)
195    {
196  0 Collection<XarEntry> xarEntries = xarFile.getEntries();
197  0 this.progressManager.pushLevelProgress(xarEntries.size(), this);
198  0 try {
199  0 for (XarEntry xarEntry : xarEntries) {
200  0 this.progressManager.startStep(this);
201   
202  0 try {
203  0 diff(this.packager.getXWikiDocument(xarFile.getInputStream(xarEntry), wikiReference), extensionId);
204    } catch (Exception e) {
205    // Skip this document and continue.
206  0 this.logger.error("Failed to parse document [{}] from XAR.", xarEntry.getDocumentName(), e);
207    }
208    }
209    } finally {
210  0 try {
211  0 xarFile.close();
212    } catch (IOException e) {
213    // Ignore.
214    }
215  0 this.progressManager.popLevelProgress(this);
216    }
217    }
218   
 
219  0 toggle private void diff(XWikiDocument document, ExtensionId extensionId)
220    {
221  0 if (getRequest().isVerbose()) {
222  0 this.logger.info("Computing differences for document [{}]", document.getDocumentReferenceWithLocale());
223    }
224    // Use the extension id as the document version.
225  0 XWikiDocument previousDocument =
226    document.duplicate(new DocumentVersionReference(document.getDocumentReference(), extensionId));
227  0 XWikiContext xcontext = this.xcontextProvider.get();
228  0 try {
229  0 XWikiDocument nextDocument =
230    xcontext.getWiki().getDocument(document.getDocumentReferenceWithLocale(), xcontext);
231  0 if (nextDocument.isNew()) {
232  0 nextDocument = null;
233    }
234  0 maybeAddDocumentDiff(this.documentDiffBuilder.diff(previousDocument, nextDocument));
235    } catch (XWikiException e) {
236  0 this.logger.error("Failed to get document [{}] from the database.", document.getDocumentReference(), e);
237    }
238    }
239   
 
240  0 toggle private void maybeAddDocumentDiff(DocumentUnifiedDiff documentDiff)
241    {
242  0 int differencesCount =
243    documentDiff.size() + documentDiff.getAttachmentDiffs().size() + documentDiff.getObjectDiffs().size()
244    + documentDiff.getClassPropertyDiffs().size();
245  0 if (getRequest().isVerbose()) {
246  0 if (documentDiff.getNextReference() == null) {
247  0 this.logger.info("The document [{}] has been deleted", documentDiff.getPreviousReference());
248  0 } else if (documentDiff.getPreviousReference() == null) {
249  0 this.logger.info("The document [{}] has been added", documentDiff.getNextReference());
250  0 } else if (differencesCount > 0) {
251  0 this.logger.info("The document [{}] has [{}] changes", documentDiff.getPreviousReference(),
252    differencesCount);
253    } else {
254  0 this.logger.info("The document [{}] has no changes", documentDiff.getPreviousReference());
255    }
256    }
257  0 if (differencesCount > 0) {
258  0 getStatus().getDocumentDiffs().add(documentDiff);
259    }
260    }
261    }