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