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 java.lang.reflect.Modifier;
22  import java.util.Optional;
23  import org.apache.commons.lang3.StringUtils;
24  import org.apache.syncope.common.lib.SyncopeClientException;
25  import org.apache.syncope.common.lib.policy.RuleConf;
26  import org.apache.syncope.common.lib.report.ReportConf;
27  import org.apache.syncope.common.lib.to.ImplementationTO;
28  import org.apache.syncope.common.lib.types.ClientExceptionType;
29  import org.apache.syncope.common.lib.types.IdMImplementationType;
30  import org.apache.syncope.common.lib.types.IdRepoImplementationType;
31  import org.apache.syncope.common.lib.types.ImplementationEngine;
32  import org.apache.syncope.common.lib.types.ImplementationTypesHolder;
33  import org.apache.syncope.core.persistence.api.entity.EntityFactory;
34  import org.apache.syncope.core.persistence.api.entity.Implementation;
35  import org.apache.syncope.core.provisioning.api.data.ImplementationDataBinder;
36  import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
37  import org.apache.syncope.core.spring.implementation.ImplementationManager;
38  import org.slf4j.Logger;
39  import org.slf4j.LoggerFactory;
40  
41  public class ImplementationDataBinderImpl implements ImplementationDataBinder {
42  
43      protected static final Logger LOG = LoggerFactory.getLogger(ImplementationDataBinder.class);
44  
45      protected final EntityFactory entityFactory;
46  
47      public ImplementationDataBinderImpl(final EntityFactory entityFactory) {
48          this.entityFactory = entityFactory;
49      }
50  
51      @Override
52      public Implementation create(final ImplementationTO implementationTO) {
53          Implementation implementation = entityFactory.newEntity(Implementation.class);
54          update(implementation, implementationTO);
55          return implementation;
56      }
57  
58      @Override
59      public void update(final Implementation implementation, final ImplementationTO implementationTO) {
60          SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidImplementation);
61  
62          if (implementation.getType() != null && !implementation.getType().equals(implementationTO.getType())) {
63              sce.getElements().add("ImplementationType cannot be changed");
64              throw sce;
65          }
66  
67          if (StringUtils.isBlank(implementationTO.getBody())) {
68              sce.getElements().add("No actual implementation provided");
69              throw sce;
70          }
71  
72          implementation.setKey(implementationTO.getKey());
73          implementation.setEngine(implementationTO.getEngine());
74          implementation.setType(implementationTO.getType());
75          implementation.setBody(implementationTO.getBody());
76  
77          if (implementation.getEngine() == ImplementationEngine.JAVA) {
78              Class<?> baseClazz = Optional.ofNullable(
79                      ImplementationTypesHolder.getInstance().getValues().get(implementation.getType())).
80                      map(intf -> {
81                          try {
82                              return Class.forName(intf);
83                          } catch (ClassNotFoundException e) {
84                              LOG.error("While resolving interface {} for implementation type {}",
85                                      intf, implementation.getType());
86                              return null;
87                          }
88                      }).
89                      orElse(null);
90  
91              if (baseClazz == null) {
92                  sce.getElements().add("No Java interface found for " + implementation.getType());
93                  throw sce;
94              }
95  
96              switch (implementation.getType()) {
97                  case IdRepoImplementationType.REPORT_DELEGATE:
98                      ReportConf conf = POJOHelper.deserialize(implementation.getBody(), ReportConf.class);
99                      if (conf == null) {
100                         sce.getElements().add("Could not deserialize as " + ReportConf.class.getName());
101                         throw sce;
102                     }
103                     break;
104 
105                 case IdRepoImplementationType.ACCOUNT_RULE:
106                 case IdRepoImplementationType.PASSWORD_RULE:
107                 case IdMImplementationType.PULL_CORRELATION_RULE:
108                 case IdMImplementationType.PUSH_CORRELATION_RULE:
109                     RuleConf rule = POJOHelper.deserialize(implementation.getBody(), RuleConf.class);
110                     if (rule == null) {
111                         sce.getElements().add("Could not deserialize as neither "
112                                 + "Account, Password, Pull nor Push Correlation RuleConf");
113                         throw sce;
114                     }
115                     break;
116 
117                 default:
118                     Class<?> clazz = null;
119                     try {
120                         clazz = Class.forName(implementation.getBody());
121                     } catch (Exception e) {
122                         LOG.error("Class '{}' not found", implementation.getBody(), e);
123                         sce.getElements().add("No Java class found: " + implementation.getBody());
124                         throw sce;
125                     }
126                     if (!baseClazz.isAssignableFrom(clazz)) {
127                         sce.getElements().add(
128                                 "Java class " + implementation.getBody() + " must comply with " + baseClazz.getName());
129                         throw sce;
130                     }
131                     if (Modifier.isAbstract(clazz.getModifiers())) {
132                         sce.getElements().add("Java class " + implementation.getBody() + " is abstract");
133                         throw sce;
134                     }
135                     break;
136             }
137         } else if (implementation.getEngine() == ImplementationEngine.GROOVY) {
138             try {
139                 ImplementationManager.build(implementation);
140             } catch (Exception e) {
141                 LOG.error("While building Groovy class {}", implementation.getKey(), e);
142 
143                 sce.getElements().add(e.getMessage());
144                 throw sce;
145             }
146         }
147     }
148 
149     @Override
150     public ImplementationTO getImplementationTO(final Implementation implementation) {
151         ImplementationTO implementationTO = new ImplementationTO();
152         implementationTO.setKey(implementation.getKey());
153         implementationTO.setEngine(implementation.getEngine());
154         implementationTO.setType(implementation.getType());
155         implementationTO.setBody(implementation.getBody());
156 
157         return implementationTO;
158     }
159 }