View Javadoc
1   /*
2    * Copyright (c) 2023. Roland T. Lichti, Kaiserpfalz EDV-Service.
3    *
4    * This program is free software: you can redistribute it and/or modify
5    * it under the terms of the GNU General Public License as published by
6    * the Free Software Foundation, either version 3 of the License, or
7    * (at your option) any later version.
8    *
9    * This program is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   * GNU General Public License for more details.
13   *
14   * You should have received a copy of the GNU General Public License
15   * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16   */
17  
18  package de.kaiserpfalzedv.commons.core.store;
19  
20  import java.util.HashMap;
21  import java.util.Optional;
22  import java.util.UUID;
23  
24  import de.kaiserpfalzedv.commons.api.resources.Resource;
25  import de.kaiserpfalzedv.commons.api.store.OptimisticLockStoreException;
26  import de.kaiserpfalzedv.commons.api.store.StoreService;
27  import lombok.EqualsAndHashCode;
28  import lombok.ToString;
29  import lombok.extern.slf4j.Slf4j;
30  
31  /**
32   * GenericStoreService -- an ephemeral store for Resources.
33   * <p>
34   * This is a memory alternative for a persistent data store.
35   *
36   * @param <T> The resource to be stored inside the data store.
37   * @author klenkes74 {@literal <rlichti@kaiserpfalz-edv.de>}
38   * @since 2.0.0  2021-05-24
39   */
40  @ToString
41  @EqualsAndHashCode
42  @Slf4j
43  public abstract class GenericStoreService<T extends Resource<?>> implements StoreService<T> {
44      /**
45       * The name based memory store for guilds.
46       */
47      private final HashMap<String, T> namedStore = new HashMap<>(10);
48  
49      /**
50       * The uid based memory store for guilds.
51       */
52      private final HashMap<UUID, T> uidStore = new HashMap<>(10);
53  
54  
55      @Override
56      public Optional<T> findByNameSpaceAndName(final String nameSpace, final String name) {
57          final String key = this.generateStoreKey(nameSpace, name);
58  
59          return Optional.ofNullable(this.namedStore.get(key));
60      }
61  
62      @Override
63      public Optional<T> findByUid(final UUID uid) {
64          return Optional.ofNullable(this.uidStore.get(uid));
65      }
66  
67      private String generateStoreKey(final String nameSpace, final String name) {
68          return nameSpace + "-" + name;
69      }
70  
71      @Override
72      public T save(final T object) throws OptimisticLockStoreException {
73          log.trace("Saving: {}", object);
74  
75          final String key = this.generateStoreKey(object.getNameSpace(), object.getName());
76  
77          @SuppressWarnings("unchecked")
78          final
79          T data = (!this.namedStore.containsKey(key))
80                  ? object
81                  : (T) object.increaseGeneration();
82  
83  
84          this.checkOptimisticLocking(key, data);
85  
86          this.namedStore.put(key, data);
87          this.uidStore.put(object.getUid(), data);
88          return data;
89      }
90  
91      private void checkOptimisticLocking(final String key, final T object) {
92          if (
93                  this.namedStore.containsKey(key)
94                          && (this.namedStore.get(key).getGeneration() >= object.getGeneration())
95          ) {
96              throw new OptimisticLockStoreException(this.namedStore.get(key).getGeneration(), object.getGeneration());
97          }
98      }
99  
100     @Override
101     public void remove(final T object) {
102         final String key = this.generateStoreKey(object.getNameSpace(), object.getName());
103 
104         this.namedStore.remove(key);
105         this.uidStore.remove(object.getUid());
106     }
107 
108     @Override
109     public void remove(final String nameSpace, final String name) {
110         final String key = this.generateStoreKey(nameSpace, name);
111 
112         if (this.namedStore.containsKey(key)) {
113             this.uidStore.remove(this.namedStore.get(key).getUid());
114             this.namedStore.remove(key);
115         }
116     }
117 
118     @Override
119     public void remove(final UUID uid) {
120         if (this.uidStore.containsKey(uid)) {
121             final T data = this.uidStore.get(uid);
122             final String key = this.generateStoreKey(data.getNameSpace(), data.getName());
123 
124             this.namedStore.remove(key);
125             this.uidStore.remove(uid);
126         }
127     }
128 }