Move RAP specific to subdirectory
[lgpl/argeo-commons.git] / rap / org.argeo.cms.ui.rap / src / org / argeo / cms / ui / script / CmsScriptApp.java
diff --git a/rap/org.argeo.cms.ui.rap/src/org/argeo/cms/ui/script/CmsScriptApp.java b/rap/org.argeo.cms.ui.rap/src/org/argeo/cms/ui/script/CmsScriptApp.java
new file mode 100644 (file)
index 0000000..9dd1509
--- /dev/null
@@ -0,0 +1,422 @@
+package org.argeo.cms.ui.script;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import javax.jcr.PropertyType;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.script.ScriptEngine;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.api.cms.CmsTheme;
+import org.argeo.cms.CmsException;
+import org.argeo.cms.ui.CmsConstants;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.cms.web.BundleResourceLoader;
+import org.argeo.cms.web.SimpleErgonomics;
+import org.argeo.cms.web.WebThemeUtils;
+import org.eclipse.rap.rwt.application.Application;
+import org.eclipse.rap.rwt.application.Application.OperationMode;
+import org.eclipse.rap.rwt.application.ApplicationConfiguration;
+import org.eclipse.rap.rwt.application.ExceptionHandler;
+import org.eclipse.rap.rwt.client.WebClient;
+import org.eclipse.rap.rwt.service.ResourceLoader;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.http.HttpContext;
+import org.osgi.service.http.HttpService;
+import org.osgi.service.http.NamespaceException;
+
+public class CmsScriptApp implements Branding {
+       public final static String CONTEXT_NAME = "contextName";
+
+       ServiceRegistration<ApplicationConfiguration> appConfigReg;
+
+       private ScriptEngine scriptEngine;
+
+       private final static Log log = LogFactory.getLog(CmsScriptApp.class);
+
+       private String webPath;
+       private String repo = "(cn=node)";
+
+       // private Branding branding = new Branding();
+       private CmsTheme theme;
+
+       private List<String> resources = new ArrayList<>();
+
+       private Map<String, AppUi> ui = new HashMap<>();
+
+       private CmsUiProvider header;
+       private Integer headerHeight = null;
+       private CmsUiProvider lead;
+       private CmsUiProvider end;
+       private CmsUiProvider footer;
+
+       // Branding
+       private String themeId;
+       private String additionalHeaders;
+       private String bodyHtml;
+       private String pageTitle;
+       private String pageOverflow;
+       private String favicon;
+
+       public CmsScriptApp(ScriptEngine scriptEngine) {
+               super();
+               this.scriptEngine = scriptEngine;
+       }
+
+       public void apply(BundleContext bundleContext, Repository repository, Application application) {
+               BundleResourceLoader bundleRL = new BundleResourceLoader(bundleContext.getBundle());
+
+               application.setOperationMode(OperationMode.SWT_COMPATIBILITY);
+               // application.setOperationMode(OperationMode.JEE_COMPATIBILITY);
+
+               application.setExceptionHandler(new CmsExceptionHandler());
+
+               // loading animated gif
+               application.addResource(CmsConstants.LOADING_IMAGE, createResourceLoader(CmsConstants.LOADING_IMAGE));
+               // empty image
+               application.addResource(CmsConstants.NO_IMAGE, createResourceLoader(CmsConstants.NO_IMAGE));
+
+               for (String resource : resources) {
+                       application.addResource(resource, bundleRL);
+                       if (log.isTraceEnabled())
+                               log.trace("Resource " + resource);
+               }
+
+               if (theme != null) {
+                       WebThemeUtils.apply(application, theme);
+                       String themeHeaders = theme.getHtmlHeaders();
+                       if (themeHeaders != null) {
+                               if (additionalHeaders == null)
+                                       additionalHeaders = themeHeaders;
+                               else
+                                       additionalHeaders = themeHeaders + "\n" + additionalHeaders;
+                       }
+                       themeId = theme.getThemeId();
+               }
+
+               // client JavaScript
+               Bundle appBundle = bundleRL.getBundle();
+               BundleContext bc = appBundle.getBundleContext();
+               HttpService httpService = bc.getService(bc.getServiceReference(HttpService.class));
+               HttpContext httpContext = new BundleHttpContext(bc);
+               Enumeration<URL> themeResources = appBundle.findEntries("/js/", "*", true);
+               if (themeResources != null)
+                       bundleResources: while (themeResources.hasMoreElements()) {
+                               try {
+                                       String name = themeResources.nextElement().getPath();
+                                       if (name.endsWith("/"))
+                                               continue bundleResources;
+                                       String alias = "/" + getWebPath() + name;
+
+                                       httpService.registerResources(alias, name, httpContext);
+                                       if (log.isDebugEnabled())
+                                               log.debug("Mapped " + name + " to alias " + alias);
+
+                               } catch (NamespaceException e) {
+                                       // TODO Auto-generated catch block
+                                       e.printStackTrace();
+                               }
+                       }
+
+               // App UIs
+               for (String appUiName : ui.keySet()) {
+                       AppUi appUi = ui.get(appUiName);
+                       appUi.apply(repository, application, this, appUiName);
+
+               }
+
+       }
+
+       public void applySides(SimpleErgonomics simpleErgonomics) {
+               simpleErgonomics.setHeader(header);
+               simpleErgonomics.setLead(lead);
+               simpleErgonomics.setEnd(end);
+               simpleErgonomics.setFooter(footer);
+       }
+
+       public void register(BundleContext bundleContext, ApplicationConfiguration appConfig) {
+               Hashtable<String, String> props = new Hashtable<>();
+               props.put(CONTEXT_NAME, webPath);
+               appConfigReg = bundleContext.registerService(ApplicationConfiguration.class, appConfig, props);
+       }
+
+       public void reload() {
+               BundleContext bundleContext = appConfigReg.getReference().getBundle().getBundleContext();
+               ApplicationConfiguration appConfig = bundleContext.getService(appConfigReg.getReference());
+               appConfigReg.unregister();
+               register(bundleContext, appConfig);
+
+               // BundleContext bundleContext = (BundleContext)
+               // getScriptEngine().get("bundleContext");
+               // try {
+               // Bundle bundle = bundleContext.getBundle();
+               // bundle.stop();
+               // bundle.start();
+               // } catch (BundleException e) {
+               // // TODO Auto-generated catch block
+               // e.printStackTrace();
+               // }
+       }
+
+       private static ResourceLoader createResourceLoader(final String resourceName) {
+               return new ResourceLoader() {
+                       public InputStream getResourceAsStream(String resourceName) throws IOException {
+                               return getClass().getClassLoader().getResourceAsStream(resourceName);
+                       }
+               };
+       }
+
+       public List<String> getResources() {
+               return resources;
+       }
+
+       public AppUi newUi(String name) {
+               if (ui.containsKey(name))
+                       throw new IllegalArgumentException("There is already an UI named " + name);
+               AppUi appUi = new AppUi(this);
+               // appUi.setApp(this);
+               ui.put(name, appUi);
+               return appUi;
+       }
+
+       public void addUi(String name, AppUi appUi) {
+               if (ui.containsKey(name))
+                       throw new IllegalArgumentException("There is already an UI named " + name);
+               // appUi.setApp(this);
+               ui.put(name, appUi);
+       }
+
+       public void applyBranding(Map<String, String> properties) {
+               if (themeId != null)
+                       properties.put(WebClient.THEME_ID, themeId);
+               if (additionalHeaders != null)
+                       properties.put(WebClient.HEAD_HTML, additionalHeaders);
+               if (bodyHtml != null)
+                       properties.put(WebClient.BODY_HTML, bodyHtml);
+               if (pageTitle != null)
+                       properties.put(WebClient.PAGE_TITLE, pageTitle);
+               if (pageOverflow != null)
+                       properties.put(WebClient.PAGE_OVERFLOW, pageOverflow);
+               if (favicon != null)
+                       properties.put(WebClient.FAVICON, favicon);
+       }
+
+       class CmsExceptionHandler implements ExceptionHandler {
+
+               @Override
+               public void handleException(Throwable throwable) {
+                       // TODO be smarter
+                       CmsUiUtils.getCmsView().exception(throwable);
+               }
+
+       }
+
+       // public Branding getBranding() {
+       // return branding;
+       // }
+
+       ScriptEngine getScriptEngine() {
+               return scriptEngine;
+       }
+
+       public static String toJson(Node node) {
+               try {
+                       StringBuilder sb = new StringBuilder();
+                       sb.append('{');
+                       PropertyIterator pit = node.getProperties();
+                       int count = 0;
+                       while (pit.hasNext()) {
+                               Property p = pit.nextProperty();
+                               int type = p.getType();
+                               if (type == PropertyType.REFERENCE || type == PropertyType.WEAKREFERENCE || type == PropertyType.PATH) {
+                                       Node ref = p.getNode();
+                                       if (count != 0)
+                                               sb.append(',');
+                                       // TODO limit depth?
+                                       sb.append(toJson(ref));
+                                       count++;
+                               } else if (!p.isMultiple()) {
+                                       if (count != 0)
+                                               sb.append(',');
+                                       sb.append('\"').append(p.getName()).append("\":\"").append(p.getString()).append('\"');
+                                       count++;
+                               }
+                       }
+                       sb.append('}');
+                       return sb.toString();
+               } catch (RepositoryException e) {
+                       throw new CmsException("Cannot convert " + node + " to JSON", e);
+               }
+       }
+
+       public void fromJson(Node node, String json) {
+               // TODO
+       }
+
+       public CmsTheme getTheme() {
+               return theme;
+       }
+
+       public void setTheme(CmsTheme theme) {
+               this.theme = theme;
+       }
+
+       public String getWebPath() {
+               return webPath;
+       }
+
+       public void setWebPath(String context) {
+               this.webPath = context;
+       }
+
+       public String getRepo() {
+               return repo;
+       }
+
+       public void setRepo(String repo) {
+               this.repo = repo;
+       }
+
+       public Map<String, AppUi> getUi() {
+               return ui;
+       }
+
+       public void setUi(Map<String, AppUi> ui) {
+               this.ui = ui;
+       }
+
+       // Branding
+       public String getThemeId() {
+               return themeId;
+       }
+
+       public void setThemeId(String themeId) {
+               this.themeId = themeId;
+       }
+
+       public String getAdditionalHeaders() {
+               return additionalHeaders;
+       }
+
+       public void setAdditionalHeaders(String additionalHeaders) {
+               this.additionalHeaders = additionalHeaders;
+       }
+
+       public String getBodyHtml() {
+               return bodyHtml;
+       }
+
+       public void setBodyHtml(String bodyHtml) {
+               this.bodyHtml = bodyHtml;
+       }
+
+       public String getPageTitle() {
+               return pageTitle;
+       }
+
+       public void setPageTitle(String pageTitle) {
+               this.pageTitle = pageTitle;
+       }
+
+       public String getPageOverflow() {
+               return pageOverflow;
+       }
+
+       public void setPageOverflow(String pageOverflow) {
+               this.pageOverflow = pageOverflow;
+       }
+
+       public String getFavicon() {
+               return favicon;
+       }
+
+       public void setFavicon(String favicon) {
+               this.favicon = favicon;
+       }
+
+       public CmsUiProvider getHeader() {
+               return header;
+       }
+
+       public void setHeader(CmsUiProvider header) {
+               this.header = header;
+       }
+
+       public Integer getHeaderHeight() {
+               return headerHeight;
+       }
+
+       public void setHeaderHeight(Integer headerHeight) {
+               this.headerHeight = headerHeight;
+       }
+
+       public CmsUiProvider getLead() {
+               return lead;
+       }
+
+       public void setLead(CmsUiProvider lead) {
+               this.lead = lead;
+       }
+
+       public CmsUiProvider getEnd() {
+               return end;
+       }
+
+       public void setEnd(CmsUiProvider end) {
+               this.end = end;
+       }
+
+       public CmsUiProvider getFooter() {
+               return footer;
+       }
+
+       public void setFooter(CmsUiProvider footer) {
+               this.footer = footer;
+       }
+
+       static class BundleHttpContext implements HttpContext {
+               private BundleContext bundleContext;
+
+               public BundleHttpContext(BundleContext bundleContext) {
+                       super();
+                       this.bundleContext = bundleContext;
+               }
+
+               @Override
+               public boolean handleSecurity(HttpServletRequest request, HttpServletResponse response) throws IOException {
+                       // TODO Auto-generated method stub
+                       return true;
+               }
+
+               @Override
+               public URL getResource(String name) {
+
+                       return bundleContext.getBundle().getEntry(name);
+               }
+
+               @Override
+               public String getMimeType(String name) {
+                       return null;
+               }
+
+       }
+
+}