]> git.argeo.org Git - lgpl/argeo-commons.git/blob - rcp/org.argeo.cms.ui.rcp/src/org/argeo/cms/ui/rcp/CmsRcpApp.java
Prepare next development cycle
[lgpl/argeo-commons.git] / rcp / org.argeo.cms.ui.rcp / src / org / argeo / cms / ui / rcp / CmsRcpApp.java
1 package org.argeo.cms.ui.rcp;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.security.PrivilegedAction;
6 import java.util.HashMap;
7 import java.util.Map;
8 import java.util.UUID;
9
10 import javax.security.auth.Subject;
11 import javax.security.auth.login.LoginContext;
12 import javax.security.auth.login.LoginException;
13
14 import org.argeo.api.cms.CmsApp;
15 import org.argeo.api.cms.CmsAuth;
16 import org.argeo.api.cms.CmsImageManager;
17 import org.argeo.api.cms.CmsSession;
18 import org.argeo.api.cms.CmsTheme;
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.osgi.CmsOsgiUtils;
24 import org.argeo.cms.swt.CmsSwtUtils;
25 import org.eclipse.e4.ui.css.core.engine.CSSEngine;
26 import org.eclipse.e4.ui.css.core.engine.CSSErrorHandler;
27 import org.eclipse.e4.ui.css.swt.engine.CSSSWTEngineImpl;
28 import org.eclipse.swt.layout.GridLayout;
29 import org.eclipse.swt.widgets.Composite;
30 import org.eclipse.swt.widgets.Display;
31 import org.eclipse.swt.widgets.Shell;
32 import org.osgi.framework.BundleContext;
33 import org.osgi.framework.FrameworkUtil;
34 import org.osgi.service.event.Event;
35 import org.osgi.service.event.EventAdmin;
36
37 /** Runs a {@link CmsApp} as an SWT desktop application. */
38 @SuppressWarnings("restriction")
39 public class CmsRcpApp implements CmsView {
40 private final static CmsLog log = CmsLog.getLog(CmsRcpApp.class);
41
42 private BundleContext bundleContext = FrameworkUtil.getBundle(CmsRcpApp.class).getBundleContext();
43
44 private Display display;
45 private Shell shell;
46 private CmsApp cmsApp;
47 private CmsUiThread uiThread;
48
49 // CMS View
50 private String uid;
51 private LoginContext loginContext;
52
53 private EventAdmin eventAdmin;
54
55 private CSSEngine cssEngine;
56
57 private CmsUi ui;
58 // TODO make it configurable
59 private String uiName = "desktop";
60
61 public CmsRcpApp() {
62 uid = UUID.randomUUID().toString();
63 }
64
65 public void init(Map<String, String> properties) {
66 try {
67 Thread.sleep(5000);
68 } catch (InterruptedException e) {
69 // silent
70 }
71 uiThread = new CmsUiThread();
72 uiThread.start();
73
74 }
75
76 public void destroy(Map<String, String> properties) {
77 if (!shell.isDisposed())
78 shell.dispose();
79 try {
80 uiThread.join();
81 } catch (InterruptedException e) {
82 // silent
83 } finally {
84 uiThread = null;
85 }
86 }
87
88 class CmsUiThread extends Thread {
89
90 public CmsUiThread() {
91 super("CMS UI");
92 }
93
94 @Override
95 public void run() {
96 display = new Display();
97 shell = new Shell(display);
98 shell.setText("Argeo CMS");
99 Composite parent = shell;
100 parent.setLayout(new GridLayout());
101 CmsSwtUtils.registerCmsView(shell, CmsRcpApp.this);
102
103 // Subject subject = new Subject();
104 // CmsLoginShell loginShell = new CmsLoginShell(CmsRcpApp.this);
105 // loginShell.setSubject(subject);
106 try {
107 // try pre-auth
108 // loginContext = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, subject, loginShell);
109 loginContext = new LoginContext(CmsAuth.LOGIN_CONTEXT_SINGLE_USER);
110 loginContext.login();
111 } catch (LoginException e) {
112 throw new IllegalStateException("Could not log in.", e);
113 // loginShell.createUi();
114 // loginShell.open();
115 //
116 // while (!loginShell.getShell().isDisposed()) {
117 // if (!display.readAndDispatch())
118 // display.sleep();
119 // }
120 }
121 if (log.isDebugEnabled())
122 log.debug("Logged in to desktop: " + loginContext.getSubject());
123
124 Subject.doAs(loginContext.getSubject(), (PrivilegedAction<Void>) () -> {
125
126 // TODO factorise with web app
127 parent.setData(CmsApp.UI_NAME_PROPERTY, uiName);
128 ui = cmsApp.initUi(parent);
129 if (ui instanceof Composite)
130 ((Composite) ui).setLayoutData(CmsSwtUtils.fillAll());
131 // ui.setLayoutData(CmsUiUtils.fillAll());
132 // we need ui to be set before refresh so that CmsView can store UI context data
133 // in it.
134 cmsApp.refreshUi(ui, null);
135
136 // Styling
137 CmsTheme theme = CmsSwtUtils.getCmsTheme(parent);
138 if (theme != null) {
139 cssEngine = new CSSSWTEngineImpl(display);
140 for (String path : theme.getSwtCssPaths()) {
141 try (InputStream in = theme.loadPath(path)) {
142 cssEngine.parseStyleSheet(in);
143 } catch (IOException e) {
144 throw new IllegalStateException("Cannot load stylesheet " + path, e);
145 }
146 }
147 cssEngine.setErrorHandler(new CSSErrorHandler() {
148 public void error(Exception e) {
149 log.error("SWT styling error: ", e);
150 }
151 });
152 applyStyles(shell);
153 }
154 shell.layout(true, true);
155
156 shell.open();
157 while (!shell.isDisposed()) {
158 if (!display.readAndDispatch())
159 display.sleep();
160 }
161 display.dispose();
162 return null;
163 });
164 }
165
166 }
167
168 /*
169 * CMS VIEW
170 */
171
172 @Override
173 public String getUid() {
174 return uid;
175 }
176
177 @Override
178 public UxContext getUxContext() {
179 throw new UnsupportedOperationException();
180 }
181
182 @Override
183 public void navigateTo(String state) {
184 throw new UnsupportedOperationException();
185 }
186
187 @Override
188 public void authChange(LoginContext loginContext) {
189 }
190
191 @Override
192 public void logout() {
193 if (loginContext != null)
194 try {
195 loginContext.logout();
196 } catch (LoginException e) {
197 log.error("Cannot log out", e);
198 }
199 }
200
201 @Override
202 public void exception(Throwable e) {
203 log.error("Unexpected exception in CMS RCP", e);
204 }
205
206 @Override
207 public CmsImageManager getImageManager() {
208 throw new UnsupportedOperationException();
209 }
210
211 @Override
212 public CmsSession getCmsSession() {
213 CmsSession cmsSession = CmsOsgiUtils.getCmsSession(bundleContext, getSubject());
214 return cmsSession;
215 }
216
217 @Override
218 public Object getData(String key) {
219 if (ui != null) {
220 return ui.getData(key);
221 } else {
222 throw new IllegalStateException("UI is not initialized");
223 }
224 }
225
226 @Override
227 public void setData(String key, Object value) {
228 if (ui != null) {
229 ui.setData(key, value);
230 } else {
231 throw new IllegalStateException("UI is not initialized");
232 }
233 }
234
235 @Override
236 public boolean isAnonymous() {
237 return false;
238 }
239
240 @Override
241 public void applyStyles(Object node) {
242 if (cssEngine != null)
243 cssEngine.applyStyles(node, true);
244 }
245
246 @Override
247 public void sendEvent(String topic, Map<String, Object> properties) {
248 if (properties == null)
249 properties = new HashMap<>();
250 if (properties.containsKey(CMS_VIEW_UID_PROPERTY) && !properties.get(CMS_VIEW_UID_PROPERTY).equals(uid))
251 throw new IllegalArgumentException("Property " + CMS_VIEW_UID_PROPERTY + " is set to another CMS view uid ("
252 + properties.get(CMS_VIEW_UID_PROPERTY) + ") then " + uid);
253 properties.put(CMS_VIEW_UID_PROPERTY, uid);
254 eventAdmin.sendEvent(new Event(topic, properties));
255 }
256
257 public <T> T doAs(PrivilegedAction<T> action) {
258 return Subject.doAs(getSubject(), action);
259 }
260
261 protected Subject getSubject() {
262 return loginContext.getSubject();
263 }
264
265 /*
266 * DEPENDENCY INJECTION
267 */
268 public void setCmsApp(CmsApp cmsApp) {
269 this.cmsApp = cmsApp;
270 }
271
272 public void setEventAdmin(EventAdmin eventAdmin) {
273 this.eventAdmin = eventAdmin;
274 }
275
276 }