]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsContextImpl.java
Fix IPA initialisation
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / internal / runtime / CmsContextImpl.java
1 package org.argeo.cms.internal.runtime;
2
3 import java.lang.management.ManagementFactory;
4 import java.util.ArrayList;
5 import java.util.HashMap;
6 import java.util.List;
7 import java.util.Locale;
8 import java.util.Map;
9 import java.util.UUID;
10 import java.util.concurrent.CompletableFuture;
11 import java.util.concurrent.ExecutionException;
12
13 import javax.security.auth.Subject;
14
15 import org.argeo.api.cms.CmsContext;
16 import org.argeo.api.cms.CmsDeployment;
17 import org.argeo.api.cms.CmsEventBus;
18 import org.argeo.api.cms.CmsLog;
19 import org.argeo.api.cms.CmsSession;
20 import org.argeo.api.cms.CmsSessionId;
21 import org.argeo.api.cms.CmsState;
22 import org.argeo.api.uuid.UuidFactory;
23 import org.argeo.cms.CmsDeployProperty;
24 import org.argeo.cms.internal.auth.CmsSessionImpl;
25 import org.ietf.jgss.GSSCredential;
26 import org.osgi.service.useradmin.UserAdmin;
27
28 /** Reference implementation of {@link CmsContext}. */
29 public class CmsContextImpl implements CmsContext {
30
31 private final CmsLog log = CmsLog.getLog(getClass());
32
33 private static CompletableFuture<CmsContextImpl> instance = new CompletableFuture<CmsContextImpl>();
34
35 private CmsState cmsState;
36 private CmsDeployment cmsDeployment;
37 private UserAdmin userAdmin;
38 private UuidFactory uuidFactory;
39 private CmsEventBus cmsEventBus;
40
41 // i18n
42 private Locale defaultLocale;
43 private List<Locale> locales = null;
44
45 private Long availableSince;
46
47 // time in ms to wait for CMS to be ready
48 private final long readynessTimeout = 30 * 1000;
49
50 // CMS sessions
51 private Map<UUID, CmsSessionImpl> cmsSessionsByUuid = new HashMap<>();
52 private Map<String, CmsSessionImpl> cmsSessionsByLocalId = new HashMap<>();
53
54 public void start() {
55 List<String> codes = CmsStateImpl.getDeployProperties(cmsState, CmsDeployProperty.LOCALE);
56 locales = getLocaleList(codes);
57 if (locales.size() == 0)
58 throw new IllegalStateException("At least one locale must be set");
59 defaultLocale = locales.get(0);
60
61 new Thread(() -> {
62 long begin = System.currentTimeMillis();
63 long duration = 0;
64 readyness: while (!checkReadiness()) {
65 duration = System.currentTimeMillis() - begin;
66 if (duration > readynessTimeout) {
67 log.error("## CMS not ready after " + duration + " ms. Giving up checking.");
68 break readyness;
69 }
70 try {
71 Thread.sleep(100);
72 } catch (InterruptedException e) {
73 }
74 }
75 }, "Check readiness").start();
76 setInstance(this);
77 }
78
79 public void stop() {
80 setInstance(null);
81 }
82
83 /**
84 * Checks whether the deployment is available according to expectations, and
85 * mark it as available.
86 */
87 private boolean checkReadiness() {
88 if (isAvailable())
89 return true;
90 if (cmsDeployment == null)
91 return false;
92
93 if (((CmsDeploymentImpl) cmsDeployment).allExpectedServicesAvailable() && userAdmin != null) {
94 String data = KernelUtils.getFrameworkProp(KernelUtils.OSGI_INSTANCE_AREA);
95 String state = KernelUtils.getFrameworkProp(KernelUtils.OSGI_CONFIGURATION_AREA);
96 availableSince = System.currentTimeMillis();
97 long jvmUptime = ManagementFactory.getRuntimeMXBean().getUptime();
98 String jvmUptimeStr = " in " + (jvmUptime / 1000) + "." + (jvmUptime % 1000) + "s";
99 log.info("## ARGEO CMS " + cmsState.getUuid() + " AVAILABLE" + (log.isDebugEnabled() ? jvmUptimeStr : "")
100 + " ##");
101 if (log.isDebugEnabled()) {
102 log.debug("## state: " + state);
103 if (data != null)
104 log.debug("## data: " + data);
105 }
106 long begin = cmsState.getAvailableSince();
107 long initDuration = System.currentTimeMillis() - begin;
108 if (log.isTraceEnabled())
109 log.trace("Kernel initialization took " + initDuration + "ms");
110 tributeToFreeSoftware(initDuration);
111
112 return true;
113 } else {
114 return false;
115 // throw new IllegalStateException("Deployment is not available");
116 }
117 }
118
119 final private void tributeToFreeSoftware(long initDuration) {
120 if (log.isTraceEnabled()) {
121 long ms = initDuration / 100;
122 log.trace("Spend " + ms + "ms" + " reflecting on the progress brought to mankind" + " by Free Software...");
123 long beginNano = System.nanoTime();
124 try {
125 Thread.sleep(ms, 0);
126 } catch (InterruptedException e) {
127 // silent
128 }
129 long durationNano = System.nanoTime() - beginNano;
130 final double M = 1000d * 1000d;
131 double sleepAccuracy = ((double) durationNano) / (ms * M);
132 log.trace("Sleep accuracy: " + String.format("%.2f", 100 - (sleepAccuracy * 100 - 100)) + " %");
133 }
134 }
135
136 @Override
137 public void createWorkgroup(String dn) {
138 // if (egoRepository == null)
139 // throw new CmsException("Ego repository is not available");
140 // // TODO add check that the group exists
141 // egoRepository.createWorkgroup(dn);
142 throw new UnsupportedOperationException();
143 }
144
145 /** Returns null if argument is null. */
146 private static List<Locale> getLocaleList(List<String> codes) {
147 if (codes == null)
148 return null;
149 ArrayList<Locale> availableLocales = new ArrayList<Locale>();
150 for (String code : codes) {
151 if (code == null)
152 continue;
153 // variant not supported
154 int indexUnd = code.indexOf("_");
155 Locale locale;
156 if (indexUnd > 0) {
157 String language = code.substring(0, indexUnd);
158 String country = code.substring(indexUnd + 1);
159 locale = new Locale(language, country);
160 } else {
161 locale = new Locale(code);
162 }
163 availableLocales.add(locale);
164 }
165 return availableLocales;
166 }
167
168 public void setCmsDeployment(CmsDeployment cmsDeployment) {
169 this.cmsDeployment = cmsDeployment;
170 }
171
172 public void setCmsState(CmsState cmsState) {
173 this.cmsState = cmsState;
174 }
175
176 public void setUserAdmin(UserAdmin userAdmin) {
177 this.userAdmin = userAdmin;
178 }
179
180 public UuidFactory getUuidFactory() {
181 return uuidFactory;
182 }
183
184 public void setUuidFactory(UuidFactory uuidFactory) {
185 this.uuidFactory = uuidFactory;
186 }
187
188 @Override
189 public Locale getDefaultLocale() {
190 return defaultLocale;
191 }
192
193 @Override
194 public UUID timeUUID() {
195 return uuidFactory.timeUUID();
196 }
197
198 @Override
199 public List<Locale> getLocales() {
200 return locales;
201 }
202
203 @Override
204 public Long getAvailableSince() {
205 return availableSince;
206 }
207
208 public boolean isAvailable() {
209 return availableSince != null;
210 }
211
212 public CmsState getCmsState() {
213 return cmsState;
214 }
215
216 @Override
217 public CmsEventBus getCmsEventBus() {
218 return cmsEventBus;
219 }
220
221 public void setCmsEventBus(CmsEventBus cmsEventBus) {
222 this.cmsEventBus = cmsEventBus;
223 }
224
225 /*
226 * STATIC
227 */
228
229 public static CmsContextImpl getCmsContext() {
230 return getInstance();
231 }
232
233 /** Required by SPNEGO login module. */
234 public GSSCredential getAcceptorCredentials() {
235 // TODO find a cleaner way
236 return ((CmsUserAdmin) userAdmin).getAcceptorCredentials();
237 }
238
239 private static void setInstance(CmsContextImpl cmsContextImpl) {
240 if (cmsContextImpl != null) {
241 if (instance.isDone())
242 throw new IllegalStateException("CMS Context is already set");
243 instance.complete(cmsContextImpl);
244 } else {
245 if (!instance.isDone())
246 instance.cancel(true);
247 instance = new CompletableFuture<CmsContextImpl>();
248 }
249 }
250
251 private static CmsContextImpl getInstance() {
252 try {
253 return instance.get();
254 } catch (InterruptedException | ExecutionException e) {
255 throw new IllegalStateException("Cannot retrieve CMS Context", e);
256 }
257 }
258
259 public UserAdmin getUserAdmin() {
260 return userAdmin;
261 }
262
263 /*
264 * CMS Sessions
265 */
266
267 @Override
268 public CmsSession getCmsSession(Subject subject) {
269 if (subject.getPrivateCredentials(CmsSessionId.class).isEmpty())
270 return null;
271 CmsSessionId cmsSessionId = subject.getPrivateCredentials(CmsSessionId.class).iterator().next();
272 return getCmsSessionByUuid(cmsSessionId.getUuid());
273 }
274
275 public void registerCmsSession(CmsSessionImpl cmsSession) {
276 if (cmsSessionsByUuid.containsKey(cmsSession.getUuid())
277 || cmsSessionsByLocalId.containsKey(cmsSession.getLocalId()))
278 throw new IllegalStateException("CMS session " + cmsSession + " is already registered.");
279 cmsSessionsByUuid.put(cmsSession.getUuid(), cmsSession);
280 cmsSessionsByLocalId.put(cmsSession.getLocalId(), cmsSession);
281 }
282
283 public void unregisterCmsSession(CmsSessionImpl cmsSession) {
284 if (!cmsSessionsByUuid.containsKey(cmsSession.getUuid())
285 || !cmsSessionsByLocalId.containsKey(cmsSession.getLocalId()))
286 throw new IllegalStateException("CMS session " + cmsSession + " is not registered.");
287 CmsSession removed = cmsSessionsByUuid.remove(cmsSession.getUuid());
288 assert removed == cmsSession;
289 cmsSessionsByLocalId.remove(cmsSession.getLocalId());
290 }
291
292 /**
293 * The {@link CmsSession} related to this UUID, or <code>null</null> if not
294 * registered.
295 */
296 public CmsSessionImpl getCmsSessionByUuid(UUID uuid) {
297 return cmsSessionsByUuid.get(uuid);
298 }
299
300 /**
301 * The {@link CmsSession} related to this local id, or <code>null</null> if not
302 * registered.
303 */
304 public CmsSessionImpl getCmsSessionByLocalId(String localId) {
305 return cmsSessionsByLocalId.get(localId);
306 }
307
308 }