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