<artifactId>org.argeo.cms.ui</artifactId>
<version>2.1.89-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.argeo.commons</groupId>
+ <artifactId>org.argeo.cms.ui.rap</artifactId>
+ <version>2.1.89-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.argeo.commons</groupId>
<artifactId>org.argeo.cms.ui.theme</artifactId>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
--- /dev/null
+/bin/
+/target/
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.argeo.cms.ui.rap</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+/MANIFEST.MF
--- /dev/null
+Import-Package:\
+org.eclipse.swt,\
+org.argeo.eclipse.ui,\
+javax.jcr.nodetype,\
+javax.jcr.security,\
+org.eclipse.swt.graphics,\
+*
--- /dev/null
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.argeo.commons</groupId>
+ <artifactId>argeo-commons</artifactId>
+ <version>2.1.89-SNAPSHOT</version>
+ <relativePath>..</relativePath>
+ </parent>
+ <artifactId>org.argeo.cms.ui.rap</artifactId>
+ <name>CMS UI RAP</name>
+ <packaging>jar</packaging>
+ <dependencies>
+ <dependency>
+ <groupId>org.argeo.commons</groupId>
+ <artifactId>org.argeo.cms.ui</artifactId>
+ <version>2.1.89-SNAPSHOT</version>
+ </dependency>
+ <!-- Specific -->
+ <dependency>
+ <groupId>org.argeo.commons</groupId>
+ <artifactId>org.argeo.eclipse.ui.rap</artifactId>
+ <version>2.1.89-SNAPSHOT</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <!-- Theme -->
+ <dependency>
+ <groupId>org.argeo.commons</groupId>
+ <artifactId>org.argeo.cms.ui.theme</artifactId>
+ <version>2.1.89-SNAPSHOT</version>
+ </dependency>
+
+ <!-- UI -->
+ <dependency>
+ <groupId>org.argeo.tp.rap.e4</groupId>
+ <artifactId>org.eclipse.rap.rwt</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.argeo.tp.rap.e4</groupId>
+ <artifactId>org.eclipse.core.commands</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.argeo.tp.rap.e4</groupId>
+ <artifactId>org.eclipse.rap.jface</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <!-- TODO move it to specific -->
+ <dependency>
+ <groupId>org.argeo.tp.rap.e4</groupId>
+ <artifactId>org.eclipse.rap.filedialog</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.argeo.tp.rap.e4</groupId>
+ <artifactId>org.eclipse.rap.fileupload</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ </dependencies>
+</project>
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.ui.script;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.script.Invocable;
+import javax.script.ScriptException;
+
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.util.CmsPane;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.cms.web.SimpleErgonomics;
+import org.argeo.eclipse.ui.Selected;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.application.Application;
+import org.eclipse.rap.rwt.application.EntryPoint;
+import org.eclipse.rap.rwt.application.EntryPointFactory;
+import org.eclipse.rap.rwt.client.WebClient;
+import org.eclipse.rap.rwt.client.service.JavaScriptExecutor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.osgi.framework.BundleContext;
+
+public class AppUi implements CmsUiProvider, Branding {
+ private final CmsScriptApp app;
+
+ private CmsUiProvider ui;
+ private String createUi;
+ private Object impl;
+ private String script;
+ // private Branding branding = new Branding();
+
+ private EntryPointFactory factory;
+
+ // Branding
+ private String themeId;
+ private String additionalHeaders;
+ private String bodyHtml;
+ private String pageTitle;
+ private String pageOverflow;
+ private String favicon;
+
+ public AppUi(CmsScriptApp app) {
+ this.app = app;
+ }
+
+ public AppUi(CmsScriptApp app, String scriptPath) {
+ this.app = app;
+ this.ui = new ScriptUi((BundleContext) app.getScriptEngine().get(CmsScriptRwtApplication.BC), app.getScriptEngine(), scriptPath);
+ }
+
+ public AppUi(CmsScriptApp app, CmsUiProvider uiProvider) {
+ this.app = app;
+ this.ui = uiProvider;
+ }
+
+ public AppUi(CmsScriptApp app, EntryPointFactory factory) {
+ this.app = app;
+ this.factory = factory;
+ }
+
+ public void apply(Repository repository, Application application, Branding appBranding, String path) {
+ Map<String, String> factoryProperties = new HashMap<>();
+ if (appBranding != null)
+ appBranding.applyBranding(factoryProperties);
+ applyBranding(factoryProperties);
+ if (factory != null) {
+ application.addEntryPoint("/" + path, factory, factoryProperties);
+ } else {
+ EntryPointFactory entryPointFactory = new EntryPointFactory() {
+ @Override
+ public EntryPoint create() {
+ SimpleErgonomics ergonomics = new SimpleErgonomics(repository, "main", "/home/root/argeo:keyring",
+ AppUi.this, factoryProperties);
+// CmsUiProvider header = app.getHeader();
+// if (header != null)
+// ergonomics.setHeader(header);
+ app.applySides(ergonomics);
+ Integer headerHeight = app.getHeaderHeight();
+ if (headerHeight != null)
+ ergonomics.setHeaderHeight(headerHeight);
+ return ergonomics;
+ }
+ };
+ application.addEntryPoint("/" + path, entryPointFactory, factoryProperties);
+ }
+ }
+
+ public void setUi(CmsUiProvider uiProvider) {
+ this.ui = uiProvider;
+ }
+
+ 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);
+ }
+
+ // public Branding getBranding() {
+ // return branding;
+ // }
+
+ @Override
+ public Control createUi(Composite parent, Node context) throws RepositoryException {
+ CmsPane cmsPane = new CmsPane(parent, SWT.NONE);
+
+ if (false) {
+ // QA
+ CmsUiUtils.style(cmsPane.getQaArea(), "qa");
+ Button reload = new Button(cmsPane.getQaArea(), SWT.FLAT);
+ CmsUiUtils.style(reload, "qa");
+ reload.setText("Reload");
+ reload.addSelectionListener(new Selected() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ new Thread() {
+ @Override
+ public void run() {
+ app.reload();
+ }
+ }.start();
+ RWT.getClient().getService(JavaScriptExecutor.class)
+ .execute("setTimeout('location.reload()',1000)");
+ }
+ });
+
+ // Support
+ CmsUiUtils.style(cmsPane.getSupportArea(), "support");
+ Label msg = new Label(cmsPane.getSupportArea(), SWT.NONE);
+ CmsUiUtils.style(msg, "support");
+ msg.setText("UNSUPPORTED DEVELOPMENT VERSION");
+ }
+
+ if (ui != null) {
+ ui.createUi(cmsPane.getMainArea(), context);
+ }
+ if (createUi != null) {
+ Invocable invocable = (Invocable) app.getScriptEngine();
+ try {
+ invocable.invokeFunction(createUi, cmsPane.getMainArea(), context);
+
+ } catch (NoSuchMethodException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (ScriptException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ if (impl != null) {
+ Invocable invocable = (Invocable) app.getScriptEngine();
+ try {
+ invocable.invokeMethod(impl, "createUi", cmsPane.getMainArea(), context);
+
+ } catch (NoSuchMethodException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (ScriptException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ // Invocable invocable = (Invocable) app.getScriptEngine();
+ // try {
+ // invocable.invokeMethod(AppUi.this, "initUi", parent, context);
+ //
+ // } catch (NoSuchMethodException e) {
+ // // TODO Auto-generated catch block
+ // e.printStackTrace();
+ // } catch (ScriptException e) {
+ // // TODO Auto-generated catch block
+ // e.printStackTrace();
+ // }
+
+ return null;
+ }
+
+ public void setCreateUi(String createUi) {
+ this.createUi = createUi;
+ }
+
+ public void setImpl(Object impl) {
+ this.impl = impl;
+ }
+
+ public Object getImpl() {
+ return impl;
+ }
+
+ public String getScript() {
+ return script;
+ }
+
+ public void setScript(String script) {
+ this.script = script;
+ }
+
+ // 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;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.ui.script;
+
+import java.util.Map;
+
+public interface Branding {
+ public void applyBranding(Map<String, String> properties);
+
+ public String getThemeId();
+
+ public String getAdditionalHeaders();
+
+ public String getBodyHtml();
+
+ public String getPageTitle();
+
+ public String getPageOverflow();
+
+ public String getFavicon();
+
+}
--- /dev/null
+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.cms.CmsException;
+import org.argeo.cms.ui.CmsConstants;
+import org.argeo.cms.ui.CmsTheme;
+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;
+ }
+
+ }
+
+}
--- /dev/null
+package org.argeo.cms.ui.script;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.net.URL;
+
+import javax.jcr.Repository;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.cms.CmsException;
+import org.eclipse.rap.rwt.application.Application;
+import org.eclipse.rap.rwt.application.ApplicationConfiguration;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.wiring.BundleWiring;
+
+public class CmsScriptRwtApplication implements ApplicationConfiguration {
+ public final static String APP = "APP";
+ public final static String BC = "BC";
+
+ private final Log log = LogFactory.getLog(CmsScriptRwtApplication.class);
+
+ BundleContext bundleContext;
+ Repository repository;
+
+ ScriptEngine engine;
+
+ public void init(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ ClassLoader bundleCl = bundleContext.getBundle().adapt(BundleWiring.class).getClassLoader();
+ ClassLoader originalCcl = Thread.currentThread().getContextClassLoader();
+ try {
+// Thread.currentThread().setContextClassLoader(bundleCl);// GraalVM needs it to be before creating manager
+// ScriptEngineManager scriptEngineManager = new ScriptEngineManager(bundleCl);
+// engine = scriptEngineManager.getEngineByName("JavaScript");
+// if (engine == null) {// Nashorn
+// Thread.currentThread().setContextClassLoader(originalCcl);
+// scriptEngineManager = new ScriptEngineManager();
+// Thread.currentThread().setContextClassLoader(bundleCl);
+// engine = scriptEngineManager.getEngineByName("JavaScript");
+// }
+ engine = loadScriptEngine(originalCcl, bundleCl);
+
+ // Load script
+ URL appUrl = bundleContext.getBundle().getEntry("cms/app.js");
+ // System.out.println("Loading " + appUrl);
+ // System.out.println("Loading " + appUrl.getHost());
+ // System.out.println("Loading " + appUrl.getPath());
+
+ CmsScriptApp app = new CmsScriptApp(engine);
+ engine.put(APP, app);
+ engine.put(BC, bundleContext);
+ try (Reader reader = new InputStreamReader(appUrl.openStream())) {
+ engine.eval(reader);
+ } catch (IOException | ScriptException e) {
+ throw new CmsException("Cannot execute " + appUrl, e);
+ }
+
+ if (log.isDebugEnabled())
+ log.debug("CMS script app initialized from " + appUrl);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ Thread.currentThread().setContextClassLoader(originalCcl);
+ }
+ }
+
+ public void destroy(BundleContext bundleContext) {
+ engine = null;
+ }
+
+ @Override
+ public void configure(Application application) {
+ load(application);
+ }
+
+ void load(Application application) {
+ CmsScriptApp app = getApp();
+ app.apply(bundleContext, repository, application);
+ if (log.isDebugEnabled())
+ log.debug("CMS script app loaded to " + app.getWebPath());
+ }
+
+ CmsScriptApp getApp() {
+ if (engine == null)
+ throw new IllegalStateException("CMS script app is not initialized");
+ return (CmsScriptApp) engine.get(APP);
+ }
+
+ void update() {
+
+ try {
+ bundleContext.getBundle().update();
+ } catch (BundleException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void setRepository(Repository repository) {
+ this.repository = repository;
+ }
+
+ private static ScriptEngine loadScriptEngine(ClassLoader originalCcl, ClassLoader bundleCl) {
+ Thread.currentThread().setContextClassLoader(bundleCl);// GraalVM needs it to be before creating manager
+ ScriptEngineManager scriptEngineManager = new ScriptEngineManager(bundleCl);
+ ScriptEngine engine = scriptEngineManager.getEngineByName("JavaScript");
+ if (engine == null) {// Nashorn
+ Thread.currentThread().setContextClassLoader(originalCcl);
+ scriptEngineManager = new ScriptEngineManager();
+ Thread.currentThread().setContextClassLoader(bundleCl);
+ engine = scriptEngineManager.getEngineByName("JavaScript");
+ }
+ return engine;
+ }
+}
--- /dev/null
+package org.argeo.cms.ui.script;
+
+import javax.jcr.Repository;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+
+public class ScriptAppActivator implements BundleActivator {
+ private final static Log log = LogFactory.getLog(ScriptAppActivator.class);
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ try {
+ CmsScriptRwtApplication appConfig = new CmsScriptRwtApplication();
+ appConfig.init(context);
+ CmsScriptApp app = appConfig.getApp();
+ ServiceTracker<Repository, Repository> repoSt = new ServiceTracker<Repository, Repository>(context,
+ FrameworkUtil.createFilter("(&" + app.getRepo() + "(objectClass=javax.jcr.Repository))"), null) {
+
+ @Override
+ public Repository addingService(ServiceReference<Repository> reference) {
+ Repository repository = super.addingService(reference);
+ appConfig.setRepository(repository);
+ CmsScriptApp app = appConfig.getApp();
+ app.register(context, appConfig);
+ return repository;
+ }
+
+ };
+ repoSt.open();
+ } catch (Exception e) {
+ log.error("Cannot initialise script bundle " + context.getBundle().getSymbolicName(), e);
+ throw e;
+ }
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ }
+
+}
--- /dev/null
+package org.argeo.cms.ui.script;
+
+import java.net.URL;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.script.Invocable;
+import javax.script.ScriptEngine;
+import javax.script.ScriptException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.osgi.framework.BundleContext;
+
+class ScriptUi implements CmsUiProvider {
+ private final static Log log = LogFactory.getLog(ScriptUi.class);
+
+ private boolean development = true;
+ private ScriptEngine scriptEngine;
+
+ private URL appUrl;
+ // private BundleContext bundleContext;
+ // private String path;
+
+ // private Bindings bindings;
+ // private String script;
+
+ public ScriptUi(BundleContext bundleContext,ScriptEngine scriptEngine, String path) {
+ this.scriptEngine = scriptEngine;
+//// ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
+// ClassLoader bundleCl = bundleContext.getBundle().adapt(BundleWiring.class).getClassLoader();
+// ClassLoader originalCcl = Thread.currentThread().getContextClassLoader();
+// try {
+//// Thread.currentThread().setContextClassLoader(bundleCl);
+//// scriptEngine = scriptEngineManager.getEngineByName("JavaScript");
+//// scriptEngine.put(CmsScriptRwtApplication.BC, bundleContext);
+// scriptEngine = CmsScriptRwtApplication.loadScriptEngine(originalCcl, bundleCl);
+//
+// } catch (Exception e) {
+// e.printStackTrace();
+// } finally {
+// Thread.currentThread().setContextClassLoader(originalCcl);
+// }
+ this.appUrl = bundleContext.getBundle().getEntry(path);
+ load();
+ }
+
+ private void load() {
+// try (Reader reader = new InputStreamReader(appUrl.openStream())) {
+// scriptEngine.eval(reader);
+// } catch (IOException | ScriptException e) {
+// log.warn("Cannot execute " + appUrl, e);
+// }
+
+ try {
+ scriptEngine.eval("load('" + appUrl + "')");
+ } catch (ScriptException e) {
+ log.warn("Cannot execute " + appUrl, e);
+ }
+
+ }
+
+ // public ScriptUiProvider(ScriptEngine scriptEngine, String script) throws
+ // ScriptException {
+ // super();
+ // this.scriptEngine = scriptEngine;
+ // this.script = script;
+ // bindings = scriptEngine.createBindings();
+ // scriptEngine.eval(script, bindings);
+ // }
+
+ @Override
+ public Control createUi(Composite parent, Node context) throws RepositoryException {
+ long begin = System.currentTimeMillis();
+ // if (bindings == null) {
+ // bindings = scriptEngine.createBindings();
+ // try {
+ // scriptEngine.eval(script, bindings);
+ // } catch (ScriptException e) {
+ // log.warn("Cannot evaluate script", e);
+ // }
+ // }
+ // Bindings bindings = scriptEngine.createBindings();
+ // bindings.put("parent", parent);
+ // bindings.put("context", context);
+ // URL appUrl = bundleContext.getBundle().getEntry(path);
+ // try (Reader reader = new InputStreamReader(appUrl.openStream())) {
+ // scriptEngine.eval(reader,bindings);
+ // } catch (IOException | ScriptException e) {
+ // log.warn("Cannot execute " + appUrl, e);
+ // }
+
+ if (development)
+ load();
+
+ Invocable invocable = (Invocable) scriptEngine;
+ try {
+ invocable.invokeFunction("createUi", parent, context);
+ } catch (NoSuchMethodException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (ScriptException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ long duration = System.currentTimeMillis() - begin;
+ if (log.isTraceEnabled())
+ log.trace(appUrl + " UI in " + duration + " ms");
+ return null;
+ }
+
+}
--- /dev/null
+// CMS
+var ScrolledPage = Java.type('org.argeo.cms.ui.widgets.ScrolledPage');
+
+var CmsScriptApp = Java.type('org.argeo.cms.ui.script.CmsScriptApp');
+var AppUi = Java.type('org.argeo.cms.ui.script.AppUi');
+var Theme = Java.type('org.argeo.cms.ui.script.Theme');
+var ScriptUi = Java.type('org.argeo.cms.ui.script.ScriptUi');
+var CmsUtils = Java.type('org.argeo.cms.ui.util.CmsUiUtils');
+var SimpleCmsHeader = Java.type('org.argeo.cms.ui.util.SimpleCmsHeader');
+var CmsLink = Java.type('org.argeo.cms.ui.util.CmsLink');
+var MenuLink = Java.type('org.argeo.cms.ui.util.MenuLink');
+var UserMenuLink = Java.type('org.argeo.cms.ui.util.UserMenuLink');
+
+// SWT
+var SWT = Java.type('org.eclipse.swt.SWT');
+var Composite = Java.type('org.eclipse.swt.widgets.Composite');
+var Label = Java.type('org.eclipse.swt.widgets.Label');
+var Button = Java.type('org.eclipse.swt.widgets.Button');
+var Text = Java.type('org.eclipse.swt.widgets.Text');
+var Browser = Java.type('org.eclipse.swt.browser.Browser');
+
+var FillLayout = Java.type('org.eclipse.swt.layout.FillLayout');
+var GridLayout = Java.type('org.eclipse.swt.layout.GridLayout');
+var RowLayout = Java.type('org.eclipse.swt.layout.RowLayout');
+var FormLayout = Java.type('org.eclipse.swt.layout.FormLayout');
+var GridData = Java.type('org.eclipse.swt.layout.GridData');
+
+function loadNode(node) {
+ var json = CmsScriptApp.toJson(node)
+ var fromJson = JSON.parse(json)
+ return fromJson
+}
+
+function newArea(parent, style, layout) {
+ var control = new Composite(parent, SWT.NONE)
+ control.setLayout(layout)
+ CmsUtils.style(control, style)
+ return control
+}
+
+function newLabel(parent, style, text) {
+ var control = new Label(parent, SWT.WRAP)
+ control.setText(text)
+ CmsUtils.style(control, style)
+ CmsUtils.markup(control)
+ return control
+}
+
+function newButton(parent, style, text) {
+ var control = new Button(parent, SWT.FLAT)
+ control.setText(text)
+ CmsUtils.style(control, style)
+ CmsUtils.markup(control)
+ return control
+}
+
+function newFormLabel(parent, style, text) {
+ return newLabel(parent, style, '<b>' + text + '</b>')
+}
+
+function newText(parent, style, msg) {
+ var control = new Text(parent, SWT.NONE)
+ control.setMessage(msg)
+ CmsUtils.style(control, style)
+ return control
+}
+
+function newScrolledPage(parent) {
+ var scrolled = new ScrolledPage(parent, SWT.NONE)
+ scrolled.setLayoutData(CmsUtils.fillAll())
+ scrolled.setLayout(CmsUtils.noSpaceGridLayout())
+ var page = new Composite(scrolled, SWT.NONE)
+ page.setLayout(CmsUtils.noSpaceGridLayout())
+ page.setBackgroundMode(SWT.INHERIT_NONE)
+ return page
+}
+
+function gridData(control) {
+ var gridData = new GridData()
+ control.setLayoutData(gridData)
+ return gridData
+}
+
+function gridData(control, hAlign, vAlign) {
+ var gridData = new GridData(hAlign, vAlign, false, false)
+ control.setLayoutData(gridData)
+ return gridData
+}
+
+// print(__FILE__, __LINE__, __DIR__)
--- /dev/null
+/** Argeo CMS user interface scripting. */
+package org.argeo.cms.ui.script;
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.web;
+
+import static org.argeo.naming.SharedSecret.X_SHARED_SECRET;
+
+import java.io.IOException;
+import java.security.PrivilegedAction;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.Property;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NodeType;
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeConstants;
+import org.argeo.cms.CmsException;
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.auth.HttpRequestCallback;
+import org.argeo.cms.auth.HttpRequestCallbackHandler;
+import org.argeo.cms.ui.CmsStyles;
+import org.argeo.cms.ui.CmsView;
+import org.argeo.eclipse.ui.specific.UiContext;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.naming.AuthPassword;
+import org.argeo.naming.SharedSecret;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.application.AbstractEntryPoint;
+import org.eclipse.rap.rwt.client.WebClient;
+import org.eclipse.rap.rwt.client.service.BrowserNavigation;
+import org.eclipse.rap.rwt.client.service.BrowserNavigationEvent;
+import org.eclipse.rap.rwt.client.service.BrowserNavigationListener;
+import org.eclipse.rap.rwt.client.service.JavaScriptExecutor;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+/** Manages history and navigation */
+public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint implements CmsView {
+ private static final long serialVersionUID = 906558779562569784L;
+
+ private final Log log = LogFactory.getLog(AbstractCmsEntryPoint.class);
+
+ // private final Subject subject;
+ private LoginContext loginContext;
+
+ private final Repository repository;
+ private final String workspace;
+ private final String defaultPath;
+ private final Map<String, String> factoryProperties;
+
+ // Current state
+ private Session session;
+ private Node node;
+ private String nodePath;// useful when changing auth
+ private String state;
+ private Throwable exception;
+
+ // Client services
+ private final JavaScriptExecutor jsExecutor;
+ private final BrowserNavigation browserNavigation;
+
+ public AbstractCmsEntryPoint(Repository repository, String workspace, String defaultPath,
+ Map<String, String> factoryProperties) {
+ this.repository = repository;
+ this.workspace = workspace;
+ this.defaultPath = defaultPath;
+ this.factoryProperties = new HashMap<String, String>(factoryProperties);
+ // subject = new Subject();
+
+ // Initial login
+ LoginContext lc;
+ try {
+ lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER,
+ new HttpRequestCallbackHandler(UiContext.getHttpRequest(), UiContext.getHttpResponse()));
+ lc.login();
+ } catch (LoginException e) {
+ try {
+ lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_ANONYMOUS);
+ lc.login();
+ } catch (LoginException e1) {
+ throw new CmsException("Cannot log in as anonymous", e1);
+ }
+ }
+ authChange(lc);
+
+ jsExecutor = RWT.getClient().getService(JavaScriptExecutor.class);
+ browserNavigation = RWT.getClient().getService(BrowserNavigation.class);
+ if (browserNavigation != null)
+ browserNavigation.addBrowserNavigationListener(new CmsNavigationListener());
+ }
+
+ @Override
+ protected Shell createShell(Display display) {
+ Shell shell = super.createShell(display);
+ shell.setData(RWT.CUSTOM_VARIANT, CmsStyles.CMS_SHELL);
+ display.disposeExec(new Runnable() {
+
+ @Override
+ public void run() {
+ if (log.isTraceEnabled())
+ log.trace("Logging out " + session);
+ JcrUtils.logoutQuietly(session);
+ }
+ });
+ return shell;
+ }
+
+ @Override
+ protected final void createContents(final Composite parent) {
+ // UiContext.setData(CmsView.KEY, this);
+ CmsView.registerCmsView(parent.getShell(), this);
+ Subject.doAs(getSubject(), new PrivilegedAction<Void>() {
+ @Override
+ public Void run() {
+ try {
+ initUi(parent);
+ } catch (Exception e) {
+ throw new CmsException("Cannot create entrypoint contents", e);
+ }
+ return null;
+ }
+ });
+ }
+
+ /** Create UI */
+ protected abstract void initUi(Composite parent);
+
+ /** Recreate UI after navigation or auth change */
+ protected abstract void refresh();
+
+ /**
+ * The node to return when no node was found (for authenticated users and
+ * anonymous)
+ */
+// private Node getDefaultNode(Session session) throws RepositoryException {
+// if (!session.hasPermission(defaultPath, "read")) {
+// String userId = session.getUserID();
+// if (userId.equals(NodeConstants.ROLE_ANONYMOUS))
+// // TODO throw a special exception
+// throw new CmsException("Login required");
+// else
+// throw new CmsException("Unauthorized");
+// }
+// return session.getNode(defaultPath);
+// }
+
+ protected String getBaseTitle() {
+ return factoryProperties.get(WebClient.PAGE_TITLE);
+ }
+
+ public void navigateTo(String state) {
+ exception = null;
+ String title = setState(state);
+ doRefresh();
+ if (browserNavigation != null)
+ browserNavigation.pushState(state, title);
+ }
+
+ // @Override
+ // public synchronized Subject getSubject() {
+ // return subject;
+ // }
+
+ // @Override
+ // public LoginContext getLoginContext() {
+ // return loginContext;
+ // }
+ protected Subject getSubject() {
+ return loginContext.getSubject();
+ }
+
+ @Override
+ public boolean isAnonymous() {
+ return CurrentUser.isAnonymous(getSubject());
+ }
+
+ @Override
+ public synchronized void logout() {
+ if (loginContext == null)
+ throw new CmsException("Login context should not be null");
+ try {
+ CurrentUser.logoutCmsSession(loginContext.getSubject());
+ loginContext.logout();
+ LoginContext anonymousLc = new LoginContext(NodeConstants.LOGIN_CONTEXT_ANONYMOUS);
+ anonymousLc.login();
+ authChange(anonymousLc);
+ } catch (LoginException e) {
+ log.error("Cannot logout", e);
+ }
+ }
+
+ @Override
+ public synchronized void authChange(LoginContext lc) {
+ if (lc == null)
+ throw new CmsException("Login context cannot be null");
+ // logout previous login context
+ if (this.loginContext != null)
+ try {
+ this.loginContext.logout();
+ } catch (LoginException e1) {
+ log.warn("Could not log out: " + e1);
+ }
+ this.loginContext = lc;
+ Subject.doAs(getSubject(), new PrivilegedAction<Void>() {
+
+ @Override
+ public Void run() {
+ try {
+ JcrUtils.logoutQuietly(session);
+ session = repository.login(workspace);
+ if (nodePath != null)
+ try {
+ node = session.getNode(nodePath);
+ } catch (PathNotFoundException e) {
+ navigateTo("~");
+ }
+
+ // refresh UI
+ doRefresh();
+ } catch (RepositoryException e) {
+ throw new CmsException("Cannot perform auth change", e);
+ }
+ return null;
+ }
+
+ });
+ }
+
+ @Override
+ public void exception(final Throwable e) {
+ AbstractCmsEntryPoint.this.exception = e;
+ log.error("Unexpected exception in CMS", e);
+ doRefresh();
+ }
+
+ protected synchronized void doRefresh() {
+ Subject.doAs(getSubject(), new PrivilegedAction<Void>() {
+ @Override
+ public Void run() {
+ refresh();
+ return null;
+ }
+ });
+ }
+
+ /** Sets the state of the entry point and retrieve the related JCR node. */
+ protected synchronized String setState(String newState) {
+ String previousState = this.state;
+
+ String newNodePath = null;
+ String prefix = null;
+ this.state = newState;
+ if (newState.equals("~"))
+ this.state = "";
+
+ try {
+ int firstSlash = state.indexOf('/');
+ if (firstSlash == 0) {
+ newNodePath = state;
+ prefix = "";
+ } else if (firstSlash > 0) {
+ prefix = state.substring(0, firstSlash);
+ newNodePath = state.substring(firstSlash);
+ } else {
+ newNodePath = defaultPath;
+ prefix = state;
+
+ }
+
+ // auth
+ int colonIndex = prefix.indexOf('$');
+ if (colonIndex > 0) {
+ SharedSecret token = new SharedSecret(new AuthPassword(X_SHARED_SECRET + '$' + prefix)) {
+
+ @Override
+ public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+ super.handle(callbacks);
+ // handle HTTP context
+ for (Callback callback : callbacks) {
+ if (callback instanceof HttpRequestCallback) {
+ ((HttpRequestCallback) callback).setRequest(UiContext.getHttpRequest());
+ ((HttpRequestCallback) callback).setResponse(UiContext.getHttpResponse());
+ }
+ }
+ }
+ };
+ LoginContext lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, token);
+ lc.login();
+ authChange(lc);// sets the node as well
+ // } else {
+ // // TODO check consistency
+ // }
+ } else {
+ Node newNode = null;
+ if (session.nodeExists(newNodePath))
+ newNode = session.getNode(newNodePath);
+ else {
+// throw new CmsException("Data " + newNodePath + " does not exist");
+ newNode = null;
+ }
+ setNode(newNode);
+ }
+ String title = publishMetaData(getNode());
+
+ if (log.isTraceEnabled())
+ log.trace("node=" + newNodePath + ", state=" + state + " (prefix=" + prefix + ")");
+
+ return title;
+ } catch (Exception e) {
+ log.error("Cannot set state '" + state + "'", e);
+ if (state.equals("") || newState.equals("~") || newState.equals(previousState))
+ return "Unrecoverable exception : " + e.getClass().getSimpleName();
+ if (previousState.equals(""))
+ previousState = "~";
+ navigateTo(previousState);
+ throw new CmsException("Unexpected issue when accessing #" + newState, e);
+ }
+ }
+
+ private String publishMetaData(Node node) throws RepositoryException {
+ // Title
+ String title;
+ if (node != null && node.isNodeType(NodeType.MIX_TITLE) && node.hasProperty(Property.JCR_TITLE))
+ title = node.getProperty(Property.JCR_TITLE).getString() + " - " + getBaseTitle();
+ else
+ title = getBaseTitle();
+
+ HttpServletRequest request = UiContext.getHttpRequest();
+ if (request == null)
+ return null;
+
+ StringBuilder js = new StringBuilder();
+ if (title == null)
+ title = "";
+ title = title.replace("'", "\\'");// sanitize
+ js.append("document.title = '" + title + "';");
+ jsExecutor.execute(js.toString());
+ return title;
+ }
+
+ // Simply remove some illegal character
+ // private String clean(String stringToClean) {
+ // return stringToClean.replaceAll("'", "").replaceAll("\\n", "")
+ // .replaceAll("\\t", "");
+ // }
+
+ protected synchronized Node getNode() {
+ return node;
+ }
+
+ private synchronized void setNode(Node node) throws RepositoryException {
+ this.node = node;
+ this.nodePath = node == null ? null : node.getPath();
+ }
+
+ protected String getState() {
+ return state;
+ }
+
+ protected Throwable getException() {
+ return exception;
+ }
+
+ protected void resetException() {
+ exception = null;
+ }
+
+ protected Session getSession() {
+ return session;
+ }
+
+ private class CmsNavigationListener implements BrowserNavigationListener {
+ private static final long serialVersionUID = -3591018803430389270L;
+
+ @Override
+ public void navigated(BrowserNavigationEvent event) {
+ setState(event.getState());
+ doRefresh();
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.web;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import org.argeo.cms.CmsException;
+import org.eclipse.rap.rwt.service.ResourceLoader;
+import org.osgi.framework.Bundle;
+
+/** {@link ResourceLoader} implementation wrapping an {@link Bundle}. */
+public class BundleResourceLoader implements ResourceLoader {
+ private final Bundle bundle;
+
+ public BundleResourceLoader(Bundle bundle) {
+ this.bundle = bundle;
+ }
+
+ @Override
+ public InputStream getResourceAsStream(String resourceName) throws IOException {
+ URL res = bundle.getEntry(resourceName);
+ if (res == null) {
+ res = bundle.getResource(resourceName);
+ if (res == null)
+ throw new CmsException("Resource " + resourceName + " not found in bundle " + bundle.getSymbolicName());
+ }
+ return res.openStream();
+ }
+
+ public Bundle getBundle() {
+ return bundle;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.web;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.argeo.cms.ui.CmsTheme;
+import org.eclipse.rap.rwt.service.ResourceLoader;
+
+/** A RAP {@link ResourceLoader} based on a {@link CmsTheme}. */
+public class CmsThemeResourceLoader implements ResourceLoader {
+ private final CmsTheme theme;
+
+ public CmsThemeResourceLoader(CmsTheme theme) {
+ super();
+ this.theme = theme;
+ }
+
+ @Override
+ public InputStream getResourceAsStream(String resourceName) throws IOException {
+ return theme.getResourceAsStream(resourceName);
+ }
+
+}
--- /dev/null
+package org.argeo.cms.web;
+
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.cms.ui.CmsApp;
+import org.argeo.cms.ui.CmsAppListener;
+import org.argeo.cms.ui.CmsTheme;
+import org.argeo.util.LangUtils;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.application.Application;
+import org.eclipse.rap.rwt.application.ApplicationConfiguration;
+import org.eclipse.rap.rwt.client.WebClient;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.event.EventAdmin;
+
+/** An RWT web app integrating with a {@link CmsApp}. */
+public class CmsWebApp implements ApplicationConfiguration, CmsAppListener {
+ private final static Log log = LogFactory.getLog(CmsWebApp.class);
+
+ private BundleContext bundleContext;
+ private CmsApp cmsApp;
+ private EventAdmin eventAdmin;
+
+ private ServiceRegistration<ApplicationConfiguration> rwtAppReg;
+
+ private final static String CONTEXT_NAME = "contextName";
+ private String contextName;
+
+ public void init(BundleContext bundleContext, Map<String, String> properties) {
+ this.bundleContext = bundleContext;
+ contextName = properties.get(CONTEXT_NAME);
+ if (cmsApp != null)
+ themingUpdated();
+// registerIfAllThemesAvailable();
+ }
+
+ public void destroy(BundleContext bundleContext, Map<String, String> properties) {
+ if (cmsApp != null)
+ cmsApp.removeCmsAppListener(this);
+ }
+
+ @Override
+ public void configure(Application application) {
+ for (String uiName : cmsApp.getUiNames()) {
+ CmsTheme theme = cmsApp.getTheme(uiName);
+ if (theme != null)
+ WebThemeUtils.apply(application, theme);
+ }
+// for (CmsTheme theme : themes.values())
+// WebThemeUtils.apply(application, theme);
+
+ Map<String, String> properties = new HashMap<>();
+ addEntryPoints(application, properties);
+
+ }
+
+ protected void addEntryPoints(Application application, Map<String, String> commonProperties) {
+ for (String uiName : cmsApp.getUiNames()) {
+ Map<String, String> properties = new HashMap<>(commonProperties);
+ CmsTheme theme = cmsApp.getTheme(uiName);
+ if (theme != null) {
+ properties.put(WebClient.THEME_ID, theme.getThemeId());
+ properties.put(WebClient.HEAD_HTML, theme.getHtmlHeaders());
+ } else {
+ properties.put(WebClient.THEME_ID, RWT.DEFAULT_THEME_ID);
+// if (themeId != null)
+// log.warn("Theme id " + themeId + " was specified but it was not found, using default RWT theme.");
+ }
+ application.addEntryPoint("/" + uiName, () -> {
+ CmsWebEntryPoint entryPoint = new CmsWebEntryPoint(this, uiName);
+ entryPoint.setEventAdmin(eventAdmin);
+ return entryPoint;
+ }, properties);
+ if (log.isDebugEnabled())
+ log.info("Added web entry point /" + (contextName != null ? contextName : "") + "/" + uiName);
+ }
+ log.debug("Published CMS web app /" + (contextName != null ? contextName : ""));
+ }
+
+// private void registerIfAllThemesAvailable() {
+// boolean themeMissing = false;
+// uiNames: for (String uiName : cmsApp.getUiNames()) {
+// String themeId = cmsApp.getThemeId(uiName);
+// if (RWT.DEFAULT_THEME_ID.equals(themeId))
+// continue uiNames;
+// if (!themes.containsKey(themeId)) {
+// themeMissing = true;
+// break uiNames;
+// }
+// }
+// if (!themeMissing) {
+// Dictionary<String, Object> regProps = LangUtils.dict(CONTEXT_NAME, contextName);
+// if (bundleContext != null) {
+// rwtAppReg = bundleContext.registerService(ApplicationConfiguration.class, this, regProps);
+// log.info("Published CMS web app /" + (contextName != null ? contextName : ""));
+// }
+// }
+// }
+
+ CmsApp getCmsApp() {
+ return cmsApp;
+ }
+
+ public void setCmsApp(CmsApp cmsApp, Map<String, String> properties) {
+ this.cmsApp = cmsApp;
+ this.cmsApp.addCmsAppListener(this);
+// registerIfAllThemesAvailable();
+ }
+
+ public void unsetCmsApp(CmsApp cmsApp, Map<String, String> properties) {
+ if (rwtAppReg != null)
+ rwtAppReg.unregister();
+ this.cmsApp = null;
+ }
+
+ @Override
+ public void themingUpdated() {
+ Dictionary<String, Object> regProps = LangUtils.dict(CONTEXT_NAME, contextName);
+ if (rwtAppReg != null)
+ rwtAppReg.unregister();
+ if (bundleContext != null) {
+ rwtAppReg = bundleContext.registerService(ApplicationConfiguration.class, this, regProps);
+ if (log.isDebugEnabled())
+ log.debug("Publishing CMS web app /" + (contextName != null ? contextName : "") + " ...");
+ }
+ }
+
+ public void setEventAdmin(EventAdmin eventAdmin) {
+ this.eventAdmin = eventAdmin;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.web;
+
+import static org.eclipse.rap.rwt.internal.service.ContextProvider.getApplicationContext;
+
+import java.security.PrivilegedAction;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeConstants;
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.auth.HttpRequestCallbackHandler;
+import org.argeo.cms.ui.CmsApp;
+import org.argeo.cms.ui.CmsImageManager;
+import org.argeo.cms.ui.CmsView;
+import org.argeo.cms.ui.UxContext;
+import org.argeo.cms.ui.dialogs.CmsFeedback;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.cms.ui.util.DefaultImageManager;
+import org.argeo.cms.ui.util.SimpleUxContext;
+import org.argeo.eclipse.ui.specific.UiContext;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.application.EntryPoint;
+import org.eclipse.rap.rwt.client.service.BrowserNavigation;
+import org.eclipse.rap.rwt.client.service.BrowserNavigationEvent;
+import org.eclipse.rap.rwt.client.service.BrowserNavigationListener;
+import org.eclipse.rap.rwt.internal.lifecycle.RWTLifeCycle;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+
+/** The {@link CmsView} for a {@link CmsWebApp}. */
+public class CmsWebEntryPoint implements EntryPoint, CmsView, BrowserNavigationListener {
+ private static final long serialVersionUID = 7733510691684570402L;
+ private final static Log log = LogFactory.getLog(CmsWebEntryPoint.class);
+
+ private EventAdmin eventAdmin;
+
+ private final CmsWebApp cmsWebApp;
+ private final String uiName;
+
+ private LoginContext loginContext;
+ private String state;
+ private Throwable exception;
+ private UxContext uxContext;
+ private CmsImageManager imageManager;
+
+ private Composite ui;
+
+ private String uid;
+
+ // Client services
+ // private final JavaScriptExecutor jsExecutor;
+ private final BrowserNavigation browserNavigation;
+
+ /** Experimental OS-like multi windows. */
+ private boolean multipleShells = false;
+
+ public CmsWebEntryPoint(CmsWebApp cmsWebApp, String uiName) {
+ assert cmsWebApp != null;
+ assert uiName != null;
+ this.cmsWebApp = cmsWebApp;
+ this.uiName = uiName;
+ uid = UUID.randomUUID().toString();
+
+ // Initial login
+ LoginContext lc;
+ try {
+ lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER,
+ new HttpRequestCallbackHandler(UiContext.getHttpRequest(), UiContext.getHttpResponse()));
+ lc.login();
+ } catch (LoginException e) {
+ try {
+ lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_ANONYMOUS);
+ lc.login();
+ } catch (LoginException e1) {
+ throw new IllegalStateException("Cannot log in as anonymous", e1);
+ }
+ }
+ authChange(lc);
+
+ // jsExecutor = RWT.getClient().getService(JavaScriptExecutor.class);
+ browserNavigation = RWT.getClient().getService(BrowserNavigation.class);
+ if (browserNavigation != null)
+ browserNavigation.addBrowserNavigationListener(this);
+ }
+
+ protected void createContents(Composite parent) {
+ Subject.doAs(loginContext.getSubject(), new PrivilegedAction<Void>() {
+ @Override
+ public Void run() {
+ try {
+ uxContext = new SimpleUxContext();
+ imageManager = new DefaultImageManager();
+ ui = cmsWebApp.getCmsApp().initUi(parent);
+ ui.setData(CmsApp.UI_NAME_PROPERTY, uiName);
+ ui.setLayoutData(CmsUiUtils.fillAll());
+ } catch (Exception e) {
+ throw new IllegalStateException("Cannot create entrypoint contents", e);
+ }
+ return null;
+ }
+ });
+ }
+
+ protected Subject getSubject() {
+ return loginContext.getSubject();
+ }
+
+ @Override
+ public boolean isAnonymous() {
+ return CurrentUser.isAnonymous(getSubject());
+ }
+
+ @Override
+ public synchronized void logout() {
+ if (loginContext == null)
+ throw new IllegalArgumentException("Login context should not be null");
+ try {
+ CurrentUser.logoutCmsSession(loginContext.getSubject());
+ loginContext.logout();
+ LoginContext anonymousLc = new LoginContext(NodeConstants.LOGIN_CONTEXT_ANONYMOUS);
+ anonymousLc.login();
+ authChange(anonymousLc);
+ } catch (LoginException e) {
+ log.error("Cannot logout", e);
+ }
+ }
+
+ @Override
+ public synchronized void authChange(LoginContext lc) {
+ if (lc == null)
+ throw new IllegalArgumentException("Login context cannot be null");
+ // logout previous login context
+ if (this.loginContext != null)
+ try {
+ this.loginContext.logout();
+ } catch (LoginException e1) {
+ log.warn("Could not log out: " + e1);
+ }
+ this.loginContext = lc;
+ doRefresh();
+ }
+
+ @Override
+ public void exception(final Throwable e) {
+ exception = e;
+ log.error("Unexpected exception in CMS", e);
+ doRefresh();
+ }
+
+ protected synchronized void doRefresh() {
+ if (ui != null)
+ Subject.doAs(getSubject(), new PrivilegedAction<Void>() {
+ @Override
+ public Void run() {
+ if (exception != null) {
+ // TODO internationalise
+ CmsFeedback.show("Unexpected exception", exception);
+ exception = null;
+ // TODO report
+ }
+ cmsWebApp.getCmsApp().refreshUi(ui, state);
+ return null;
+ }
+ });
+ }
+
+ /** Sets the state of the entry point and retrieve the related JCR node. */
+ protected String setState(String newState) {
+ cmsWebApp.getCmsApp().setState(ui, newState);
+ state = newState;
+ return null;
+ }
+
+ @Override
+ public UxContext getUxContext() {
+ return uxContext;
+ }
+
+ @Override
+ public String getUid() {
+ return uid;
+ }
+
+ @Override
+ public void navigateTo(String state) {
+ exception = null;
+ String title = setState(state);
+ doRefresh();
+ if (browserNavigation != null)
+ browserNavigation.pushState(state, title);
+ }
+
+ @Override
+ public CmsImageManager getImageManager() {
+ return imageManager;
+ }
+
+ @Override
+ public void navigated(BrowserNavigationEvent event) {
+ setState(event.getState());
+ doRefresh();
+ }
+
+ @Override
+ public void sendEvent(String topic, Map<String, Object> properties) {
+ if (properties == null)
+ properties = new HashMap<>();
+ if (properties.containsKey(CMS_VIEW_UID_PROPERTY) && !properties.get(CMS_VIEW_UID_PROPERTY).equals(uid))
+ throw new IllegalArgumentException("Property " + CMS_VIEW_UID_PROPERTY + " is set to another CMS view uid ("
+ + properties.get(CMS_VIEW_UID_PROPERTY) + ") then " + uid);
+ properties.put(CMS_VIEW_UID_PROPERTY, uid);
+ eventAdmin.sendEvent(new Event(topic, properties));
+ }
+
+ /*
+ * EntryPoint IMPLEMENTATION
+ */
+
+ @Override
+ public int createUI() {
+ Display display = new Display();
+ Shell shell = createShell(display);
+ shell.setLayout(CmsUiUtils.noSpaceGridLayout());
+ CmsView.registerCmsView(shell, this);
+ createContents(shell);
+ shell.layout();
+// if (shell.getMaximized()) {
+// shell.layout();
+// } else {
+//// shell.pack();
+// }
+ shell.open();
+ if (getApplicationContext().getLifeCycleFactory().getLifeCycle() instanceof RWTLifeCycle) {
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ display.dispose();
+ }
+ return 0;
+ }
+
+ protected Shell createShell(Display display) {
+ Shell shell;
+ if (!multipleShells) {
+ shell = new Shell(display, SWT.NO_TRIM);
+ shell.setMaximized(true);
+ } else {
+ shell = new Shell(display, SWT.SHELL_TRIM);
+ shell.setSize(800, 600);
+ }
+ return shell;
+ }
+
+ public void setEventAdmin(EventAdmin eventAdmin) {
+ this.eventAdmin = eventAdmin;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.web;
+
+import static org.argeo.cms.ui.util.BundleCmsTheme.CMS_THEME_BUNDLE_PROPERTY;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.argeo.cms.ui.util.BundleCmsTheme;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.application.Application;
+import org.eclipse.rap.rwt.application.ApplicationConfiguration;
+import org.eclipse.rap.rwt.client.WebClient;
+import org.osgi.framework.BundleContext;
+
+/** Lightweight web app using only RWT and not the whole Eclipse platform. */
+public class MinimalWebApp implements ApplicationConfiguration {
+
+ private BundleCmsTheme theme;
+
+ public void init(BundleContext bundleContext, Map<String, Object> properties) {
+ if (properties.containsKey(CMS_THEME_BUNDLE_PROPERTY)) {
+ String cmsThemeBundle = properties.get(CMS_THEME_BUNDLE_PROPERTY).toString();
+ theme = new BundleCmsTheme(bundleContext, cmsThemeBundle);
+ }
+ }
+
+ public void destroy() {
+
+ }
+
+ /** To be overridden. Does nothing by default. */
+ protected void addEntryPoints(Application application, Map<String, String> properties) {
+
+ }
+
+ @Override
+ public void configure(Application application) {
+ if (theme != null)
+ WebThemeUtils.apply(application, theme);
+
+ Map<String, String> properties = new HashMap<>();
+ if (theme != null) {
+ properties.put(WebClient.THEME_ID, theme.getThemeId());
+ properties.put(WebClient.HEAD_HTML, theme.getHtmlHeaders());
+ } else {
+ properties.put(WebClient.THEME_ID, RWT.DEFAULT_THEME_ID);
+ }
+ addEntryPoints(application, properties);
+
+ }
+
+ public void setTheme(BundleCmsTheme theme) {
+ this.theme = theme;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.web;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.security.Privilege;
+import javax.jcr.version.VersionManager;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeConstants;
+import org.argeo.api.NodeUtils;
+import org.argeo.cms.CmsException;
+import org.argeo.cms.ui.CmsConstants;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.LifeCycleUiProvider;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.cms.ui.util.StyleSheetResourceLoader;
+import org.argeo.jcr.JcrUtils;
+import org.eclipse.rap.rwt.RWT;
+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.EntryPoint;
+import org.eclipse.rap.rwt.application.EntryPointFactory;
+import org.eclipse.rap.rwt.application.ExceptionHandler;
+import org.eclipse.rap.rwt.client.WebClient;
+import org.eclipse.rap.rwt.client.service.JavaScriptExecutor;
+import org.eclipse.rap.rwt.service.ResourceLoader;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+/** A basic generic app based on {@link SimpleErgonomics}. */
+public class SimpleApp implements CmsConstants, ApplicationConfiguration {
+ private final static Log log = LogFactory.getLog(SimpleApp.class);
+
+ private String contextName = null;
+
+ private Map<String, Map<String, String>> branding = new HashMap<String, Map<String, String>>();
+ private Map<String, List<String>> styleSheets = new HashMap<String, List<String>>();
+
+ private List<String> resources = new ArrayList<String>();
+
+ private BundleContext bundleContext;
+
+ private Repository repository;
+ private String workspace = null;
+ private String jcrBasePath = "/";
+ private List<String> roPrincipals = Arrays.asList(NodeConstants.ROLE_ANONYMOUS, NodeConstants.ROLE_USER);
+ private List<String> rwPrincipals = Arrays.asList(NodeConstants.ROLE_USER);
+
+ private CmsUiProvider header;
+ private Map<String, CmsUiProvider> pages = new LinkedHashMap<String, CmsUiProvider>();
+
+ private Integer headerHeight = 40;
+
+ private ServiceRegistration<ApplicationConfiguration> appReg;
+
+ public void configure(Application application) {
+ try {
+ 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(LOADING_IMAGE, createResourceLoader(LOADING_IMAGE));
+ // empty image
+ application.addResource(NO_IMAGE, createResourceLoader(NO_IMAGE));
+
+ for (String resource : resources) {
+ application.addResource(resource, bundleRL);
+ if (log.isTraceEnabled())
+ log.trace("Resource " + resource);
+ }
+
+ Map<String, String> defaultBranding = null;
+ if (branding.containsKey("*"))
+ defaultBranding = branding.get("*");
+ // String defaultTheme = defaultBranding.get(WebClient.THEME_ID);
+
+ // entry points
+ for (String page : pages.keySet()) {
+ Map<String, String> properties = defaultBranding != null ? new HashMap<String, String>(defaultBranding)
+ : new HashMap<String, String>();
+ if (branding.containsKey(page)) {
+ properties.putAll(branding.get(page));
+ }
+ // favicon
+ if (properties.containsKey(WebClient.FAVICON)) {
+ String themeId = defaultBranding.get(WebClient.THEME_ID);
+ Bundle themeBundle = findThemeBundle(bundleContext, themeId);
+ String faviconRelPath = properties.get(WebClient.FAVICON);
+ application.addResource(faviconRelPath,
+ new BundleResourceLoader(themeBundle != null ? themeBundle : bundleContext.getBundle()));
+ if (log.isTraceEnabled())
+ log.trace("Favicon " + faviconRelPath);
+
+ }
+
+ // page title
+ if (!properties.containsKey(WebClient.PAGE_TITLE)) {
+ if (page.length() > 0)
+ properties.put(WebClient.PAGE_TITLE, Character.toUpperCase(page.charAt(0)) + page.substring(1));
+ }
+
+ // default body HTML
+ if (!properties.containsKey(WebClient.BODY_HTML))
+ properties.put(WebClient.BODY_HTML, DEFAULT_LOADING_BODY);
+
+ //
+ // ADD ENTRY POINT
+ //
+ application.addEntryPoint("/" + page,
+ new CmsEntryPointFactory(pages.get(page), repository, workspace, properties), properties);
+ log.info("Page /" + page);
+ }
+
+ // stylesheets and themes
+ Set<Bundle> themeBundles = new HashSet<>();
+ for (String themeId : styleSheets.keySet()) {
+ Bundle themeBundle = findThemeBundle(bundleContext, themeId);
+ StyleSheetResourceLoader styleSheetRL = new StyleSheetResourceLoader(
+ themeBundle != null ? themeBundle : bundleContext.getBundle());
+ if (themeBundle != null)
+ themeBundles.add(themeBundle);
+ List<String> cssLst = styleSheets.get(themeId);
+ if (log.isDebugEnabled())
+ log.debug("Theme " + themeId);
+ for (String css : cssLst) {
+ application.addStyleSheet(themeId, css, styleSheetRL);
+ if (log.isDebugEnabled())
+ log.debug(" CSS " + css);
+ }
+
+ }
+ for (Bundle themeBundle : themeBundles) {
+ BundleResourceLoader themeBRL = new BundleResourceLoader(themeBundle);
+ SimpleApp.addThemeResources(application, themeBundle, themeBRL, "*.png");
+ SimpleApp.addThemeResources(application, themeBundle, themeBRL, "*.gif");
+ SimpleApp.addThemeResources(application, themeBundle, themeBRL, "*.jpg");
+ }
+ } catch (RuntimeException e) {
+ // Easier access to initialisation errors
+ log.error("Unexpected exception when configuring RWT application.", e);
+ throw e;
+ }
+ }
+
+ public void init() throws RepositoryException {
+ Session session = null;
+ try {
+ session = NodeUtils.openDataAdminSession(repository, workspace);
+ // session = JcrUtils.loginOrCreateWorkspace(repository, workspace);
+ VersionManager vm = session.getWorkspace().getVersionManager();
+ JcrUtils.mkdirs(session, jcrBasePath);
+ session.save();
+ if (!vm.isCheckedOut(jcrBasePath))
+ vm.checkout(jcrBasePath);
+ for (String principal : rwPrincipals)
+ JcrUtils.addPrivilege(session, jcrBasePath, principal, Privilege.JCR_WRITE);
+ for (String principal : roPrincipals)
+ JcrUtils.addPrivilege(session, jcrBasePath, principal, Privilege.JCR_READ);
+
+ for (String pageName : pages.keySet()) {
+ try {
+ initPage(session, pages.get(pageName));
+ session.save();
+ } catch (Exception e) {
+ throw new CmsException("Cannot initialize page " + pageName, e);
+ }
+ }
+
+ } finally {
+ JcrUtils.logoutQuietly(session);
+ }
+
+ // publish to OSGi
+ register();
+ }
+
+ protected void initPage(Session adminSession, CmsUiProvider page) throws RepositoryException {
+ if (page instanceof LifeCycleUiProvider)
+ ((LifeCycleUiProvider) page).init(adminSession);
+ }
+
+ public void destroy() {
+ for (String pageName : pages.keySet()) {
+ try {
+ CmsUiProvider page = pages.get(pageName);
+ if (page instanceof LifeCycleUiProvider)
+ ((LifeCycleUiProvider) page).destroy();
+ } catch (Exception e) {
+ log.error("Cannot destroy page " + pageName, e);
+ }
+ }
+ }
+
+ protected void register() {
+ Hashtable<String, String> props = new Hashtable<String, String>();
+ if (contextName != null)
+ props.put("contextName", contextName);
+ appReg = bundleContext.registerService(ApplicationConfiguration.class, this, props);
+ if (log.isDebugEnabled())
+ log.debug("Registered " + (contextName == null ? "/" : contextName));
+ }
+
+ protected void unregister() {
+ appReg.unregister();
+ if (log.isDebugEnabled())
+ log.debug("Unregistered " + (contextName == null ? "/" : contextName));
+ }
+
+ public void setRepository(Repository repository) {
+ this.repository = repository;
+ }
+
+ public void setWorkspace(String workspace) {
+ this.workspace = workspace;
+ }
+
+ public void setHeader(CmsUiProvider header) {
+ this.header = header;
+ }
+
+ public void setPages(Map<String, CmsUiProvider> pages) {
+ this.pages = pages;
+ }
+
+ public void setJcrBasePath(String basePath) {
+ this.jcrBasePath = basePath;
+ }
+
+ public void setRoPrincipals(List<String> roPrincipals) {
+ this.roPrincipals = roPrincipals;
+ }
+
+ public void setRwPrincipals(List<String> rwPrincipals) {
+ this.rwPrincipals = rwPrincipals;
+ }
+
+ public void setHeaderHeight(Integer headerHeight) {
+ this.headerHeight = headerHeight;
+ }
+
+ public void setBranding(Map<String, Map<String, String>> branding) {
+ this.branding = branding;
+ }
+
+ public void setStyleSheets(Map<String, List<String>> styleSheets) {
+ this.styleSheets = styleSheets;
+ }
+
+ public void setBundleContext(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
+ public void setResources(List<String> resources) {
+ this.resources = resources;
+ }
+
+ public void setContextName(String contextName) {
+ this.contextName = contextName;
+ }
+
+ private static void addThemeResources(Application application, Bundle themeBundle, BundleResourceLoader themeBRL,
+ String pattern) {
+ Enumeration<URL> themeResources = themeBundle.findEntries("/", pattern, true);
+ if (themeResources == null)
+ return;
+ while (themeResources.hasMoreElements()) {
+ String resource = themeResources.nextElement().getPath();
+ // remove first '/' so that RWT registers it
+ resource = resource.substring(1);
+ if (!resource.endsWith("/")) {
+ application.addResource(resource, themeBRL);
+ if (log.isTraceEnabled())
+ log.trace("Registered " + resource + " from theme " + themeBundle);
+ }
+
+ }
+
+ }
+
+ private static Bundle findThemeBundle(BundleContext bundleContext, String themeId) {
+ if (themeId == null)
+ return null;
+ // TODO optimize
+ // TODO deal with multiple versions
+ Bundle themeBundle = null;
+ if (themeId != null) {
+ for (Bundle bundle : bundleContext.getBundles())
+ if (themeId.equals(bundle.getSymbolicName())) {
+ themeBundle = bundle;
+ break;
+ }
+ }
+ return themeBundle;
+ }
+
+ class CmsExceptionHandler implements ExceptionHandler {
+
+ @Override
+ public void handleException(Throwable throwable) {
+ // TODO be smarter
+ CmsUiUtils.getCmsView().exception(throwable);
+ }
+
+ }
+
+ private class CmsEntryPointFactory implements EntryPointFactory {
+ private final CmsUiProvider page;
+ private final Repository repository;
+ private final String workspace;
+ private final Map<String, String> properties;
+
+ public CmsEntryPointFactory(CmsUiProvider page, Repository repository, String workspace,
+ Map<String, String> properties) {
+ this.page = page;
+ this.repository = repository;
+ this.workspace = workspace;
+ this.properties = properties;
+ }
+
+ @Override
+ public EntryPoint create() {
+ SimpleErgonomics entryPoint = new SimpleErgonomics(repository, workspace, jcrBasePath, page, properties) {
+ private static final long serialVersionUID = -637940404865527290L;
+
+ @Override
+ protected void createAdminArea(Composite parent) {
+ Composite adminArea = new Composite(parent, SWT.NONE);
+ adminArea.setLayout(new FillLayout());
+ Button refresh = new Button(adminArea, SWT.PUSH);
+ refresh.setText("Reload App");
+ refresh.addSelectionListener(new SelectionAdapter() {
+ private static final long serialVersionUID = -7671999525536351366L;
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ long timeBeforeReload = 1000;
+ RWT.getClient().getService(JavaScriptExecutor.class).execute(
+ "setTimeout(function() { " + "location.reload();" + "}," + timeBeforeReload + ");");
+ reloadApp();
+ }
+ });
+ }
+ };
+ // entryPoint.setState("");
+ entryPoint.setHeader(header);
+ entryPoint.setHeaderHeight(headerHeight);
+ // CmsSession.current.set(entryPoint);
+ return entryPoint;
+ }
+
+ private void reloadApp() {
+ new Thread("Refresh app") {
+ @Override
+ public void run() {
+ unregister();
+ register();
+ }
+ }.start();
+ }
+ }
+
+ private static ResourceLoader createResourceLoader(final String resourceName) {
+ return new ResourceLoader() {
+ public InputStream getResourceAsStream(String resourceName) throws IOException {
+ return getClass().getClassLoader().getResourceAsStream(resourceName);
+ }
+ };
+ }
+
+ // private static ResourceLoader createUrlResourceLoader(final URL url) {
+ // return new ResourceLoader() {
+ // public InputStream getResourceAsStream(String resourceName)
+ // throws IOException {
+ // return url.openStream();
+ // }
+ // };
+ // }
+
+ /*
+ * TEXTS
+ */
+ private static String DEFAULT_LOADING_BODY = "<div"
+ + " style=\"position: absolute; left: 50%; top: 50%; margin: -32px -32px; width: 64px; height:64px\">"
+ + "<img src=\"./rwt-resources/" + LOADING_IMAGE
+ + "\" width=\"32\" height=\"32\" style=\"margin: 16px 16px\"/>" + "</div>";
+}
--- /dev/null
+package org.argeo.cms.web;
+
+import java.util.Map;
+import java.util.UUID;
+
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.cms.CmsException;
+import org.argeo.cms.ui.CmsImageManager;
+import org.argeo.cms.ui.CmsStyles;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.UxContext;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.cms.ui.util.DefaultImageManager;
+import org.argeo.cms.ui.util.SimpleUxContext;
+import org.argeo.cms.ui.util.SystemNotifications;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+/** Simple header/body ergonomics. */
+public class SimpleErgonomics extends AbstractCmsEntryPoint {
+ private static final long serialVersionUID = 8743413921359548523L;
+
+ private final static Log log = LogFactory.getLog(SimpleErgonomics.class);
+
+ private boolean uiInitialized = false;
+ private Composite headerArea;
+ private Composite leftArea;
+ private Composite rightArea;
+ private Composite footerArea;
+ private Composite bodyArea;
+ private final CmsUiProvider uiProvider;
+
+ private CmsUiProvider header;
+ private Integer headerHeight = 0;
+ private Integer footerHeight = 0;
+ private CmsUiProvider lead;
+ private CmsUiProvider end;
+ private CmsUiProvider footer;
+
+ private CmsImageManager imageManager = new DefaultImageManager();
+ private UxContext uxContext = null;
+ private String uid;
+
+ public SimpleErgonomics(Repository repository, String workspace, String defaultPath, CmsUiProvider uiProvider,
+ Map<String, String> factoryProperties) {
+ super(repository, workspace, defaultPath, factoryProperties);
+ this.uiProvider = uiProvider;
+ }
+
+ @Override
+ protected void initUi(Composite parent) {
+ uid = UUID.randomUUID().toString();
+ parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ parent.setLayout(CmsUiUtils.noSpaceGridLayout(new GridLayout(3, false)));
+
+ uxContext = new SimpleUxContext();
+ if (!getUxContext().isMasterData())
+ createAdminArea(parent);
+ headerArea = new Composite(parent, SWT.NONE);
+ headerArea.setLayout(new FillLayout());
+ GridData headerData = new GridData(SWT.FILL, SWT.FILL, false, false, 3, 1);
+ headerData.heightHint = headerHeight;
+ headerArea.setLayoutData(headerData);
+
+ // TODO: bi-directional
+ leftArea = new Composite(parent, SWT.NONE);
+ leftArea.setLayoutData(new GridData(SWT.LEAD, SWT.TOP, false, false));
+ leftArea.setLayout(CmsUiUtils.noSpaceGridLayout());
+
+ bodyArea = new Composite(parent, SWT.NONE);
+ bodyArea.setData(RWT.CUSTOM_VARIANT, CmsStyles.CMS_BODY);
+ bodyArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ bodyArea.setLayout(CmsUiUtils.noSpaceGridLayout());
+
+ // TODO: bi-directional
+ rightArea = new Composite(parent, SWT.NONE);
+ rightArea.setLayoutData(new GridData(SWT.END, SWT.TOP, false, false));
+ rightArea.setLayout(CmsUiUtils.noSpaceGridLayout());
+
+ footerArea = new Composite(parent, SWT.NONE);
+ // footerArea.setLayout(new FillLayout());
+ GridData footerData = new GridData(SWT.FILL, SWT.FILL, false, false, 3, 1);
+ footerData.heightHint = footerHeight;
+ footerArea.setLayoutData(footerData);
+
+ uiInitialized = true;
+ refresh();
+ }
+
+ @Override
+ protected void refresh() {
+ if (!uiInitialized)
+ return;
+ if (getState() == null)
+ setState("");
+ refreshSides();
+ refreshBody();
+ if (log.isTraceEnabled())
+ log.trace("UI refreshed " + getNode());
+ }
+
+ protected void createAdminArea(Composite parent) {
+ }
+
+ @Deprecated
+ protected void refreshHeader() {
+ if (header == null)
+ return;
+
+ for (Control child : headerArea.getChildren())
+ child.dispose();
+ try {
+ header.createUi(headerArea, getNode());
+ } catch (RepositoryException e) {
+ throw new CmsException("Cannot refresh header", e);
+ }
+ headerArea.layout(true, true);
+ }
+
+ protected void refreshSides() {
+ refresh(headerArea, header, CmsStyles.CMS_HEADER);
+ refresh(leftArea, lead, CmsStyles.CMS_LEAD);
+ refresh(rightArea, end, CmsStyles.CMS_END);
+ refresh(footerArea, footer, CmsStyles.CMS_FOOTER);
+ }
+
+ private void refresh(Composite area, CmsUiProvider uiProvider, String style) {
+ if (uiProvider == null)
+ return;
+
+ for (Control child : area.getChildren())
+ child.dispose();
+ CmsUiUtils.style(area, style);
+ try {
+ uiProvider.createUi(area, getNode());
+ } catch (RepositoryException e) {
+ throw new CmsException("Cannot refresh header", e);
+ }
+ area.layout(true, true);
+ }
+
+ protected void refreshBody() {
+ // Exception
+ Throwable exception = getException();
+ if (exception != null) {
+ SystemNotifications systemNotifications = new SystemNotifications(bodyArea);
+ systemNotifications.notifyException(exception);
+ resetException();
+ return;
+ // TODO report
+ }
+
+ // clear
+ for (Control child : bodyArea.getChildren())
+ child.dispose();
+ bodyArea.setLayout(CmsUiUtils.noSpaceGridLayout());
+
+ try {
+ Node node = getNode();
+// if (node == null)
+// log.error("Context cannot be null");
+// else
+ uiProvider.createUi(bodyArea, node);
+ } catch (RepositoryException e) {
+ throw new CmsException("Cannot refresh body", e);
+ }
+
+ bodyArea.layout(true, true);
+ }
+
+ @Override
+ public UxContext getUxContext() {
+ return uxContext;
+ }
+ @Override
+ public String getUid() {
+ return uid;
+ }
+
+ @Override
+ public CmsImageManager getImageManager() {
+ return imageManager;
+ }
+
+ public void setHeader(CmsUiProvider header) {
+ this.header = header;
+ }
+
+ public void setHeaderHeight(Integer headerHeight) {
+ this.headerHeight = headerHeight;
+ }
+
+ public void setImageManager(CmsImageManager imageManager) {
+ this.imageManager = imageManager;
+ }
+
+ 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;
+ }
+
+ public CmsUiProvider getHeader() {
+ return header;
+ }
+
+ public void setFooterHeight(Integer footerHeight) {
+ this.footerHeight = footerHeight;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.web;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.cms.ui.CmsTheme;
+import org.eclipse.rap.rwt.application.Application;
+import org.eclipse.rap.rwt.service.ResourceLoader;
+
+/** Web specific utilities around theming. */
+public class WebThemeUtils {
+ private final static Log log = LogFactory.getLog(WebThemeUtils.class);
+
+ public static void apply(Application application, CmsTheme theme) {
+ ResourceLoader resourceLoader = new CmsThemeResourceLoader(theme);
+ resources: for (String path : theme.getImagesPaths()) {
+ if (path.startsWith("target/"))
+ continue resources; // skip maven output
+ application.addResource(path, resourceLoader);
+ if (log.isTraceEnabled())
+ log.trace("Theme " + theme.getThemeId() + ": added resource " + path);
+ }
+ for (String path : theme.getRapCssPaths()) {
+ application.addStyleSheet(theme.getThemeId(), path, resourceLoader);
+ if (log.isDebugEnabled())
+ log.debug("Theme " + theme.getThemeId() + ": added RAP CSS " + path);
+ }
+ }
+
+}
+++ /dev/null
-package org.argeo.cms.ui.script;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.jcr.Node;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.script.Invocable;
-import javax.script.ScriptException;
-
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.util.CmsPane;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.cms.web.SimpleErgonomics;
-import org.argeo.eclipse.ui.Selected;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.rap.rwt.application.Application;
-import org.eclipse.rap.rwt.application.EntryPoint;
-import org.eclipse.rap.rwt.application.EntryPointFactory;
-import org.eclipse.rap.rwt.client.WebClient;
-import org.eclipse.rap.rwt.client.service.JavaScriptExecutor;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.osgi.framework.BundleContext;
-
-public class AppUi implements CmsUiProvider, Branding {
- private final CmsScriptApp app;
-
- private CmsUiProvider ui;
- private String createUi;
- private Object impl;
- private String script;
- // private Branding branding = new Branding();
-
- private EntryPointFactory factory;
-
- // Branding
- private String themeId;
- private String additionalHeaders;
- private String bodyHtml;
- private String pageTitle;
- private String pageOverflow;
- private String favicon;
-
- public AppUi(CmsScriptApp app) {
- this.app = app;
- }
-
- public AppUi(CmsScriptApp app, String scriptPath) {
- this.app = app;
- this.ui = new ScriptUi((BundleContext) app.getScriptEngine().get(CmsScriptRwtApplication.BC), app.getScriptEngine(), scriptPath);
- }
-
- public AppUi(CmsScriptApp app, CmsUiProvider uiProvider) {
- this.app = app;
- this.ui = uiProvider;
- }
-
- public AppUi(CmsScriptApp app, EntryPointFactory factory) {
- this.app = app;
- this.factory = factory;
- }
-
- public void apply(Repository repository, Application application, Branding appBranding, String path) {
- Map<String, String> factoryProperties = new HashMap<>();
- if (appBranding != null)
- appBranding.applyBranding(factoryProperties);
- applyBranding(factoryProperties);
- if (factory != null) {
- application.addEntryPoint("/" + path, factory, factoryProperties);
- } else {
- EntryPointFactory entryPointFactory = new EntryPointFactory() {
- @Override
- public EntryPoint create() {
- SimpleErgonomics ergonomics = new SimpleErgonomics(repository, "main", "/home/root/argeo:keyring",
- AppUi.this, factoryProperties);
-// CmsUiProvider header = app.getHeader();
-// if (header != null)
-// ergonomics.setHeader(header);
- app.applySides(ergonomics);
- Integer headerHeight = app.getHeaderHeight();
- if (headerHeight != null)
- ergonomics.setHeaderHeight(headerHeight);
- return ergonomics;
- }
- };
- application.addEntryPoint("/" + path, entryPointFactory, factoryProperties);
- }
- }
-
- public void setUi(CmsUiProvider uiProvider) {
- this.ui = uiProvider;
- }
-
- 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);
- }
-
- // public Branding getBranding() {
- // return branding;
- // }
-
- @Override
- public Control createUi(Composite parent, Node context) throws RepositoryException {
- CmsPane cmsPane = new CmsPane(parent, SWT.NONE);
-
- if (false) {
- // QA
- CmsUiUtils.style(cmsPane.getQaArea(), "qa");
- Button reload = new Button(cmsPane.getQaArea(), SWT.FLAT);
- CmsUiUtils.style(reload, "qa");
- reload.setText("Reload");
- reload.addSelectionListener(new Selected() {
- private static final long serialVersionUID = 1L;
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- new Thread() {
- @Override
- public void run() {
- app.reload();
- }
- }.start();
- RWT.getClient().getService(JavaScriptExecutor.class)
- .execute("setTimeout('location.reload()',1000)");
- }
- });
-
- // Support
- CmsUiUtils.style(cmsPane.getSupportArea(), "support");
- Label msg = new Label(cmsPane.getSupportArea(), SWT.NONE);
- CmsUiUtils.style(msg, "support");
- msg.setText("UNSUPPORTED DEVELOPMENT VERSION");
- }
-
- if (ui != null) {
- ui.createUi(cmsPane.getMainArea(), context);
- }
- if (createUi != null) {
- Invocable invocable = (Invocable) app.getScriptEngine();
- try {
- invocable.invokeFunction(createUi, cmsPane.getMainArea(), context);
-
- } catch (NoSuchMethodException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (ScriptException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- if (impl != null) {
- Invocable invocable = (Invocable) app.getScriptEngine();
- try {
- invocable.invokeMethod(impl, "createUi", cmsPane.getMainArea(), context);
-
- } catch (NoSuchMethodException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (ScriptException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
-
- // Invocable invocable = (Invocable) app.getScriptEngine();
- // try {
- // invocable.invokeMethod(AppUi.this, "initUi", parent, context);
- //
- // } catch (NoSuchMethodException e) {
- // // TODO Auto-generated catch block
- // e.printStackTrace();
- // } catch (ScriptException e) {
- // // TODO Auto-generated catch block
- // e.printStackTrace();
- // }
-
- return null;
- }
-
- public void setCreateUi(String createUi) {
- this.createUi = createUi;
- }
-
- public void setImpl(Object impl) {
- this.impl = impl;
- }
-
- public Object getImpl() {
- return impl;
- }
-
- public String getScript() {
- return script;
- }
-
- public void setScript(String script) {
- this.script = script;
- }
-
- // 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;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.ui.script;
-
-import java.util.Map;
-
-public interface Branding {
- public void applyBranding(Map<String, String> properties);
-
- public String getThemeId();
-
- public String getAdditionalHeaders();
-
- public String getBodyHtml();
-
- public String getPageTitle();
-
- public String getPageOverflow();
-
- public String getFavicon();
-
-}
+++ /dev/null
-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.cms.CmsException;
-import org.argeo.cms.ui.CmsConstants;
-import org.argeo.cms.ui.CmsTheme;
-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;
- }
-
- }
-
-}
+++ /dev/null
-package org.argeo.cms.ui.script;
-
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.net.URL;
-
-import javax.jcr.Repository;
-import javax.script.ScriptEngine;
-import javax.script.ScriptEngineManager;
-import javax.script.ScriptException;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.cms.CmsException;
-import org.eclipse.rap.rwt.application.Application;
-import org.eclipse.rap.rwt.application.ApplicationConfiguration;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleException;
-import org.osgi.framework.wiring.BundleWiring;
-
-public class CmsScriptRwtApplication implements ApplicationConfiguration {
- public final static String APP = "APP";
- public final static String BC = "BC";
-
- private final Log log = LogFactory.getLog(CmsScriptRwtApplication.class);
-
- BundleContext bundleContext;
- Repository repository;
-
- ScriptEngine engine;
-
- public void init(BundleContext bundleContext) {
- this.bundleContext = bundleContext;
- ClassLoader bundleCl = bundleContext.getBundle().adapt(BundleWiring.class).getClassLoader();
- ClassLoader originalCcl = Thread.currentThread().getContextClassLoader();
- try {
-// Thread.currentThread().setContextClassLoader(bundleCl);// GraalVM needs it to be before creating manager
-// ScriptEngineManager scriptEngineManager = new ScriptEngineManager(bundleCl);
-// engine = scriptEngineManager.getEngineByName("JavaScript");
-// if (engine == null) {// Nashorn
-// Thread.currentThread().setContextClassLoader(originalCcl);
-// scriptEngineManager = new ScriptEngineManager();
-// Thread.currentThread().setContextClassLoader(bundleCl);
-// engine = scriptEngineManager.getEngineByName("JavaScript");
-// }
- engine = loadScriptEngine(originalCcl, bundleCl);
-
- // Load script
- URL appUrl = bundleContext.getBundle().getEntry("cms/app.js");
- // System.out.println("Loading " + appUrl);
- // System.out.println("Loading " + appUrl.getHost());
- // System.out.println("Loading " + appUrl.getPath());
-
- CmsScriptApp app = new CmsScriptApp(engine);
- engine.put(APP, app);
- engine.put(BC, bundleContext);
- try (Reader reader = new InputStreamReader(appUrl.openStream())) {
- engine.eval(reader);
- } catch (IOException | ScriptException e) {
- throw new CmsException("Cannot execute " + appUrl, e);
- }
-
- if (log.isDebugEnabled())
- log.debug("CMS script app initialized from " + appUrl);
-
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- Thread.currentThread().setContextClassLoader(originalCcl);
- }
- }
-
- public void destroy(BundleContext bundleContext) {
- engine = null;
- }
-
- @Override
- public void configure(Application application) {
- load(application);
- }
-
- void load(Application application) {
- CmsScriptApp app = getApp();
- app.apply(bundleContext, repository, application);
- if (log.isDebugEnabled())
- log.debug("CMS script app loaded to " + app.getWebPath());
- }
-
- CmsScriptApp getApp() {
- if (engine == null)
- throw new IllegalStateException("CMS script app is not initialized");
- return (CmsScriptApp) engine.get(APP);
- }
-
- void update() {
-
- try {
- bundleContext.getBundle().update();
- } catch (BundleException e) {
- e.printStackTrace();
- }
- }
-
- public void setRepository(Repository repository) {
- this.repository = repository;
- }
-
- private static ScriptEngine loadScriptEngine(ClassLoader originalCcl, ClassLoader bundleCl) {
- Thread.currentThread().setContextClassLoader(bundleCl);// GraalVM needs it to be before creating manager
- ScriptEngineManager scriptEngineManager = new ScriptEngineManager(bundleCl);
- ScriptEngine engine = scriptEngineManager.getEngineByName("JavaScript");
- if (engine == null) {// Nashorn
- Thread.currentThread().setContextClassLoader(originalCcl);
- scriptEngineManager = new ScriptEngineManager();
- Thread.currentThread().setContextClassLoader(bundleCl);
- engine = scriptEngineManager.getEngineByName("JavaScript");
- }
- return engine;
- }
-}
+++ /dev/null
-package org.argeo.cms.ui.script;
-
-import javax.jcr.Repository;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.ServiceReference;
-import org.osgi.util.tracker.ServiceTracker;
-
-public class ScriptAppActivator implements BundleActivator {
- private final static Log log = LogFactory.getLog(ScriptAppActivator.class);
-
- @Override
- public void start(BundleContext context) throws Exception {
- try {
- CmsScriptRwtApplication appConfig = new CmsScriptRwtApplication();
- appConfig.init(context);
- CmsScriptApp app = appConfig.getApp();
- ServiceTracker<Repository, Repository> repoSt = new ServiceTracker<Repository, Repository>(context,
- FrameworkUtil.createFilter("(&" + app.getRepo() + "(objectClass=javax.jcr.Repository))"), null) {
-
- @Override
- public Repository addingService(ServiceReference<Repository> reference) {
- Repository repository = super.addingService(reference);
- appConfig.setRepository(repository);
- CmsScriptApp app = appConfig.getApp();
- app.register(context, appConfig);
- return repository;
- }
-
- };
- repoSt.open();
- } catch (Exception e) {
- log.error("Cannot initialise script bundle " + context.getBundle().getSymbolicName(), e);
- throw e;
- }
- }
-
- @Override
- public void stop(BundleContext context) throws Exception {
- }
-
-}
+++ /dev/null
-package org.argeo.cms.ui.script;
-
-import java.net.URL;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.script.Invocable;
-import javax.script.ScriptEngine;
-import javax.script.ScriptException;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.osgi.framework.BundleContext;
-
-class ScriptUi implements CmsUiProvider {
- private final static Log log = LogFactory.getLog(ScriptUi.class);
-
- private boolean development = true;
- private ScriptEngine scriptEngine;
-
- private URL appUrl;
- // private BundleContext bundleContext;
- // private String path;
-
- // private Bindings bindings;
- // private String script;
-
- public ScriptUi(BundleContext bundleContext,ScriptEngine scriptEngine, String path) {
- this.scriptEngine = scriptEngine;
-//// ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
-// ClassLoader bundleCl = bundleContext.getBundle().adapt(BundleWiring.class).getClassLoader();
-// ClassLoader originalCcl = Thread.currentThread().getContextClassLoader();
-// try {
-//// Thread.currentThread().setContextClassLoader(bundleCl);
-//// scriptEngine = scriptEngineManager.getEngineByName("JavaScript");
-//// scriptEngine.put(CmsScriptRwtApplication.BC, bundleContext);
-// scriptEngine = CmsScriptRwtApplication.loadScriptEngine(originalCcl, bundleCl);
-//
-// } catch (Exception e) {
-// e.printStackTrace();
-// } finally {
-// Thread.currentThread().setContextClassLoader(originalCcl);
-// }
- this.appUrl = bundleContext.getBundle().getEntry(path);
- load();
- }
-
- private void load() {
-// try (Reader reader = new InputStreamReader(appUrl.openStream())) {
-// scriptEngine.eval(reader);
-// } catch (IOException | ScriptException e) {
-// log.warn("Cannot execute " + appUrl, e);
-// }
-
- try {
- scriptEngine.eval("load('" + appUrl + "')");
- } catch (ScriptException e) {
- log.warn("Cannot execute " + appUrl, e);
- }
-
- }
-
- // public ScriptUiProvider(ScriptEngine scriptEngine, String script) throws
- // ScriptException {
- // super();
- // this.scriptEngine = scriptEngine;
- // this.script = script;
- // bindings = scriptEngine.createBindings();
- // scriptEngine.eval(script, bindings);
- // }
-
- @Override
- public Control createUi(Composite parent, Node context) throws RepositoryException {
- long begin = System.currentTimeMillis();
- // if (bindings == null) {
- // bindings = scriptEngine.createBindings();
- // try {
- // scriptEngine.eval(script, bindings);
- // } catch (ScriptException e) {
- // log.warn("Cannot evaluate script", e);
- // }
- // }
- // Bindings bindings = scriptEngine.createBindings();
- // bindings.put("parent", parent);
- // bindings.put("context", context);
- // URL appUrl = bundleContext.getBundle().getEntry(path);
- // try (Reader reader = new InputStreamReader(appUrl.openStream())) {
- // scriptEngine.eval(reader,bindings);
- // } catch (IOException | ScriptException e) {
- // log.warn("Cannot execute " + appUrl, e);
- // }
-
- if (development)
- load();
-
- Invocable invocable = (Invocable) scriptEngine;
- try {
- invocable.invokeFunction("createUi", parent, context);
- } catch (NoSuchMethodException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (ScriptException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
-
- long duration = System.currentTimeMillis() - begin;
- if (log.isTraceEnabled())
- log.trace(appUrl + " UI in " + duration + " ms");
- return null;
- }
-
-}
+++ /dev/null
-// CMS
-var ScrolledPage = Java.type('org.argeo.cms.ui.widgets.ScrolledPage');
-
-var CmsScriptApp = Java.type('org.argeo.cms.ui.script.CmsScriptApp');
-var AppUi = Java.type('org.argeo.cms.ui.script.AppUi');
-var Theme = Java.type('org.argeo.cms.ui.script.Theme');
-var ScriptUi = Java.type('org.argeo.cms.ui.script.ScriptUi');
-var CmsUtils = Java.type('org.argeo.cms.ui.util.CmsUiUtils');
-var SimpleCmsHeader = Java.type('org.argeo.cms.ui.util.SimpleCmsHeader');
-var CmsLink = Java.type('org.argeo.cms.ui.util.CmsLink');
-var MenuLink = Java.type('org.argeo.cms.ui.util.MenuLink');
-var UserMenuLink = Java.type('org.argeo.cms.ui.util.UserMenuLink');
-
-// SWT
-var SWT = Java.type('org.eclipse.swt.SWT');
-var Composite = Java.type('org.eclipse.swt.widgets.Composite');
-var Label = Java.type('org.eclipse.swt.widgets.Label');
-var Button = Java.type('org.eclipse.swt.widgets.Button');
-var Text = Java.type('org.eclipse.swt.widgets.Text');
-var Browser = Java.type('org.eclipse.swt.browser.Browser');
-
-var FillLayout = Java.type('org.eclipse.swt.layout.FillLayout');
-var GridLayout = Java.type('org.eclipse.swt.layout.GridLayout');
-var RowLayout = Java.type('org.eclipse.swt.layout.RowLayout');
-var FormLayout = Java.type('org.eclipse.swt.layout.FormLayout');
-var GridData = Java.type('org.eclipse.swt.layout.GridData');
-
-function loadNode(node) {
- var json = CmsScriptApp.toJson(node)
- var fromJson = JSON.parse(json)
- return fromJson
-}
-
-function newArea(parent, style, layout) {
- var control = new Composite(parent, SWT.NONE)
- control.setLayout(layout)
- CmsUtils.style(control, style)
- return control
-}
-
-function newLabel(parent, style, text) {
- var control = new Label(parent, SWT.WRAP)
- control.setText(text)
- CmsUtils.style(control, style)
- CmsUtils.markup(control)
- return control
-}
-
-function newButton(parent, style, text) {
- var control = new Button(parent, SWT.FLAT)
- control.setText(text)
- CmsUtils.style(control, style)
- CmsUtils.markup(control)
- return control
-}
-
-function newFormLabel(parent, style, text) {
- return newLabel(parent, style, '<b>' + text + '</b>')
-}
-
-function newText(parent, style, msg) {
- var control = new Text(parent, SWT.NONE)
- control.setMessage(msg)
- CmsUtils.style(control, style)
- return control
-}
-
-function newScrolledPage(parent) {
- var scrolled = new ScrolledPage(parent, SWT.NONE)
- scrolled.setLayoutData(CmsUtils.fillAll())
- scrolled.setLayout(CmsUtils.noSpaceGridLayout())
- var page = new Composite(scrolled, SWT.NONE)
- page.setLayout(CmsUtils.noSpaceGridLayout())
- page.setBackgroundMode(SWT.INHERIT_NONE)
- return page
-}
-
-function gridData(control) {
- var gridData = new GridData()
- control.setLayoutData(gridData)
- return gridData
-}
-
-function gridData(control, hAlign, vAlign) {
- var gridData = new GridData(hAlign, vAlign, false, false)
- control.setLayoutData(gridData)
- return gridData
-}
-
-// print(__FILE__, __LINE__, __DIR__)
+++ /dev/null
-/** Argeo CMS user interface scripting. */
-package org.argeo.cms.ui.script;
\ No newline at end of file
+++ /dev/null
-package org.argeo.cms.ui.util;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Hashtable;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.security.Privilege;
-import javax.jcr.version.VersionManager;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.api.NodeConstants;
-import org.argeo.api.NodeUtils;
-import org.argeo.cms.CmsException;
-import org.argeo.cms.ui.CmsConstants;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.LifeCycleUiProvider;
-import org.argeo.cms.web.BundleResourceLoader;
-import org.argeo.cms.web.SimpleErgonomics;
-import org.argeo.jcr.JcrUtils;
-import org.eclipse.rap.rwt.RWT;
-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.EntryPoint;
-import org.eclipse.rap.rwt.application.EntryPointFactory;
-import org.eclipse.rap.rwt.application.ExceptionHandler;
-import org.eclipse.rap.rwt.client.WebClient;
-import org.eclipse.rap.rwt.client.service.JavaScriptExecutor;
-import org.eclipse.rap.rwt.service.ResourceLoader;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.layout.FillLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceRegistration;
-
-/** A basic generic app based on {@link SimpleErgonomics}. */
-public class SimpleApp implements CmsConstants, ApplicationConfiguration {
- private final static Log log = LogFactory.getLog(SimpleApp.class);
-
- private String contextName = null;
-
- private Map<String, Map<String, String>> branding = new HashMap<String, Map<String, String>>();
- private Map<String, List<String>> styleSheets = new HashMap<String, List<String>>();
-
- private List<String> resources = new ArrayList<String>();
-
- private BundleContext bundleContext;
-
- private Repository repository;
- private String workspace = null;
- private String jcrBasePath = "/";
- private List<String> roPrincipals = Arrays.asList(NodeConstants.ROLE_ANONYMOUS, NodeConstants.ROLE_USER);
- private List<String> rwPrincipals = Arrays.asList(NodeConstants.ROLE_USER);
-
- private CmsUiProvider header;
- private Map<String, CmsUiProvider> pages = new LinkedHashMap<String, CmsUiProvider>();
-
- private Integer headerHeight = 40;
-
- private ServiceRegistration<ApplicationConfiguration> appReg;
-
- public void configure(Application application) {
- try {
- 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(LOADING_IMAGE, createResourceLoader(LOADING_IMAGE));
- // empty image
- application.addResource(NO_IMAGE, createResourceLoader(NO_IMAGE));
-
- for (String resource : resources) {
- application.addResource(resource, bundleRL);
- if (log.isTraceEnabled())
- log.trace("Resource " + resource);
- }
-
- Map<String, String> defaultBranding = null;
- if (branding.containsKey("*"))
- defaultBranding = branding.get("*");
- // String defaultTheme = defaultBranding.get(WebClient.THEME_ID);
-
- // entry points
- for (String page : pages.keySet()) {
- Map<String, String> properties = defaultBranding != null ? new HashMap<String, String>(defaultBranding)
- : new HashMap<String, String>();
- if (branding.containsKey(page)) {
- properties.putAll(branding.get(page));
- }
- // favicon
- if (properties.containsKey(WebClient.FAVICON)) {
- String themeId = defaultBranding.get(WebClient.THEME_ID);
- Bundle themeBundle = findThemeBundle(bundleContext, themeId);
- String faviconRelPath = properties.get(WebClient.FAVICON);
- application.addResource(faviconRelPath,
- new BundleResourceLoader(themeBundle != null ? themeBundle : bundleContext.getBundle()));
- if (log.isTraceEnabled())
- log.trace("Favicon " + faviconRelPath);
-
- }
-
- // page title
- if (!properties.containsKey(WebClient.PAGE_TITLE)) {
- if (page.length() > 0)
- properties.put(WebClient.PAGE_TITLE, Character.toUpperCase(page.charAt(0)) + page.substring(1));
- }
-
- // default body HTML
- if (!properties.containsKey(WebClient.BODY_HTML))
- properties.put(WebClient.BODY_HTML, DEFAULT_LOADING_BODY);
-
- //
- // ADD ENTRY POINT
- //
- application.addEntryPoint("/" + page,
- new CmsEntryPointFactory(pages.get(page), repository, workspace, properties), properties);
- log.info("Page /" + page);
- }
-
- // stylesheets and themes
- Set<Bundle> themeBundles = new HashSet<>();
- for (String themeId : styleSheets.keySet()) {
- Bundle themeBundle = findThemeBundle(bundleContext, themeId);
- StyleSheetResourceLoader styleSheetRL = new StyleSheetResourceLoader(
- themeBundle != null ? themeBundle : bundleContext.getBundle());
- if (themeBundle != null)
- themeBundles.add(themeBundle);
- List<String> cssLst = styleSheets.get(themeId);
- if (log.isDebugEnabled())
- log.debug("Theme " + themeId);
- for (String css : cssLst) {
- application.addStyleSheet(themeId, css, styleSheetRL);
- if (log.isDebugEnabled())
- log.debug(" CSS " + css);
- }
-
- }
- for (Bundle themeBundle : themeBundles) {
- BundleResourceLoader themeBRL = new BundleResourceLoader(themeBundle);
- SimpleApp.addThemeResources(application, themeBundle, themeBRL, "*.png");
- SimpleApp.addThemeResources(application, themeBundle, themeBRL, "*.gif");
- SimpleApp.addThemeResources(application, themeBundle, themeBRL, "*.jpg");
- }
- } catch (RuntimeException e) {
- // Easier access to initialisation errors
- log.error("Unexpected exception when configuring RWT application.", e);
- throw e;
- }
- }
-
- public void init() throws RepositoryException {
- Session session = null;
- try {
- session = NodeUtils.openDataAdminSession(repository, workspace);
- // session = JcrUtils.loginOrCreateWorkspace(repository, workspace);
- VersionManager vm = session.getWorkspace().getVersionManager();
- JcrUtils.mkdirs(session, jcrBasePath);
- session.save();
- if (!vm.isCheckedOut(jcrBasePath))
- vm.checkout(jcrBasePath);
- for (String principal : rwPrincipals)
- JcrUtils.addPrivilege(session, jcrBasePath, principal, Privilege.JCR_WRITE);
- for (String principal : roPrincipals)
- JcrUtils.addPrivilege(session, jcrBasePath, principal, Privilege.JCR_READ);
-
- for (String pageName : pages.keySet()) {
- try {
- initPage(session, pages.get(pageName));
- session.save();
- } catch (Exception e) {
- throw new CmsException("Cannot initialize page " + pageName, e);
- }
- }
-
- } finally {
- JcrUtils.logoutQuietly(session);
- }
-
- // publish to OSGi
- register();
- }
-
- protected void initPage(Session adminSession, CmsUiProvider page) throws RepositoryException {
- if (page instanceof LifeCycleUiProvider)
- ((LifeCycleUiProvider) page).init(adminSession);
- }
-
- public void destroy() {
- for (String pageName : pages.keySet()) {
- try {
- CmsUiProvider page = pages.get(pageName);
- if (page instanceof LifeCycleUiProvider)
- ((LifeCycleUiProvider) page).destroy();
- } catch (Exception e) {
- log.error("Cannot destroy page " + pageName, e);
- }
- }
- }
-
- protected void register() {
- Hashtable<String, String> props = new Hashtable<String, String>();
- if (contextName != null)
- props.put("contextName", contextName);
- appReg = bundleContext.registerService(ApplicationConfiguration.class, this, props);
- if (log.isDebugEnabled())
- log.debug("Registered " + (contextName == null ? "/" : contextName));
- }
-
- protected void unregister() {
- appReg.unregister();
- if (log.isDebugEnabled())
- log.debug("Unregistered " + (contextName == null ? "/" : contextName));
- }
-
- public void setRepository(Repository repository) {
- this.repository = repository;
- }
-
- public void setWorkspace(String workspace) {
- this.workspace = workspace;
- }
-
- public void setHeader(CmsUiProvider header) {
- this.header = header;
- }
-
- public void setPages(Map<String, CmsUiProvider> pages) {
- this.pages = pages;
- }
-
- public void setJcrBasePath(String basePath) {
- this.jcrBasePath = basePath;
- }
-
- public void setRoPrincipals(List<String> roPrincipals) {
- this.roPrincipals = roPrincipals;
- }
-
- public void setRwPrincipals(List<String> rwPrincipals) {
- this.rwPrincipals = rwPrincipals;
- }
-
- public void setHeaderHeight(Integer headerHeight) {
- this.headerHeight = headerHeight;
- }
-
- public void setBranding(Map<String, Map<String, String>> branding) {
- this.branding = branding;
- }
-
- public void setStyleSheets(Map<String, List<String>> styleSheets) {
- this.styleSheets = styleSheets;
- }
-
- public void setBundleContext(BundleContext bundleContext) {
- this.bundleContext = bundleContext;
- }
-
- public void setResources(List<String> resources) {
- this.resources = resources;
- }
-
- public void setContextName(String contextName) {
- this.contextName = contextName;
- }
-
- private static void addThemeResources(Application application, Bundle themeBundle, BundleResourceLoader themeBRL,
- String pattern) {
- Enumeration<URL> themeResources = themeBundle.findEntries("/", pattern, true);
- if (themeResources == null)
- return;
- while (themeResources.hasMoreElements()) {
- String resource = themeResources.nextElement().getPath();
- // remove first '/' so that RWT registers it
- resource = resource.substring(1);
- if (!resource.endsWith("/")) {
- application.addResource(resource, themeBRL);
- if (log.isTraceEnabled())
- log.trace("Registered " + resource + " from theme " + themeBundle);
- }
-
- }
-
- }
-
- private static Bundle findThemeBundle(BundleContext bundleContext, String themeId) {
- if (themeId == null)
- return null;
- // TODO optimize
- // TODO deal with multiple versions
- Bundle themeBundle = null;
- if (themeId != null) {
- for (Bundle bundle : bundleContext.getBundles())
- if (themeId.equals(bundle.getSymbolicName())) {
- themeBundle = bundle;
- break;
- }
- }
- return themeBundle;
- }
-
- class CmsExceptionHandler implements ExceptionHandler {
-
- @Override
- public void handleException(Throwable throwable) {
- // TODO be smarter
- CmsUiUtils.getCmsView().exception(throwable);
- }
-
- }
-
- private class CmsEntryPointFactory implements EntryPointFactory {
- private final CmsUiProvider page;
- private final Repository repository;
- private final String workspace;
- private final Map<String, String> properties;
-
- public CmsEntryPointFactory(CmsUiProvider page, Repository repository, String workspace,
- Map<String, String> properties) {
- this.page = page;
- this.repository = repository;
- this.workspace = workspace;
- this.properties = properties;
- }
-
- @Override
- public EntryPoint create() {
- SimpleErgonomics entryPoint = new SimpleErgonomics(repository, workspace, jcrBasePath, page, properties) {
- private static final long serialVersionUID = -637940404865527290L;
-
- @Override
- protected void createAdminArea(Composite parent) {
- Composite adminArea = new Composite(parent, SWT.NONE);
- adminArea.setLayout(new FillLayout());
- Button refresh = new Button(adminArea, SWT.PUSH);
- refresh.setText("Reload App");
- refresh.addSelectionListener(new SelectionAdapter() {
- private static final long serialVersionUID = -7671999525536351366L;
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- long timeBeforeReload = 1000;
- RWT.getClient().getService(JavaScriptExecutor.class).execute(
- "setTimeout(function() { " + "location.reload();" + "}," + timeBeforeReload + ");");
- reloadApp();
- }
- });
- }
- };
- // entryPoint.setState("");
- entryPoint.setHeader(header);
- entryPoint.setHeaderHeight(headerHeight);
- // CmsSession.current.set(entryPoint);
- return entryPoint;
- }
-
- private void reloadApp() {
- new Thread("Refresh app") {
- @Override
- public void run() {
- unregister();
- register();
- }
- }.start();
- }
- }
-
- private static ResourceLoader createResourceLoader(final String resourceName) {
- return new ResourceLoader() {
- public InputStream getResourceAsStream(String resourceName) throws IOException {
- return getClass().getClassLoader().getResourceAsStream(resourceName);
- }
- };
- }
-
- // private static ResourceLoader createUrlResourceLoader(final URL url) {
- // return new ResourceLoader() {
- // public InputStream getResourceAsStream(String resourceName)
- // throws IOException {
- // return url.openStream();
- // }
- // };
- // }
-
- /*
- * TEXTS
- */
- private static String DEFAULT_LOADING_BODY = "<div"
- + " style=\"position: absolute; left: 50%; top: 50%; margin: -32px -32px; width: 64px; height:64px\">"
- + "<img src=\"./rwt-resources/" + LOADING_IMAGE
- + "\" width=\"32\" height=\"32\" style=\"margin: 16px 16px\"/>" + "</div>";
-}
+++ /dev/null
-package org.argeo.cms.web;
-
-import static org.argeo.naming.SharedSecret.X_SHARED_SECRET;
-
-import java.io.IOException;
-import java.security.PrivilegedAction;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.jcr.Node;
-import javax.jcr.PathNotFoundException;
-import javax.jcr.Property;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.nodetype.NodeType;
-import javax.security.auth.Subject;
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.UnsupportedCallbackException;
-import javax.security.auth.login.LoginContext;
-import javax.security.auth.login.LoginException;
-import javax.servlet.http.HttpServletRequest;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.api.NodeConstants;
-import org.argeo.cms.CmsException;
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.auth.HttpRequestCallback;
-import org.argeo.cms.auth.HttpRequestCallbackHandler;
-import org.argeo.cms.ui.CmsStyles;
-import org.argeo.cms.ui.CmsView;
-import org.argeo.eclipse.ui.specific.UiContext;
-import org.argeo.jcr.JcrUtils;
-import org.argeo.naming.AuthPassword;
-import org.argeo.naming.SharedSecret;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.rap.rwt.application.AbstractEntryPoint;
-import org.eclipse.rap.rwt.client.WebClient;
-import org.eclipse.rap.rwt.client.service.BrowserNavigation;
-import org.eclipse.rap.rwt.client.service.BrowserNavigationEvent;
-import org.eclipse.rap.rwt.client.service.BrowserNavigationListener;
-import org.eclipse.rap.rwt.client.service.JavaScriptExecutor;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Shell;
-
-/** Manages history and navigation */
-public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint implements CmsView {
- private static final long serialVersionUID = 906558779562569784L;
-
- private final Log log = LogFactory.getLog(AbstractCmsEntryPoint.class);
-
- // private final Subject subject;
- private LoginContext loginContext;
-
- private final Repository repository;
- private final String workspace;
- private final String defaultPath;
- private final Map<String, String> factoryProperties;
-
- // Current state
- private Session session;
- private Node node;
- private String nodePath;// useful when changing auth
- private String state;
- private Throwable exception;
-
- // Client services
- private final JavaScriptExecutor jsExecutor;
- private final BrowserNavigation browserNavigation;
-
- public AbstractCmsEntryPoint(Repository repository, String workspace, String defaultPath,
- Map<String, String> factoryProperties) {
- this.repository = repository;
- this.workspace = workspace;
- this.defaultPath = defaultPath;
- this.factoryProperties = new HashMap<String, String>(factoryProperties);
- // subject = new Subject();
-
- // Initial login
- LoginContext lc;
- try {
- lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER,
- new HttpRequestCallbackHandler(UiContext.getHttpRequest(), UiContext.getHttpResponse()));
- lc.login();
- } catch (LoginException e) {
- try {
- lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_ANONYMOUS);
- lc.login();
- } catch (LoginException e1) {
- throw new CmsException("Cannot log in as anonymous", e1);
- }
- }
- authChange(lc);
-
- jsExecutor = RWT.getClient().getService(JavaScriptExecutor.class);
- browserNavigation = RWT.getClient().getService(BrowserNavigation.class);
- if (browserNavigation != null)
- browserNavigation.addBrowserNavigationListener(new CmsNavigationListener());
- }
-
- @Override
- protected Shell createShell(Display display) {
- Shell shell = super.createShell(display);
- shell.setData(RWT.CUSTOM_VARIANT, CmsStyles.CMS_SHELL);
- display.disposeExec(new Runnable() {
-
- @Override
- public void run() {
- if (log.isTraceEnabled())
- log.trace("Logging out " + session);
- JcrUtils.logoutQuietly(session);
- }
- });
- return shell;
- }
-
- @Override
- protected final void createContents(final Composite parent) {
- // UiContext.setData(CmsView.KEY, this);
- CmsView.registerCmsView(parent.getShell(), this);
- Subject.doAs(getSubject(), new PrivilegedAction<Void>() {
- @Override
- public Void run() {
- try {
- initUi(parent);
- } catch (Exception e) {
- throw new CmsException("Cannot create entrypoint contents", e);
- }
- return null;
- }
- });
- }
-
- /** Create UI */
- protected abstract void initUi(Composite parent);
-
- /** Recreate UI after navigation or auth change */
- protected abstract void refresh();
-
- /**
- * The node to return when no node was found (for authenticated users and
- * anonymous)
- */
-// private Node getDefaultNode(Session session) throws RepositoryException {
-// if (!session.hasPermission(defaultPath, "read")) {
-// String userId = session.getUserID();
-// if (userId.equals(NodeConstants.ROLE_ANONYMOUS))
-// // TODO throw a special exception
-// throw new CmsException("Login required");
-// else
-// throw new CmsException("Unauthorized");
-// }
-// return session.getNode(defaultPath);
-// }
-
- protected String getBaseTitle() {
- return factoryProperties.get(WebClient.PAGE_TITLE);
- }
-
- public void navigateTo(String state) {
- exception = null;
- String title = setState(state);
- doRefresh();
- if (browserNavigation != null)
- browserNavigation.pushState(state, title);
- }
-
- // @Override
- // public synchronized Subject getSubject() {
- // return subject;
- // }
-
- // @Override
- // public LoginContext getLoginContext() {
- // return loginContext;
- // }
- protected Subject getSubject() {
- return loginContext.getSubject();
- }
-
- @Override
- public boolean isAnonymous() {
- return CurrentUser.isAnonymous(getSubject());
- }
-
- @Override
- public synchronized void logout() {
- if (loginContext == null)
- throw new CmsException("Login context should not be null");
- try {
- CurrentUser.logoutCmsSession(loginContext.getSubject());
- loginContext.logout();
- LoginContext anonymousLc = new LoginContext(NodeConstants.LOGIN_CONTEXT_ANONYMOUS);
- anonymousLc.login();
- authChange(anonymousLc);
- } catch (LoginException e) {
- log.error("Cannot logout", e);
- }
- }
-
- @Override
- public synchronized void authChange(LoginContext lc) {
- if (lc == null)
- throw new CmsException("Login context cannot be null");
- // logout previous login context
- if (this.loginContext != null)
- try {
- this.loginContext.logout();
- } catch (LoginException e1) {
- log.warn("Could not log out: " + e1);
- }
- this.loginContext = lc;
- Subject.doAs(getSubject(), new PrivilegedAction<Void>() {
-
- @Override
- public Void run() {
- try {
- JcrUtils.logoutQuietly(session);
- session = repository.login(workspace);
- if (nodePath != null)
- try {
- node = session.getNode(nodePath);
- } catch (PathNotFoundException e) {
- navigateTo("~");
- }
-
- // refresh UI
- doRefresh();
- } catch (RepositoryException e) {
- throw new CmsException("Cannot perform auth change", e);
- }
- return null;
- }
-
- });
- }
-
- @Override
- public void exception(final Throwable e) {
- AbstractCmsEntryPoint.this.exception = e;
- log.error("Unexpected exception in CMS", e);
- doRefresh();
- }
-
- protected synchronized void doRefresh() {
- Subject.doAs(getSubject(), new PrivilegedAction<Void>() {
- @Override
- public Void run() {
- refresh();
- return null;
- }
- });
- }
-
- /** Sets the state of the entry point and retrieve the related JCR node. */
- protected synchronized String setState(String newState) {
- String previousState = this.state;
-
- String newNodePath = null;
- String prefix = null;
- this.state = newState;
- if (newState.equals("~"))
- this.state = "";
-
- try {
- int firstSlash = state.indexOf('/');
- if (firstSlash == 0) {
- newNodePath = state;
- prefix = "";
- } else if (firstSlash > 0) {
- prefix = state.substring(0, firstSlash);
- newNodePath = state.substring(firstSlash);
- } else {
- newNodePath = defaultPath;
- prefix = state;
-
- }
-
- // auth
- int colonIndex = prefix.indexOf('$');
- if (colonIndex > 0) {
- SharedSecret token = new SharedSecret(new AuthPassword(X_SHARED_SECRET + '$' + prefix)) {
-
- @Override
- public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
- super.handle(callbacks);
- // handle HTTP context
- for (Callback callback : callbacks) {
- if (callback instanceof HttpRequestCallback) {
- ((HttpRequestCallback) callback).setRequest(UiContext.getHttpRequest());
- ((HttpRequestCallback) callback).setResponse(UiContext.getHttpResponse());
- }
- }
- }
- };
- LoginContext lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, token);
- lc.login();
- authChange(lc);// sets the node as well
- // } else {
- // // TODO check consistency
- // }
- } else {
- Node newNode = null;
- if (session.nodeExists(newNodePath))
- newNode = session.getNode(newNodePath);
- else {
-// throw new CmsException("Data " + newNodePath + " does not exist");
- newNode = null;
- }
- setNode(newNode);
- }
- String title = publishMetaData(getNode());
-
- if (log.isTraceEnabled())
- log.trace("node=" + newNodePath + ", state=" + state + " (prefix=" + prefix + ")");
-
- return title;
- } catch (Exception e) {
- log.error("Cannot set state '" + state + "'", e);
- if (state.equals("") || newState.equals("~") || newState.equals(previousState))
- return "Unrecoverable exception : " + e.getClass().getSimpleName();
- if (previousState.equals(""))
- previousState = "~";
- navigateTo(previousState);
- throw new CmsException("Unexpected issue when accessing #" + newState, e);
- }
- }
-
- private String publishMetaData(Node node) throws RepositoryException {
- // Title
- String title;
- if (node != null && node.isNodeType(NodeType.MIX_TITLE) && node.hasProperty(Property.JCR_TITLE))
- title = node.getProperty(Property.JCR_TITLE).getString() + " - " + getBaseTitle();
- else
- title = getBaseTitle();
-
- HttpServletRequest request = UiContext.getHttpRequest();
- if (request == null)
- return null;
-
- StringBuilder js = new StringBuilder();
- if (title == null)
- title = "";
- title = title.replace("'", "\\'");// sanitize
- js.append("document.title = '" + title + "';");
- jsExecutor.execute(js.toString());
- return title;
- }
-
- // Simply remove some illegal character
- // private String clean(String stringToClean) {
- // return stringToClean.replaceAll("'", "").replaceAll("\\n", "")
- // .replaceAll("\\t", "");
- // }
-
- protected synchronized Node getNode() {
- return node;
- }
-
- private synchronized void setNode(Node node) throws RepositoryException {
- this.node = node;
- this.nodePath = node == null ? null : node.getPath();
- }
-
- protected String getState() {
- return state;
- }
-
- protected Throwable getException() {
- return exception;
- }
-
- protected void resetException() {
- exception = null;
- }
-
- protected Session getSession() {
- return session;
- }
-
- private class CmsNavigationListener implements BrowserNavigationListener {
- private static final long serialVersionUID = -3591018803430389270L;
-
- @Override
- public void navigated(BrowserNavigationEvent event) {
- setState(event.getState());
- doRefresh();
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-package org.argeo.cms.web;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-
-import org.argeo.cms.CmsException;
-import org.eclipse.rap.rwt.service.ResourceLoader;
-import org.osgi.framework.Bundle;
-
-/** {@link ResourceLoader} implementation wrapping an {@link Bundle}. */
-public class BundleResourceLoader implements ResourceLoader {
- private final Bundle bundle;
-
- public BundleResourceLoader(Bundle bundle) {
- this.bundle = bundle;
- }
-
- @Override
- public InputStream getResourceAsStream(String resourceName) throws IOException {
- URL res = bundle.getEntry(resourceName);
- if (res == null) {
- res = bundle.getResource(resourceName);
- if (res == null)
- throw new CmsException("Resource " + resourceName + " not found in bundle " + bundle.getSymbolicName());
- }
- return res.openStream();
- }
-
- public Bundle getBundle() {
- return bundle;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.web;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.argeo.cms.ui.CmsTheme;
-import org.eclipse.rap.rwt.service.ResourceLoader;
-
-/** A RAP {@link ResourceLoader} based on a {@link CmsTheme}. */
-public class CmsThemeResourceLoader implements ResourceLoader {
- private final CmsTheme theme;
-
- public CmsThemeResourceLoader(CmsTheme theme) {
- super();
- this.theme = theme;
- }
-
- @Override
- public InputStream getResourceAsStream(String resourceName) throws IOException {
- return theme.getResourceAsStream(resourceName);
- }
-
-}
+++ /dev/null
-package org.argeo.cms.web;
-
-import java.util.Dictionary;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.cms.ui.CmsApp;
-import org.argeo.cms.ui.CmsAppListener;
-import org.argeo.cms.ui.CmsTheme;
-import org.argeo.util.LangUtils;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.rap.rwt.application.Application;
-import org.eclipse.rap.rwt.application.ApplicationConfiguration;
-import org.eclipse.rap.rwt.client.WebClient;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceRegistration;
-import org.osgi.service.event.EventAdmin;
-
-/** An RWT web app integrating with a {@link CmsApp}. */
-public class CmsWebApp implements ApplicationConfiguration, CmsAppListener {
- private final static Log log = LogFactory.getLog(CmsWebApp.class);
-
- private BundleContext bundleContext;
- private CmsApp cmsApp;
- private EventAdmin eventAdmin;
-
- private ServiceRegistration<ApplicationConfiguration> rwtAppReg;
-
- private final static String CONTEXT_NAME = "contextName";
- private String contextName;
-
- public void init(BundleContext bundleContext, Map<String, String> properties) {
- this.bundleContext = bundleContext;
- contextName = properties.get(CONTEXT_NAME);
- if (cmsApp != null)
- themingUpdated();
-// registerIfAllThemesAvailable();
- }
-
- public void destroy(BundleContext bundleContext, Map<String, String> properties) {
- if (cmsApp != null)
- cmsApp.removeCmsAppListener(this);
- }
-
- @Override
- public void configure(Application application) {
- for (String uiName : cmsApp.getUiNames()) {
- CmsTheme theme = cmsApp.getTheme(uiName);
- if (theme != null)
- WebThemeUtils.apply(application, theme);
- }
-// for (CmsTheme theme : themes.values())
-// WebThemeUtils.apply(application, theme);
-
- Map<String, String> properties = new HashMap<>();
- addEntryPoints(application, properties);
-
- }
-
- protected void addEntryPoints(Application application, Map<String, String> commonProperties) {
- for (String uiName : cmsApp.getUiNames()) {
- Map<String, String> properties = new HashMap<>(commonProperties);
- CmsTheme theme = cmsApp.getTheme(uiName);
- if (theme != null) {
- properties.put(WebClient.THEME_ID, theme.getThemeId());
- properties.put(WebClient.HEAD_HTML, theme.getHtmlHeaders());
- } else {
- properties.put(WebClient.THEME_ID, RWT.DEFAULT_THEME_ID);
-// if (themeId != null)
-// log.warn("Theme id " + themeId + " was specified but it was not found, using default RWT theme.");
- }
- application.addEntryPoint("/" + uiName, () -> {
- CmsWebEntryPoint entryPoint = new CmsWebEntryPoint(this, uiName);
- entryPoint.setEventAdmin(eventAdmin);
- return entryPoint;
- }, properties);
- if (log.isDebugEnabled())
- log.info("Added web entry point /" + (contextName != null ? contextName : "") + "/" + uiName);
- }
- log.debug("Published CMS web app /" + (contextName != null ? contextName : ""));
- }
-
-// private void registerIfAllThemesAvailable() {
-// boolean themeMissing = false;
-// uiNames: for (String uiName : cmsApp.getUiNames()) {
-// String themeId = cmsApp.getThemeId(uiName);
-// if (RWT.DEFAULT_THEME_ID.equals(themeId))
-// continue uiNames;
-// if (!themes.containsKey(themeId)) {
-// themeMissing = true;
-// break uiNames;
-// }
-// }
-// if (!themeMissing) {
-// Dictionary<String, Object> regProps = LangUtils.dict(CONTEXT_NAME, contextName);
-// if (bundleContext != null) {
-// rwtAppReg = bundleContext.registerService(ApplicationConfiguration.class, this, regProps);
-// log.info("Published CMS web app /" + (contextName != null ? contextName : ""));
-// }
-// }
-// }
-
- CmsApp getCmsApp() {
- return cmsApp;
- }
-
- public void setCmsApp(CmsApp cmsApp, Map<String, String> properties) {
- this.cmsApp = cmsApp;
- this.cmsApp.addCmsAppListener(this);
-// registerIfAllThemesAvailable();
- }
-
- public void unsetCmsApp(CmsApp cmsApp, Map<String, String> properties) {
- if (rwtAppReg != null)
- rwtAppReg.unregister();
- this.cmsApp = null;
- }
-
- @Override
- public void themingUpdated() {
- Dictionary<String, Object> regProps = LangUtils.dict(CONTEXT_NAME, contextName);
- if (rwtAppReg != null)
- rwtAppReg.unregister();
- if (bundleContext != null) {
- rwtAppReg = bundleContext.registerService(ApplicationConfiguration.class, this, regProps);
- if (log.isDebugEnabled())
- log.debug("Publishing CMS web app /" + (contextName != null ? contextName : "") + " ...");
- }
- }
-
- public void setEventAdmin(EventAdmin eventAdmin) {
- this.eventAdmin = eventAdmin;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.web;
-
-import static org.eclipse.rap.rwt.internal.service.ContextProvider.getApplicationContext;
-
-import java.security.PrivilegedAction;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.UUID;
-
-import javax.security.auth.Subject;
-import javax.security.auth.login.LoginContext;
-import javax.security.auth.login.LoginException;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.api.NodeConstants;
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.auth.HttpRequestCallbackHandler;
-import org.argeo.cms.ui.CmsApp;
-import org.argeo.cms.ui.CmsImageManager;
-import org.argeo.cms.ui.CmsView;
-import org.argeo.cms.ui.UxContext;
-import org.argeo.cms.ui.dialogs.CmsFeedback;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.cms.ui.util.DefaultImageManager;
-import org.argeo.cms.ui.util.SimpleUxContext;
-import org.argeo.eclipse.ui.specific.UiContext;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.rap.rwt.application.EntryPoint;
-import org.eclipse.rap.rwt.client.service.BrowserNavigation;
-import org.eclipse.rap.rwt.client.service.BrowserNavigationEvent;
-import org.eclipse.rap.rwt.client.service.BrowserNavigationListener;
-import org.eclipse.rap.rwt.internal.lifecycle.RWTLifeCycle;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Shell;
-import org.osgi.service.event.Event;
-import org.osgi.service.event.EventAdmin;
-
-/** The {@link CmsView} for a {@link CmsWebApp}. */
-public class CmsWebEntryPoint implements EntryPoint, CmsView, BrowserNavigationListener {
- private static final long serialVersionUID = 7733510691684570402L;
- private final static Log log = LogFactory.getLog(CmsWebEntryPoint.class);
-
- private EventAdmin eventAdmin;
-
- private final CmsWebApp cmsWebApp;
- private final String uiName;
-
- private LoginContext loginContext;
- private String state;
- private Throwable exception;
- private UxContext uxContext;
- private CmsImageManager imageManager;
-
- private Composite ui;
-
- private String uid;
-
- // Client services
- // private final JavaScriptExecutor jsExecutor;
- private final BrowserNavigation browserNavigation;
-
- /** Experimental OS-like multi windows. */
- private boolean multipleShells = false;
-
- public CmsWebEntryPoint(CmsWebApp cmsWebApp, String uiName) {
- assert cmsWebApp != null;
- assert uiName != null;
- this.cmsWebApp = cmsWebApp;
- this.uiName = uiName;
- uid = UUID.randomUUID().toString();
-
- // Initial login
- LoginContext lc;
- try {
- lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER,
- new HttpRequestCallbackHandler(UiContext.getHttpRequest(), UiContext.getHttpResponse()));
- lc.login();
- } catch (LoginException e) {
- try {
- lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_ANONYMOUS);
- lc.login();
- } catch (LoginException e1) {
- throw new IllegalStateException("Cannot log in as anonymous", e1);
- }
- }
- authChange(lc);
-
- // jsExecutor = RWT.getClient().getService(JavaScriptExecutor.class);
- browserNavigation = RWT.getClient().getService(BrowserNavigation.class);
- if (browserNavigation != null)
- browserNavigation.addBrowserNavigationListener(this);
- }
-
- protected void createContents(Composite parent) {
- Subject.doAs(loginContext.getSubject(), new PrivilegedAction<Void>() {
- @Override
- public Void run() {
- try {
- uxContext = new SimpleUxContext();
- imageManager = new DefaultImageManager();
- ui = cmsWebApp.getCmsApp().initUi(parent);
- ui.setData(CmsApp.UI_NAME_PROPERTY, uiName);
- ui.setLayoutData(CmsUiUtils.fillAll());
- } catch (Exception e) {
- throw new IllegalStateException("Cannot create entrypoint contents", e);
- }
- return null;
- }
- });
- }
-
- protected Subject getSubject() {
- return loginContext.getSubject();
- }
-
- @Override
- public boolean isAnonymous() {
- return CurrentUser.isAnonymous(getSubject());
- }
-
- @Override
- public synchronized void logout() {
- if (loginContext == null)
- throw new IllegalArgumentException("Login context should not be null");
- try {
- CurrentUser.logoutCmsSession(loginContext.getSubject());
- loginContext.logout();
- LoginContext anonymousLc = new LoginContext(NodeConstants.LOGIN_CONTEXT_ANONYMOUS);
- anonymousLc.login();
- authChange(anonymousLc);
- } catch (LoginException e) {
- log.error("Cannot logout", e);
- }
- }
-
- @Override
- public synchronized void authChange(LoginContext lc) {
- if (lc == null)
- throw new IllegalArgumentException("Login context cannot be null");
- // logout previous login context
- if (this.loginContext != null)
- try {
- this.loginContext.logout();
- } catch (LoginException e1) {
- log.warn("Could not log out: " + e1);
- }
- this.loginContext = lc;
- doRefresh();
- }
-
- @Override
- public void exception(final Throwable e) {
- exception = e;
- log.error("Unexpected exception in CMS", e);
- doRefresh();
- }
-
- protected synchronized void doRefresh() {
- if (ui != null)
- Subject.doAs(getSubject(), new PrivilegedAction<Void>() {
- @Override
- public Void run() {
- if (exception != null) {
- // TODO internationalise
- CmsFeedback.show("Unexpected exception", exception);
- exception = null;
- // TODO report
- }
- cmsWebApp.getCmsApp().refreshUi(ui, state);
- return null;
- }
- });
- }
-
- /** Sets the state of the entry point and retrieve the related JCR node. */
- protected String setState(String newState) {
- cmsWebApp.getCmsApp().setState(ui, newState);
- state = newState;
- return null;
- }
-
- @Override
- public UxContext getUxContext() {
- return uxContext;
- }
-
- @Override
- public String getUid() {
- return uid;
- }
-
- @Override
- public void navigateTo(String state) {
- exception = null;
- String title = setState(state);
- doRefresh();
- if (browserNavigation != null)
- browserNavigation.pushState(state, title);
- }
-
- @Override
- public CmsImageManager getImageManager() {
- return imageManager;
- }
-
- @Override
- public void navigated(BrowserNavigationEvent event) {
- setState(event.getState());
- doRefresh();
- }
-
- @Override
- public void sendEvent(String topic, Map<String, Object> properties) {
- if (properties == null)
- properties = new HashMap<>();
- if (properties.containsKey(CMS_VIEW_UID_PROPERTY) && !properties.get(CMS_VIEW_UID_PROPERTY).equals(uid))
- throw new IllegalArgumentException("Property " + CMS_VIEW_UID_PROPERTY + " is set to another CMS view uid ("
- + properties.get(CMS_VIEW_UID_PROPERTY) + ") then " + uid);
- properties.put(CMS_VIEW_UID_PROPERTY, uid);
- eventAdmin.sendEvent(new Event(topic, properties));
- }
-
- /*
- * EntryPoint IMPLEMENTATION
- */
-
- @Override
- public int createUI() {
- Display display = new Display();
- Shell shell = createShell(display);
- shell.setLayout(CmsUiUtils.noSpaceGridLayout());
- CmsView.registerCmsView(shell, this);
- createContents(shell);
- shell.layout();
-// if (shell.getMaximized()) {
-// shell.layout();
-// } else {
-//// shell.pack();
-// }
- shell.open();
- if (getApplicationContext().getLifeCycleFactory().getLifeCycle() instanceof RWTLifeCycle) {
- while (!shell.isDisposed()) {
- if (!display.readAndDispatch()) {
- display.sleep();
- }
- }
- display.dispose();
- }
- return 0;
- }
-
- protected Shell createShell(Display display) {
- Shell shell;
- if (!multipleShells) {
- shell = new Shell(display, SWT.NO_TRIM);
- shell.setMaximized(true);
- } else {
- shell = new Shell(display, SWT.SHELL_TRIM);
- shell.setSize(800, 600);
- }
- return shell;
- }
-
- public void setEventAdmin(EventAdmin eventAdmin) {
- this.eventAdmin = eventAdmin;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.web;
-
-import static org.argeo.cms.ui.util.BundleCmsTheme.CMS_THEME_BUNDLE_PROPERTY;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.argeo.cms.ui.util.BundleCmsTheme;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.rap.rwt.application.Application;
-import org.eclipse.rap.rwt.application.ApplicationConfiguration;
-import org.eclipse.rap.rwt.client.WebClient;
-import org.osgi.framework.BundleContext;
-
-/** Lightweight web app using only RWT and not the whole Eclipse platform. */
-public class MinimalWebApp implements ApplicationConfiguration {
-
- private BundleCmsTheme theme;
-
- public void init(BundleContext bundleContext, Map<String, Object> properties) {
- if (properties.containsKey(CMS_THEME_BUNDLE_PROPERTY)) {
- String cmsThemeBundle = properties.get(CMS_THEME_BUNDLE_PROPERTY).toString();
- theme = new BundleCmsTheme(bundleContext, cmsThemeBundle);
- }
- }
-
- public void destroy() {
-
- }
-
- /** To be overridden. Does nothing by default. */
- protected void addEntryPoints(Application application, Map<String, String> properties) {
-
- }
-
- @Override
- public void configure(Application application) {
- if (theme != null)
- WebThemeUtils.apply(application, theme);
-
- Map<String, String> properties = new HashMap<>();
- if (theme != null) {
- properties.put(WebClient.THEME_ID, theme.getThemeId());
- properties.put(WebClient.HEAD_HTML, theme.getHtmlHeaders());
- } else {
- properties.put(WebClient.THEME_ID, RWT.DEFAULT_THEME_ID);
- }
- addEntryPoints(application, properties);
-
- }
-
- public void setTheme(BundleCmsTheme theme) {
- this.theme = theme;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.web;
-
-import java.util.Map;
-import java.util.UUID;
-
-import javax.jcr.Node;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.cms.CmsException;
-import org.argeo.cms.ui.CmsImageManager;
-import org.argeo.cms.ui.CmsStyles;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.UxContext;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.cms.ui.util.DefaultImageManager;
-import org.argeo.cms.ui.util.SimpleUxContext;
-import org.argeo.cms.ui.util.SystemNotifications;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.FillLayout;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-
-/** Simple header/body ergonomics. */
-public class SimpleErgonomics extends AbstractCmsEntryPoint {
- private static final long serialVersionUID = 8743413921359548523L;
-
- private final static Log log = LogFactory.getLog(SimpleErgonomics.class);
-
- private boolean uiInitialized = false;
- private Composite headerArea;
- private Composite leftArea;
- private Composite rightArea;
- private Composite footerArea;
- private Composite bodyArea;
- private final CmsUiProvider uiProvider;
-
- private CmsUiProvider header;
- private Integer headerHeight = 0;
- private Integer footerHeight = 0;
- private CmsUiProvider lead;
- private CmsUiProvider end;
- private CmsUiProvider footer;
-
- private CmsImageManager imageManager = new DefaultImageManager();
- private UxContext uxContext = null;
- private String uid;
-
- public SimpleErgonomics(Repository repository, String workspace, String defaultPath, CmsUiProvider uiProvider,
- Map<String, String> factoryProperties) {
- super(repository, workspace, defaultPath, factoryProperties);
- this.uiProvider = uiProvider;
- }
-
- @Override
- protected void initUi(Composite parent) {
- uid = UUID.randomUUID().toString();
- parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- parent.setLayout(CmsUiUtils.noSpaceGridLayout(new GridLayout(3, false)));
-
- uxContext = new SimpleUxContext();
- if (!getUxContext().isMasterData())
- createAdminArea(parent);
- headerArea = new Composite(parent, SWT.NONE);
- headerArea.setLayout(new FillLayout());
- GridData headerData = new GridData(SWT.FILL, SWT.FILL, false, false, 3, 1);
- headerData.heightHint = headerHeight;
- headerArea.setLayoutData(headerData);
-
- // TODO: bi-directional
- leftArea = new Composite(parent, SWT.NONE);
- leftArea.setLayoutData(new GridData(SWT.LEAD, SWT.TOP, false, false));
- leftArea.setLayout(CmsUiUtils.noSpaceGridLayout());
-
- bodyArea = new Composite(parent, SWT.NONE);
- bodyArea.setData(RWT.CUSTOM_VARIANT, CmsStyles.CMS_BODY);
- bodyArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- bodyArea.setLayout(CmsUiUtils.noSpaceGridLayout());
-
- // TODO: bi-directional
- rightArea = new Composite(parent, SWT.NONE);
- rightArea.setLayoutData(new GridData(SWT.END, SWT.TOP, false, false));
- rightArea.setLayout(CmsUiUtils.noSpaceGridLayout());
-
- footerArea = new Composite(parent, SWT.NONE);
- // footerArea.setLayout(new FillLayout());
- GridData footerData = new GridData(SWT.FILL, SWT.FILL, false, false, 3, 1);
- footerData.heightHint = footerHeight;
- footerArea.setLayoutData(footerData);
-
- uiInitialized = true;
- refresh();
- }
-
- @Override
- protected void refresh() {
- if (!uiInitialized)
- return;
- if (getState() == null)
- setState("");
- refreshSides();
- refreshBody();
- if (log.isTraceEnabled())
- log.trace("UI refreshed " + getNode());
- }
-
- protected void createAdminArea(Composite parent) {
- }
-
- @Deprecated
- protected void refreshHeader() {
- if (header == null)
- return;
-
- for (Control child : headerArea.getChildren())
- child.dispose();
- try {
- header.createUi(headerArea, getNode());
- } catch (RepositoryException e) {
- throw new CmsException("Cannot refresh header", e);
- }
- headerArea.layout(true, true);
- }
-
- protected void refreshSides() {
- refresh(headerArea, header, CmsStyles.CMS_HEADER);
- refresh(leftArea, lead, CmsStyles.CMS_LEAD);
- refresh(rightArea, end, CmsStyles.CMS_END);
- refresh(footerArea, footer, CmsStyles.CMS_FOOTER);
- }
-
- private void refresh(Composite area, CmsUiProvider uiProvider, String style) {
- if (uiProvider == null)
- return;
-
- for (Control child : area.getChildren())
- child.dispose();
- CmsUiUtils.style(area, style);
- try {
- uiProvider.createUi(area, getNode());
- } catch (RepositoryException e) {
- throw new CmsException("Cannot refresh header", e);
- }
- area.layout(true, true);
- }
-
- protected void refreshBody() {
- // Exception
- Throwable exception = getException();
- if (exception != null) {
- SystemNotifications systemNotifications = new SystemNotifications(bodyArea);
- systemNotifications.notifyException(exception);
- resetException();
- return;
- // TODO report
- }
-
- // clear
- for (Control child : bodyArea.getChildren())
- child.dispose();
- bodyArea.setLayout(CmsUiUtils.noSpaceGridLayout());
-
- try {
- Node node = getNode();
-// if (node == null)
-// log.error("Context cannot be null");
-// else
- uiProvider.createUi(bodyArea, node);
- } catch (RepositoryException e) {
- throw new CmsException("Cannot refresh body", e);
- }
-
- bodyArea.layout(true, true);
- }
-
- @Override
- public UxContext getUxContext() {
- return uxContext;
- }
- @Override
- public String getUid() {
- return uid;
- }
-
- @Override
- public CmsImageManager getImageManager() {
- return imageManager;
- }
-
- public void setHeader(CmsUiProvider header) {
- this.header = header;
- }
-
- public void setHeaderHeight(Integer headerHeight) {
- this.headerHeight = headerHeight;
- }
-
- public void setImageManager(CmsImageManager imageManager) {
- this.imageManager = imageManager;
- }
-
- 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;
- }
-
- public CmsUiProvider getHeader() {
- return header;
- }
-
- public void setFooterHeight(Integer footerHeight) {
- this.footerHeight = footerHeight;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.web;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.cms.ui.CmsTheme;
-import org.eclipse.rap.rwt.application.Application;
-import org.eclipse.rap.rwt.service.ResourceLoader;
-
-/** Web specific utilities around theming. */
-public class WebThemeUtils {
- private final static Log log = LogFactory.getLog(WebThemeUtils.class);
-
- public static void apply(Application application, CmsTheme theme) {
- ResourceLoader resourceLoader = new CmsThemeResourceLoader(theme);
- resources: for (String path : theme.getImagesPaths()) {
- if (path.startsWith("target/"))
- continue resources; // skip maven output
- application.addResource(path, resourceLoader);
- if (log.isTraceEnabled())
- log.trace("Theme " + theme.getThemeId() + ": added resource " + path);
- }
- for (String path : theme.getRapCssPaths()) {
- application.addStyleSheet(theme.getThemeId(), path, resourceLoader);
- if (log.isDebugEnabled())
- log.debug("Theme " + theme.getThemeId() + ": added RAP CSS " + path);
- }
- }
-
-}
<module>org.argeo.cms</module>
<module>org.argeo.cms.ui.theme</module>
<module>org.argeo.cms.ui</module>
+ <module>org.argeo.cms.ui.rap</module>
<!-- CMS E4 -->
<module>org.argeo.cms.e4</module>
<module>org.argeo.cms.e4.rap</module>