Update javadoc for CdmPreference related classes.
[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 * Service to store and access {@link CdmPreference cdm preferences}.
34 * On how to use cdm preferences see the documentation there.
35 *
36 * @author a.mueller
37 * @since 2013-09-09
38 */
39 @Service
40 @Transactional(readOnly = true)
41 public class PreferenceServiceImpl implements IPreferenceService {
42
43 @SuppressWarnings("unused")
44 private static final Logger logger = Logger.getLogger(PreferenceServiceImpl.class);
45
46 @Autowired
47 private IPreferenceDao dao;
48
49 private Map<String, CdmPreference> cache = new ConcurrentHashMap<>();
50
51 private boolean cacheIsComplete = false;
52
53 private boolean cacheIsLocked = false;
54
55 @Override
56 public CdmPreference findExact(PrefKey key) {
57 String cacheKey = cacheKey(key);
58 return fromCacheGet(key, cacheKey);
59 }
60
61 @Override
62 public CdmPreference find(PrefKey key) {
63 CdmPreference pref = PreferenceResolver.resolve(list(), key);
64 return pref;
65 }
66
67 @Override
68 public CdmPreference findDatabase(IPreferencePredicate<?> predicate){
69 PrefKey key = CdmPreference.NewKey(PreferenceSubject.NewDatabaseInstance(), predicate);
70 return find(key);
71 }
72
73 @Override
74 public CdmPreference findVaadin(IPreferencePredicate<?> predicate){
75 PrefKey key = CdmPreference.NewKey(PreferenceSubject.NewVaadinInstance(), predicate);
76 return find(key);
77 }
78
79 @Override
80 public CdmPreference findTaxEditor(IPreferencePredicate<?> predicate){
81 PrefKey key = CdmPreference.NewKey(PreferenceSubject.NewTaxEditorInstance(), predicate);
82 return find(key);
83 }
84
85 @Override
86 @Transactional(readOnly = false)
87 public void set(CdmPreference preference) {
88 dao.set(preference);
89 cachePut(preference);
90 }
91
92 @Override
93 @Transactional(readOnly = false)
94 public void remove(PrefKey key) {
95 dao.remove(key);
96 removeFromCache(key);
97 }
98
99 @Override
100 public long count() {
101 return dao.count();
102 }
103
104 @Override
105 public List<CdmPreference> list() {
106 if(!cacheIsComplete) {
107 cacheFullUpdate();
108 }
109 return new ArrayList<>(cacheValues());
110 }
111
112 @Override
113 public List<CdmPreference> list(IPreferencePredicate<?> predicate) {
114 // using the cache for this method makes not much sense
115 return dao.list(predicate);
116 }
117
118 @Override
119 public CdmPreference find(TaxonNode taxonNode, String predicate) {
120
121 return dao.find(taxonNode, predicate);
122 // caching of taxon node related prefs disabled, see https://dev.e-taxonomy.eu/redmine/issues/9152#note-8
123 // code has been left here in case we decide later for solution 2 which has been suggested also in comment 5
124 // String cacheKey = cacheKey(taxonNode, predicate);
125 // return fromCacheOrFind(taxonNode, predicate, cacheKey);
126 }
127
128 @Override
129 public CdmPreference find(TaxonNode taxonNode, IPreferencePredicate<?> predicate){
130 return find(taxonNode, predicate.getKey());
131 }
132
133 // ********************** NOT YET HANDLED *******************/
134
135 @Override
136 public List<CdmPreference> list(String subject, String predicate) {
137 //FIXME
138 throw new RuntimeException("list(String, String) not yet implemented" );
139 }
140
141 @Override
142 //this method is only partly implemented
143 public CdmPreference find(CdmBase taxonNodeRelatedCdmBase, String predicate) {
144 TaxonNode taxonNode = mapToTaxonNode(taxonNodeRelatedCdmBase);
145 return dao.find(taxonNode, predicate);
146 }
147
148 private TaxonNode mapToTaxonNode(CdmBase taxonNodeRelatedCdmBase) {
149 if (taxonNodeRelatedCdmBase == null){
150 return null;
151 }else if (taxonNodeRelatedCdmBase.isInstanceOf(TaxonNode.class)){
152 return CdmBase.deproxy(taxonNodeRelatedCdmBase, TaxonNode.class);
153 }else{
154 throw new RuntimeException("mapToTaxonNode not yet implemented for " + taxonNodeRelatedCdmBase.getClass().getSimpleName());
155 }
156 }
157
158 // ====================== Cache methods ======================= //
159
160 /**
161 * Concatenates subject and predicate as key for the cache map
162 */
163 private String cacheKey(PrefKey key) {
164 return key.getSubject() + "@" + key.getPredicate();
165 }
166
167 /**
168 * @deprecated caching of taxon node related prefs disabled, see https://dev.e-taxonomy.eu/redmine/issues/9152#note-8
169 * code has been left here in case we decide later for solution 2 which has been suggested also in comment 5
170 */
171 @Deprecated
172 private String cacheKey(TaxonNode taxonNode, String predicate) {
173 return taxonNode.treeIndex() + predicate;
174 }
175
176
177 // --------------- non locking cache read methods --------------- //
178
179 protected Collection<CdmPreference> cacheValues() {
180 waitForCache();
181 return cache.values();
182 }
183
184 protected CdmPreference fromCacheGet(PrefKey key, String cacheKey) {
185 waitForCache();
186 return cache.computeIfAbsent(cacheKey, k -> dao.get(key));
187 }
188
189
190 /**
191 * @deprecated caching of taxon node related prefs disabled, see https://dev.e-taxonomy.eu/redmine/issues/9152#note-8
192 * code has been left here in case we decide later for solution 2 which has been suggested also in comment 5
193 */
194 @Deprecated
195 protected CdmPreference fromCacheOrFind(TaxonNode taxonNode, String predicate, String cacheKey) {
196 waitForCache();
197 return cache.computeIfAbsent(cacheKey, k -> dao.find(taxonNode, predicate));
198 }
199
200 // --------------- cache locking methods --------------- //
201
202 protected void cachePut(CdmPreference preference) {
203 waitForCache();
204 cacheIsLocked = true;
205 cache.put(cacheKey(preference.getKey()), preference);
206 cacheIsLocked = false;
207 }
208
209
210 protected void removeFromCache(PrefKey key) {
211 waitForCache();
212 cacheIsLocked = true;
213 cache.remove(cacheKey(key));
214 cacheIsLocked = false;
215 }
216
217 protected void cacheFullUpdate() {
218 waitForCache();
219 cacheIsLocked = true;
220 cache.clear();
221 for(CdmPreference pref : dao.list()){
222 cache.put(cacheKey(pref.getKey()), pref);
223 }
224 cacheIsComplete = true;
225 cacheIsLocked = false;
226 }
227
228 protected void waitForCache() {
229 while(cacheIsLocked) {
230 try {
231 Thread.sleep(1);
232 } catch (InterruptedException e) {
233 // just keep on sleeping, we may improve this later on
234 }
235 }
236 }
237
238 }