+package org.argeo.cms.script;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+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 org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.cms.CmsException;
+import org.argeo.cms.ui.CmsConstants;
+import org.argeo.cms.util.BundleResourceLoader;
+import org.argeo.cms.util.CmsUtils;
+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.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+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 Theme theme;
+
+ private List<String> resources = new ArrayList<>();
+
+ private Map<String, AppUi> ui = new HashMap<>();
+
+ // 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) {
+ theme.apply(application);
+ String themeHeaders = theme.getAdditionalHeaders();
+ if (themeHeaders != null) {
+ if (additionalHeaders == null)
+ additionalHeaders = themeHeaders;
+ else
+ additionalHeaders = themeHeaders + "\n" + additionalHeaders;
+ }
+ themeId = theme.getThemeId();
+ }
+
+ for (String appUiName : ui.keySet()) {
+ AppUi appUi = ui.get(appUiName);
+ appUi.apply(repository, application, this, appUiName);
+ }
+
+ }
+
+ 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
+ CmsUtils.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 Theme getTheme() {
+ return theme;
+ }
+
+ public void setTheme(Theme 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;
+ }
+
+}