View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.syncope.core.rest.cxf.service;
20  
21  import java.net.URI;
22  import java.util.HashSet;
23  import java.util.List;
24  import java.util.Map;
25  import java.util.Set;
26  import javax.ws.rs.core.MultivaluedMap;
27  import javax.ws.rs.core.Response;
28  import javax.ws.rs.core.UriBuilder;
29  import org.apache.commons.lang3.StringUtils;
30  import org.apache.commons.lang3.exception.ExceptionUtils;
31  import org.apache.commons.lang3.tuple.Pair;
32  import org.apache.cxf.jaxrs.ext.search.SearchBean;
33  import org.apache.cxf.jaxrs.ext.search.SearchCondition;
34  import org.apache.syncope.common.lib.SyncopeClientException;
35  import org.apache.syncope.common.lib.SyncopeConstants;
36  import org.apache.syncope.common.lib.to.ConnObject;
37  import org.apache.syncope.common.lib.to.PagedConnObjectResult;
38  import org.apache.syncope.common.lib.to.ResourceTO;
39  import org.apache.syncope.common.lib.types.ClientExceptionType;
40  import org.apache.syncope.common.rest.api.RESTHeaders;
41  import org.apache.syncope.common.rest.api.beans.ConnObjectTOQuery;
42  import org.apache.syncope.common.rest.api.service.ResourceService;
43  import org.apache.syncope.core.logic.ResourceLogic;
44  import org.apache.syncope.core.persistence.api.search.FilterVisitor;
45  import org.identityconnectors.framework.common.objects.SearchResult;
46  import org.identityconnectors.framework.common.objects.filter.Filter;
47  import org.springframework.stereotype.Service;
48  
49  @Service
50  public class ResourceServiceImpl extends AbstractService implements ResourceService {
51  
52      protected final ResourceLogic logic;
53  
54      public ResourceServiceImpl(final ResourceLogic logic) {
55          this.logic = logic;
56      }
57  
58      @Override
59      public Response create(final ResourceTO resourceTO) {
60          ResourceTO created = logic.create(resourceTO);
61          URI location = uriInfo.getAbsolutePathBuilder().path(created.getKey()).build();
62          return Response.created(location).
63                  header(RESTHeaders.RESOURCE_KEY, created.getKey()).
64                  build();
65      }
66  
67      @Override
68      public void update(final ResourceTO resourceTO) {
69          logic.update(resourceTO);
70      }
71  
72      @Override
73      public void setLatestSyncToken(final String key, final String anyTypeKey) {
74          logic.setLatestSyncToken(key, anyTypeKey);
75      }
76  
77      @Override
78      public void removeSyncToken(final String key, final String anyTypeKey) {
79          logic.removeSyncToken(key, anyTypeKey);
80      }
81  
82      @Override
83      public void delete(final String key) {
84          logic.delete(key);
85      }
86  
87      @Override
88      public ResourceTO read(final String key) {
89          return logic.read(key);
90      }
91  
92      @Override
93      public List<ResourceTO> list() {
94          return logic.list();
95      }
96  
97      @Override
98      public Response getConnObjectKeyValue(final String key, final String anyTypeKey, final String anyKey) {
99          String connObjectKeyValue = logic.getConnObjectKeyValue(key, anyTypeKey, anyKey);
100         return Response.noContent().header(RESTHeaders.CONNOBJECT_KEY, connObjectKeyValue).build();
101     }
102 
103     @Override
104     public ConnObject readConnObject(final String key, final String anyTypeKey, final String value) {
105         return SyncopeConstants.UUID_PATTERN.matcher(value).matches()
106                 ? logic.readConnObjectByAnyKey(key, anyTypeKey, value)
107                 : logic.readConnObjectByConnObjectKeyValue(key, anyTypeKey, value);
108     }
109 
110     @Override
111     public PagedConnObjectResult searchConnObjects(
112             final String key, final String anyTypeKey, final ConnObjectTOQuery query) {
113 
114         Filter filter = null;
115         Set<String> moreAttrsToGet = new HashSet<>();
116         if (query.getMoreAttrsToGet() != null) {
117             moreAttrsToGet.addAll(query.getMoreAttrsToGet());
118         }
119         if (StringUtils.isNotBlank(query.getFiql())) {
120             try {
121                 FilterVisitor visitor = new FilterVisitor();
122                 SearchCondition<SearchBean> sc = searchContext.getCondition(query.getFiql(), SearchBean.class);
123                 sc.accept(visitor);
124 
125                 filter = visitor.getQuery();
126                 moreAttrsToGet.addAll(visitor.getAttrs());
127             } catch (Exception e) {
128                 LOG.error("Invalid FIQL expression: {}", query.getFiql(), e);
129 
130                 SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidSearchParameters);
131                 sce.getElements().add(query.getFiql());
132                 sce.getElements().add(ExceptionUtils.getRootCauseMessage(e));
133                 throw sce;
134             }
135         }
136 
137         Pair<SearchResult, List<ConnObject>> list = logic.searchConnObjects(
138                 filter,
139                 moreAttrsToGet,
140                 key,
141                 anyTypeKey,
142                 query.getSize(),
143                 query.getPagedResultsCookie(),
144                 getOrderByClauses(query.getOrderBy()));
145 
146         PagedConnObjectResult result = new PagedConnObjectResult();
147         if (list.getLeft() != null) {
148             result.setAllResultsReturned(list.getLeft().isAllResultsReturned());
149             result.setPagedResultsCookie(list.getLeft().getPagedResultsCookie());
150             result.setRemainingPagedResults(list.getLeft().getRemainingPagedResults());
151         }
152         result.getResult().addAll(list.getRight());
153 
154         UriBuilder builder = uriInfo.getAbsolutePathBuilder();
155         MultivaluedMap<String, String> queryParams = uriInfo.getQueryParameters();
156         for (Map.Entry<String, List<String>> queryParam : queryParams.entrySet()) {
157             builder = builder.queryParam(queryParam.getKey(), queryParam.getValue().toArray());
158         }
159 
160         if (StringUtils.isNotBlank(result.getPagedResultsCookie())) {
161             result.setNext(builder.
162                     replaceQueryParam(PARAM_CONNID_PAGED_RESULTS_COOKIE, result.getPagedResultsCookie()).
163                     replaceQueryParam(PARAM_SIZE, query.getSize()).
164                     build());
165         }
166 
167         return result;
168     }
169 
170     @Override
171     public void check(final ResourceTO resourceTO) {
172         logic.check(resourceTO);
173     }
174 }