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