package org.argeo.api.cms;
+import java.util.Map;
import java.util.Set;
import org.argeo.api.cms.ux.CmsTheme;
import org.argeo.api.cms.ux.CmsUi;
/** An extensible user interface base on the CMS backend. */
-public interface CmsApp {
+public interface CmsApp extends CmsEventSubscriber {
/**
* If {@link CmsUi#setData(String, Object)} is set with this property, it
* indicates a different UI (typically with another theming. The {@link CmsApp}
void removeCmsAppListener(CmsAppListener listener);
CmsContext getCmsContext();
+
+ @Override
+ default void onEvent(String topic, Map<String, Object> properties) {
+ }
+
+
}
package org.argeo.api.cms.ux;
-import java.security.PrivilegedAction;
import java.util.HashMap;
import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executors;
import javax.security.auth.login.LoginContext;
}
- default <T> T doAs(PrivilegedAction<T> action) {
- throw new UnsupportedOperationException();
- }
-
- default Void runAs(Runnable runnable) {
- return doAs(new PrivilegedAction<Void>() {
+ /**
+ * Make sure that this action is executed with the proper subject and in a
+ * proper thread.
+ */
+ <T> T doAs(Callable<T> action);
- @Override
- public Void run() {
- if (runnable != null)
- runnable.run();
- return null;
- }
- });
+ default void runAs(Runnable runnable) {
+ doAs(Executors.callable(runnable));
}
default void stateChanged(String state, String title) {
/** Where the search for a message is actually performed. */
public static String local(String key, Locale locale, String resource, ClassLoader classLoader) {
ResourceBundle rb = ResourceBundle.getBundle(resource, locale, classLoader);
- assert key.length() > 2;
- if (isLocaleKey(key))
+ if (isLocaleKey(key)) {
+ assert key.length() > 1;
key = key.substring(1);
+ }
if (rb.containsKey(key))
return rb.getString(key);
else // for simple cases, the key will actually be the English word
@Override
public void onSubscribe(Subscription subscription) {
this.subscription = subscription;
- subscription.request(1);
+ this.subscription.request(Long.MAX_VALUE);
}
@Override
public void onNext(Map<String, Object> item) {
eventSubscriber.onEvent(topic, item);
- subscription.request(1);
}
@Override
package org.argeo.cms.swt;
-import java.security.PrivilegedAction;
import java.util.HashMap;
import java.util.Map;
+import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
import java.util.concurrent.ExecutionException;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
+import org.argeo.api.cms.CmsApp;
import org.argeo.api.cms.CmsEventBus;
+import org.argeo.api.cms.CmsLog;
import org.argeo.api.cms.ux.CmsImageManager;
import org.argeo.api.cms.ux.CmsUi;
import org.argeo.api.cms.ux.CmsView;
import org.argeo.api.cms.ux.UxContext;
import org.argeo.cms.auth.CurrentUser;
+import org.argeo.util.CurrentSubject;
import org.eclipse.swt.widgets.Display;
public abstract class AbstractSwtCmsView implements CmsView {
+ private final static CmsLog log = CmsLog.getLog(AbstractSwtCmsView.class);
+
protected final String uiName;
protected LoginContext loginContext;
public abstract CmsEventBus getCmsEventBus();
+ public abstract CmsApp getCmsApp();
+
@Override
public void sendEvent(String topic, Map<String, Object> properties) {
if (properties == null)
throw new IllegalArgumentException("Property " + CMS_VIEW_UID_PROPERTY + " is set to another CMS view uid ("
+ properties.get(CMS_VIEW_UID_PROPERTY) + ") then " + uid);
properties.put(CMS_VIEW_UID_PROPERTY, uid);
+
+ log.debug(() -> uid + ": send event to " + topic);
+
getCmsEventBus().sendEvent(topic, properties);
+ //getCmsApp().onEvent(topic, properties);
}
- public <T> T doAs(PrivilegedAction<T> action) {
+// public void runAs(Runnable runnable) {
+// display.asyncExec(() -> doAs(Executors.callable(runnable)));
+// }
+
+ public <T> T doAs(Callable<T> action) {
try {
CompletableFuture<T> result = new CompletableFuture<>();
Runnable toDo = () -> {
- T res = Subject.doAs(getSubject(), action);
+ log.debug(() -> uid + ": process doAs");
+ Subject subject = CurrentSubject.current();
+ T res;
+ if (subject != null) {
+ assert subject == getSubject();
+ try {
+ res = action.call();
+ } catch (Exception e) {
+ throw new CompletionException("Failed to execute action for " + subject, e);
+ }
+ } else {
+ res = CurrentSubject.callAs(getSubject(), action);
+ }
result.complete(res);
};
if (Thread.currentThread() == display.getThread())
toDo.run();
- else
- display.syncExec(toDo);
+ else {
+ display.asyncExec(toDo);
+ display.wake();
+ }
+// throw new IllegalStateException("Must be called from UI thread");
return result.get();
} catch (InterruptedException | ExecutionException e) {
throw new IllegalStateException("Cannot execute action ins CMS view " + uid, e);
package org.argeo.cms.swt.dialogs;
-import java.security.PrivilegedAction;
import java.util.Arrays;
+import java.util.concurrent.Callable;
import org.argeo.api.cms.CmsLog;
import org.argeo.api.cms.ux.CmsView;
private CmsUserManager cmsUserManager;
private CmsView cmsView;
- private PrivilegedAction<Integer> doIt;
+ private Callable<Integer> doIt;
public ChangePasswordDialog(Shell parentShell, String message, int kind, CmsUserManager cmsUserManager) {
super(parentShell, message, kind);
import java.security.AccessController;
import java.util.UUID;
+import java.util.concurrent.Callable;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
return state;
}
+ @Override
+ public <T> T doAs(Callable<T> action) {
+ throw new UnsupportedOperationException();
+ }
+
}
import org.eclipse.rap.rwt.client.service.BrowserNavigationEvent;
import org.eclipse.rap.rwt.client.service.BrowserNavigationListener;
import org.eclipse.rap.rwt.internal.lifecycle.RWTLifeCycle;
+import org.eclipse.rap.rwt.service.ServerPushSession;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTError;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Widget;
/** The {@link CmsView} for a {@link CmsWebApp}. */
@SuppressWarnings("restriction")
/** Experimental OS-like multi windows. */
private boolean multipleShells = false;
+ private ServerPushSession serverPushSession;
+
public CmsWebEntryPoint(CmsWebApp cmsWebApp, String uiName) {
super(uiName);
assert cmsWebApp != null;
browserNavigation = RWT.getClient().getService(BrowserNavigation.class);
if (browserNavigation != null)
browserNavigation.addBrowserNavigationListener(this);
+
}
protected void createContents(Composite parent) {
ui = cmsWebApp.getCmsApp().initUi(parent);
if (ui instanceof Composite)
((Composite) ui).setLayoutData(CmsSwtUtils.fillAll());
+ serverPushSession = new ServerPushSession();
+
+ // required in order to doAs to work
+ // TODO check whether it would be worth optimising
+ serverPushSession.start();
// we need ui to be set before refresh so that CmsView can store UI context data
// in it.
cmsWebApp.getCmsApp().refreshUi(ui, null);
return cmsWebApp.getCmsEventBus();
}
+ @Override
+ public CmsApp getCmsApp() {
+ return cmsWebApp.getCmsApp();
+ }
+
@Override
public void stateChanged(String state, String title) {
browserNavigation.pushState(state, title);