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