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