]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.cms.ui.rap/src/org/argeo/cms/web/SimpleApp.java
Remove dependency to JTA
[lgpl/argeo-commons.git] / org.argeo.cms.ui.rap / src / org / argeo / cms / web / SimpleApp.java
1 package org.argeo.cms.web;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.net.URL;
6 import java.util.ArrayList;
7 import java.util.Arrays;
8 import java.util.Enumeration;
9 import java.util.HashMap;
10 import java.util.HashSet;
11 import java.util.Hashtable;
12 import java.util.LinkedHashMap;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.Set;
16
17 import javax.jcr.Repository;
18 import javax.jcr.RepositoryException;
19 import javax.jcr.Session;
20 import javax.jcr.security.Privilege;
21 import javax.jcr.version.VersionManager;
22
23 import org.apache.commons.logging.Log;
24 import org.apache.commons.logging.LogFactory;
25 import org.argeo.api.NodeConstants;
26 import org.argeo.api.NodeUtils;
27 import org.argeo.cms.CmsException;
28 import org.argeo.cms.ui.CmsConstants;
29 import org.argeo.cms.ui.CmsUiProvider;
30 import org.argeo.cms.ui.LifeCycleUiProvider;
31 import org.argeo.cms.ui.util.CmsUiUtils;
32 import org.argeo.cms.ui.util.StyleSheetResourceLoader;
33 import org.argeo.jcr.JcrUtils;
34 import org.eclipse.rap.rwt.RWT;
35 import org.eclipse.rap.rwt.application.Application;
36 import org.eclipse.rap.rwt.application.Application.OperationMode;
37 import org.eclipse.rap.rwt.application.ApplicationConfiguration;
38 import org.eclipse.rap.rwt.application.EntryPoint;
39 import org.eclipse.rap.rwt.application.EntryPointFactory;
40 import org.eclipse.rap.rwt.application.ExceptionHandler;
41 import org.eclipse.rap.rwt.client.WebClient;
42 import org.eclipse.rap.rwt.client.service.JavaScriptExecutor;
43 import org.eclipse.rap.rwt.service.ResourceLoader;
44 import org.eclipse.swt.SWT;
45 import org.eclipse.swt.events.SelectionAdapter;
46 import org.eclipse.swt.events.SelectionEvent;
47 import org.eclipse.swt.layout.FillLayout;
48 import org.eclipse.swt.widgets.Button;
49 import org.eclipse.swt.widgets.Composite;
50 import org.osgi.framework.Bundle;
51 import org.osgi.framework.BundleContext;
52 import org.osgi.framework.ServiceRegistration;
53
54 /** A basic generic app based on {@link SimpleErgonomics}. */
55 @Deprecated
56 public class SimpleApp implements CmsConstants, ApplicationConfiguration {
57 private final static Log log = LogFactory.getLog(SimpleApp.class);
58
59 private String contextName = null;
60
61 private Map<String, Map<String, String>> branding = new HashMap<String, Map<String, String>>();
62 private Map<String, List<String>> styleSheets = new HashMap<String, List<String>>();
63
64 private List<String> resources = new ArrayList<String>();
65
66 private BundleContext bundleContext;
67
68 private Repository repository;
69 private String workspace = null;
70 private String jcrBasePath = "/";
71 private List<String> roPrincipals = Arrays.asList(NodeConstants.ROLE_ANONYMOUS, NodeConstants.ROLE_USER);
72 private List<String> rwPrincipals = Arrays.asList(NodeConstants.ROLE_USER);
73
74 private CmsUiProvider header;
75 private Map<String, CmsUiProvider> pages = new LinkedHashMap<String, CmsUiProvider>();
76
77 private Integer headerHeight = 40;
78
79 private ServiceRegistration<ApplicationConfiguration> appReg;
80
81 public void configure(Application application) {
82 try {
83 BundleResourceLoader bundleRL = new BundleResourceLoader(bundleContext.getBundle());
84
85 application.setOperationMode(OperationMode.SWT_COMPATIBILITY);
86 // application.setOperationMode(OperationMode.JEE_COMPATIBILITY);
87
88 application.setExceptionHandler(new CmsExceptionHandler());
89
90 // loading animated gif
91 application.addResource(LOADING_IMAGE, createResourceLoader(LOADING_IMAGE));
92 // empty image
93 application.addResource(NO_IMAGE, createResourceLoader(NO_IMAGE));
94
95 for (String resource : resources) {
96 application.addResource(resource, bundleRL);
97 if (log.isTraceEnabled())
98 log.trace("Resource " + resource);
99 }
100
101 Map<String, String> defaultBranding = null;
102 if (branding.containsKey("*"))
103 defaultBranding = branding.get("*");
104 // String defaultTheme = defaultBranding.get(WebClient.THEME_ID);
105
106 // entry points
107 for (String page : pages.keySet()) {
108 Map<String, String> properties = defaultBranding != null ? new HashMap<String, String>(defaultBranding)
109 : new HashMap<String, String>();
110 if (branding.containsKey(page)) {
111 properties.putAll(branding.get(page));
112 }
113 // favicon
114 if (properties.containsKey(WebClient.FAVICON)) {
115 String themeId = defaultBranding.get(WebClient.THEME_ID);
116 Bundle themeBundle = findThemeBundle(bundleContext, themeId);
117 String faviconRelPath = properties.get(WebClient.FAVICON);
118 application.addResource(faviconRelPath,
119 new BundleResourceLoader(themeBundle != null ? themeBundle : bundleContext.getBundle()));
120 if (log.isTraceEnabled())
121 log.trace("Favicon " + faviconRelPath);
122
123 }
124
125 // page title
126 if (!properties.containsKey(WebClient.PAGE_TITLE)) {
127 if (page.length() > 0)
128 properties.put(WebClient.PAGE_TITLE, Character.toUpperCase(page.charAt(0)) + page.substring(1));
129 }
130
131 // default body HTML
132 if (!properties.containsKey(WebClient.BODY_HTML))
133 properties.put(WebClient.BODY_HTML, DEFAULT_LOADING_BODY);
134
135 //
136 // ADD ENTRY POINT
137 //
138 application.addEntryPoint("/" + page,
139 new CmsEntryPointFactory(pages.get(page), repository, workspace, properties), properties);
140 log.info("Page /" + page);
141 }
142
143 // stylesheets and themes
144 Set<Bundle> themeBundles = new HashSet<>();
145 for (String themeId : styleSheets.keySet()) {
146 Bundle themeBundle = findThemeBundle(bundleContext, themeId);
147 StyleSheetResourceLoader styleSheetRL = new StyleSheetResourceLoader(
148 themeBundle != null ? themeBundle : bundleContext.getBundle());
149 if (themeBundle != null)
150 themeBundles.add(themeBundle);
151 List<String> cssLst = styleSheets.get(themeId);
152 if (log.isDebugEnabled())
153 log.debug("Theme " + themeId);
154 for (String css : cssLst) {
155 application.addStyleSheet(themeId, css, styleSheetRL);
156 if (log.isDebugEnabled())
157 log.debug(" CSS " + css);
158 }
159
160 }
161 for (Bundle themeBundle : themeBundles) {
162 BundleResourceLoader themeBRL = new BundleResourceLoader(themeBundle);
163 SimpleApp.addThemeResources(application, themeBundle, themeBRL, "*.png");
164 SimpleApp.addThemeResources(application, themeBundle, themeBRL, "*.gif");
165 SimpleApp.addThemeResources(application, themeBundle, themeBRL, "*.jpg");
166 }
167 } catch (RuntimeException e) {
168 // Easier access to initialisation errors
169 log.error("Unexpected exception when configuring RWT application.", e);
170 throw e;
171 }
172 }
173
174 public void init() throws RepositoryException {
175 Session session = null;
176 try {
177 session = NodeUtils.openDataAdminSession(repository, workspace);
178 // session = JcrUtils.loginOrCreateWorkspace(repository, workspace);
179 VersionManager vm = session.getWorkspace().getVersionManager();
180 JcrUtils.mkdirs(session, jcrBasePath);
181 session.save();
182 if (!vm.isCheckedOut(jcrBasePath))
183 vm.checkout(jcrBasePath);
184 for (String principal : rwPrincipals)
185 JcrUtils.addPrivilege(session, jcrBasePath, principal, Privilege.JCR_WRITE);
186 for (String principal : roPrincipals)
187 JcrUtils.addPrivilege(session, jcrBasePath, principal, Privilege.JCR_READ);
188
189 for (String pageName : pages.keySet()) {
190 try {
191 initPage(session, pages.get(pageName));
192 session.save();
193 } catch (Exception e) {
194 throw new CmsException("Cannot initialize page " + pageName, e);
195 }
196 }
197
198 } finally {
199 JcrUtils.logoutQuietly(session);
200 }
201
202 // publish to OSGi
203 register();
204 }
205
206 protected void initPage(Session adminSession, CmsUiProvider page) throws RepositoryException {
207 if (page instanceof LifeCycleUiProvider)
208 ((LifeCycleUiProvider) page).init(adminSession);
209 }
210
211 public void destroy() {
212 for (String pageName : pages.keySet()) {
213 try {
214 CmsUiProvider page = pages.get(pageName);
215 if (page instanceof LifeCycleUiProvider)
216 ((LifeCycleUiProvider) page).destroy();
217 } catch (Exception e) {
218 log.error("Cannot destroy page " + pageName, e);
219 }
220 }
221 }
222
223 protected void register() {
224 Hashtable<String, String> props = new Hashtable<String, String>();
225 if (contextName != null)
226 props.put("contextName", contextName);
227 appReg = bundleContext.registerService(ApplicationConfiguration.class, this, props);
228 if (log.isDebugEnabled())
229 log.debug("Registered " + (contextName == null ? "/" : contextName));
230 }
231
232 protected void unregister() {
233 appReg.unregister();
234 if (log.isDebugEnabled())
235 log.debug("Unregistered " + (contextName == null ? "/" : contextName));
236 }
237
238 public void setRepository(Repository repository) {
239 this.repository = repository;
240 }
241
242 public void setWorkspace(String workspace) {
243 this.workspace = workspace;
244 }
245
246 public void setHeader(CmsUiProvider header) {
247 this.header = header;
248 }
249
250 public void setPages(Map<String, CmsUiProvider> pages) {
251 this.pages = pages;
252 }
253
254 public void setJcrBasePath(String basePath) {
255 this.jcrBasePath = basePath;
256 }
257
258 public void setRoPrincipals(List<String> roPrincipals) {
259 this.roPrincipals = roPrincipals;
260 }
261
262 public void setRwPrincipals(List<String> rwPrincipals) {
263 this.rwPrincipals = rwPrincipals;
264 }
265
266 public void setHeaderHeight(Integer headerHeight) {
267 this.headerHeight = headerHeight;
268 }
269
270 public void setBranding(Map<String, Map<String, String>> branding) {
271 this.branding = branding;
272 }
273
274 public void setStyleSheets(Map<String, List<String>> styleSheets) {
275 this.styleSheets = styleSheets;
276 }
277
278 public void setBundleContext(BundleContext bundleContext) {
279 this.bundleContext = bundleContext;
280 }
281
282 public void setResources(List<String> resources) {
283 this.resources = resources;
284 }
285
286 public void setContextName(String contextName) {
287 this.contextName = contextName;
288 }
289
290 private static void addThemeResources(Application application, Bundle themeBundle, BundleResourceLoader themeBRL,
291 String pattern) {
292 Enumeration<URL> themeResources = themeBundle.findEntries("/", pattern, true);
293 if (themeResources == null)
294 return;
295 while (themeResources.hasMoreElements()) {
296 String resource = themeResources.nextElement().getPath();
297 // remove first '/' so that RWT registers it
298 resource = resource.substring(1);
299 if (!resource.endsWith("/")) {
300 application.addResource(resource, themeBRL);
301 if (log.isTraceEnabled())
302 log.trace("Registered " + resource + " from theme " + themeBundle);
303 }
304
305 }
306
307 }
308
309 private static Bundle findThemeBundle(BundleContext bundleContext, String themeId) {
310 if (themeId == null)
311 return null;
312 // TODO optimize
313 // TODO deal with multiple versions
314 Bundle themeBundle = null;
315 if (themeId != null) {
316 for (Bundle bundle : bundleContext.getBundles())
317 if (themeId.equals(bundle.getSymbolicName())) {
318 themeBundle = bundle;
319 break;
320 }
321 }
322 return themeBundle;
323 }
324
325 class CmsExceptionHandler implements ExceptionHandler {
326
327 @Override
328 public void handleException(Throwable throwable) {
329 // TODO be smarter
330 CmsUiUtils.getCmsView().exception(throwable);
331 }
332
333 }
334
335 private class CmsEntryPointFactory implements EntryPointFactory {
336 private final CmsUiProvider page;
337 private final Repository repository;
338 private final String workspace;
339 private final Map<String, String> properties;
340
341 public CmsEntryPointFactory(CmsUiProvider page, Repository repository, String workspace,
342 Map<String, String> properties) {
343 this.page = page;
344 this.repository = repository;
345 this.workspace = workspace;
346 this.properties = properties;
347 }
348
349 @Override
350 public EntryPoint create() {
351 SimpleErgonomics entryPoint = new SimpleErgonomics(repository, workspace, jcrBasePath, page, properties) {
352 private static final long serialVersionUID = -637940404865527290L;
353
354 @Override
355 protected void createAdminArea(Composite parent) {
356 Composite adminArea = new Composite(parent, SWT.NONE);
357 adminArea.setLayout(new FillLayout());
358 Button refresh = new Button(adminArea, SWT.PUSH);
359 refresh.setText("Reload App");
360 refresh.addSelectionListener(new SelectionAdapter() {
361 private static final long serialVersionUID = -7671999525536351366L;
362
363 @Override
364 public void widgetSelected(SelectionEvent e) {
365 long timeBeforeReload = 1000;
366 RWT.getClient().getService(JavaScriptExecutor.class).execute(
367 "setTimeout(function() { " + "location.reload();" + "}," + timeBeforeReload + ");");
368 reloadApp();
369 }
370 });
371 }
372 };
373 // entryPoint.setState("");
374 entryPoint.setHeader(header);
375 entryPoint.setHeaderHeight(headerHeight);
376 // CmsSession.current.set(entryPoint);
377 return entryPoint;
378 }
379
380 private void reloadApp() {
381 new Thread("Refresh app") {
382 @Override
383 public void run() {
384 unregister();
385 register();
386 }
387 }.start();
388 }
389 }
390
391 private static ResourceLoader createResourceLoader(final String resourceName) {
392 return new ResourceLoader() {
393 public InputStream getResourceAsStream(String resourceName) throws IOException {
394 return getClass().getClassLoader().getResourceAsStream(resourceName);
395 }
396 };
397 }
398
399 // private static ResourceLoader createUrlResourceLoader(final URL url) {
400 // return new ResourceLoader() {
401 // public InputStream getResourceAsStream(String resourceName)
402 // throws IOException {
403 // return url.openStream();
404 // }
405 // };
406 // }
407
408 /*
409 * TEXTS
410 */
411 private static String DEFAULT_LOADING_BODY = "<div"
412 + " style=\"position: absolute; left: 50%; top: 50%; margin: -32px -32px; width: 64px; height:64px\">"
413 + "<img src=\"./rwt-resources/" + LOADING_IMAGE
414 + "\" width=\"32\" height=\"32\" style=\"margin: 16px 16px\"/>" + "</div>";
415 }