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