View Javadoc

1   /*
2    * Copyright (c) 2015 Maxim Yunusov
3    *    Licensed under the Apache License, Version 2.0 (the "License");
4    *    you may not use this file except in compliance with the License.
5    *    You may obtain a copy of the License at
6    *
7    *        http://www.apache.org/licenses/LICENSE-2.0
8    *
9    *    Unless required by applicable law or agreed to in writing, software
10   *    distributed under the License is distributed on an "AS IS" BASIS,
11   *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   *    See the License for the specific language governing permissions and
13   *    limitations under the License.
14   */
15  
16  package org.maxur.perfmodel.backend.infrastructure;
17  
18  import org.iq80.leveldb.WriteBatch;
19  import org.jvnet.hk2.annotations.Service;
20  import org.maxur.perfmodel.backend.domain.ConflictException;
21  import org.maxur.perfmodel.backend.domain.Project;
22  import org.maxur.perfmodel.backend.domain.Repository;
23  import org.maxur.perfmodel.backend.service.Benchmark;
24  import org.maxur.perfmodel.backend.service.DataSource;
25  import org.slf4j.Logger;
26  
27  import javax.inject.Inject;
28  import java.io.IOException;
29  import java.util.Collection;
30  import java.util.Optional;
31  
32  import static java.lang.String.format;
33  import static java.util.Optional.empty;
34  import static org.slf4j.LoggerFactory.getLogger;
35  
36  /**
37   * Level Db Implementation of Project Repository.
38   *
39   * @author myunusov
40   * @version 1.0
41   * @since <pre>30.08.2015</pre>
42   */
43  @Service
44  public class ProjectRepositoryLevelDbImpl implements Repository<Project> {
45  
46      private static final Logger LOGGER = getLogger(ProjectRepositoryLevelDbImpl.class);
47  
48      public static final String ROOT_PREFIX = "/";
49  
50      @Inject
51      private DataSource dataSource;
52  
53      @Override
54      @Benchmark
55      public Optional<Project> get(final String key) {
56          try {
57              return dataSource.get(key);
58          } catch (IOException | ClassNotFoundException e) {
59              return throwError(e, "Cannot find project by id '%s'", key);
60          }
61      }
62  
63      @Override
64      @Benchmark
65      public Collection<Project> findAll() {
66          try {
67              return dataSource.findAllByPrefix(ROOT_PREFIX);
68          } catch (IOException | ClassNotFoundException e) {
69              return throwError(e, "Cannot get all projects");
70          }
71      }
72  
73      @Override
74      @Benchmark
75      public Optional<Project> findByName(final String name) {
76          try {
77              return dataSource.get(path(name));
78          } catch (IOException | ClassNotFoundException e) {
79              return throwError(e, "Cannot find project by name '%s'", name);
80          }
81      }
82  
83      @Override
84      @Benchmark
85      public Optional<Project> remove(final String key) {
86          try (WriteBatch batch = dataSource.createWriteBatch()) {
87              final Optional<Project> result = dataSource.get(key);
88              if (result.isPresent()) {
89                  dataSource.delete(key);
90                  dataSource.delete(path(result.get().getName()));
91                  dataSource.commit(batch);
92              }
93              return result;
94          } catch (IOException | ClassNotFoundException e) {
95              return throwError(e, "Cannot remove project '%s'", key);
96          }
97  
98      }
99  
100     @Override
101     @Benchmark
102     public Optional<Project> add(final Project value) throws ConflictException {
103         final String id = value.getId();
104         final String newName = value.getName();
105         try (WriteBatch batch = dataSource.createWriteBatch()) {
106             final Optional<Project> other = dataSource.get(id);
107             if (value.isSame(other)) {
108                 return other;
109             }
110             value.checkUniqueId(other);
111             value.checkNamesakes(findByName(newName));
112             value.makeVersion();
113             dataSource.put(id, value);
114             dataSource.put(path(newName), value.brief());
115             dataSource.commit(batch);
116             return Optional.of(value);
117         } catch (IOException | ClassNotFoundException e) {
118             return throwError(e, "Cannot save project '%s'", newName);
119         }
120     }
121 
122     @Override
123     @Benchmark
124     // idempotent
125     public Optional<Project> amend(final Project value) throws ConflictException  {
126         final String id = value.getId();
127         final String newName = value.getName();
128         value.incVersion();
129 
130         try (WriteBatch batch = dataSource.createWriteBatch()) {
131             final Optional<Project> prev = dataSource.get(id);
132             if (!prev.isPresent()) {
133                 return empty();
134             }
135             if (value.isSame(prev)) {
136                 return prev;
137             }
138             value.checkConflictWith(prev);
139             final boolean mustBeRenamed = !prev.get().getName().equals(newName);
140             if (mustBeRenamed) {
141                 value.checkNamesakes(findByName(newName));
142                 dataSource.delete(path(prev.get().getName()));
143             }
144             dataSource.put(id, value);
145             dataSource.put(path(newName), value.brief());
146             dataSource.commit(batch);
147             return Optional.of(value);
148         } catch (IOException | ClassNotFoundException e) {
149             return throwError(e, "Cannot save project '%s'", newName);
150         }
151     }
152 
153     private String path(final String name) {
154         return ROOT_PREFIX + name;
155     }
156 
157     private static <T> T throwError(final Exception e, final String message, final String... args) {
158         final String msg = format(message, args);
159         LOGGER.error(msg, e);
160         throw new IllegalStateException(msg, e);
161     }
162 
163 }