EMMA Coverage Report (generated Tue Apr 17 08:51:20 BST 2007)
[all classes][org.jtoolkit.essence.data.impl]

COVERAGE SUMMARY FOR SOURCE FILE [TabStore.java]

nameclass, %method, %block, %line, %
TabStore.java100% (1/1)88%  (7/8)76%  (331/437)83%  (69.6/84)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class TabStore100% (1/1)88%  (7/8)76%  (331/437)83%  (69.6/84)
run (): void 0%   (0/1)0%   (0/9)0%   (0/4)
notifyUpdate (Object, Object): void 100% (1/1)59%  (10/17)89%  (3.6/4)
TabStore (String, Store$CollectionType, DataValueClass, DataValueClass, Strin... 100% (1/1)72%  (126/174)79%  (23/29)
flush (): void 100% (1/1)73%  (102/139)86%  (20.6/24)
<static initializer> 100% (1/1)82%  (9/11)90%  (1.8/2)
close (): void 100% (1/1)94%  (16/17)97%  (5.8/6)
output (PrintWriter, Object []): void 100% (1/1)97%  (57/59)99%  (9.9/10)
clear (): void 100% (1/1)100% (11/11)100% (5/5)

1package org.jtoolkit.essence.data.impl;
2 
3import org.apache.commons.logging.Log;
4import static org.apache.commons.logging.LogFactory.getLog;
5import org.jetbrains.annotations.NotNull;
6import org.jetbrains.annotations.Nullable;
7import org.jtoolkit.essence.app.pojo.impl.DataValueClass;
8import org.jtoolkit.essence.app.pojo.impl.PojoContext;
9import org.jtoolkit.essence.concurrency.Concurrency;
10import org.jtoolkit.essence.concurrency.ThreadSafe;
11import org.jtoolkit.essence.concurrency.Threads;
12import org.jtoolkit.essence.utils.IOUtils;
13import static org.jtoolkit.essence.utils.IOUtils.getInputStream;
14import static org.jtoolkit.essence.utils.IOUtils.readTab;
15import static org.jtoolkit.essence.utils.impl.MapArray.asKeys;
16import static org.jtoolkit.essence.utils.impl.MapArray.create;
17 
18import java.io.File;
19import java.io.FileNotFoundException;
20import java.io.IOException;
21import java.io.PrintWriter;
22import static java.util.Arrays.asList;
23import java.util.*;
24import java.util.concurrent.ScheduledFuture;
25import java.util.concurrent.TimeUnit;
26 
27/*
28   Copyright 2006 Peter Lawrey
29 
30   Licensed under the Apache License, Version 2.0 (the "License");
31   you may not use this file except in compliance with the License.
32   You may obtain a copy of the License at
33 
34       http://www.apache.org/licenses/LICENSE-2.0
35 
36   Unless required by applicable law or agreed to in writing, software
37   distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
38   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
39   See the License for the specific language governing permissions and
40   limitations under the License.
41*/
42 
43/**
44 * @author Peter Lawrey
45 */
46@ThreadSafe(Concurrency.CONCURRENT_READ_WRITE)
47public class TabStore<K, V> extends MemoryStore<K, V> implements Runnable {
48    private static final Log LOG = getLog(TabStore.class);
49    private static final long PERIOD = 5 * 1000;
50    private final String filename;
51    private final ScheduledFuture updateTask;
52    private final String[] headingArr;
53    private final Object diskLock = new Object();
54 
55    private boolean dirty = false;
56 
57    public TabStore(@NotNull String name, @NotNull CollectionType collectionType, @NotNull DataValueClass<K> keyClass, @NotNull DataValueClass<V> valueClass, @NotNull String filename) throws IOException, InstantiationException {
58        super(name, collectionType, keyClass, valueClass, ReadMode.ALL, PersistMode.ASYNC);
59        this.filename = filename;
60        try {
61            List<String[]> strings = readTab(getInputStream(filename));
62            Map<String, Integer> heading = asKeys(strings.get(0));
63            for (String[] row : strings.subList(1, strings.size())) {
64                Map<String, String> rowMap = create(heading, row);
65                K key = keyClass.build(rowMap, PojoContext.EMPTY);
66                V value = valueClass.build(rowMap, PojoContext.EMPTY);
67                V prev = doPut(key, value, true, true);
68                if (prev != null) {
69                    if (!prev.equals(value))
70                        LOG.warn(name + ": previous entry for key " + key + " detected. was " + prev + " now " + value);
71                    dirty = true;
72                }
73            }
74        } catch (IllegalArgumentException e) {
75            LOG.error(Thread.currentThread().getName() + ": Unable to read " + filename + ", has the format or columns changed? " + e);
76            throw e;
77        } catch (FileNotFoundException e) {
78            if (LOG.isInfoEnabled()) LOG.info(Thread.currentThread().getName() + ": Tab file not found, creating " + e);
79            dirty = true;
80        }
81        Set<String> headings = new LinkedHashSet<String>();
82        headings.addAll(asList(keyClass.getFields()));
83        headings.addAll(asList(valueClass.getFields()));
84        headingArr = headings.toArray(new String[headings.size()]);
85 
86        updateTask = canWrite() ?
87                getStoreMonitor().scheduleAtFixedRate(Threads.getWeakRunnable(this), PERIOD, PERIOD, TimeUnit.MILLISECONDS) : null;
88    }
89 
90    protected void clear() {
91        super.clear();
92        if (canWrite()) {
93            dirty = true;
94            flush();
95        }
96    }
97 
98    public void close() {
99        super.close();
100        if (!canWrite()) return;
101        updateTask.cancel(false);
102        // NOTE: Unsynchronised flush().
103        if (dirty)
104            flush();
105    }
106 
107    protected void notifyUpdate(@NotNull K key, @Nullable V newValue) {
108        try {
109            super.notifyUpdate(key, newValue);
110        } finally {
111            dirty = canWrite();
112        }
113    }
114 
115    public void run() {
116        if (dirty)
117            flush();
118        dirty = false;
119    }
120 
121    private void flush() {
122        synchronized (diskLock) {
123            File file = new File(filename);
124            IOUtils.deleteIfTmp(file);
125 
126            File file2 = IOUtils.getNewFile(filename);
127            PrintWriter pw = null;
128            try {
129                pw = new PrintWriter(IOUtils.getOutputStream(file2));
130                output(pw, headingArr);
131                assert keyClass != null;
132                for (Map.Entry<K, V> entry : asMap().entrySet()) {
133                    Map<String, Object> dump = new LinkedHashMap<String, Object>();
134                    dump.putAll(valueClass.asMap2(entry.getValue()));
135                    dump.putAll(keyClass.asMap2(entry.getKey()));
136                    Object[] out = new Object[headingArr.length];
137                    for (int i = 0; i < headingArr.length; i++)
138                        out[i] = dump.get(headingArr[i]);
139                    output(pw, out);
140                }
141            } catch (Exception e) {
142                LOG.error(name + ": Unable to save " + filename + " cannot create.", e);
143                return;
144            } finally {
145                IOUtils.close(pw);
146            }
147            IOUtils.rename(file, file2);
148        }
149    }
150 
151    private static void output(PrintWriter pw, Object[] fields) {
152        String sep = "";
153        for (Object field : fields) {
154            pw.print(sep);
155            String str = field == null ? "" : field.toString();
156            if (str.indexOf('"') >= 0 || !str.trim().equals(str))
157                str = '"' + str.replaceAll("\"", "\"\"") + '"';
158            pw.print(str);
159            sep = "\t";
160        }
161        pw.println();
162    }
163}

[all classes][org.jtoolkit.essence.data.impl]
EMMA 2.0.5312 (C) Vladimir Roubtsov