X-Git-Url: https://git.argeo.org/?a=blobdiff_plain;f=org.argeo.cms%2Fsrc%2Forg%2Fargeo%2Fcms%2Finternal%2Fruntime%2FCmsContextImpl.java;h=7a0f3388c07a4f79cabdd6928de9fa210e3bc511;hb=f3ea14abccc33b1c3326417a87c91145be776c72;hp=7ce2e8bd5dfa76a2a9546cfd56129795c8cd3ae5;hpb=f4da6777015da3fc392138f0c01cea2f2add9ed3;p=lgpl%2Fargeo-commons.git diff --git a/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsContextImpl.java b/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsContextImpl.java index 7ce2e8bd5..7a0f3388c 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsContextImpl.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsContextImpl.java @@ -1,24 +1,36 @@ package org.argeo.cms.internal.runtime; -import static java.util.Locale.ENGLISH; - import java.lang.management.ManagementFactory; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Locale; +import java.util.Map; +import java.util.TreeMap; +import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import java.util.concurrent.Flow; +import java.util.concurrent.Flow.Subscription; +import java.util.concurrent.SubmissionPublisher; + +import javax.security.auth.Subject; -import org.argeo.api.cms.CmsConstants; import org.argeo.api.cms.CmsContext; import org.argeo.api.cms.CmsDeployment; +import org.argeo.api.cms.CmsEventSubscriber; import org.argeo.api.cms.CmsLog; +import org.argeo.api.cms.CmsSession; +import org.argeo.api.cms.CmsSessionId; import org.argeo.api.cms.CmsState; -import org.argeo.cms.LocaleUtils; -import org.argeo.cms.internal.osgi.NodeUserAdmin; +import org.argeo.api.uuid.UuidFactory; +import org.argeo.cms.CmsDeployProperty; +import org.argeo.cms.internal.auth.CmsSessionImpl; import org.ietf.jgss.GSSCredential; import org.osgi.service.useradmin.UserAdmin; public class CmsContextImpl implements CmsContext { + private final CmsLog log = CmsLog.getLog(getClass()); // private final BundleContext bc = FrameworkUtil.getBundle(getClass()).getBundleContext(); @@ -28,6 +40,8 @@ public class CmsContextImpl implements CmsContext { private CmsState cmsState; private CmsDeployment cmsDeployment; private UserAdmin userAdmin; + private UuidFactory uuidFactory; +// private ProvidedRepository contentRepository; // i18n private Locale defaultLocale; @@ -35,15 +49,27 @@ public class CmsContextImpl implements CmsContext { private Long availableSince; + // CMS sessions + private Map cmsSessionsByUuid = new HashMap<>(); + private Map cmsSessionsByLocalId = new HashMap<>(); + + // CMS events + private Map>> topics = new TreeMap<>(); +// private IdentityHashMap> subscriptions = new IdentityHashMap<>(); + // public CmsContextImpl() { // initTrackers(); // } - public void init() { - Object defaultLocaleValue = KernelUtils.getFrameworkProp(CmsConstants.I18N_DEFAULT_LOCALE); - defaultLocale = defaultLocaleValue != null ? new Locale(defaultLocaleValue.toString()) - : new Locale(ENGLISH.getLanguage()); - locales = LocaleUtils.asLocaleList(KernelUtils.getFrameworkProp(CmsConstants.I18N_LOCALES)); + public void start() { + List codes = CmsStateImpl.getDeployProperties(cmsState, CmsDeployProperty.LOCALE); + locales = getLocaleList(codes); + if (locales.size() == 0) + throw new IllegalStateException("At least one locale must be set"); + defaultLocale = locales.get(0); +// Object defaultLocaleValue = KernelUtils.getFrameworkProp(CmsConstants.I18N_DEFAULT_LOCALE); +// defaultLocale = defaultLocaleValue != null ? new Locale(defaultLocaleValue.toString()) +// : new Locale(ENGLISH.getLanguage()); // node repository // new ServiceTracker(bc, Repository.class, null) { // @Override @@ -70,7 +96,7 @@ public class CmsContextImpl implements CmsContext { setInstance(this); } - public void destroy() { + public void stop() { setInstance(null); } @@ -129,6 +155,29 @@ public class CmsContextImpl implements CmsContext { throw new UnsupportedOperationException(); } + /** Returns null if argument is null. */ + private static List getLocaleList(List codes) { + if (codes == null) + return null; + ArrayList availableLocales = new ArrayList(); + for (String code : codes) { + if (code == null) + continue; + // variant not supported + int indexUnd = code.indexOf("_"); + Locale locale; + if (indexUnd > 0) { + String language = code.substring(0, indexUnd); + String country = code.substring(indexUnd + 1); + locale = new Locale(language, country); + } else { + locale = new Locale(code); + } + availableLocales.add(locale); + } + return availableLocales; + } + public void setCmsDeployment(CmsDeployment cmsDeployment) { this.cmsDeployment = cmsDeployment; } @@ -141,6 +190,22 @@ public class CmsContextImpl implements CmsContext { this.userAdmin = userAdmin; } + public UuidFactory getUuidFactory() { + return uuidFactory; + } + + public void setUuidFactory(UuidFactory uuidFactory) { + this.uuidFactory = uuidFactory; + } + +// public ProvidedRepository getContentRepository() { +// return contentRepository; +// } +// +// public void setContentRepository(ProvidedRepository contentRepository) { +// this.contentRepository = contentRepository; +// } + @Override public Locale getDefaultLocale() { return defaultLocale; @@ -160,24 +225,29 @@ public class CmsContextImpl implements CmsContext { return availableSince != null; } + @Override + public CmsState getCmsState() { + return cmsState; + } + /* * STATIC */ - public synchronized static CmsContext getCmsContext() { + public synchronized static CmsContextImpl getCmsContext() { return getInstance(); } - /** Required by USER login module. */ - public synchronized static UserAdmin getUserAdmin() { - return getInstance().userAdmin; - } +// /** Required by USER login module. */ +// public synchronized static UserAdmin getUserAdmin() { +// return getInstance().userAdmin; +// } /** Required by SPNEGO login module. */ @Deprecated public synchronized static GSSCredential getAcceptorCredentials() { // FIXME find a cleaner way - return ((NodeUserAdmin) getInstance().userAdmin).getAcceptorCredentials(); + return ((CmsUserAdmin) getInstance().userAdmin).getAcceptorCredentials(); } private synchronized static void setInstance(CmsContextImpl cmsContextImpl) { @@ -198,4 +268,135 @@ public class CmsContextImpl implements CmsContext { } } + public UserAdmin getUserAdmin() { + return userAdmin; + } + + /* + * CMS Sessions + */ + + @Override + public synchronized CmsSession getCmsSession(Subject subject) { + if (subject.getPrivateCredentials(CmsSessionId.class).isEmpty()) + return null; + CmsSessionId cmsSessionId = subject.getPrivateCredentials(CmsSessionId.class).iterator().next(); + return getCmsSessionByUuid(cmsSessionId.getUuid()); + } + + public synchronized void registerCmsSession(CmsSessionImpl cmsSession) { + if (cmsSessionsByUuid.containsKey(cmsSession.getUuid()) + || cmsSessionsByLocalId.containsKey(cmsSession.getLocalId())) + throw new IllegalStateException("CMS session " + cmsSession + " is already registered."); + cmsSessionsByUuid.put(cmsSession.getUuid(), cmsSession); + cmsSessionsByLocalId.put(cmsSession.getLocalId(), cmsSession); + } + + public synchronized void unregisterCmsSession(CmsSessionImpl cmsSession) { + if (!cmsSessionsByUuid.containsKey(cmsSession.getUuid()) + || !cmsSessionsByLocalId.containsKey(cmsSession.getLocalId())) + throw new IllegalStateException("CMS session " + cmsSession + " is not registered."); + CmsSession removed = cmsSessionsByUuid.remove(cmsSession.getUuid()); + assert removed == cmsSession; + cmsSessionsByLocalId.remove(cmsSession.getLocalId()); + } + + /** + * The {@link CmsSession} related to this UUID, or null if not + * registered. + */ + public synchronized CmsSessionImpl getCmsSessionByUuid(UUID uuid) { + return cmsSessionsByUuid.get(uuid); + } + + /** + * The {@link CmsSession} related to this local id, or null if not + * registered. + */ + public synchronized CmsSessionImpl getCmsSessionByLocalId(String localId) { + return cmsSessionsByLocalId.get(localId); + } + + /* + * CMS Events + */ + public void sendEvent(String topic, Map event) { + SubmissionPublisher> publisher = topics.get(topic); + if (publisher == null) + return; // no one is interested + publisher.submit(event); + } + + public void addEventSubscriber(String topic, CmsEventSubscriber subscriber) { + synchronized (topics) { + if (!topics.containsKey(topic)) + topics.put(topic, new SubmissionPublisher<>()); + } + SubmissionPublisher> publisher = topics.get(topic); + CmsEventFlowSubscriber flowSubscriber = new CmsEventFlowSubscriber(topic, subscriber); + publisher.subscribe(flowSubscriber); + } + + public void removeEventSubscriber(String topic, CmsEventSubscriber subscriber) { + SubmissionPublisher> publisher = topics.get(topic); + if (publisher == null) { + log.error("There should be an event topic " + topic); + return; + } + for (Flow.Subscriber> flowSubscriber : publisher.getSubscribers()) { + if (flowSubscriber instanceof CmsEventFlowSubscriber) + ((CmsEventFlowSubscriber) flowSubscriber).unsubscribe(); + } + synchronized (topics) { + if (!publisher.hasSubscribers()) { + publisher.close(); + topics.remove(topic); + } + } + } + + static class CmsEventFlowSubscriber implements Flow.Subscriber> { + private String topic; + private CmsEventSubscriber eventSubscriber; + + private Subscription subscription; + + public CmsEventFlowSubscriber(String topic, CmsEventSubscriber eventSubscriber) { + this.topic = topic; + this.eventSubscriber = eventSubscriber; + } + + @Override + public void onSubscribe(Subscription subscription) { + this.subscription = subscription; + subscription.request(Long.MAX_VALUE); + } + + @Override + public void onNext(Map item) { + eventSubscriber.onEvent(topic, item); + + } + + @Override + public void onError(Throwable throwable) { + // TODO Auto-generated method stub + + } + + @Override + public void onComplete() { + // TODO Auto-generated method stub + + } + + void unsubscribe() { + if (subscription != null) + subscription.cancel(); + else + throw new IllegalStateException("No subscription to cancel"); + } + + } + }