HookServices.groovy
6.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
import javax.transaction.Synchronization
import javax.transaction.xa.XAResource
import javax.transaction.xa.Xid
import groovy.transform.Field
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.moqui.util.RestClient
import org.moqui.util.ObjectUtilities
import org.moqui.context.ExecutionContext
import org.moqui.entity.EntityCondition
import org.moqui.entity.EntityFind
import org.moqui.entity.EntityList
import org.moqui.entity.EntityValue
@Field Logger logger = LoggerFactory.getLogger(getClass().getName())
//'HookServices')
class HookSynchronization implements Synchronization {
private final ExecutionContext ec;
private static class EntityToken {
protected final String entityName
protected final String keyName
protected final Object keyValue
protected final Map<String, Object> extraParameters = new HashMap<String, Object>()
protected EntityToken(String entityName, String keyName, Object keyValue) {
this.entityName = entityName
this.keyName = keyName
this.keyValue = keyValue
}
public boolean equals(Object other) {
if (!(other instanceof EntityToken)) {
return false
}
EntityToken that = (EntityToken) other
return entityName.equals(that.entityName) && keyName.equals(that.keyName) && keyValue.equals(that.keyValue)
}
public int hashCode() {
return entityName.hashCode() ^ keyName.hashCode() ^ keyValue.hashCode()
}
}
private Map<EntityToken, Map<String, Object>> updates = new LinkedHashMap<>()
protected HookSynchronization(ExecutionContext ec) {
this.ec = ec
}
protected void add(String entityName, String keyName, Object keyValue, Map<String, Object> extraParameters) {
EntityToken entityToken = new EntityToken(entityName, keyName, keyValue)
// This always move the value to the end of the list
Map<String, Object> existingExtraParameters = updates.remove(entityToken)
Map<String, Object> newExtraParameters = [:]
if (existingExtraParameters) {
newExtraParameters.putAll(existingExtraParameters)
}
if (extraParameters) {
newExtraParameters.putAll(extraParameters)
}
updates.put(entityToken, newExtraParameters)
if (existingExtraParameters == null) {
ec.getLogger().info("Add new synchronization for ${entityName}: [${keyValue}]")
} else {
ec.getLogger().info("Updated synchronization for ${entityName}: [${keyValue}]")
}
}
@Override
public void beforeCompletion() {
List<Map<String, Object>> updates = []
for (Map.Entry<EntityToken, Map<String, Object>> entry: this.updates.entrySet()) {
EntityToken token = entry.getKey()
Map<String, Object> extraParameters = entry.getValue()
updates.add([
entityName: token.entityName,
keyName: token.keyName,
keyValue: token.keyValue,
extraParameters: extraParameters,
])
}
if (updates) {
ec.getService().async().name("keycloak.HookServices.process#Updates").parameter('updates', updates).call()
}
}
@Override
public void afterCompletion(int status) {
}
}
HookSynchronization getHookSync() {
HookSynchronization hookSync = ec.transaction.getActiveSynchronization(getClass().getName())
if (hookSync == null) {
hookSync = new HookSynchronization(ec)
ec.transaction.putAndEnlistActiveSynchronization(getClass().getName(), hookSync)
}
return hookSync
}
Map<String, Object> handleEntityUpdate() {
logger.info("handleEntityUpdate: ${context.entityName}[${context.value}]")
logger.info("context: ${context}")
ExecutionContext ec = context.ec
Map<String, Object> contextRoot = ec.getContextRoot()
HookSynchronization hookSync = getHookSync()
List<Map<String, Object>> queue = [[entityName: context.entityName, value: context.value]]
while (!queue.isEmpty()) {
Map<String, Object> entry = queue.remove(0)
logger.info("processing entry: ${entry}")
String entityName = entry.entityName
Object value = entry.value
String keyName
switch (entityName) {
case 'Party':
EntityList userAccounts = ec.entity.find('UserAccount').condition('partyId', value).list()
for (EntityValue userAccount: userAccounts) {
queue.add([entityName: 'UserAccount', value: userAccount.userId])
}
continue
case 'ContactMech':
EntityList partyContactMechs = ec.entity.find('PartyContactMech').condition('contactMechId', value).list()
for (EntityValue partyContactMech: partyContactMechs) {
queue.add([entityName: 'Party', value: partyContactMech.partyId])
}
continue
case 'UserAccount':
keyName = 'userId'
break
case 'UserGroup':
keyName = 'userGroupId'
break
case 'UserGroupMember':
keyName = 'userGroupId'
break
case 'UserPermission':
keyName = 'userPermissionId'
break
case 'PartyClassification':
keyName = 'partyClassificationId'
break
case 'RoleType':
keyName = 'roleTypeId'
break
}
hookSync.add(entityName, keyName, value, [:])
//ec.getService().special().name("keycloak.KeycloakServices.send#${entityName}").parameter(keyName, value).registerOnCommit()
}
}
Map<String, Object> handleUpdatePasswordInternal() {
String userId = ec.context.userId
String newPassword = ec.context.newPassword
Boolean requirePasswordChange = ec.context.requirePasswordChange
ec.getLogger().info("Registered synchronization for update#PasswordInternal: [${userId}]")
HookSynchronization hookSync = getHookSync()
hookSync.add('UserAccount', 'userId', userId, [
newPassword: newPassword,
requirePasswordChange: requirePasswordChange,
])
}
Map<String, Object> processUpdates() {
List<Map<String, Object>> updates = context.updates
for (Map<String, Object> update: updates) {
Map<String, Object> parameters = [:]
parameters[update.keyName] = update.keyValue
parameters.putAll(update.extraParameters)
ec.getService().sync().name("keycloak.KeycloakServices.send#${update.entityName}").parameters(parameters).call()
}
return [:]
}