Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit ca656dd

Browse files
author
Gerald Unterrainer
committedMay 31, 2021
finish rewrite
1 parent 1cc8b68 commit ca656dd

13 files changed

+348
-265
lines changed
 

‎src/main/java/info/unterrainer/commons/httpserver/GenericHandlerGroup.java

+13-14
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@
77
import java.util.Map.Entry;
88
import java.util.concurrent.ExecutorService;
99

10-
import info.unterrainer.commons.httpserver.daos.BasicDao;
10+
import info.unterrainer.commons.httpserver.daos.CoreDao;
1111
import info.unterrainer.commons.httpserver.daos.DaoTransaction;
12-
import info.unterrainer.commons.httpserver.daos.DaoTransactionManager;
1312
import info.unterrainer.commons.httpserver.enums.Attribute;
1413
import info.unterrainer.commons.httpserver.enums.Endpoint;
1514
import info.unterrainer.commons.httpserver.enums.QueryField;
@@ -33,10 +32,9 @@
3332
@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
3433
public class GenericHandlerGroup<P extends BasicJpa, J extends BasicJson, E> implements HandlerGroup {
3534

36-
private final BasicDao<P, E> dao;
35+
private final CoreDao<P, E> dao;
3736
private final Class<P> jpaType;
3837
private final Class<J> jsonType;
39-
private final DaoTransactionManager<E> daoTransactionManager;
4038
private final JsonMapper jsonMapper;
4139
private final MapperFacade orikaMapper;
4240
private final String path;
@@ -47,7 +45,7 @@ public class GenericHandlerGroup<P extends BasicJpa, J extends BasicJson, E> imp
4745
private final ExecutorService executorService;
4846
private final HandlerUtils hu = new HandlerUtils();
4947
private final String tenantIdRowName;
50-
private final BasicDao<? extends BasicJpa, E> tenantDao;
48+
private final CoreDao<? extends BasicJpa, E> tenantDao;
5149
private final Class<? extends BasicJpa> tenantJpaType;
5250
private final String fieldRowName;
5351
private final String tenantRowName;
@@ -97,7 +95,7 @@ private Role[] rolesFor(final List<Endpoint> endpointList) {
9795
}
9896

9997
private void getEntry(final Context ctx) {
100-
DaoTransaction<E> transaction = daoTransactionManager.beginTransaction();
98+
DaoTransaction<E> transaction = dao.getTransactionManager().beginTransaction();
10199

102100
P jpa = hu.getJpaById(ctx, transaction.getManager(), dao);
103101
J json = orikaMapper.map(jpa, jsonType);
@@ -130,7 +128,7 @@ private void getList(final Context ctx) {
130128
e.getMessage());
131129
}
132130

133-
DaoTransaction<E> transaction = daoTransactionManager.beginTransaction();
131+
DaoTransaction<E> transaction = dao.getTransactionManager().beginTransaction();
134132

135133
ListJson<P> bList = dao.getList(transaction.getManager(), offset, size, interceptorResult.getSelectClause(),
136134
interceptorResult.getJoinClause(), interceptorResult.getWhereClause(), interceptorResult.getParams(),
@@ -152,7 +150,7 @@ private void create(final Context ctx) throws IOException {
152150
try {
153151
J json = jsonMapper.fromStringTo(jsonType, b);
154152
P mappedJpa = orikaMapper.map(json, jpaType);
155-
DaoTransaction<E> transaction = daoTransactionManager.beginTransaction();
153+
DaoTransaction<E> transaction = dao.getTransactionManager().beginTransaction();
156154

157155
mappedJpa = extensions.runPreInsert(ctx, transaction.getManager(), json, mappedJpa, executorService);
158156
P createdJpa = dao.create(transaction.getManager(), mappedJpa);
@@ -170,38 +168,39 @@ private void create(final Context ctx) throws IOException {
170168
}
171169

172170
private void fullUpdate(final Context ctx) throws IOException {
173-
P jpa = hu.getJpaById(ctx, dao);
171+
DaoTransaction<E> transaction = dao.getTransactionManager().beginTransaction();
172+
P jpa = hu.getJpaById(ctx, transaction.getManager(), dao);
174173
try {
175174
J json = jsonMapper.fromStringTo(jsonType, ctx.body());
176175
P mappedJpa = orikaMapper.map(json, jpaType);
177176
mappedJpa.setId(jpa.getId());
178177
mappedJpa.setCreatedOn(jpa.getCreatedOn());
179178
mappedJpa.setEditedOn(jpa.getEditedOn());
180-
DaoTransaction<E> transaction = daoTransactionManager.beginTransaction();
181179

182180
mappedJpa = extensions.runPreModify(ctx, transaction.getManager(), jpa.getId(), json, jpa, mappedJpa,
183181
executorService);
184-
P persistedJpa = dao.update(mappedJpa);
182+
P persistedJpa = dao.update(transaction.getManager(), mappedJpa);
185183

186184
J r = orikaMapper.map(persistedJpa, jsonType);
187185
r = extensions.runPostModify(ctx, transaction.getManager(), jpa.getId(), json, jpa, mappedJpa, persistedJpa,
188186
r, executorService);
189187

190-
transaction.end();
191188
ctx.attribute(Attribute.RESPONSE_OBJECT, r);
192189

193190
} catch (JsonProcessingException | JsonMappingException e) {
194191
throw new BadRequestException();
192+
} finally {
193+
transaction.end();
195194
}
196195
}
197196

198197
private void delete(final Context ctx) {
199198
ctx.attribute(Attribute.RESPONSE_OBJECT, null);
200199
Long id = hu.checkAndGetId(ctx);
201-
DaoTransaction<E> transaction = daoTransactionManager.beginTransaction();
200+
DaoTransaction<E> transaction = dao.getTransactionManager().beginTransaction();
202201

203202
id = extensions.runPreDelete(ctx, transaction.getManager(), id, executorService);
204-
dao._delete(id);
203+
dao.delete(transaction.getManager(), id);
205204
ctx.status(204);
206205
extensions.runPostDelete(ctx, transaction.getManager(), id, executorService);
207206

‎src/main/java/info/unterrainer/commons/httpserver/GenericHandlerGroupBuilder.java

+6-13
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@
66
import java.util.List;
77
import java.util.concurrent.ExecutorService;
88

9-
import info.unterrainer.commons.httpserver.daos.BasicDao;
10-
import info.unterrainer.commons.httpserver.daos.DaoTransactionManager;
9+
import info.unterrainer.commons.httpserver.daos.CoreDao;
1110
import info.unterrainer.commons.httpserver.daos.ParamMap;
1211
import info.unterrainer.commons.httpserver.enums.Endpoint;
1312
import info.unterrainer.commons.httpserver.interceptors.InterceptorData;
@@ -28,10 +27,9 @@
2827
public class GenericHandlerGroupBuilder<P extends BasicJpa, J extends BasicJson, E> {
2928

3029
private final HttpServer server;
31-
private BasicDao<P, E> dao;
3230
private final Class<P> jpaType;
3331
private final Class<J> jsonType;
34-
private final DaoTransactionManager<E> daoTransactionManager;
32+
private final CoreDao<P, E> dao;
3533
private JsonMapper jsonMapper;
3634
private MapperFactory orikaFactory;
3735
private String path;
@@ -42,7 +40,7 @@ public class GenericHandlerGroupBuilder<P extends BasicJpa, J extends BasicJson,
4240
private String tenantIdRowName;
4341
private String tenantRowName;
4442
private String tenantFieldRowName;
45-
private BasicDao<? extends BasicJpa, E> tenantDao;
43+
private CoreDao<? extends BasicJpa, E> tenantDao;
4644
private Class<? extends BasicJpa> tenantJpaType;
4745

4846
HandlerExtensions<P, J, E> extensions = new HandlerExtensions<>();
@@ -56,8 +54,8 @@ public HttpServer add() {
5654
if (executorService == null)
5755
executorService = server.executorService;
5856
GenericHandlerGroup<P, J, E> handlerGroupInstance = new GenericHandlerGroup<>(dao, jpaType, jsonType,
59-
daoTransactionManager, jsonMapper, orikaFactory.getMapperFacade(), path, endpoints, getListInterceptors,
60-
extensions, accessRoles, executorService, tenantIdRowName, tenantDao, tenantJpaType, tenantFieldRowName,
57+
jsonMapper, orikaFactory.getMapperFacade(), path, endpoints, getListInterceptors, extensions,
58+
accessRoles, executorService, tenantIdRowName, tenantDao, tenantJpaType, tenantFieldRowName,
6159
tenantRowName);
6260
server.addHandlerGroup(handlerGroupInstance);
6361
return server;
@@ -78,7 +76,7 @@ public GenericHandlerGroupBuilder<P, J, E> isMultiTenantEnabledByIdRow(final Str
7876
}
7977

8078
public <TP extends BasicJpa> GenericHandlerGroupBuilder<P, J, E> isMultiTenantEnabledByTable(
81-
final BasicDao<TP, E> tenantDao, final Class<TP> tenantJpaType, final String fieldRowName,
79+
final CoreDao<TP, E> tenantDao, final Class<TP> tenantJpaType, final String fieldRowName,
8280
final String tenantRowName) {
8381
this.tenantDao = tenantDao;
8482
this.tenantJpaType = tenantJpaType;
@@ -87,11 +85,6 @@ public <TP extends BasicJpa> GenericHandlerGroupBuilder<P, J, E> isMultiTenantEn
8785
return this;
8886
}
8987

90-
public GenericHandlerGroupBuilder<P, J, E> dao(final BasicDao<P, E> dao) {
91-
this.dao = dao;
92-
return this;
93-
}
94-
9588
public GenericHandlerGroupBuilder<P, J, E> jsonMapper(final JsonMapper jsonMapper) {
9689
this.jsonMapper = jsonMapper;
9790
return this;

‎src/main/java/info/unterrainer/commons/httpserver/HandlerUtils.java

+14-8
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
import java.time.format.DateTimeFormatter;
55
import java.time.format.DateTimeParseException;
66

7-
import info.unterrainer.commons.httpserver.daos.BasicDao;
7+
import info.unterrainer.commons.httpserver.daos.CoreDao;
8+
import info.unterrainer.commons.httpserver.daos.DaoTransaction;
89
import info.unterrainer.commons.httpserver.enums.QueryField;
910
import info.unterrainer.commons.httpserver.exceptions.BadRequestException;
1011
import info.unterrainer.commons.httpserver.exceptions.NotFoundException;
@@ -19,20 +20,25 @@ public Long checkAndGetId(final Context ctx) {
1920
return convertToLong(s);
2021
}
2122

22-
public <P extends BasicJpa, E> P getJpaById(final Context ctx, final E entityManager, final BasicDao<P, E> dao) {
23+
public <P extends BasicJpa, E> P getJpaById(final Context ctx, final E manager, final CoreDao<P, E> dao) {
2324
Long id = checkAndGetId(ctx);
24-
P jpa = dao._getById(entityManager, id);
25+
P jpa = dao.getById(manager, id);
2526
if (jpa == null)
2627
throw new NotFoundException();
2728
return jpa;
2829
}
2930

30-
public <P extends BasicJpa, E> P getJpaById(final Context ctx, final BasicDao<P, E> dao) {
31+
public <P extends BasicJpa, E> P getJpaById(final Context ctx, final CoreDao<P, E> dao) {
3132
Long id = checkAndGetId(ctx);
32-
P jpa = dao._getById(id);
33-
if (jpa == null)
34-
throw new NotFoundException();
35-
return jpa;
33+
DaoTransaction<E> transaction = dao.getTransactionManager().beginTransaction();
34+
try {
35+
P jpa = dao.getById(transaction.getManager(), id);
36+
if (jpa == null)
37+
throw new NotFoundException();
38+
return jpa;
39+
} finally {
40+
transaction.end();
41+
}
3642
}
3743

3844
public <J> void setPaginationParamsFor(final ListJson<J> jList, final long offset, final long pageSize,

‎src/main/java/info/unterrainer/commons/httpserver/HttpServer.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import org.eclipse.jetty.server.ServerConnector;
1717

1818
import info.unterrainer.commons.httpserver.accessmanager.HttpAccessManager;
19-
import info.unterrainer.commons.httpserver.daos.DaoTransactionManager;
19+
import info.unterrainer.commons.httpserver.daos.CoreDaoProvider;
2020
import info.unterrainer.commons.httpserver.enums.Attribute;
2121
import info.unterrainer.commons.httpserver.enums.ResponseType;
2222
import info.unterrainer.commons.httpserver.exceptions.HttpException;
@@ -98,8 +98,8 @@ public void addHandlerGroup(final HandlerGroup group) {
9898
}
9999

100100
public <P extends BasicJpa, J extends BasicJson, E> GenericHandlerGroupBuilder<P, J, E> handlerGroupFor(
101-
final Class<P> jpaType, final Class<J> jsonType, final DaoTransactionManager<E> daoTransactionManager) {
102-
return new GenericHandlerGroupBuilder<>(this, jpaType, jsonType, daoTransactionManager);
101+
final Class<P> jpaType, final Class<J> jsonType, final CoreDaoProvider<P, E> coreDaoProvider) {
102+
return new GenericHandlerGroupBuilder<>(this, jpaType, jsonType, coreDaoProvider.getCoreDao());
103103
}
104104

105105
private void create() {

‎src/main/java/info/unterrainer/commons/httpserver/daos/BasicJpqlDao.java

+27-215
Original file line numberDiff line numberDiff line change
@@ -2,66 +2,59 @@
22

33
import java.time.LocalDateTime;
44
import java.util.List;
5-
import java.util.Map;
6-
import java.util.Map.Entry;
7-
import java.util.Set;
85

96
import javax.persistence.EntityManager;
107
import javax.persistence.EntityManagerFactory;
11-
import javax.persistence.LockModeType;
12-
import javax.persistence.NoResultException;
13-
import javax.persistence.Query;
148
import javax.persistence.TypedQuery;
159

1610
import info.unterrainer.commons.httpserver.jsons.ListJson;
1711
import info.unterrainer.commons.jreutils.DateUtils;
1812
import info.unterrainer.commons.rdbutils.Transactions;
1913
import info.unterrainer.commons.rdbutils.entities.BasicJpa;
20-
import info.unterrainer.commons.rdbutils.enums.AsyncState;
21-
import lombok.RequiredArgsConstructor;
22-
import lombok.extern.slf4j.Slf4j;
14+
import lombok.Getter;
2315

24-
@RequiredArgsConstructor
25-
@Slf4j
26-
public class BasicJpqlDao<P extends BasicJpa> implements BasicDao<P, EntityManager> {
16+
public class BasicJpqlDao<P extends BasicJpa> implements CoreDaoProvider<P, EntityManager> {
2717

2818
protected final EntityManagerFactory emf;
2919
protected final Class<P> type;
20+
@Getter
21+
protected JpqlCoreDao<P> coreDao;
22+
23+
public BasicJpqlDao(final EntityManagerFactory emf, final Class<P> type) {
24+
super();
25+
this.emf = emf;
26+
this.type = type;
27+
coreDao = new JpqlCoreDao<>(emf, type);
28+
}
3029

3130
P _getById(final Long id) {
32-
return Transactions.withNewTransactionReturning(emf, em -> _getById(em, id));
31+
return Transactions.withNewTransactionReturning(emf, em -> coreDao.getById(em, id));
3332
}
3433

3534
ListJson<P> getList(final EntityManager em, final long offset, final long size, final String selectClause,
3635
final String joinClause, final String whereClause, final ParamMap params, final String orderByClause) {
3736
ListJson<P> r = new ListJson<>();
38-
r.setEntries(
39-
getList(em,
40-
getQuery(em, selectClause, joinClause, whereClause,
41-
params == null ? null : params.getParameters(), type, orderByClause, false, null),
42-
offset, size));
43-
r.setCount((Long) getCountQuery(em, selectClause, joinClause, whereClause,
44-
params == null ? null : params.getParameters(), null).getSingleResult());
37+
r.setEntries(getList(em,
38+
coreDao.getQuery(em, selectClause, joinClause, whereClause,
39+
params == null ? null : params.getParameters(), type, orderByClause, false, null),
40+
offset, size));
41+
r.setCount(
42+
(Long) coreDao
43+
.getCountQuery(em, selectClause, joinClause, whereClause,
44+
params == null ? null : params.getParameters(), null)
45+
.getSingleResult());
4546
return r;
4647
}
4748

4849
P create(final P entity) {
49-
return Transactions.withNewTransactionReturning(emf, em -> create(em, entity));
50-
}
51-
52-
P create(final EntityManager em, final P entity) {
53-
LocalDateTime time = DateUtils.nowUtc();
54-
entity.setCreatedOn(time);
55-
entity.setEditedOn(time);
56-
em.persist(entity);
57-
return entity;
50+
return Transactions.withNewTransactionReturning(emf, em -> coreDao.create(em, entity));
5851
}
5952

6053
P _update(final P entity) {
61-
return Transactions.withNewTransactionReturning(emf, em -> _update(em, entity));
54+
return Transactions.withNewTransactionReturning(emf, em -> update(em, entity));
6255
}
6356

64-
P _update(final EntityManager em, final P entity) {
57+
P update(final EntityManager em, final P entity) {
6558
LocalDateTime time = DateUtils.nowUtc();
6659
entity.setEditedOn(time);
6760
return em.merge(entity);
@@ -93,201 +86,20 @@ UpsertResult<P> _upsert(final EntityManager em, final TypedQuery<P> query, final
9386
boolean wasUpdated = false;
9487
P e = getFirst(em, query);
9588
if (e == null) {
96-
e = create(em, entity);
89+
e = coreDao.create(em, entity);
9790
wasInserted = true;
9891
} else {
9992
entity.setId(e.getId());
10093
entity.setCreatedOn(e.getCreatedOn());
101-
e = _update(em, entity);
94+
e = update(em, entity);
10295
wasUpdated = true;
10396
}
10497
return UpsertResult.<P>builder().wasInserted(wasInserted).wasUpdated(wasUpdated).jpa(e).build();
10598
}
10699

107100
void _delete(final Long id) {
108101
Transactions.withNewTransaction(emf, em -> {
109-
_delete(em, id);
102+
coreDao.delete(em, id);
110103
});
111104
}
112-
113-
void _delete(final EntityManager em, final Long id) {
114-
em.createQuery(String.format("DELETE FROM %s AS o WHERE o.id = :id", type.getSimpleName()))
115-
.setParameter("id", id)
116-
.executeUpdate();
117-
}
118-
119-
P _getById(final EntityManager em, final Long id) {
120-
try {
121-
return getQuery(em, "o", null, "o.id = :id", Map.of("id", id), type, null, false, null).getSingleResult();
122-
} catch (NoResultException e) {
123-
return null;
124-
}
125-
}
126-
127-
private boolean isSet(final String str) {
128-
return str != null && !str.isBlank();
129-
}
130-
131-
private boolean isSet(final Set<?> set) {
132-
return set != null && !set.isEmpty();
133-
}
134-
135-
private String buildWhereClause(final String whereClause, final Set<AsyncState> asyncStates) {
136-
String r = "";
137-
if (!isSet(whereClause) && !isSet(asyncStates))
138-
return r;
139-
140-
r = " WHERE ";
141-
if (isSet(whereClause) && !isSet(asyncStates))
142-
r += whereClause;
143-
144-
if (!isSet(whereClause) && isSet(asyncStates))
145-
r += addAsyncStatesToWhereClause(asyncStates);
146-
147-
if (isSet(whereClause) && isSet(asyncStates))
148-
r += "( " + whereClause + " ) AND ( " + addAsyncStatesToWhereClause(asyncStates) + " )";
149-
150-
return r;
151-
}
152-
153-
private String addAsyncStatesToWhereClause(final Set<AsyncState> asyncStates) {
154-
StringBuilder sb = new StringBuilder();
155-
boolean isFirst = true;
156-
157-
for (int i = 0; i < asyncStates.size(); i++) {
158-
if (isFirst)
159-
isFirst = false;
160-
else
161-
sb.append(" OR ");
162-
sb.append("state = :state");
163-
sb.append(i);
164-
}
165-
166-
return sb.toString();
167-
}
168-
169-
private <T> TypedQuery<T> addAsyncStatesParamsToQuery(final Set<AsyncState> asyncStates,
170-
final TypedQuery<T> query) {
171-
172-
if (!isSet(asyncStates))
173-
return query;
174-
175-
int count = 0;
176-
for (AsyncState state : asyncStates)
177-
query.setParameter("state" + count++, state);
178-
179-
return query;
180-
}
181-
182-
private Query addAsyncStatesParamsToQuery(final Set<AsyncState> asyncStates, final Query query) {
183-
184-
if (!isSet(asyncStates))
185-
return query;
186-
187-
int count = 0;
188-
for (AsyncState state : asyncStates)
189-
query.setParameter("state" + count++, state);
190-
191-
return query;
192-
}
193-
194-
<T> TypedQuery<T> getQuery(final EntityManager em, final String selectClause, final String joinClause,
195-
final String whereClause, final Map<String, Object> params, final Class<T> type, final String orderBy,
196-
final boolean lockPessimistic, final Set<AsyncState> asyncStates) {
197-
String query = "SELECT ";
198-
if (selectClause == null || selectClause.isBlank())
199-
query += "o";
200-
else
201-
query += selectClause;
202-
query += " FROM %s AS o";
203-
204-
if (joinClause != null && !joinClause.isBlank())
205-
query += " " + joinClause;
206-
207-
query += buildWhereClause(whereClause, asyncStates);
208-
209-
if (orderBy == null)
210-
query += " ORDER BY o.id ASC";
211-
else if (!orderBy.isBlank())
212-
query += " ORDER BY " + orderBy;
213-
214-
query = String.format(query, this.type.getSimpleName());
215-
216-
String msg = query;
217-
if (params != null)
218-
for (Entry<String, Object> p : params.entrySet())
219-
msg += "\\n " + p.getKey() + ": " + p.getValue();
220-
log.debug(msg);
221-
222-
@SuppressWarnings("unchecked")
223-
Class<T> t = (Class<T>) this.type;
224-
if (type != null)
225-
t = type;
226-
227-
TypedQuery<T> q = em.createQuery(query, t);
228-
if (lockPessimistic)
229-
q.setLockMode(LockModeType.PESSIMISTIC_WRITE);
230-
q = addAsyncStatesParamsToQuery(asyncStates, q);
231-
if (params != null)
232-
for (Entry<String, Object> e : params.entrySet())
233-
q.setParameter(e.getKey(), e.getValue());
234-
return q;
235-
}
236-
237-
<T> TypedQuery<T> getDeleteQuery(final EntityManager em, final String joinClause, final String whereClause,
238-
final Map<String, Object> params) {
239-
String query = "DELETE FROM %s AS o";
240-
241-
if (joinClause != null && !joinClause.isBlank())
242-
query += " " + joinClause;
243-
244-
query += buildWhereClause(whereClause, null);
245-
246-
query = String.format(query, this.type.getSimpleName());
247-
248-
String msg = query;
249-
if (params != null)
250-
for (Entry<String, Object> p : params.entrySet())
251-
msg += "\\n " + p.getKey() + ": " + p.getValue();
252-
log.debug(msg);
253-
254-
@SuppressWarnings("unchecked")
255-
Class<T> t = (Class<T>) this.type;
256-
257-
TypedQuery<T> q = em.createQuery(query, t);
258-
if (params != null)
259-
for (Entry<String, Object> e : params.entrySet())
260-
q.setParameter(e.getKey(), e.getValue());
261-
return q;
262-
}
263-
264-
private boolean isAllowed(final info.unterrainer.commons.httpserver.daos.ListQueryBuilder query,
265-
final EntityManager em) {
266-
String tenantReferenceField = "testId";
267-
String tenantIdField = "tenantId";
268-
Long tenantId = 55L;
269-
BasicJpa tenantJpa = null;
270-
getQuery(em, "o",
271-
"RIGHT JOIN " + tenantJpa.getClass().getSimpleName() + " tenantTable on o.id = tenantTable."
272-
+ tenantReferenceField,
273-
"tenantTable." + tenantReferenceField + " IS NULL OR tenantTable." + tenantIdField + " = :tenantId",
274-
null, type, null, false, null);
275-
return true;
276-
}
277-
278-
Query getCountQuery(final EntityManager em, final String selectClause, final String joinClause,
279-
final String whereClause, final Map<String, Object> params, final Set<AsyncState> asyncStates) {
280-
String query = "SELECT COUNT(" + selectClause + ") FROM %s AS o";
281-
if (joinClause != null && !joinClause.isBlank())
282-
query += " " + joinClause;
283-
query += buildWhereClause(whereClause, asyncStates);
284-
285-
Query q = em.createQuery(String.format(query, this.type.getSimpleName()));
286-
287-
q = addAsyncStatesParamsToQuery(asyncStates, q);
288-
if (params != null)
289-
for (Entry<String, Object> e : params.entrySet())
290-
q.setParameter(e.getKey(), e.getValue());
291-
return q;
292-
}
293105
}

‎src/main/java/info/unterrainer/commons/httpserver/daos/BasicListQueryBuilder.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,16 @@ void setSelect(final String selectClause) {
3131
}
3232

3333
public TypedQuery<T> getTypedQuery(final EntityManager em) {
34-
return dao.getQuery(em, selectClause, joinClause, whereClause, parameters, resultType, orderByClause,
34+
return dao.coreDao.getQuery(em, selectClause, joinClause, whereClause, parameters, resultType, orderByClause,
3535
lockPessimistic, null);
3636
}
3737

3838
public TypedQuery<T> getDeleteQuery(final EntityManager em) {
39-
return dao.getDeleteQuery(em, joinClause, whereClause, parameters);
39+
return dao.coreDao.getDeleteQuery(em, joinClause, whereClause, parameters);
4040
}
4141

4242
public javax.persistence.Query getCountQuery(final EntityManager em) {
43-
return dao.getCountQuery(em, selectClause, joinClause, whereClause, parameters, null);
43+
return dao.coreDao.getCountQuery(em, selectClause, joinClause, whereClause, parameters, null);
4444
}
4545

4646
/**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package info.unterrainer.commons.httpserver.daos;
2+
3+
import info.unterrainer.commons.httpserver.jsons.ListJson;
4+
import info.unterrainer.commons.rdbutils.entities.BasicJpa;
5+
6+
public interface CoreDao<P extends BasicJpa, E> {
7+
8+
DaoTransactionManager<E> getTransactionManager();
9+
10+
P create(E manager, P mappedJpa);
11+
12+
P getById(E manager, Long id);
13+
14+
ListJson<P> getList(E manager, Long offset, Long size, String selectClause, String joinClause, String whereClause,
15+
ParamMap params, String orderByClause);
16+
17+
void delete(E manager, Long id);
18+
19+
P update(E manager, P mappedJpa);
20+
}

‎src/main/java/info/unterrainer/commons/httpserver/daos/BasicDao.java ‎src/main/java/info/unterrainer/commons/httpserver/daos/CoreDaoProvider.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import info.unterrainer.commons.rdbutils.entities.BasicJpa;
44

5-
public interface BasicDao<P extends BasicJpa, E> {
5+
public interface CoreDaoProvider<P extends BasicJpa, E> {
66

7+
CoreDao<P, E> getCoreDao();
78
}

‎src/main/java/info/unterrainer/commons/httpserver/daos/CountQueryBuilder.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@ public class CountQueryBuilder<P extends BasicJpa> extends BasicListQueryBuilder
1313

1414
public Long build() {
1515
if (entityManager != null)
16-
return (Long) dao.getCountQuery(entityManager, selectClause, joinClause, whereClause, parameters, null)
16+
return (Long) dao.coreDao
17+
.getCountQuery(entityManager, selectClause, joinClause, whereClause, parameters, null)
1718
.getSingleResult();
1819
return (Long) Transactions.withNewTransactionReturning(emf,
19-
em -> dao.getCountQuery(em, selectClause, joinClause, whereClause, parameters, null).getSingleResult());
20+
em -> dao.coreDao.getCountQuery(em, selectClause, joinClause, whereClause, parameters, null)
21+
.getSingleResult());
2022
}
2123
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
package info.unterrainer.commons.httpserver.daos;
2+
3+
import java.time.LocalDateTime;
4+
import java.util.List;
5+
import java.util.Map;
6+
import java.util.Map.Entry;
7+
import java.util.Set;
8+
9+
import javax.persistence.EntityManager;
10+
import javax.persistence.EntityManagerFactory;
11+
import javax.persistence.LockModeType;
12+
import javax.persistence.NoResultException;
13+
import javax.persistence.Query;
14+
import javax.persistence.TypedQuery;
15+
16+
import info.unterrainer.commons.httpserver.jsons.ListJson;
17+
import info.unterrainer.commons.jreutils.DateUtils;
18+
import info.unterrainer.commons.rdbutils.entities.BasicJpa;
19+
import info.unterrainer.commons.rdbutils.enums.AsyncState;
20+
import lombok.Getter;
21+
22+
public class JpqlCoreDao<P extends BasicJpa> implements CoreDao<P, EntityManager> {
23+
24+
protected final EntityManagerFactory emf;
25+
protected final Class<P> type;
26+
@Getter
27+
protected JpqlTransactionManager transactionManager;
28+
29+
public JpqlCoreDao(final EntityManagerFactory emf, final Class<P> type) {
30+
super();
31+
this.emf = emf;
32+
this.type = type;
33+
transactionManager = new JpqlTransactionManager(emf);
34+
}
35+
36+
@Override
37+
public P create(final EntityManager em, final P entity) {
38+
LocalDateTime time = DateUtils.nowUtc();
39+
entity.setCreatedOn(time);
40+
entity.setEditedOn(time);
41+
em.persist(entity);
42+
return entity;
43+
}
44+
45+
@Override
46+
public void delete(final EntityManager em, final Long id) {
47+
em.createQuery(String.format("DELETE FROM %s AS o WHERE o.id = :id", type.getSimpleName()))
48+
.setParameter("id", id)
49+
.executeUpdate();
50+
}
51+
52+
@Override
53+
public P getById(final EntityManager em, final Long id) {
54+
try {
55+
return getQuery(em, "o", null, "o.id = :id", Map.of("id", id), type, null, false, null).getSingleResult();
56+
} catch (NoResultException e) {
57+
return null;
58+
}
59+
}
60+
61+
@Override
62+
public ListJson<P> getList(final EntityManager em, final Long offset, final Long size, final String selectClause,
63+
final String joinClause, final String whereClause, final ParamMap params, final String orderByClause) {
64+
ListJson<P> r = new ListJson<>();
65+
r.setEntries(
66+
getList(em,
67+
getQuery(em, selectClause, joinClause, whereClause,
68+
params == null ? null : params.getParameters(), type, orderByClause, false, null),
69+
offset, size));
70+
r.setCount((Long) getCountQuery(em, selectClause, joinClause, whereClause,
71+
params == null ? null : params.getParameters(), null).getSingleResult());
72+
return r;
73+
}
74+
75+
@Override
76+
public P update(final EntityManager em, final P entity) {
77+
LocalDateTime time = DateUtils.nowUtc();
78+
entity.setEditedOn(time);
79+
return em.merge(entity);
80+
}
81+
82+
<T> TypedQuery<T> getQuery(final EntityManager em, final String selectClause, final String joinClause,
83+
final String whereClause, final Map<String, Object> params, final Class<T> type, final String orderBy,
84+
final boolean lockPessimistic, final Set<AsyncState> asyncStates) {
85+
String query = "SELECT ";
86+
if (selectClause == null || selectClause.isBlank())
87+
query += "o";
88+
else
89+
query += selectClause;
90+
query += " FROM %s AS o";
91+
92+
if (joinClause != null && !joinClause.isBlank())
93+
query += " " + joinClause;
94+
95+
query += buildWhereClause(whereClause, asyncStates);
96+
97+
if (orderBy == null)
98+
query += " ORDER BY o.id ASC";
99+
else if (!orderBy.isBlank())
100+
query += " ORDER BY " + orderBy;
101+
102+
query = String.format(query, this.type.getSimpleName());
103+
104+
@SuppressWarnings("unchecked")
105+
Class<T> t = (Class<T>) this.type;
106+
if (type != null)
107+
t = type;
108+
109+
TypedQuery<T> q = em.createQuery(query, t);
110+
if (lockPessimistic)
111+
q.setLockMode(LockModeType.PESSIMISTIC_WRITE);
112+
q = addAsyncStatesParamsToQuery(asyncStates, q);
113+
if (params != null)
114+
for (Entry<String, Object> e : params.entrySet())
115+
q.setParameter(e.getKey(), e.getValue());
116+
return q;
117+
}
118+
119+
<T> TypedQuery<T> getDeleteQuery(final EntityManager em, final String joinClause, final String whereClause,
120+
final Map<String, Object> params) {
121+
String query = "DELETE FROM %s AS o";
122+
123+
if (joinClause != null && !joinClause.isBlank())
124+
query += " " + joinClause;
125+
126+
query += buildWhereClause(whereClause, null);
127+
128+
query = String.format(query, this.type.getSimpleName());
129+
130+
@SuppressWarnings("unchecked")
131+
Class<T> t = (Class<T>) this.type;
132+
133+
TypedQuery<T> q = em.createQuery(query, t);
134+
if (params != null)
135+
for (Entry<String, Object> e : params.entrySet())
136+
q.setParameter(e.getKey(), e.getValue());
137+
return q;
138+
}
139+
140+
Query getCountQuery(final EntityManager em, final String selectClause, final String joinClause,
141+
final String whereClause, final Map<String, Object> params, final Set<AsyncState> asyncStates) {
142+
String query = "SELECT COUNT(";
143+
if (selectClause == null || selectClause.isBlank())
144+
query += "o.id";
145+
else
146+
query += selectClause;
147+
query += ") FROM %s AS o";
148+
if (joinClause != null && !joinClause.isBlank())
149+
query += " " + joinClause;
150+
query += buildWhereClause(whereClause, asyncStates);
151+
152+
Query q = em.createQuery(String.format(query, this.type.getSimpleName()));
153+
154+
q = addAsyncStatesParamsToQuery(asyncStates, q);
155+
if (params != null)
156+
for (Entry<String, Object> e : params.entrySet())
157+
q.setParameter(e.getKey(), e.getValue());
158+
return q;
159+
}
160+
161+
<T> List<T> getList(final EntityManager em, final TypedQuery<T> query, final long offset, final long size) {
162+
int s = Integer.MAX_VALUE;
163+
if (size < s)
164+
s = (int) size;
165+
int o = Integer.MAX_VALUE;
166+
if (offset < o)
167+
o = (int) offset;
168+
query.setFirstResult(o);
169+
query.setMaxResults(s);
170+
return query.getResultList();
171+
}
172+
173+
private boolean isAllowed(final info.unterrainer.commons.httpserver.daos.ListQueryBuilder query,
174+
final EntityManager em) {
175+
String tenantReferenceField = "testId";
176+
String tenantIdField = "tenantId";
177+
Long tenantId = 55L;
178+
BasicJpa tenantJpa = null;
179+
getQuery(em, "o",
180+
"RIGHT JOIN " + tenantJpa.getClass().getSimpleName() + " tenantTable on o.id = tenantTable."
181+
+ tenantReferenceField,
182+
"tenantTable." + tenantReferenceField + " IS NULL OR tenantTable." + tenantIdField + " = :tenantId",
183+
null, type, null, false, null);
184+
return true;
185+
}
186+
187+
private boolean isSet(final String str) {
188+
return str != null && !str.isBlank();
189+
}
190+
191+
private boolean isSet(final Set<?> set) {
192+
return set != null && !set.isEmpty();
193+
}
194+
195+
private String buildWhereClause(final String whereClause, final Set<AsyncState> asyncStates) {
196+
String r = "";
197+
if (!isSet(whereClause) && !isSet(asyncStates))
198+
return r;
199+
200+
r = " WHERE ";
201+
if (isSet(whereClause) && !isSet(asyncStates))
202+
r += whereClause;
203+
204+
if (!isSet(whereClause) && isSet(asyncStates))
205+
r += addAsyncStatesToWhereClause(asyncStates);
206+
207+
if (isSet(whereClause) && isSet(asyncStates))
208+
r += "( " + whereClause + " ) AND ( " + addAsyncStatesToWhereClause(asyncStates) + " )";
209+
210+
return r;
211+
}
212+
213+
private String addAsyncStatesToWhereClause(final Set<AsyncState> asyncStates) {
214+
StringBuilder sb = new StringBuilder();
215+
boolean isFirst = true;
216+
217+
for (int i = 0; i < asyncStates.size(); i++) {
218+
if (isFirst)
219+
isFirst = false;
220+
else
221+
sb.append(" OR ");
222+
sb.append("state = :state");
223+
sb.append(i);
224+
}
225+
226+
return sb.toString();
227+
}
228+
229+
private <T> TypedQuery<T> addAsyncStatesParamsToQuery(final Set<AsyncState> asyncStates,
230+
final TypedQuery<T> query) {
231+
232+
if (!isSet(asyncStates))
233+
return query;
234+
235+
int count = 0;
236+
for (AsyncState state : asyncStates)
237+
query.setParameter("state" + count++, state);
238+
239+
return query;
240+
}
241+
242+
private Query addAsyncStatesParamsToQuery(final Set<AsyncState> asyncStates, final Query query) {
243+
244+
if (!isSet(asyncStates))
245+
return query;
246+
247+
int count = 0;
248+
for (AsyncState state : asyncStates)
249+
query.setParameter("state" + count++, state);
250+
251+
return query;
252+
}
253+
}

‎src/main/java/info/unterrainer/commons/httpserver/daos/JpqlDao.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
package info.unterrainer.commons.httpserver.daos;
22

3-
import javax.persistence.EntityManager;
43
import javax.persistence.EntityManagerFactory;
54

65
import info.unterrainer.commons.rdbutils.entities.BasicJpa;
76

8-
public class JpqlDao<P extends BasicJpa> extends BasicJpqlDao<P> implements BasicDao<P, EntityManager> {
7+
public class JpqlDao<P extends BasicJpa> extends BasicJpqlDao<P> {
98

109
/**
1110
* Generates a DAO that lets you build and execute queries.

‎src/main/java/info/unterrainer/commons/httpserver/daos/SingleQueryBuilder.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ protected <V> V withEntityManager(final Function<EntityManager, V> func) {
3131
*/
3232
public P get() {
3333
return withEntityManager(
34-
em -> dao.getQuery(em, "o", null, "o.id = :id", Map.of("id", id), dao.type, null, false, null)
34+
em -> dao.coreDao.getQuery(em, "o", null, "o.id = :id", Map.of("id", id), dao.type, null, false, null)
3535
.getSingleResult());
3636
}
3737

‎src/test/java/info/unterrainer/commons/httpserver/scripts/LocalTestServer.java

+1-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import info.unterrainer.commons.httpserver.HttpServer;
66
import info.unterrainer.commons.httpserver.accessmanager.RoleBuilder;
77
import info.unterrainer.commons.httpserver.daos.JpqlDao;
8-
import info.unterrainer.commons.httpserver.daos.JpqlTransactionManager;
98
import info.unterrainer.commons.httpserver.enums.Endpoint;
109
import info.unterrainer.commons.httpserver.scripts.handlers.StatusHandler;
1110
import info.unterrainer.commons.httpserver.scripts.jpas.TestJpa;
@@ -45,10 +44,9 @@ private static void startServer() {
4544

4645
server.get("/status", new StatusHandler(mapper), RoleBuilder.authenticated());
4746
server.get("/status2", new StatusHandler(mapper), RoleBuilder.named("admin"));
48-
server.handlerGroupFor(TestJpa.class, TestJson.class, new JpqlTransactionManager(emf))
47+
server.handlerGroupFor(TestJpa.class, TestJson.class, new JpqlDao<>(emf, TestJpa.class))
4948
.path("/test")
5049
.endpoints(Endpoint.ALL)
51-
.dao(new JpqlDao<>(emf, TestJpa.class))
5250
.jsonMapper(mapper)
5351
.addRoleFor(Endpoint.ALL, RoleBuilder.authenticated())
5452
.addRoleFor(Endpoint.GET_SINGLE, RoleBuilder.named("user"))

0 commit comments

Comments
 (0)
Please sign in to comment.