]> git.argeo.org Git - lgpl/argeo-commons.git/blob - swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/web/CmsWebEntryPoint.java
9c94da8f34c2de11bac5ab89c34f8980ca464f14
[lgpl/argeo-commons.git] / swt / rap / org.argeo.cms.swt.rap / src / org / argeo / cms / web / CmsWebEntryPoint.java
1 package org.argeo.cms.web;
2
3 import static org.eclipse.rap.rwt.internal.service.ContextProvider.getApplicationContext;
4
5 import java.net.URI;
6 import java.net.URISyntaxException;
7 import java.security.PrivilegedAction;
8 import java.util.Locale;
9 import java.util.UUID;
10
11 import javax.security.auth.Subject;
12 import javax.security.auth.login.LoginContext;
13 import javax.security.auth.login.LoginException;
14
15 import org.argeo.api.cms.CmsApp;
16 import org.argeo.api.cms.CmsAuth;
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.ux.CmsImageManager;
21 import org.argeo.api.cms.ux.CmsView;
22 import org.argeo.cms.CurrentUser;
23 import org.argeo.cms.LocaleUtils;
24 import org.argeo.cms.auth.RemoteAuthCallbackHandler;
25 import org.argeo.cms.servlet.ServletHttpRequest;
26 import org.argeo.cms.servlet.ServletHttpResponse;
27 import org.argeo.cms.swt.AbstractSwtCmsView;
28 import org.argeo.cms.swt.CmsSwtUtils;
29 import org.argeo.cms.swt.SimpleSwtUxContext;
30 import org.argeo.cms.swt.acr.AcrSwtImageManager;
31 import org.argeo.cms.swt.dialogs.CmsFeedback;
32 import org.argeo.eclipse.ui.specific.UiContext;
33 import org.eclipse.rap.rwt.RWT;
34 import org.eclipse.rap.rwt.application.EntryPoint;
35 import org.eclipse.rap.rwt.client.service.BrowserNavigation;
36 import org.eclipse.rap.rwt.client.service.BrowserNavigationEvent;
37 import org.eclipse.rap.rwt.client.service.BrowserNavigationListener;
38 import org.eclipse.rap.rwt.internal.lifecycle.RWTLifeCycle;
39 import org.eclipse.rap.rwt.service.ServerPushSession;
40 import org.eclipse.swt.SWT;
41 import org.eclipse.swt.SWTError;
42 import org.eclipse.swt.widgets.Composite;
43 import org.eclipse.swt.widgets.Display;
44 import org.eclipse.swt.widgets.Shell;
45
46 /** The {@link CmsView} for a {@link CmsWebApp}. */
47 @SuppressWarnings("restriction")
48 public class CmsWebEntryPoint extends AbstractSwtCmsView implements EntryPoint, CmsView, BrowserNavigationListener {
49 private static final long serialVersionUID = 7733510691684570402L;
50 private final static CmsLog log = CmsLog.getLog(CmsWebEntryPoint.class);
51
52 private final CmsWebApp cmsWebApp;
53
54 // Client services
55 // private final JavaScriptExecutor jsExecutor;
56 private final BrowserNavigation browserNavigation;
57
58 /** Experimental OS-like multi windows. */
59 private boolean multipleShells = false;
60
61 private ServerPushSession serverPushSession;
62
63 public CmsWebEntryPoint(CmsWebApp cmsWebApp, String uiName) {
64 super(uiName);
65 assert cmsWebApp != null;
66 assert uiName != null;
67 this.cmsWebApp = cmsWebApp;
68 uid = UUID.randomUUID().toString();
69
70 // Initial login
71 LoginContext lc;
72 try {
73 lc = new LoginContext(CmsAuth.LOGIN_CONTEXT_USER,
74 new RemoteAuthCallbackHandler(new ServletHttpRequest(UiContext.getHttpRequest()),
75 new ServletHttpResponse(UiContext.getHttpResponse())));
76 lc.login();
77 } catch (LoginException e) {
78 try {
79 lc = new LoginContext(CmsAuth.LOGIN_CONTEXT_ANONYMOUS,
80 new RemoteAuthCallbackHandler(new ServletHttpRequest(UiContext.getHttpRequest()),
81 new ServletHttpResponse(UiContext.getHttpResponse())));
82 lc.login();
83 } catch (LoginException e1) {
84 throw new IllegalStateException("Cannot log in as anonymous", e1);
85 }
86 }
87 authChange(lc);
88
89 // jsExecutor = RWT.getClient().getService(JavaScriptExecutor.class);
90 browserNavigation = RWT.getClient().getService(BrowserNavigation.class);
91 if (browserNavigation != null)
92 browserNavigation.addBrowserNavigationListener(this);
93
94 }
95
96 protected void createContents(Composite parent) {
97 Subject.doAs(loginContext.getSubject(), new PrivilegedAction<Void>() {
98 @Override
99 public Void run() {
100 try {
101 uxContext = new SimpleSwtUxContext();
102 imageManager = (CmsImageManager) new AcrSwtImageManager();
103 CmsSession cmsSession = getCmsSession();
104 if (cmsSession != null) {
105 UiContext.setLocale(cmsSession.getLocale());
106 LocaleUtils.setThreadLocale(cmsSession.getLocale());
107 } else {
108 Locale rwtLocale = RWT.getUISession().getLocale();
109 LocaleUtils.setThreadLocale(rwtLocale);
110 }
111 parent.setData(CmsApp.UI_NAME_PROPERTY, uiName);
112 display = parent.getDisplay();
113 ui = cmsWebApp.getCmsApp().initUi(parent);
114 if (ui instanceof Composite)
115 ((Composite) ui).setLayoutData(CmsSwtUtils.fillAll());
116 serverPushSession = new ServerPushSession();
117
118 // required in order to doAs to work
119 // TODO check whether it would be worth optimising
120 serverPushSession.start();
121 // we need ui to be set before refresh so that CmsView can store UI context data
122 // in it.
123 cmsWebApp.getCmsApp().refreshUi(ui, null);
124 } catch (Exception e) {
125 throw new IllegalStateException("Cannot create entrypoint contents", e);
126 }
127 return null;
128 }
129 });
130 }
131
132 @Override
133 public synchronized void logout() {
134 if (loginContext == null)
135 throw new IllegalArgumentException("Login context should not be null");
136 try {
137 CurrentUser.logoutCmsSession(loginContext.getSubject());
138 loginContext.logout();
139 LoginContext anonymousLc = new LoginContext(CmsAuth.LOGIN_CONTEXT_ANONYMOUS,
140 new RemoteAuthCallbackHandler(new ServletHttpRequest(UiContext.getHttpRequest()),
141 new ServletHttpResponse(UiContext.getHttpResponse())));
142 anonymousLc.login();
143 authChange(anonymousLc);
144 } catch (LoginException e) {
145 log.error("Cannot logout", e);
146 }
147 }
148
149 @Override
150 public synchronized void authChange(LoginContext lc) {
151 if (lc == null)
152 throw new IllegalArgumentException("Login context cannot be null");
153 // logout previous login context
154 if (this.loginContext != null)
155 try {
156 this.loginContext.logout();
157 } catch (LoginException e1) {
158 log.warn("Could not log out: " + e1);
159 }
160 this.loginContext = lc;
161 doRefresh();
162 }
163
164 @Override
165 public void exception(final Throwable e) {
166 if (e instanceof SWTError) {
167 SWTError swtError = (SWTError) e;
168 if (swtError.code == SWT.ERROR_FUNCTION_DISPOSED)
169 return;
170 }
171 display.syncExec(() -> {
172 // TODO internationalise
173 CmsFeedback.error("Unexpected exception", e);
174 // TODO report
175 // doRefresh();
176 });
177 }
178
179 protected synchronized void doRefresh() {
180 if (ui != null)
181 Subject.doAs(getSubject(), new PrivilegedAction<Void>() {
182 @Override
183 public Void run() {
184 // if (exception != null) {
185 // // TODO internationalise
186 // CmsFeedback.error("Unexpected exception", exception);
187 // exception = null;
188 // // TODO report
189 // }
190 cmsWebApp.getCmsApp().refreshUi(ui, state);
191 return null;
192 }
193 });
194 }
195
196 /** Sets the state of the entry point and retrieve the related content. */
197 protected String setState(String newState) {
198 cmsWebApp.getCmsApp().setState(ui, newState);
199 state = newState;
200 return null;
201 }
202
203 @Override
204 public void navigateTo(String state) {
205 // exception = null;
206 String title = setState(state);
207 if (title != null)
208 doRefresh();
209 if (browserNavigation != null)
210 browserNavigation.pushState(state, title);
211 }
212
213 public CmsImageManager getImageManager() {
214 return imageManager;
215 }
216
217 @Override
218 public void navigated(BrowserNavigationEvent event) {
219 setState(event.getState());
220 // doRefresh();
221 }
222
223 @Override
224 public CmsEventBus getCmsEventBus() {
225 return cmsWebApp.getCmsEventBus();
226 }
227
228 @Override
229 public CmsApp getCmsApp() {
230 return cmsWebApp.getCmsApp();
231 }
232
233 @Override
234 public void stateChanged(String state, String title) {
235 browserNavigation.pushState(state, title);
236 }
237
238 @Override
239 public CmsSession getCmsSession() {
240 CmsSession cmsSession = cmsWebApp.getCmsApp().getCmsContext().getCmsSession(getSubject());
241 if (cmsSession == null)
242 throw new IllegalStateException("No CMS session available for " + getSubject());
243 return cmsSession;
244 }
245
246 @Override
247 public URI toBackendUri(String url) {
248 try {
249 return new URI(url);
250 } catch (URISyntaxException e) {
251 throw new IllegalArgumentException("Cannot convert " + url, e);
252 }
253 }
254
255 /*
256 * EntryPoint IMPLEMENTATION
257 */
258
259 @Override
260 public int createUI() {
261 Display display = new Display();
262 Shell shell = createShell(display);
263 shell.setLayout(CmsSwtUtils.noSpaceGridLayout());
264 CmsSwtUtils.registerCmsView(shell, this);
265 createContents(shell);
266 shell.layout();
267 // if (shell.getMaximized()) {
268 // shell.layout();
269 // } else {
270 //// shell.pack();
271 // }
272 shell.open();
273 if (getApplicationContext().getLifeCycleFactory().getLifeCycle() instanceof RWTLifeCycle) {
274 eventLoop: while (!shell.isDisposed()) {
275 try {
276 Subject.doAs(loginContext.getSubject(), new PrivilegedAction<Void>() {
277 @Override
278 public Void run() {
279 if (!display.readAndDispatch()) {
280 display.sleep();
281 }
282 return null;
283 }
284 });
285 } catch (SWTError e) {
286 SWTError swtError = (SWTError) e;
287 if (swtError.code == SWT.ERROR_FUNCTION_DISPOSED) {
288 log.error("Unexpected SWT error in event loop, ignoring it. " + e.getMessage());
289 continue eventLoop;
290 } else {
291 log.error("Unexpected SWT error in event loop, shutting down...", e);
292 break eventLoop;
293 }
294 } catch (ThreadDeath e) {
295 // ThreadDeath is expected when the UI thread terminates
296 throw (ThreadDeath) e;
297 } catch (Error e) {
298 log.error("Unexpected error in event loop, shutting down...", e);
299 break eventLoop;
300 } catch (Throwable e) {
301 log.error("Unexpected exception in event loop, ignoring it. " + e.getMessage());
302 continue eventLoop;
303 }
304 }
305 if (serverPushSession != null)
306 serverPushSession.stop();
307 if (!display.isDisposed())
308 display.dispose();
309 }
310 return 0;
311 }
312
313 protected Shell createShell(Display display) {
314 Shell shell;
315 if (!multipleShells) {
316 shell = new Shell(display, SWT.NO_TRIM);
317 shell.setMaximized(true);
318 } else {
319 shell = new Shell(display, SWT.SHELL_TRIM);
320 shell.setSize(800, 600);
321 }
322 return shell;
323 }
324 }