cleanup
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / PreferenceServiceImpl.java
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 cacheIsLocked = false;
208 }
209
210 protected void waitForCache() {
211 while(cacheIsLocked) {
212 try {
213 Thread.sleep(1);
214 } catch (InterruptedException e) {
215 // just keep on sleeping, we may improve this later on
216 }
217 }
218 }
219
220 }