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

File DefaultExtensionJobHistory.java

 

Coverage histogram

../../../../../../img/srcFileCovDistChart9.png
38% of files have more coverage

Code metrics

14
44
10
2
198
146
23
0.52
4.4
5
2.3

Classes

Class Line # Actions
DefaultExtensionJobHistory 61 33 0% 19 9
0.826923182.7%
DefaultExtensionJobHistory.SaveRunnable 63 11 0% 4 3
0.812581.2%
 

Contributing tests

This file is covered by 118 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.extension.job.history.internal;
21   
22    import java.io.File;
23    import java.io.FileFilter;
24    import java.io.IOException;
25    import java.text.SimpleDateFormat;
26    import java.util.ArrayList;
27    import java.util.Arrays;
28    import java.util.Collections;
29    import java.util.Date;
30    import java.util.Deque;
31    import java.util.Iterator;
32    import java.util.List;
33    import java.util.concurrent.BlockingQueue;
34    import java.util.concurrent.ConcurrentLinkedDeque;
35    import java.util.concurrent.LinkedBlockingQueue;
36   
37    import javax.inject.Inject;
38    import javax.inject.Singleton;
39   
40    import org.apache.commons.collections4.Predicate;
41    import org.apache.commons.lang3.exception.ExceptionUtils;
42    import org.slf4j.Logger;
43    import org.xwiki.component.annotation.Component;
44    import org.xwiki.component.manager.ComponentLifecycleException;
45    import org.xwiki.component.phase.Disposable;
46    import org.xwiki.component.phase.Initializable;
47    import org.xwiki.component.phase.InitializationException;
48    import org.xwiki.extension.job.history.ExtensionJobHistory;
49    import org.xwiki.extension.job.history.ExtensionJobHistoryConfiguration;
50    import org.xwiki.extension.job.history.ExtensionJobHistoryRecord;
51    import org.xwiki.extension.job.history.ExtensionJobHistorySerializer;
52   
53    /**
54    * Default {@link ExtensionJobHistory} implementation.
55    *
56    * @version $Id: dd960cf1519238c7d66ac9ce1a6bea3233c53978 $
57    * @since 7.1RC1
58    */
59    @Component
60    @Singleton
 
61    public class DefaultExtensionJobHistory implements ExtensionJobHistory, Initializable, Disposable
62    {
 
63    private class SaveRunnable implements Runnable
64    {
 
65  260 toggle @Override
66    public void run()
67    {
68  260 logger.debug("Start extension job history saving thread.");
69   
70  304 while (!Thread.interrupted()) {
71  304 ExtensionJobHistoryRecord record;
72  304 try {
73  304 record = saveQueue.take();
74    } catch (InterruptedException e) {
75  0 logger.warn("Extension job history saving thread has been interrupted. Root cause [{}].",
76    ExceptionUtils.getRootCauseMessage(e));
77  0 record = SAVE_QUEUE_END;
78    }
79   
80  304 if (record == SAVE_QUEUE_END) {
81  260 break;
82    } else {
83  44 save(record);
84    }
85    }
86   
87  260 logger.debug("Stop extension job history saving thread.");
88    }
89    }
90   
91    private static final SimpleDateFormat FILE_NAME_FORMAT = new SimpleDateFormat("yyyy.MM.dd.'xml'");
92   
93    private static final ExtensionJobHistoryRecord SAVE_QUEUE_END = new ExtensionJobHistoryRecord("SAVE_QUEUE_END",
94    null, null, null, null);
95   
96    @Inject
97    private Logger logger;
98   
99    @Inject
100    private ExtensionJobHistoryConfiguration config;
101   
102    @Inject
103    private ExtensionJobHistorySerializer serializer;
104   
105    private final Deque<ExtensionJobHistoryRecord> records = new ConcurrentLinkedDeque<>();
106   
107    private BlockingQueue<ExtensionJobHistoryRecord> saveQueue = new LinkedBlockingQueue<>();
108   
 
109  261 toggle @Override
110    public void initialize() throws InitializationException
111    {
112  261 load();
113   
114  260 Thread saveThread = new Thread(new SaveRunnable());
115  260 saveThread.setName("XWiki's extension job history saving thread");
116  260 saveThread.setDaemon(true);
117  260 saveThread.setPriority(Thread.MIN_PRIORITY);
118  260 saveThread.start();
119    }
120   
 
121  260 toggle @Override
122    public void dispose() throws ComponentLifecycleException
123    {
124    // Stop the history saving thread by sending the stop signal.
125  260 this.saveQueue.offer(SAVE_QUEUE_END);
126    }
127   
 
128  44 toggle @Override
129    public void addRecord(ExtensionJobHistoryRecord record)
130    {
131  44 this.records.offerFirst(record);
132  44 this.saveQueue.offer(record);
133    }
134   
 
135  4 toggle @Override
136    public List<ExtensionJobHistoryRecord> getRecords(Predicate<ExtensionJobHistoryRecord> filter,
137    String offsetRecordId, int limit)
138    {
139  4 Iterator<ExtensionJobHistoryRecord> iterator = this.records.iterator();
140  4 if (offsetRecordId != null) {
141  1 while (iterator.hasNext() && !offsetRecordId.equals(iterator.next().getId())) {
142    // Do nothing.
143    }
144    }
145   
146  4 List<ExtensionJobHistoryRecord> page = new ArrayList<>();
147  10 while (iterator.hasNext() && (limit < 0 || page.size() < limit)) {
148  6 ExtensionJobHistoryRecord record = iterator.next();
149  6 if (filter.evaluate(record)) {
150  5 page.add(record);
151    }
152    }
153   
154  4 return page;
155    }
156   
 
157  44 toggle private void save(ExtensionJobHistoryRecord record)
158    {
159  44 try {
160  44 this.serializer.append(record, new File(this.config.getStorage(), getFileName()));
161    } catch (IOException e) {
162  0 this.logger.error("Failed to save extension job history.", e);
163    }
164    }
165   
 
166  44 toggle private String getFileName()
167    {
168  44 return FILE_NAME_FORMAT.format(new Date());
169    }
170   
 
171  261 toggle private void load()
172    {
173  261 for (File historyFile : getHistoryFiles()) {
174  0 try {
175  0 List<ExtensionJobHistoryRecord> storedRecords = this.serializer.read(historyFile);
176  0 Collections.reverse(storedRecords);
177  0 this.records.addAll(storedRecords);
178    } catch (Exception e) {
179  0 this.logger.error("Failed to read extension job history from [{}].", historyFile.getAbsolutePath(), e);
180    }
181    }
182    }
183   
 
184  261 toggle private List<File> getHistoryFiles()
185    {
186  261 File[] files = this.config.getStorage().listFiles(new FileFilter()
187    {
 
188  0 toggle @Override
189    public boolean accept(File file)
190    {
191  0 return file.isFile() && file.getName().endsWith(".xml");
192    }
193    });
194  260 List<File> fileList = files != null ? Arrays.asList(files) : Collections.<File>emptyList();
195  260 Collections.sort(fileList, Collections.reverseOrder());
196  260 return fileList;
197    }
198    }