-
-
Notifications
You must be signed in to change notification settings - Fork 3.9k
/
HazelcastTicketRegistryConfiguration.java
121 lines (112 loc) · 5.85 KB
/
HazelcastTicketRegistryConfiguration.java
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
package org.apereo.cas.config;
import org.apereo.cas.configuration.CasConfigurationProperties;
import org.apereo.cas.configuration.features.CasFeatureModule;
import org.apereo.cas.hz.HazelcastConfigurationFactory;
import org.apereo.cas.ticket.TicketCatalog;
import org.apereo.cas.ticket.TicketDefinition;
import org.apereo.cas.ticket.registry.HazelcastTicketHolder;
import org.apereo.cas.ticket.registry.HazelcastTicketRegistry;
import org.apereo.cas.ticket.registry.NoOpTicketRegistryCleaner;
import org.apereo.cas.ticket.registry.TicketRegistry;
import org.apereo.cas.ticket.registry.TicketRegistryCleaner;
import org.apereo.cas.util.CoreTicketUtils;
import org.apereo.cas.util.spring.boot.ConditionalOnFeatureEnabled;
import com.hazelcast.config.IndexConfig;
import com.hazelcast.config.IndexType;
import com.hazelcast.config.MapConfig;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.instance.impl.HazelcastInstanceFactory;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ScopedProxyMode;
/**
* Spring's Java configuration component for {@code HazelcastInstance} that is consumed and used by
* {@link HazelcastTicketRegistry}.
* <p>
* This configuration class has the smarts to choose the configuration source for the {@link HazelcastInstance}
* that it produces by either loading the native hazelcast XML config file from a resource location
* or it creates the {@link HazelcastInstance} programmatically
* with a handful properties and their defaults (if not set) that it exposes to CAS deployers.
*
* @author Misagh Moayyed
* @author Dmitriy Kopylenko
* @since 4.2.0
*/
@EnableConfigurationProperties(CasConfigurationProperties.class)
@Slf4j
@ConditionalOnFeatureEnabled(feature = CasFeatureModule.FeatureCatalog.TicketRegistry, module = "hazelcast")
@AutoConfiguration
public class HazelcastTicketRegistryConfiguration {
@Bean
@RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
public TicketRegistry ticketRegistry(
@Qualifier("casTicketRegistryHazelcastInstance")
final HazelcastInstance casTicketRegistryHazelcastInstance,
@Qualifier(TicketCatalog.BEAN_NAME)
final TicketCatalog ticketCatalog,
final CasConfigurationProperties casProperties) {
val hz = casProperties.getTicket().getRegistry().getHazelcast();
val r = new HazelcastTicketRegistry(casTicketRegistryHazelcastInstance, ticketCatalog, hz.getPageSize());
r.setCipherExecutor(CoreTicketUtils.newTicketRegistryCipherExecutor(hz.getCrypto(), "hazelcast"));
return r;
}
@Bean(destroyMethod = "shutdown")
@ConditionalOnMissingBean(name = "casTicketRegistryHazelcastInstance")
@RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
public HazelcastInstance casTicketRegistryHazelcastInstance(
@Qualifier(TicketCatalog.BEAN_NAME)
final TicketCatalog ticketCatalog,
final CasConfigurationProperties casProperties) {
val hz = casProperties.getTicket().getRegistry().getHazelcast();
LOGGER.debug("Creating Hazelcast instance for members [{}]", hz.getCluster().getNetwork().getMembers());
val hazelcastInstance = HazelcastInstanceFactory.getOrCreateHazelcastInstance(HazelcastConfigurationFactory.build(hz));
val ticketDefinitions = ticketCatalog.findAll();
ticketDefinitions
.stream()
.map(defn -> {
LOGGER.debug("Creating Hazelcast map configuration for [{}]", defn.getProperties());
val props = defn.getProperties();
val cfg = HazelcastConfigurationFactory.buildMapConfig(hz, props.getStorageName(), props.getStorageTimeout());
if (cfg instanceof MapConfig) {
val mapConfig = (MapConfig) cfg;
mapConfig.addIndexConfig(new IndexConfig(IndexType.HASH, "id"));
mapConfig.addIndexConfig(new IndexConfig(IndexType.HASH, "type"));
mapConfig.addIndexConfig(new IndexConfig(IndexType.HASH, "principal"));
}
return cfg;
})
.forEach(map -> HazelcastConfigurationFactory.setConfigMap(map, hazelcastInstance.getConfig()));
if (hz.getCore().isEnableJet()) {
ticketDefinitions.forEach(defn -> {
val query = buildCreateMappingQuery(defn);
LOGGER.trace("Creating mapping for [{}] via [{}]", defn.getPrefix(), query);
try (val createResults = hazelcastInstance.getSql().execute(query)) {
LOGGER.info("Created Hazelcast SQL mapping for [{}]", defn.getPrefix());
}
});
}
return hazelcastInstance;
}
private static String buildCreateMappingQuery(final TicketDefinition defn) {
val builder = new StringBuilder(String.format("CREATE MAPPING IF NOT EXISTS \"%s\" ", defn.getProperties().getStorageName()));
builder.append("TYPE IMap ");
builder.append("OPTIONS (");
builder.append("'keyFormat' = 'java',");
builder.append("'keyJavaClass' = 'java.lang.String',");
builder.append("'valueFormat' = 'java',");
builder.append(String.format("'valueJavaClass' = '%s'", HazelcastTicketHolder.class.getName()));
builder.append(')');
return builder.toString();
}
@Bean
@RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
public TicketRegistryCleaner ticketRegistryCleaner() {
return NoOpTicketRegistryCleaner.getInstance();
}
}