1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.core.logic;
20
21 import java.lang.reflect.Method;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Objects;
25 import java.util.Optional;
26 import java.util.Set;
27 import java.util.concurrent.ConcurrentHashMap;
28 import java.util.stream.Collectors;
29 import javax.validation.ConstraintViolation;
30 import javax.validation.ValidationException;
31 import javax.validation.Validator;
32 import org.apache.commons.lang3.tuple.Pair;
33 import org.apache.syncope.common.lib.SyncopeClientException;
34 import org.apache.syncope.common.lib.command.CommandArgs;
35 import org.apache.syncope.common.lib.command.CommandTO;
36 import org.apache.syncope.common.lib.to.EntityTO;
37 import org.apache.syncope.common.lib.types.ClientExceptionType;
38 import org.apache.syncope.common.lib.types.IdRepoEntitlement;
39 import org.apache.syncope.common.lib.types.IdRepoImplementationType;
40 import org.apache.syncope.core.logic.api.Command;
41 import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidEntityException;
42 import org.apache.syncope.core.persistence.api.dao.ImplementationDAO;
43 import org.apache.syncope.core.persistence.api.dao.NotFoundException;
44 import org.apache.syncope.core.persistence.api.entity.Implementation;
45 import org.apache.syncope.core.spring.implementation.ImplementationManager;
46 import org.springframework.security.access.prepost.PreAuthorize;
47 import org.springframework.transaction.annotation.Transactional;
48
49 public class CommandLogic extends AbstractLogic<EntityTO> {
50
51 protected final ImplementationDAO implementationDAO;
52
53 protected final Validator validator;
54
55 protected final Map<String, Command<?>> perContextCommands = new ConcurrentHashMap<>();
56
57 public CommandLogic(final ImplementationDAO implementationDAO, final Validator validator) {
58 this.implementationDAO = implementationDAO;
59 this.validator = validator;
60 }
61
62 @PreAuthorize("hasRole('" + IdRepoEntitlement.IMPLEMENTATION_LIST + "')")
63 @Transactional(readOnly = true)
64 public Pair<Integer, List<CommandTO>> search(final int page, final int size, final String keyword) {
65 List<Implementation> result = implementationDAO.findByTypeAndKeyword(IdRepoImplementationType.COMMAND, keyword);
66
67 int count = result.size();
68
69 List<CommandTO> commands = result.stream().
70 skip((page - 1) * size).
71 limit(size).
72 map(command -> {
73 try {
74 return new CommandTO.Builder(command.getKey()).
75 args(ImplementationManager.emptyArgs(command)).build();
76 } catch (Exception e) {
77 LOG.error("Could not get arg class for {}", command, e);
78 return null;
79 }
80 }).
81 filter(Objects::nonNull).
82 collect(Collectors.toList());
83
84 return Pair.of(count, commands);
85 }
86
87 @PreAuthorize("hasRole('" + IdRepoEntitlement.IMPLEMENTATION_READ + "')")
88 @Transactional(readOnly = true)
89 public CommandTO read(final String key) {
90 Implementation impl = Optional.ofNullable(implementationDAO.find(key)).
91 orElseThrow(() -> new NotFoundException("Implementation " + key));
92
93 try {
94 return new CommandTO.Builder(impl.getKey()).
95 args(ImplementationManager.emptyArgs(impl)).build();
96 } catch (Exception e) {
97 SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidImplementation);
98 sce.getElements().add("Could not build " + impl.getKey());
99 throw sce;
100 }
101 }
102
103 @PreAuthorize("hasRole('" + IdRepoEntitlement.COMMAND_RUN + "')")
104 @SuppressWarnings("unchecked")
105 public String run(final CommandTO command) {
106 Implementation impl = Optional.ofNullable(implementationDAO.find(command.getKey())).
107 orElseThrow(() -> new NotFoundException("Implementation " + command.getKey()));
108
109 Command<CommandArgs> runnable;
110 try {
111 runnable = (Command<CommandArgs>) ImplementationManager.build(
112 impl,
113 () -> perContextCommands.get(impl.getKey()),
114 instance -> perContextCommands.put(impl.getKey(), instance));
115 } catch (Exception e) {
116 SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidImplementation);
117 sce.getElements().add("Could not build " + impl.getKey());
118 throw sce;
119 }
120
121 if (command.getArgs() != null) {
122 try {
123 Set<ConstraintViolation<Object>> violations = validator.validate(command.getArgs());
124 if (!violations.isEmpty()) {
125 throw new InvalidEntityException(command.getArgs().getClass().getName(), violations);
126 }
127 } catch (ValidationException e) {
128 LOG.error("While validating {}", command.getArgs(), e);
129
130 SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidValues);
131 sce.getElements().add(e.getMessage());
132 throw sce;
133 }
134 }
135
136 try {
137 return runnable.run(command.getArgs());
138 } catch (Exception e) {
139 LOG.error("While running {} on {}", command.getKey(), command.getArgs(), e);
140
141 SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.RunError);
142 sce.getElements().add(e.getMessage());
143 throw sce;
144 }
145 }
146
147 @Override
148 protected EntityTO resolveReference(final Method method, final Object... args)
149 throws UnresolvedReferenceException {
150
151 throw new UnsupportedOperationException();
152 }
153 }