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