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