Working SPNEGO HTTP client
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / internal / runtime / CmsContextImpl.java
index e14b21e7073cd39241250fa0ec337a2a795a83e8..cc98072a3827fd7a5836f700dab6a47fc7a0e2e1 100644 (file)
@@ -1,34 +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.api.uuid.UuidFactory;
 import org.argeo.cms.CmsDeployProperty;
-import org.argeo.cms.LocaleUtils;
 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();
 
@@ -51,6 +53,10 @@ public class CmsContextImpl implements CmsContext {
        private Map<UUID, CmsSessionImpl> cmsSessionsByUuid = new HashMap<>();
        private Map<String, CmsSessionImpl> cmsSessionsByLocalId = new HashMap<>();
 
+       // CMS events
+       private Map<String, SubmissionPublisher<Map<String, Object>>> topics = new TreeMap<>();
+//     private IdentityHashMap<CmsEventSubscriber, List<CmsEventFlowSubscriber>> subscriptions = new IdentityHashMap<>();
+
 //     public CmsContextImpl() {
 //             initTrackers();
 //     }
@@ -85,7 +91,16 @@ public class CmsContextImpl implements CmsContext {
 //
 //             }.open();
 
-               checkReadiness();
+               new Thread(() -> {
+                       while (!checkReadiness()) {
+                               try {
+                                       Thread.sleep(500);
+                               } catch (InterruptedException e) {
+                               }
+                       }
+               }, "Check readiness").start();
+               
+               // checkReadiness();
 
                setInstance(this);
        }
@@ -98,10 +113,13 @@ public class CmsContextImpl implements CmsContext {
         * Checks whether the deployment is available according to expectations, and
         * mark it as available.
         */
-       private void checkReadiness() {
+       private boolean checkReadiness() {
                if (isAvailable())
-                       return;
-               if (cmsDeployment != null && userAdmin != null) {
+                       return true;
+               if (cmsDeployment == null)
+                       return false;
+
+               if (((CmsDeploymentImpl) cmsDeployment).allExpectedServicesAvailable() && userAdmin != null) {
                        String data = KernelUtils.getFrameworkProp(KernelUtils.OSGI_INSTANCE_AREA);
                        String state = KernelUtils.getFrameworkProp(KernelUtils.OSGI_CONFIGURATION_AREA);
                        availableSince = System.currentTimeMillis();
@@ -118,8 +136,11 @@ public class CmsContextImpl implements CmsContext {
                        if (log.isTraceEnabled())
                                log.trace("Kernel initialization took " + initDuration + "ms");
                        tributeToFreeSoftware(initDuration);
+
+                       return true;
                } else {
-                       throw new IllegalStateException("Deployment is not available");
+                       return false;
+                       // throw new IllegalStateException("Deployment is not available");
                }
        }
 
@@ -232,15 +253,9 @@ public class CmsContextImpl implements CmsContext {
                return getInstance();
        }
 
-//     /** 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
+               // TODO find a cleaner way
                return ((CmsUserAdmin) getInstance().userAdmin).getAcceptorCredentials();
        }
 
@@ -311,4 +326,86 @@ public class CmsContextImpl implements CmsContext {
                return cmsSessionsByLocalId.get(localId);
        }
 
+       /*
+        * CMS Events
+        */
+       public void sendEvent(String topic, Map<String, Object> event) {
+               SubmissionPublisher<Map<String, Object>> 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<Map<String, Object>> publisher = topics.get(topic);
+               CmsEventFlowSubscriber flowSubscriber = new CmsEventFlowSubscriber(topic, subscriber);
+               publisher.subscribe(flowSubscriber);
+       }
+
+       public void removeEventSubscriber(String topic, CmsEventSubscriber subscriber) {
+               SubmissionPublisher<Map<String, Object>> publisher = topics.get(topic);
+               if (publisher == null) {
+                       log.error("There should be an event topic " + topic);
+                       return;
+               }
+               for (Flow.Subscriber<? super Map<String, Object>> 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<Map<String, Object>> {
+               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<String, Object> 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");
+               }
+
+       }
+
 }