1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.core.rest.cxf.service;
20
21 import java.util.ArrayList;
22 import java.util.List;
23 import javax.ws.rs.core.Context;
24 import javax.ws.rs.core.EntityTag;
25 import javax.ws.rs.core.MultivaluedMap;
26 import javax.ws.rs.core.Response;
27 import javax.ws.rs.core.UriBuilder;
28 import javax.ws.rs.core.UriInfo;
29 import org.apache.commons.lang3.BooleanUtils;
30 import org.apache.commons.lang3.StringUtils;
31 import org.apache.cxf.jaxrs.ext.MessageContext;
32 import org.apache.cxf.jaxrs.ext.search.SearchContext;
33 import org.apache.syncope.common.lib.BaseBean;
34 import org.apache.syncope.common.lib.SyncopeClientException;
35 import org.apache.syncope.common.lib.SyncopeConstants;
36 import org.apache.syncope.common.lib.to.PagedResult;
37 import org.apache.syncope.common.lib.to.ProvisioningResult;
38 import org.apache.syncope.common.lib.types.ClientExceptionType;
39 import org.apache.syncope.common.rest.api.Preference;
40 import org.apache.syncope.common.rest.api.RESTHeaders;
41 import org.apache.syncope.common.rest.api.service.JAXRSService;
42 import org.apache.syncope.core.persistence.api.dao.AnyDAO;
43 import org.apache.syncope.core.persistence.api.dao.GroupDAO;
44 import org.apache.syncope.core.persistence.api.dao.UserDAO;
45 import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49 public abstract class AbstractService implements JAXRSService {
50
51 protected static final Logger LOG = LoggerFactory.getLogger(AbstractService.class);
52
53 protected static final String OPTIONS_ALLOW = "GET,POST,OPTIONS,HEAD";
54
55 @Context
56 protected UriInfo uriInfo;
57
58 @Context
59 protected MessageContext messageContext;
60
61 @Context
62 protected SearchContext searchContext;
63
64 protected String findActualKey(final AnyDAO<?> dao, final String pretendingKey) {
65 String actualKey = pretendingKey;
66 if (uriInfo.getPathParameters(true).containsKey("key")) {
67 String keyInPath = uriInfo.getPathParameters(true).get("key").get(0);
68 if (actualKey == null) {
69 actualKey = keyInPath;
70 } else if (!actualKey.equals(keyInPath)) {
71 SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidRequest);
72 sce.getElements().add("Key specified in request does not match key in the path");
73 throw sce;
74 }
75 }
76 if (actualKey == null) {
77 SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidRequest);
78 sce.getElements().add("Key is null");
79 throw sce;
80 }
81 if (!SyncopeConstants.UUID_PATTERN.matcher(actualKey).matches()) {
82 actualKey = dao instanceof UserDAO
83 ? ((UserDAO) dao).findKey(actualKey)
84 : dao instanceof GroupDAO
85 ? ((GroupDAO) dao).findKey(actualKey)
86 : null;
87 }
88 return actualKey;
89 }
90
91 protected boolean isNullPriorityAsync() {
92 return BooleanUtils.toBoolean(
93 messageContext.getHttpServletRequest().getHeader(RESTHeaders.NULL_PRIORITY_ASYNC));
94 }
95
96
97
98
99
100
101
102 protected Preference getPreference() {
103 return Preference.fromString(messageContext.getHttpServletRequest().getHeader(RESTHeaders.PREFER));
104 }
105
106 protected Response.ResponseBuilder applyPreference(
107 final ProvisioningResult<?> provisioningResult, final Response.ResponseBuilder builder) {
108
109 switch (getPreference()) {
110 case RETURN_NO_CONTENT:
111 break;
112
113 case RETURN_CONTENT:
114 case NONE:
115 default:
116 builder.entity(provisioningResult);
117 break;
118
119 }
120 if (getPreference() == Preference.RETURN_CONTENT || getPreference() == Preference.RETURN_NO_CONTENT) {
121 builder.header(RESTHeaders.PREFERENCE_APPLIED, getPreference().toString());
122 }
123
124 return builder;
125 }
126
127
128
129
130
131
132
133 protected Response createResponse(final ProvisioningResult<?> provisioningResult) {
134 String entityId = provisioningResult.getEntity().getKey();
135 Response.ResponseBuilder builder = Response.
136 created(uriInfo.getAbsolutePathBuilder().path(entityId).build()).
137 header(RESTHeaders.RESOURCE_KEY, entityId);
138
139 return applyPreference(provisioningResult, builder).build();
140 }
141
142
143
144
145
146
147
148 protected Response modificationResponse(final Object entity) {
149 Response.ResponseBuilder builder;
150 switch (getPreference()) {
151 case RETURN_NO_CONTENT:
152 builder = Response.noContent();
153 break;
154
155 case RETURN_CONTENT:
156 case NONE:
157 default:
158 builder = Response.ok(entity);
159 break;
160 }
161 if (getPreference() == Preference.RETURN_CONTENT || getPreference() == Preference.RETURN_NO_CONTENT) {
162 builder.header(RESTHeaders.PREFERENCE_APPLIED, getPreference().toString());
163 }
164
165 return builder.build();
166 }
167
168 protected void checkETag(final String etag) {
169 Response.ResponseBuilder builder = messageContext.getRequest().evaluatePreconditions(new EntityTag(etag));
170 if (builder != null) {
171 SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.ConcurrentModification);
172 sce.getElements().add("Mismatching ETag value");
173 throw sce;
174 }
175 }
176
177 protected List<OrderByClause> getOrderByClauses(final String orderBy) {
178 if (StringUtils.isBlank(orderBy)) {
179 return List.of();
180 }
181
182 List<OrderByClause> result = new ArrayList<>();
183
184 for (String clause : orderBy.split(",")) {
185 String[] elems = clause.trim().split(" ");
186
187 if (elems.length > 0 && StringUtils.isNotBlank(elems[0])) {
188 OrderByClause obc = new OrderByClause();
189 obc.setField(elems[0].trim());
190 if (elems.length > 1 && StringUtils.isNotBlank(elems[1])) {
191 obc.setDirection(elems[1].trim().equalsIgnoreCase(OrderByClause.Direction.ASC.name())
192 ? OrderByClause.Direction.ASC : OrderByClause.Direction.DESC);
193 }
194 result.add(obc);
195 }
196 }
197
198 return result;
199 }
200
201
202
203
204
205
206
207
208
209
210
211 protected <T extends BaseBean> PagedResult<T> buildPagedResult(
212 final List<T> list, final int page, final int size, final int totalCount) {
213
214 PagedResult<T> result = new PagedResult<>();
215 result.getResult().addAll(list);
216
217 result.setPage(page);
218 result.setSize(result.getResult().size());
219 result.setTotalCount(totalCount);
220
221 UriBuilder builder = uriInfo.getAbsolutePathBuilder();
222 MultivaluedMap<String, String> queryParams = uriInfo.getQueryParameters();
223 queryParams.forEach((key, value) -> builder.queryParam(key, value.toArray()));
224
225 if (result.getPage() > 1) {
226 result.setPrev(builder.
227 replaceQueryParam(PARAM_PAGE, result.getPage() - 1).
228 replaceQueryParam(PARAM_SIZE, size).
229 build());
230 }
231 if ((result.getPage() - 1) * size + result.getSize() < totalCount) {
232 result.setNext(builder.
233 replaceQueryParam(PARAM_PAGE, result.getPage() + 1).
234 replaceQueryParam(PARAM_SIZE, size).
235 build());
236 }
237
238 return result;
239 }
240 }