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.logic;
20  
21  import java.lang.reflect.Method;
22  import java.util.ArrayList;
23  import java.util.List;
24  import java.util.Optional;
25  import java.util.stream.Collectors;
26  import org.apache.commons.lang3.ArrayUtils;
27  import org.apache.commons.lang3.StringUtils;
28  import org.apache.syncope.common.lib.SyncopeClientException;
29  import org.apache.syncope.common.lib.to.DerSchemaTO;
30  import org.apache.syncope.common.lib.to.PlainSchemaTO;
31  import org.apache.syncope.common.lib.to.SchemaTO;
32  import org.apache.syncope.common.lib.to.VirSchemaTO;
33  import org.apache.syncope.common.lib.types.AnyTypeKind;
34  import org.apache.syncope.common.lib.types.ClientExceptionType;
35  import org.apache.syncope.common.lib.types.IdRepoEntitlement;
36  import org.apache.syncope.common.lib.types.SchemaType;
37  import org.apache.syncope.core.persistence.api.dao.AnyTypeClassDAO;
38  import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO;
39  import org.apache.syncope.core.persistence.api.dao.DuplicateException;
40  import org.apache.syncope.core.persistence.api.dao.NotFoundException;
41  import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
42  import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
43  import org.apache.syncope.core.persistence.api.entity.AnyTypeClass;
44  import org.apache.syncope.core.persistence.api.entity.DerSchema;
45  import org.apache.syncope.core.persistence.api.entity.PlainSchema;
46  import org.apache.syncope.core.persistence.api.entity.VirSchema;
47  import org.apache.syncope.core.provisioning.api.data.SchemaDataBinder;
48  import org.springframework.security.access.prepost.PreAuthorize;
49  import org.springframework.transaction.annotation.Transactional;
50  
51  public class SchemaLogic extends AbstractTransactionalLogic<SchemaTO> {
52  
53      protected final PlainSchemaDAO plainSchemaDAO;
54  
55      protected final DerSchemaDAO derSchemaDAO;
56  
57      protected final VirSchemaDAO virSchemaDAO;
58  
59      protected final AnyTypeClassDAO anyTypeClassDAO;
60  
61      protected final SchemaDataBinder binder;
62  
63      public SchemaLogic(
64              final PlainSchemaDAO plainSchemaDAO,
65              final DerSchemaDAO derSchemaDAO,
66              final VirSchemaDAO virSchemaDAO,
67              final AnyTypeClassDAO anyTypeClassDAO,
68              final SchemaDataBinder binder) {
69  
70          this.plainSchemaDAO = plainSchemaDAO;
71          this.derSchemaDAO = derSchemaDAO;
72          this.virSchemaDAO = virSchemaDAO;
73          this.anyTypeClassDAO = anyTypeClassDAO;
74          this.binder = binder;
75      }
76  
77      protected boolean doesSchemaExist(final SchemaType schemaType, final String name) {
78          boolean found;
79  
80          switch (schemaType) {
81              case VIRTUAL:
82                  found = virSchemaDAO.find(name) != null;
83                  break;
84  
85              case DERIVED:
86                  found = derSchemaDAO.find(name) != null;
87                  break;
88  
89              case PLAIN:
90                  found = plainSchemaDAO.find(name) != null;
91                  break;
92  
93              default:
94                  found = false;
95          }
96  
97          return found;
98      }
99  
100     @PreAuthorize("hasRole('" + IdRepoEntitlement.SCHEMA_CREATE + "')")
101     @SuppressWarnings("unchecked")
102     public <T extends SchemaTO> T create(final SchemaType schemaType, final T schemaTO) {
103         if (StringUtils.isBlank(schemaTO.getKey())) {
104             SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.RequiredValuesMissing);
105             sce.getElements().add("Schema key");
106             throw sce;
107         }
108 
109         if (doesSchemaExist(schemaType, schemaTO.getKey())) {
110             throw new DuplicateException(schemaType + "/" + schemaTO.getKey());
111         }
112 
113         T created;
114         switch (schemaType) {
115             case VIRTUAL:
116                 created = (T) binder.getVirSchemaTO(binder.create((VirSchemaTO) schemaTO).getKey());
117                 break;
118 
119             case DERIVED:
120                 created = (T) binder.getDerSchemaTO(binder.create((DerSchemaTO) schemaTO).getKey());
121                 break;
122 
123             case PLAIN:
124             default:
125                 created = (T) binder.getPlainSchemaTO(binder.create((PlainSchemaTO) schemaTO).getKey());
126         }
127         return created;
128     }
129 
130     @PreAuthorize("hasRole('" + IdRepoEntitlement.SCHEMA_DELETE + "')")
131     public void delete(final SchemaType schemaType, final String schemaKey) {
132         if (!doesSchemaExist(schemaType, schemaKey)) {
133             throw new NotFoundException(schemaType + "/" + schemaKey);
134         }
135 
136         switch (schemaType) {
137             case VIRTUAL:
138                 virSchemaDAO.delete(schemaKey);
139                 break;
140 
141             case DERIVED:
142                 derSchemaDAO.delete(schemaKey);
143                 break;
144 
145             case PLAIN:
146             default:
147                 plainSchemaDAO.delete(schemaKey);
148         }
149     }
150 
151     @PreAuthorize("isAuthenticated()")
152     @Transactional(readOnly = true)
153     @SuppressWarnings("unchecked")
154     public <T extends SchemaTO> List<T> search(
155             final SchemaType schemaType, final List<String> anyTypeClasses, final String keyword) {
156 
157         List<AnyTypeClass> classes = new ArrayList<>(Optional.ofNullable(anyTypeClasses).map(List::size).orElse(0));
158         if (anyTypeClasses != null) {
159             anyTypeClasses.remove(AnyTypeKind.USER.name());
160             anyTypeClasses.remove(AnyTypeKind.GROUP.name());
161             anyTypeClasses.forEach(anyTypeClass -> {
162                 AnyTypeClass clazz = anyTypeClassDAO.find(anyTypeClass);
163                 if (clazz == null) {
164                     LOG.warn("Ignoring invalid {}: {}", AnyTypeClass.class.getSimpleName(), anyTypeClass);
165                 } else {
166                     classes.add(clazz);
167                 }
168             });
169         }
170 
171         List<T> result;
172         switch (schemaType) {
173             case VIRTUAL:
174                 result = (classes.isEmpty()
175                         ? Optional.ofNullable(keyword).
176                                 map(k -> virSchemaDAO.findByKeyword(k)).
177                                 orElseGet(() -> virSchemaDAO.findAll())
178                         : virSchemaDAO.findByAnyTypeClasses(classes)).stream().
179                         map(schema -> (T) binder.getVirSchemaTO(schema.getKey())).collect(Collectors.toList());
180                 break;
181 
182             case DERIVED:
183                 result = (classes.isEmpty()
184                         ? Optional.ofNullable(keyword).
185                                 map(k -> derSchemaDAO.findByKeyword(k)).
186                                 orElseGet(() -> derSchemaDAO.findAll())
187                         : derSchemaDAO.findByAnyTypeClasses(classes)).stream().
188                         map(schema -> (T) binder.getDerSchemaTO(schema.getKey())).collect(Collectors.toList());
189                 break;
190 
191             case PLAIN:
192             default:
193                 result = (classes.isEmpty()
194                         ? Optional.ofNullable(keyword).
195                                 map(k -> plainSchemaDAO.findByKeyword(k)).
196                                 orElseGet(() -> plainSchemaDAO.findAll())
197                         : plainSchemaDAO.findByAnyTypeClasses(classes)).stream().
198                         map(schema -> (T) binder.getPlainSchemaTO(schema.getKey())).collect(Collectors.toList());
199         }
200 
201         return result;
202     }
203 
204     @PreAuthorize("isAuthenticated()")
205     @SuppressWarnings("unchecked")
206     public <T extends SchemaTO> T read(final SchemaType schemaType, final String schemaKey) {
207         T read;
208         switch (schemaType) {
209             case VIRTUAL:
210                 read = (T) binder.getVirSchemaTO(schemaKey);
211                 break;
212 
213             case DERIVED:
214                 read = (T) binder.getDerSchemaTO(schemaKey);
215                 break;
216 
217             case PLAIN:
218             default:
219                 read = (T) binder.getPlainSchemaTO(schemaKey);
220         }
221 
222         return read;
223     }
224 
225     @PreAuthorize("hasRole('" + IdRepoEntitlement.SCHEMA_UPDATE + "')")
226     public <T extends SchemaTO> void update(final SchemaType schemaType, final T schemaTO) {
227         if (!doesSchemaExist(schemaType, schemaTO.getKey())) {
228             throw new NotFoundException(schemaType + "/" + schemaTO.getKey());
229         }
230 
231         switch (schemaType) {
232             case VIRTUAL:
233                 VirSchema virSchema = Optional.ofNullable(virSchemaDAO.find(schemaTO.getKey())).
234                         orElseThrow(() -> new NotFoundException("Virtual Schema '" + schemaTO.getKey() + '\''));
235 
236                 binder.update((VirSchemaTO) schemaTO, virSchema);
237                 break;
238 
239             case DERIVED:
240                 DerSchema derSchema = Optional.ofNullable(derSchemaDAO.find(schemaTO.getKey())).
241                         orElseThrow(() -> new NotFoundException("Derived Schema '" + schemaTO.getKey() + '\''));
242 
243                 binder.update((DerSchemaTO) schemaTO, derSchema);
244                 break;
245 
246             case PLAIN:
247             default:
248                 PlainSchema plainSchema = Optional.ofNullable(plainSchemaDAO.find(schemaTO.getKey())).
249                         orElseThrow(() -> new NotFoundException("Plain Schema '" + schemaTO.getKey() + '\''));
250 
251                 binder.update((PlainSchemaTO) schemaTO, plainSchema);
252         }
253     }
254 
255     @Override
256     protected SchemaTO resolveReference(final Method method, final Object... args)
257             throws UnresolvedReferenceException {
258 
259         String key = null;
260         if (ArrayUtils.isNotEmpty(args)) {
261             for (int i = 0; key == null && i < args.length; i++) {
262                 if (args[i] instanceof String) {
263                     key = (String) args[i];
264                 } else if (args[i] instanceof SchemaTO) {
265                     key = ((SchemaTO) args[i]).getKey();
266                 }
267             }
268         }
269 
270         if (key != null) {
271             try {
272                 SchemaTO result = null;
273 
274                 PlainSchema plainSchema = plainSchemaDAO.find(key);
275                 if (plainSchema == null) {
276                     DerSchema derSchema = derSchemaDAO.find(key);
277                     if (derSchema == null) {
278                         VirSchema virSchema = virSchemaDAO.find(key);
279                         if (virSchema != null) {
280                             result = binder.getVirSchemaTO(key);
281                         }
282                     } else {
283                         result = binder.getDerSchemaTO(key);
284                     }
285                 } else {
286                     result = binder.getPlainSchemaTO(key);
287                 }
288 
289                 return result;
290             } catch (Throwable ignore) {
291                 LOG.debug("Unresolved reference", ignore);
292                 throw new UnresolvedReferenceException(ignore);
293             }
294         }
295 
296         throw new UnresolvedReferenceException();
297     }
298 }