Project

General

Profile

Download (6.46 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2007 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9

    
10
package eu.etaxonomy.cdm.api.service;
11

    
12
import java.util.ArrayList;
13
import java.util.Collection;
14
import java.util.List;
15
import java.util.Map;
16
import java.util.concurrent.ConcurrentHashMap;
17

    
18
import org.apache.log4j.Logger;
19
import org.springframework.beans.factory.annotation.Autowired;
20
import org.springframework.stereotype.Service;
21
import org.springframework.transaction.annotation.Transactional;
22

    
23
import eu.etaxonomy.cdm.model.common.CdmBase;
24
import eu.etaxonomy.cdm.model.metadata.CdmPreference;
25
import eu.etaxonomy.cdm.model.metadata.CdmPreference.PrefKey;
26
import eu.etaxonomy.cdm.model.metadata.IPreferencePredicate;
27
import eu.etaxonomy.cdm.model.metadata.PreferenceResolver;
28
import eu.etaxonomy.cdm.model.metadata.PreferenceSubject;
29
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
30
import eu.etaxonomy.cdm.persistence.dao.common.IPreferenceDao;
31

    
32
/**
33
 * @author a.mueller
34
 * @since 2013-09-09
35
 */
36
@Service
37
@Transactional(readOnly = true)
38
public class PreferenceServiceImpl implements IPreferenceService {
39

    
40
    @SuppressWarnings("unused")
41
	private static final Logger logger = Logger.getLogger(PreferenceServiceImpl.class);
42

    
43
    @Autowired
44
    private IPreferenceDao dao;
45

    
46
    private Map<String, CdmPreference> cache = new ConcurrentHashMap<>();
47

    
48
    private boolean cacheIsComplete = false;
49

    
50
    private boolean cacheIsLocked = false;
51

    
52
    @Override
53
	public CdmPreference findExact(PrefKey key) {
54
		String cacheKey = cacheKey(key);
55
        return fromCacheGet(key, cacheKey);
56
	}
57

    
58
    @Override
59
    public CdmPreference find(PrefKey key) {
60
        CdmPreference pref = PreferenceResolver.resolve(list(), key);
61
        return pref;
62
    }
63

    
64
    @Override
65
    public CdmPreference findDatabase(IPreferencePredicate<?> predicate){
66
        PrefKey key = CdmPreference.NewKey(PreferenceSubject.NewDatabaseInstance(), predicate);
67
        return find(key);
68
    }
69

    
70
    @Override
71
    public CdmPreference findVaadin(IPreferencePredicate<?> predicate){
72
        PrefKey key = CdmPreference.NewKey(PreferenceSubject.NewVaadinInstance(), predicate);
73
        return find(key);
74
    }
75

    
76
    @Override
77
    public CdmPreference findTaxEditor(IPreferencePredicate<?> predicate){
78
        PrefKey key = CdmPreference.NewKey(PreferenceSubject.NewTaxEditorInstance(), predicate);
79
        return find(key);
80
    }
81

    
82
	@Override
83
    @Transactional(readOnly = false)
84
	public void set(CdmPreference preference) {
85
		dao.set(preference);
86
		cachePut(preference);
87
	}
88

    
89
    @Override
90
    @Transactional(readOnly = false)
91
    public void remove(PrefKey key) {
92
        dao.remove(key);
93
        removeFromCache(key);
94
    }
95

    
96
    @Override
97
	public long count() {
98
		return dao.count();
99
	}
100

    
101
	@Override
102
    public List<CdmPreference> list() {
103
	    if(!cacheIsComplete) {
104
	        cacheFullUpdate();
105
	    }
106
        return new ArrayList<>(cacheValues());
107
    }
108

    
109
    @Override
110
    public List<CdmPreference> list(IPreferencePredicate<?> predicate) {
111
        // using the cache for this method makes not much sense
112
        return dao.list(predicate);
113
    }
114

    
115
    @Override
116
    public CdmPreference find(TaxonNode taxonNode, String predicate) {
117
        String cacheKey = cacheKey(taxonNode, predicate);
118
        return fromCacheOrFind(taxonNode, predicate, cacheKey);
119
    }
120

    
121
    @Override
122
    public CdmPreference find(TaxonNode taxonNode, IPreferencePredicate<?> predicate){
123
        return find(taxonNode, predicate.getKey());
124
    }
125

    
126
// ********************** NOT YET HANDLED *******************/
127

    
128
    @Override
129
    public List<CdmPreference> list(String subject, String predicate) {
130
        //FIXME
131
        throw new RuntimeException("list(String, String) not yet implemented" );
132
    }
133

    
134
    @Override
135
    //this method is only partly implemented
136
    public CdmPreference find(CdmBase taxonNodeRelatedCdmBase, String predicate) {
137
        TaxonNode taxonNode = mapToTaxonNode(taxonNodeRelatedCdmBase);
138
        return dao.find(taxonNode, predicate);
139
    }
140

    
141
    private TaxonNode mapToTaxonNode(CdmBase taxonNodeRelatedCdmBase) {
142
        if (taxonNodeRelatedCdmBase == null){
143
            return null;
144
        }else if (taxonNodeRelatedCdmBase.isInstanceOf(TaxonNode.class)){
145
            return CdmBase.deproxy(taxonNodeRelatedCdmBase, TaxonNode.class);
146
        }else{
147
            throw new RuntimeException("mapToTaxonNode not yet implemented for " + taxonNodeRelatedCdmBase.getClass().getSimpleName());
148
        }
149
    }
150

    
151
    // ====================== Cache methods ======================= //
152

    
153
    /**
154
     * Concatenates subject and predicate as key for the cache map
155
     */
156
    private String cacheKey(PrefKey key) {
157
        return key.getSubject() + key.getPredicate();
158
    }
159

    
160
    private String cacheKey(TaxonNode taxonNode, String predicate) {
161
        return taxonNode.treeIndex() + predicate;
162
    }
163

    
164

    
165
    // --------------- non locking cache read methods --------------- //
166

    
167
    protected Collection<CdmPreference> cacheValues() {
168
        waitForCache();
169
        return cache.values();
170
    }
171

    
172
    protected CdmPreference fromCacheGet(PrefKey key, String cacheKey) {
173
        waitForCache();
174
        return cache.computeIfAbsent(cacheKey, k -> dao.get(key));
175
    }
176

    
177

    
178
    protected CdmPreference fromCacheOrFind(TaxonNode taxonNode, String predicate, String cacheKey) {
179
        waitForCache();
180
        return cache.computeIfAbsent(cacheKey, k -> dao.find(taxonNode, predicate));
181
    }
182

    
183
    // --------------- cache locking methods --------------- //
184

    
185
    protected void cachePut(CdmPreference preference) {
186
        waitForCache();
187
        cacheIsLocked = true;
188
        cache.put(cacheKey(preference.getKey()), preference);
189
        cacheIsLocked = false;
190
    }
191

    
192

    
193
    protected void removeFromCache(PrefKey key) {
194
        waitForCache();
195
        cacheIsLocked = true;
196
        cache.remove(cacheKey(key));
197
        cacheIsLocked = false;
198
    }
199

    
200
    protected void cacheFullUpdate() {
201
        waitForCache();
202
        cacheIsLocked = true;
203
        cache.clear();
204
        for(CdmPreference pref :  dao.list()){
205
            cache.put(cacheKey(pref.getKey()), pref);
206
        }
207
        cacheIsComplete = true;
208
        cacheIsLocked = false;
209
    }
210

    
211
    protected void waitForCache() {
212
        while(cacheIsLocked) {
213
            try {
214
                Thread.sleep(1);
215
            } catch (InterruptedException e) {
216
                // just keep on sleeping, we may improve this later on
217
            }
218
        }
219
    }
220

    
221
}
(79-79/100)