1 package net.avcompris.commons3.core.impl;
2
3 import static com.google.common.base.Preconditions.checkNotNull;
4
5 import java.io.IOException;
6 import java.sql.SQLException;
7 import java.util.ConcurrentModificationException;
8
9 import javax.annotation.Nullable;
10
11 import org.apache.commons.logging.Log;
12 import org.apache.commons.logging.LogFactory;
13
14 import net.avcompris.commons3.api.EntitiesQuery;
15 import net.avcompris.commons3.api.exception.DaoException;
16 import net.avcompris.commons3.api.exception.IllegalStateUpdateException;
17 import net.avcompris.commons3.api.exception.ServiceException;
18 import net.avcompris.commons3.core.Permissions;
19 import net.avcompris.commons3.dao.exception.ForeignEntityViolationException;
20 import net.avcompris.commons3.utils.Clock;
21
22 public abstract class AbstractServiceImpl {
23
24 protected final Permissions permissions;
25 protected final Clock clock;
26
27 private static final Log logger = LogFactory.getLog(AbstractServiceImpl.class);
28
29 protected AbstractServiceImpl(final Permissions permissions, final Clock clock) {
30
31 this.permissions = checkNotNull(permissions, "permissions");
32 this.clock = checkNotNull(clock, "clock");
33 }
34
35 protected static void wrap(final ActionVoid action) throws ServiceException {
36
37 try {
38
39 action.execute();
40
41 } catch (final ConcurrentModificationException e) {
42
43 throw new IllegalStateUpdateException(e);
44
45 } catch (final SQLException | IOException e) {
46
47 throw new DaoException(e);
48 }
49 }
50
51 protected static <T> T wrap(final Action<T> action) throws ServiceException {
52
53 try {
54
55 return action.execute();
56
57 } catch (final ConcurrentModificationException e) {
58
59 throw new IllegalStateUpdateException(e);
60
61 } catch (final SQLException | IOException e) {
62
63 throw new DaoException(e);
64 }
65 }
66
67 protected static void unchecked(final ActionVoid action) {
68
69 try {
70
71 action.execute();
72
73 } catch (final ServiceException e) {
74
75 throw new RuntimeException(e);
76
77 } catch (final SQLException | IOException e) {
78
79 throw new RuntimeException(e);
80 }
81 }
82
83 @FunctionalInterface
84 protected interface ActionVoid {
85
86 void execute() throws SQLException, IOException, ServiceException;
87 }
88
89 @FunctionalInterface
90 protected interface Action<T> {
91
92 T execute() throws SQLException, IOException, ServiceException;
93 }
94
95 @FunctionalInterface
96 protected interface ServiceAction<T> {
97
98 T execute() throws ServiceException;
99 }
100
101 protected final int getQueryStart(@Nullable final EntitiesQuery<?, ?> query, final int defaultValue) {
102
103 final Integer start = (query == null) ? null : query.getStart();
104
105 return (start != null) ? start : defaultValue;
106 }
107
108 protected final int getQueryLimit(@Nullable final EntitiesQuery<?, ?> query, final int defaultValue) {
109
110 final Integer limit = (query == null) ? null : query.getLimit();
111
112 return (limit != null) ? limit : defaultValue;
113 }
114
115 @FunctionalInterface
116 protected interface DaoAction<T> {
117
118 T action() throws SQLException, IOException, ServiceException;
119 }
120
121 @FunctionalInterface
122 protected interface DaoActionWithForeignEntity<T> {
123
124 T action() throws SQLException, IOException, ForeignEntityViolationException;
125 }
126
127 protected static <T> T retryDaoUntil(final long timeoutMs, final long delayMs, final DaoAction<T> action)
128 throws SQLException, IOException, ServiceException {
129
130 return retryDaoUntil(timeoutMs, delayMs, true, action);
131 }
132
133 protected static <T> T retryDaoWithForeignEntityUntil(final long timeoutMs, final long delayMs,
134 final DaoActionWithForeignEntity<T> action)
135 throws SQLException, IOException, ForeignEntityViolationException {
136
137 return retryDaoWithForeignEntityUntil(timeoutMs, delayMs, true, action);
138 }
139
140 protected static <T> T retryDaoUntil(final long timeoutMs, final long delayMs,
141 final boolean throwExceptionInCaseOfTimeout, final DaoAction<T> action)
142 throws SQLException, IOException, ServiceException {
143
144 checkNotNull(action, "action");
145
146 for (final long startMs = System.currentTimeMillis(); System.currentTimeMillis() < startMs + timeoutMs;) {
147
148 T result = null;
149
150 try {
151
152 result = action.action();
153
154 } catch (final SQLException | IOException | RuntimeException | Error e) {
155
156 throw e;
157
158 } catch (final Exception e) {
159
160 throw new RuntimeException(e);
161 }
162
163 if (result != null) {
164
165 return result;
166 }
167
168 try {
169
170 Thread.sleep(delayMs);
171
172 } catch (final InterruptedException e) {
173
174 e.printStackTrace();
175
176
177 }
178 }
179
180 logger.error("A timeout occurs (" + timeoutMs + " ms)");
181
182 if (throwExceptionInCaseOfTimeout) {
183
184 throw new RuntimeException("Timeout after: " + timeoutMs + " ms");
185
186 } else {
187
188 return null;
189 }
190 }
191
192 protected static <T> T retryDaoWithForeignEntityUntil(final long timeoutMs, final long delayMs,
193 final boolean throwExceptionInCaseOfTimeout, final DaoActionWithForeignEntity<T> action)
194 throws SQLException, IOException, ForeignEntityViolationException {
195
196 checkNotNull(action, "action");
197
198 for (final long startMs = System.currentTimeMillis(); System.currentTimeMillis() < startMs + timeoutMs;) {
199
200 T result = null;
201
202 try {
203
204 result = action.action();
205
206 } catch (final SQLException | IOException | RuntimeException | ForeignEntityViolationException | Error e) {
207
208 throw e;
209
210 } catch (final Exception e) {
211
212 throw new RuntimeException(e);
213 }
214
215 if (result != null) {
216
217 return result;
218 }
219
220 try {
221
222 Thread.sleep(delayMs);
223
224 } catch (final InterruptedException e) {
225
226 e.printStackTrace();
227
228
229 }
230 }
231
232 logger.error("A timeout occurs (" + timeoutMs + " ms)");
233
234 if (throwExceptionInCaseOfTimeout) {
235
236 throw new RuntimeException("Timeout after: " + timeoutMs + " ms");
237
238 } else {
239
240 return null;
241 }
242 }
243 }