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