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