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.provisioning.java.data;
20  
21  import org.apache.commons.lang3.StringUtils;
22  import org.apache.syncope.common.lib.SyncopeClientCompositeException;
23  import org.apache.syncope.common.lib.SyncopeClientException;
24  import org.apache.syncope.common.lib.to.DerSchemaTO;
25  import org.apache.syncope.common.lib.to.PlainSchemaTO;
26  import org.apache.syncope.common.lib.to.Provision;
27  import org.apache.syncope.common.lib.to.VirSchemaTO;
28  import org.apache.syncope.common.lib.types.AnyTypeKind;
29  import org.apache.syncope.common.lib.types.ClientExceptionType;
30  import org.apache.syncope.core.persistence.api.dao.AnyTypeClassDAO;
31  import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
32  import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO;
33  import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
34  import org.apache.syncope.core.persistence.api.dao.ImplementationDAO;
35  import org.apache.syncope.core.persistence.api.dao.NotFoundException;
36  import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
37  import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
38  import org.apache.syncope.core.persistence.api.entity.AnyType;
39  import org.apache.syncope.core.persistence.api.entity.AnyTypeClass;
40  import org.apache.syncope.core.persistence.api.entity.AnyUtils;
41  import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
42  import org.apache.syncope.core.persistence.api.entity.DerSchema;
43  import org.apache.syncope.core.persistence.api.entity.EntityFactory;
44  import org.apache.syncope.core.persistence.api.entity.ExternalResource;
45  import org.apache.syncope.core.persistence.api.entity.Implementation;
46  import org.apache.syncope.core.persistence.api.entity.PlainSchema;
47  import org.apache.syncope.core.persistence.api.entity.VirSchema;
48  import org.apache.syncope.core.provisioning.api.data.SchemaDataBinder;
49  import org.apache.syncope.core.provisioning.api.jexl.JexlUtils;
50  import org.slf4j.Logger;
51  import org.slf4j.LoggerFactory;
52  
53  public class SchemaDataBinderImpl implements SchemaDataBinder {
54  
55      protected static final Logger LOG = LoggerFactory.getLogger(SchemaDataBinder.class);
56  
57      protected final AnyTypeClassDAO anyTypeClassDAO;
58  
59      protected final PlainSchemaDAO plainSchemaDAO;
60  
61      protected final DerSchemaDAO derSchemaDAO;
62  
63      protected final VirSchemaDAO virSchemaDAO;
64  
65      protected final ExternalResourceDAO resourceDAO;
66  
67      protected final AnyTypeDAO anyTypeDAO;
68  
69      protected final ImplementationDAO implementationDAO;
70  
71      protected final EntityFactory entityFactory;
72  
73      protected final AnyUtilsFactory anyUtilsFactory;
74  
75      public SchemaDataBinderImpl(
76              final AnyTypeClassDAO anyTypeClassDAO,
77              final PlainSchemaDAO plainSchemaDAO,
78              final DerSchemaDAO derSchemaDAO,
79              final VirSchemaDAO virSchemaDAO,
80              final ExternalResourceDAO resourceDAO,
81              final AnyTypeDAO anyTypeDAO,
82              final ImplementationDAO implementationDAO,
83              final EntityFactory entityFactory,
84              final AnyUtilsFactory anyUtilsFactory) {
85  
86          this.anyTypeClassDAO = anyTypeClassDAO;
87          this.plainSchemaDAO = plainSchemaDAO;
88          this.derSchemaDAO = derSchemaDAO;
89          this.virSchemaDAO = virSchemaDAO;
90          this.resourceDAO = resourceDAO;
91          this.anyTypeDAO = anyTypeDAO;
92          this.implementationDAO = implementationDAO;
93          this.entityFactory = entityFactory;
94          this.anyUtilsFactory = anyUtilsFactory;
95      }
96  
97      // --------------- PLAIN -----------------
98      protected PlainSchema fill(final PlainSchema schema, final PlainSchemaTO schemaTO) {
99          if (!JexlUtils.isExpressionValid(schemaTO.getMandatoryCondition())) {
100             SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidValues);
101             sce.getElements().add(schemaTO.getMandatoryCondition());
102             throw sce;
103         }
104 
105         schema.setKey(schemaTO.getKey());
106         schema.setType(schemaTO.getType());
107         schema.setCipherAlgorithm(schemaTO.getCipherAlgorithm());
108         schema.setConversionPattern(schemaTO.getConversionPattern());
109         schema.setEnumerationKeys(schemaTO.getEnumerationKeys());
110         schema.setEnumerationValues(schemaTO.getEnumerationValues());
111         schema.setMandatoryCondition(schemaTO.getMandatoryCondition());
112         schema.setMimeType(schemaTO.getMimeType());
113         schema.setMultivalue(schemaTO.isMultivalue());
114         schema.setReadonly(schemaTO.isReadonly());
115         schema.setSecretKey(schemaTO.getSecretKey());
116         schema.setUniqueConstraint(schemaTO.isUniqueConstraint());
117 
118         schema.getLabels().clear();
119         schema.getLabels().putAll(schemaTO.getLabels());
120         
121         if (schemaTO.getValidator() == null) {
122             schema.setValidator(null);
123         } else {
124             Implementation validator = implementationDAO.find(schemaTO.getValidator());
125             if (validator == null) {
126                 LOG.debug("Invalid " + Implementation.class.getSimpleName() + " {}, ignoring...",
127                         schemaTO.getValidator());
128             } else {
129                 schema.setValidator(validator);
130             }
131         }
132 
133         PlainSchema merged = plainSchemaDAO.save(schema);
134 
135         if (schemaTO.getAnyTypeClass() != null
136                 && (merged.getAnyTypeClass() == null
137                 || !schemaTO.getAnyTypeClass().equals(merged.getAnyTypeClass().getKey()))) {
138 
139             AnyTypeClass anyTypeClass = anyTypeClassDAO.find(schemaTO.getAnyTypeClass());
140             if (anyTypeClass == null) {
141                 LOG.debug("Invalid " + AnyTypeClass.class.getSimpleName()
142                         + "{}, ignoring...", schemaTO.getAnyTypeClass());
143             } else {
144                 anyTypeClass.add(merged);
145                 merged.setAnyTypeClass(anyTypeClass);
146             }
147         } else if (schemaTO.getAnyTypeClass() == null && merged.getAnyTypeClass() != null) {
148             merged.getAnyTypeClass().getPlainSchemas().remove(merged);
149             merged.setAnyTypeClass(null);
150         }
151 
152         return merged;
153     }
154 
155     @Override
156     public PlainSchema create(final PlainSchemaTO schemaTO) {
157         return fill(entityFactory.newEntity(PlainSchema.class), schemaTO);
158     }
159 
160     @Override
161     public PlainSchema update(final PlainSchemaTO schemaTO, final PlainSchema schema) {
162         SyncopeClientCompositeException scce = SyncopeClientException.buildComposite();
163 
164         boolean hasAttrs = false;
165         for (AnyTypeKind anyTypeKind : AnyTypeKind.values()) {
166             AnyUtils anyUtils = anyUtilsFactory.getInstance(anyTypeKind);
167             hasAttrs |= plainSchemaDAO.hasAttrs(schema, anyUtils.plainAttrClass());
168         }
169 
170         if (hasAttrs) {
171             if (schema.getType() != schemaTO.getType()) {
172                 SyncopeClientException e = SyncopeClientException.build(ClientExceptionType.InvalidPlainSchema);
173                 e.getElements().add("Cannot change type since " + schema.getKey() + " has attributes");
174 
175                 scce.addException(e);
176             }
177             if (schema.isUniqueConstraint() != schemaTO.isUniqueConstraint()) {
178                 SyncopeClientException e = SyncopeClientException.build(ClientExceptionType.InvalidPlainSchema);
179                 e.getElements().add("Cannot alter unique contraint since " + schema.getKey() + " has attributes");
180 
181                 scce.addException(e);
182             }
183         }
184 
185         if (scce.hasExceptions()) {
186             throw scce;
187         }
188 
189         return fill(schema, schemaTO);
190     }
191 
192     @Override
193     public PlainSchemaTO getPlainSchemaTO(final String key) {
194         PlainSchema schema = plainSchemaDAO.find(key);
195         if (schema == null) {
196             throw new NotFoundException("Schema '" + key + '\'');
197         }
198 
199         PlainSchemaTO schemaTO = new PlainSchemaTO();
200         schemaTO.setKey(schema.getKey());
201         schemaTO.setType(schema.getType());
202         schemaTO.setCipherAlgorithm(schema.getCipherAlgorithm());
203         schemaTO.setConversionPattern(schema.getConversionPattern());
204         schemaTO.setEnumerationKeys(schema.getEnumerationKeys());
205         schemaTO.setEnumerationValues(schema.getEnumerationValues());
206         schemaTO.setMandatoryCondition(schema.getMandatoryCondition());
207         schemaTO.setMimeType(schema.getMimeType());
208         schemaTO.setMultivalue(schema.isMultivalue());
209         schemaTO.setReadonly(schema.isReadonly());
210         schemaTO.setSecretKey(schema.getSecretKey());
211         schemaTO.setUniqueConstraint(schema.isUniqueConstraint());
212         schemaTO.getLabels().putAll(schema.getLabels());
213         schemaTO.setAnyTypeClass(schema.getAnyTypeClass() == null ? null : schema.getAnyTypeClass().getKey());
214         if (schema.getValidator() != null) {
215             schemaTO.setValidator(schema.getValidator().getKey());
216         }
217 
218         return schemaTO;
219     }
220 
221     // --------------- DERIVED -----------------
222     protected DerSchema fill(final DerSchema schema, final DerSchemaTO schemaTO) {
223         SyncopeClientCompositeException scce = SyncopeClientException.buildComposite();
224 
225         if (StringUtils.isBlank(schemaTO.getExpression())) {
226             SyncopeClientException requiredValuesMissing =
227                     SyncopeClientException.build(ClientExceptionType.RequiredValuesMissing);
228             requiredValuesMissing.getElements().add("expression");
229 
230             scce.addException(requiredValuesMissing);
231         } else if (!JexlUtils.isExpressionValid(schemaTO.getExpression())) {
232             SyncopeClientException e = SyncopeClientException.build(ClientExceptionType.InvalidValues);
233             e.getElements().add(schemaTO.getExpression());
234 
235             scce.addException(e);
236         }
237 
238         if (scce.hasExceptions()) {
239             throw scce;
240         }
241 
242         schema.setKey(schemaTO.getKey());
243         schema.setExpression(schemaTO.getExpression());
244 
245         schema.getLabels().clear();
246         schema.getLabels().putAll(schemaTO.getLabels());
247 
248         DerSchema merged = derSchemaDAO.save(schema);
249 
250         if (schemaTO.getAnyTypeClass() != null
251                 && (merged.getAnyTypeClass() == null
252                 || !schemaTO.getAnyTypeClass().equals(merged.getAnyTypeClass().getKey()))) {
253 
254             AnyTypeClass anyTypeClass = anyTypeClassDAO.find(schemaTO.getAnyTypeClass());
255             if (anyTypeClass == null) {
256                 LOG.debug("Invalid " + AnyTypeClass.class.getSimpleName()
257                         + "{}, ignoring...", schemaTO.getAnyTypeClass());
258             } else {
259                 anyTypeClass.add(merged);
260                 merged.setAnyTypeClass(anyTypeClass);
261             }
262         } else if (schemaTO.getAnyTypeClass() == null && merged.getAnyTypeClass() != null) {
263             merged.getAnyTypeClass().getDerSchemas().remove(merged);
264             merged.setAnyTypeClass(null);
265         }
266 
267         return merged;
268     }
269 
270     @Override
271     public DerSchema create(final DerSchemaTO schemaTO) {
272         return fill(entityFactory.newEntity(DerSchema.class), schemaTO);
273     }
274 
275     @Override
276     public DerSchema update(final DerSchemaTO schemaTO, final DerSchema schema) {
277         return fill(schema, schemaTO);
278     }
279 
280     @Override
281     public DerSchemaTO getDerSchemaTO(final String key) {
282         DerSchema schema = derSchemaDAO.find(key);
283         if (schema == null) {
284             throw new NotFoundException("Derived schema '" + key + '\'');
285         }
286 
287         DerSchemaTO schemaTO = new DerSchemaTO();
288         schemaTO.setKey(schema.getKey());
289         schemaTO.setExpression(schema.getExpression());
290         schemaTO.getLabels().putAll(schema.getLabels());
291         schemaTO.setAnyTypeClass(schema.getAnyTypeClass() == null ? null : schema.getAnyTypeClass().getKey());
292         return schemaTO;
293     }
294 
295     // --------------- VIRTUAL -----------------
296     protected VirSchema fill(final VirSchema schema, final VirSchemaTO schemaTO) {
297         schema.setKey(schemaTO.getKey());
298         schema.setExtAttrName(schemaTO.getExtAttrName());
299         schema.setReadonly(schemaTO.isReadonly());
300 
301         schema.getLabels().clear();
302         schema.getLabels().putAll(schemaTO.getLabels());
303 
304         if (schemaTO.getAnyTypeClass() != null
305                 && (schema.getAnyTypeClass() == null
306                 || !schemaTO.getAnyTypeClass().equals(schema.getAnyTypeClass().getKey()))) {
307 
308             AnyTypeClass anyTypeClass = anyTypeClassDAO.find(schemaTO.getAnyTypeClass());
309             if (anyTypeClass == null) {
310                 LOG.debug("Invalid " + AnyTypeClass.class.getSimpleName()
311                         + "{}, ignoring...", schemaTO.getAnyTypeClass());
312             } else {
313                 anyTypeClass.add(schema);
314                 schema.setAnyTypeClass(anyTypeClass);
315             }
316         } else if (schemaTO.getAnyTypeClass() == null && schema.getAnyTypeClass() != null) {
317             schema.getAnyTypeClass().getVirSchemas().remove(schema);
318             schema.setAnyTypeClass(null);
319         }
320 
321         ExternalResource resource = resourceDAO.find(schemaTO.getResource());
322         if (resource == null) {
323             SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidSchemaDefinition);
324             sce.getElements().add("Resource " + schemaTO.getResource() + " not found");
325             throw sce;
326         }
327         AnyType anyType = anyTypeDAO.find(schemaTO.getAnyType());
328         if (anyType == null) {
329             SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidSchemaDefinition);
330             sce.getElements().add("AnyType " + schemaTO.getAnyType() + " not found");
331             throw sce;
332         }
333         Provision provision = resource.getProvisionByAnyType(anyType.getKey()).orElse(null);
334         if (provision == null) {
335             SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidSchemaDefinition);
336             sce.getElements().add("Provision for AnyType" + schemaTO.getAnyType()
337                     + " not found in " + schemaTO.getResource());
338             throw sce;
339         }
340         schema.setResource(resource);
341         schema.setAnyType(anyType);
342 
343         return virSchemaDAO.save(schema);
344     }
345 
346     @Override
347     public VirSchema create(final VirSchemaTO schemaTO) {
348         return fill(entityFactory.newEntity(VirSchema.class), schemaTO);
349     }
350 
351     @Override
352     public VirSchema update(final VirSchemaTO schemaTO, final VirSchema schema) {
353         return fill(schema, schemaTO);
354     }
355 
356     @Override
357     public VirSchemaTO getVirSchemaTO(final String key) {
358         VirSchema schema = virSchemaDAO.find(key);
359         if (schema == null) {
360             throw new NotFoundException("Virtual Schema '" + key + '\'');
361         }
362 
363         VirSchemaTO schemaTO = new VirSchemaTO();
364         schemaTO.setKey(schema.getKey());
365         schemaTO.setExtAttrName(schema.getExtAttrName());
366         schemaTO.setReadonly(schema.isReadonly());
367         schemaTO.getLabels().putAll(schema.getLabels());
368         schemaTO.setAnyTypeClass(schema.getAnyTypeClass() == null ? null : schema.getAnyTypeClass().getKey());
369         schemaTO.setResource(schema.getResource().getKey());
370         schemaTO.setAnyType(schema.getAnyType().getKey());
371         return schemaTO;
372     }
373 }