]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.cms.ui.rap/src/org/argeo/cms/ui/script/CmsScriptApp.java
Merge remote-tracking branch 'origin/v2.x'
[lgpl/argeo-commons.git] / org.argeo.cms.ui.rap / src / org / argeo / cms / ui / script / CmsScriptApp.java
1 package org.argeo.cms.ui.script;
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.Enumeration;
8 import java.util.HashMap;
9 import java.util.Hashtable;
10 import java.util.List;
11 import java.util.Map;
12
13 import javax.jcr.Node;
14 import javax.jcr.Property;
15 import javax.jcr.PropertyIterator;
16 import javax.jcr.PropertyType;
17 import javax.jcr.Repository;
18 import javax.jcr.RepositoryException;
19 import javax.script.ScriptEngine;
20 import javax.servlet.http.HttpServletRequest;
21 import javax.servlet.http.HttpServletResponse;
22
23 import org.apache.commons.logging.Log;
24 import org.apache.commons.logging.LogFactory;
25 import org.argeo.cms.CmsException;
26 import org.argeo.cms.ui.CmsConstants;
27 import org.argeo.cms.ui.CmsTheme;
28 import org.argeo.cms.ui.CmsUiProvider;
29 import org.argeo.cms.ui.util.CmsUiUtils;
30 import org.argeo.cms.web.BundleResourceLoader;
31 import org.argeo.cms.web.SimpleErgonomics;
32 import org.argeo.cms.web.WebThemeUtils;
33 import org.eclipse.rap.rwt.application.Application;
34 import org.eclipse.rap.rwt.application.Application.OperationMode;
35 import org.eclipse.rap.rwt.application.ApplicationConfiguration;
36 import org.eclipse.rap.rwt.application.ExceptionHandler;
37 import org.eclipse.rap.rwt.client.WebClient;
38 import org.eclipse.rap.rwt.service.ResourceLoader;
39 import org.osgi.framework.Bundle;
40 import org.osgi.framework.BundleContext;
41 import org.osgi.framework.ServiceRegistration;
42 import org.osgi.service.http.HttpContext;
43 import org.osgi.service.http.HttpService;
44 import org.osgi.service.http.NamespaceException;
45
46 public class CmsScriptApp implements Branding {
47 public final static String CONTEXT_NAME = "contextName";
48
49 ServiceRegistration<ApplicationConfiguration> appConfigReg;
50
51 private ScriptEngine scriptEngine;
52
53 private final static Log log = LogFactory.getLog(CmsScriptApp.class);
54
55 private String webPath;
56 private String repo = "(cn=node)";
57
58 // private Branding branding = new Branding();
59 private CmsTheme theme;
60
61 private List<String> resources = new ArrayList<>();
62
63 private Map<String, AppUi> ui = new HashMap<>();
64
65 private CmsUiProvider header;
66 private Integer headerHeight = null;
67 private CmsUiProvider lead;
68 private CmsUiProvider end;
69 private CmsUiProvider footer;
70
71 // Branding
72 private String themeId;
73 private String additionalHeaders;
74 private String bodyHtml;
75 private String pageTitle;
76 private String pageOverflow;
77 private String favicon;
78
79 public CmsScriptApp(ScriptEngine scriptEngine) {
80 super();
81 this.scriptEngine = scriptEngine;
82 }
83
84 public void apply(BundleContext bundleContext, Repository repository, Application application) {
85 BundleResourceLoader bundleRL = new BundleResourceLoader(bundleContext.getBundle());
86
87 application.setOperationMode(OperationMode.SWT_COMPATIBILITY);
88 // application.setOperationMode(OperationMode.JEE_COMPATIBILITY);
89
90 application.setExceptionHandler(new CmsExceptionHandler());
91
92 // loading animated gif
93 application.addResource(CmsConstants.LOADING_IMAGE, createResourceLoader(CmsConstants.LOADING_IMAGE));
94 // empty image
95 application.addResource(CmsConstants.NO_IMAGE, createResourceLoader(CmsConstants.NO_IMAGE));
96
97 for (String resource : resources) {
98 application.addResource(resource, bundleRL);
99 if (log.isTraceEnabled())
100 log.trace("Resource " + resource);
101 }
102
103 if (theme != null) {
104 WebThemeUtils.apply(application, theme);
105 String themeHeaders = theme.getHtmlHeaders();
106 if (themeHeaders != null) {
107 if (additionalHeaders == null)
108 additionalHeaders = themeHeaders;
109 else
110 additionalHeaders = themeHeaders + "\n" + additionalHeaders;
111 }
112 themeId = theme.getThemeId();
113 }
114
115 // client JavaScript
116 Bundle appBundle = bundleRL.getBundle();
117 BundleContext bc = appBundle.getBundleContext();
118 HttpService httpService = bc.getService(bc.getServiceReference(HttpService.class));
119 HttpContext httpContext = new BundleHttpContext(bc);
120 Enumeration<URL> themeResources = appBundle.findEntries("/js/", "*", true);
121 if (themeResources != null)
122 bundleResources: while (themeResources.hasMoreElements()) {
123 try {
124 String name = themeResources.nextElement().getPath();
125 if (name.endsWith("/"))
126 continue bundleResources;
127 String alias = "/" + getWebPath() + name;
128
129 httpService.registerResources(alias, name, httpContext);
130 if (log.isDebugEnabled())
131 log.debug("Mapped " + name + " to alias " + alias);
132
133 } catch (NamespaceException e) {
134 // TODO Auto-generated catch block
135 e.printStackTrace();
136 }
137 }
138
139 // App UIs
140 for (String appUiName : ui.keySet()) {
141 AppUi appUi = ui.get(appUiName);
142 appUi.apply(repository, application, this, appUiName);
143
144 }
145
146 }
147
148 public void applySides(SimpleErgonomics simpleErgonomics) {
149 simpleErgonomics.setHeader(header);
150 simpleErgonomics.setLead(lead);
151 simpleErgonomics.setEnd(end);
152 simpleErgonomics.setFooter(footer);
153 }
154
155 public void register(BundleContext bundleContext, ApplicationConfiguration appConfig) {
156 Hashtable<String, String> props = new Hashtable<>();
157 props.put(CONTEXT_NAME, webPath);
158 appConfigReg = bundleContext.registerService(ApplicationConfiguration.class, appConfig, props);
159 }
160
161 public void reload() {
162 BundleContext bundleContext = appConfigReg.getReference().getBundle().getBundleContext();
163 ApplicationConfiguration appConfig = bundleContext.getService(appConfigReg.getReference());
164 appConfigReg.unregister();
165 register(bundleContext, appConfig);
166
167 // BundleContext bundleContext = (BundleContext)
168 // getScriptEngine().get("bundleContext");
169 // try {
170 // Bundle bundle = bundleContext.getBundle();
171 // bundle.stop();
172 // bundle.start();
173 // } catch (BundleException e) {
174 // // TODO Auto-generated catch block
175 // e.printStackTrace();
176 // }
177 }
178
179 private static ResourceLoader createResourceLoader(final String resourceName) {
180 return new ResourceLoader() {
181 public InputStream getResourceAsStream(String resourceName) throws IOException {
182 return getClass().getClassLoader().getResourceAsStream(resourceName);
183 }
184 };
185 }
186
187 public List<String> getResources() {
188 return resources;
189 }
190
191 public AppUi newUi(String name) {
192 if (ui.containsKey(name))
193 throw new IllegalArgumentException("There is already an UI named " + name);
194 AppUi appUi = new AppUi(this);
195 // appUi.setApp(this);
196 ui.put(name, appUi);
197 return appUi;
198 }
199
200 public void addUi(String name, AppUi appUi) {
201 if (ui.containsKey(name))
202 throw new IllegalArgumentException("There is already an UI named " + name);
203 // appUi.setApp(this);
204 ui.put(name, appUi);
205 }
206
207 public void applyBranding(Map<String, String> properties) {
208 if (themeId != null)
209 properties.put(WebClient.THEME_ID, themeId);
210 if (additionalHeaders != null)
211 properties.put(WebClient.HEAD_HTML, additionalHeaders);
212 if (bodyHtml != null)
213 properties.put(WebClient.BODY_HTML, bodyHtml);
214 if (pageTitle != null)
215 properties.put(WebClient.PAGE_TITLE, pageTitle);
216 if (pageOverflow != null)
217 properties.put(WebClient.PAGE_OVERFLOW, pageOverflow);
218 if (favicon != null)
219 properties.put(WebClient.FAVICON, favicon);
220 }
221
222 class CmsExceptionHandler implements ExceptionHandler {
223
224 @Override
225 public void handleException(Throwable throwable) {
226 // TODO be smarter
227 CmsUiUtils.getCmsView().exception(throwable);
228 }
229
230 }
231
232 // public Branding getBranding() {
233 // return branding;
234 // }
235
236 ScriptEngine getScriptEngine() {
237 return scriptEngine;
238 }
239
240 public static String toJson(Node node) {
241 try {
242 StringBuilder sb = new StringBuilder();
243 sb.append('{');
244 PropertyIterator pit = node.getProperties();
245 int count = 0;
246 while (pit.hasNext()) {
247 Property p = pit.nextProperty();
248 int type = p.getType();
249 if (type == PropertyType.REFERENCE || type == PropertyType.WEAKREFERENCE || type == PropertyType.PATH) {
250 Node ref = p.getNode();
251 if (count != 0)
252 sb.append(',');
253 // TODO limit depth?
254 sb.append(toJson(ref));
255 count++;
256 } else if (!p.isMultiple()) {
257 if (count != 0)
258 sb.append(',');
259 sb.append('\"').append(p.getName()).append("\":\"").append(p.getString()).append('\"');
260 count++;
261 }
262 }
263 sb.append('}');
264 return sb.toString();
265 } catch (RepositoryException e) {
266 throw new CmsException("Cannot convert " + node + " to JSON", e);
267 }
268 }
269
270 public void fromJson(Node node, String json) {
271 // TODO
272 }
273
274 public CmsTheme getTheme() {
275 return theme;
276 }
277
278 public void setTheme(CmsTheme theme) {
279 this.theme = theme;
280 }
281
282 public String getWebPath() {
283 return webPath;
284 }
285
286 public void setWebPath(String context) {
287 this.webPath = context;
288 }
289
290 public String getRepo() {
291 return repo;
292 }
293
294 public void setRepo(String repo) {
295 this.repo = repo;
296 }
297
298 public Map<String, AppUi> getUi() {
299 return ui;
300 }
301
302 public void setUi(Map<String, AppUi> ui) {
303 this.ui = ui;
304 }
305
306 // Branding
307 public String getThemeId() {
308 return themeId;
309 }
310
311 public void setThemeId(String themeId) {
312 this.themeId = themeId;
313 }
314
315 public String getAdditionalHeaders() {
316 return additionalHeaders;
317 }
318
319 public void setAdditionalHeaders(String additionalHeaders) {
320 this.additionalHeaders = additionalHeaders;
321 }
322
323 public String getBodyHtml() {
324 return bodyHtml;
325 }
326
327 public void setBodyHtml(String bodyHtml) {
328 this.bodyHtml = bodyHtml;
329 }
330
331 public String getPageTitle() {
332 return pageTitle;
333 }
334
335 public void setPageTitle(String pageTitle) {
336 this.pageTitle = pageTitle;
337 }
338
339 public String getPageOverflow() {
340 return pageOverflow;
341 }
342
343 public void setPageOverflow(String pageOverflow) {
344 this.pageOverflow = pageOverflow;
345 }
346
347 public String getFavicon() {
348 return favicon;
349 }
350
351 public void setFavicon(String favicon) {
352 this.favicon = favicon;
353 }
354
355 public CmsUiProvider getHeader() {
356 return header;
357 }
358
359 public void setHeader(CmsUiProvider header) {
360 this.header = header;
361 }
362
363 public Integer getHeaderHeight() {
364 return headerHeight;
365 }
366
367 public void setHeaderHeight(Integer headerHeight) {
368 this.headerHeight = headerHeight;
369 }
370
371 public CmsUiProvider getLead() {
372 return lead;
373 }
374
375 public void setLead(CmsUiProvider lead) {
376 this.lead = lead;
377 }
378
379 public CmsUiProvider getEnd() {
380 return end;
381 }
382
383 public void setEnd(CmsUiProvider end) {
384 this.end = end;
385 }
386
387 public CmsUiProvider getFooter() {
388 return footer;
389 }
390
391 public void setFooter(CmsUiProvider footer) {
392 this.footer = footer;
393 }
394
395 static class BundleHttpContext implements HttpContext {
396 private BundleContext bundleContext;
397
398 public BundleHttpContext(BundleContext bundleContext) {
399 super();
400 this.bundleContext = bundleContext;
401 }
402
403 @Override
404 public boolean handleSecurity(HttpServletRequest request, HttpServletResponse response) throws IOException {
405 // TODO Auto-generated method stub
406 return true;
407 }
408
409 @Override
410 public URL getResource(String name) {
411
412 return bundleContext.getBundle().getEntry(name);
413 }
414
415 @Override
416 public String getMimeType(String name) {
417 return null;
418 }
419
420 }
421
422 }