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