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.argeo.api.cms.CmsConstants; import org.argeo.api.cms.CmsLog; import org.argeo.cms.CmsException; import org.argeo.cms.jcr.CmsJcrUtils; import org.argeo.cms.ui.CmsUiConstants; 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}. */ @Deprecated public class SimpleApp implements CmsUiConstants, ApplicationConfiguration { private final static CmsLog log = CmsLog.getLog(SimpleApp.class); private String contextName = null; private Map> branding = new HashMap>(); private Map> styleSheets = new HashMap>(); private List resources = new ArrayList(); private BundleContext bundleContext; private Repository repository; private String workspace = null; private String jcrBasePath = "/"; private List roPrincipals = Arrays.asList(CmsConstants.ROLE_ANONYMOUS, CmsConstants.ROLE_USER); private List rwPrincipals = Arrays.asList(CmsConstants.ROLE_USER); private CmsUiProvider header; private Map pages = new LinkedHashMap(); private Integer headerHeight = 40; private ServiceRegistration 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 defaultBranding = null; if (branding.containsKey("*")) defaultBranding = branding.get("*"); // String defaultTheme = defaultBranding.get(WebClient.THEME_ID); // entry points for (String page : pages.keySet()) { Map properties = defaultBranding != null ? new HashMap(defaultBranding) : new HashMap(); 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 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 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 = CmsJcrUtils.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 props = new Hashtable(); 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 pages) { this.pages = pages; } public void setJcrBasePath(String basePath) { this.jcrBasePath = basePath; } public void setRoPrincipals(List roPrincipals) { this.roPrincipals = roPrincipals; } public void setRwPrincipals(List rwPrincipals) { this.rwPrincipals = rwPrincipals; } public void setHeaderHeight(Integer headerHeight) { this.headerHeight = headerHeight; } public void setBranding(Map> branding) { this.branding = branding; } public void setStyleSheets(Map> styleSheets) { this.styleSheets = styleSheets; } public void setBundleContext(BundleContext bundleContext) { this.bundleContext = bundleContext; } public void setResources(List 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 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 properties; public CmsEntryPointFactory(CmsUiProvider page, Repository repository, String workspace, Map 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 = "" + "" + ""; }