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.CmsUiProvider; import org.argeo.cms.ui.util.BundleResourceLoader; import org.argeo.cms.ui.util.CmsUiUtils; import org.argeo.cms.ui.util.SimpleErgonomics; 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 appConfigReg; private ScriptEngine scriptEngine; private final static Log log = LogFactory.getLog(CmsScriptApp.class); private String webPath; private String repo = "(cn=node)"; // private Branding branding = new Branding(); private Theme theme; private List resources = new ArrayList<>(); private Map 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) { theme.apply(application); String themeHeaders = theme.getAdditionalHeaders(); 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 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 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 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 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 Theme getTheme() { return theme; } public void setTheme(Theme theme) { this.theme = theme; } public String getWebPath() { return webPath; } public void setWebPath(String context) { this.webPath = context; } public String getRepo() { return repo; } public void setRepo(String repo) { this.repo = repo; } public Map getUi() { return ui; } public void setUi(Map 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; } } }