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