package org.argeo.cms; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javax.jcr.Node; 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.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.cms.internal.ImageManagerImpl; import org.argeo.cms.util.CmsUtils; import org.argeo.jcr.JcrUtils; import org.eclipse.gemini.blueprint.context.BundleContextAware; 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.service.ResourceLoader; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; import org.osgi.framework.BundleContext; /** Configures an Argeo CMS RWT application. */ public class CmsApplication implements CmsConstants, ApplicationConfiguration, BundleContextAware { final static Log log = LogFactory.getLog(CmsApplication.class); // private Map entryPoints = new HashMap(); private Map> branding = new HashMap>(); private Map> styleSheets = new HashMap>(); private List resources = new ArrayList(); // private Bundle clientScriptingBundle; private BundleContext bundleContext; private Repository repository; private String workspace = null; private String basePath = "/"; private List roPrincipals = Arrays.asList("anonymous", "everyone"); private List rwPrincipals = Arrays.asList("everyone"); private CmsLogin cmsLogin; private CmsUiProvider header; private Map pages = new LinkedHashMap(); private Integer headerHeight = 40; // Managers private CmsImageManager imageManager = new ImageManagerImpl(); public void configure(Application application) { try { application.setOperationMode(OperationMode.SWT_COMPATIBILITY); application.setExceptionHandler(new CmsExceptionHandler()); // TODO load all pics under icons // 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, new BundleResourceLoader( bundleContext)); if (log.isDebugEnabled()) log.debug("Registered resource " + resource); } Map defaultBranding = null; if (branding.containsKey("*")) defaultBranding = branding.get("*"); // 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 faviconRelPath = properties.get(WebClient.FAVICON); application.addResource(faviconRelPath, new BundleResourceLoader(bundleContext)); if (log.isTraceEnabled()) log.trace("Registered favicon " + faviconRelPath); } // page title if (!properties.containsKey(WebClient.PAGE_TITLE)) 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); application.addEntryPoint("/" + page, new CmsEntryPointFactory( page), properties); log.info("Registered entry point /" + page); } // stylesheets for (String themeId : styleSheets.keySet()) { List cssLst = styleSheets.get(themeId); for (String css : cssLst) { application.addStyleSheet(themeId, css, new BundleResourceLoader(bundleContext)); } } } catch (RuntimeException e) { // Easier access to initialisation errors log.error("Unexpected exception when configuring RWT application.", e); throw e; } } public void init() throws RepositoryException { if (workspace == null) throw new CmsException( "Workspace must be set when calling initialization." + " Please make sure that read-only and read-write roles" + " have been properly configured:" + " the defaults are open."); Session session = null; try { session = JcrUtils.loginOrCreateWorkspace(repository, workspace); VersionManager vm = session.getWorkspace().getVersionManager(); if (!vm.isCheckedOut("/")) vm.checkout("/"); JcrUtils.mkdirs(session, basePath); for (String principal : rwPrincipals) JcrUtils.addPrivilege(session, basePath, principal, Privilege.JCR_WRITE); for (String principal : roPrincipals) JcrUtils.addPrivilege(session, basePath, 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); } } 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); } } } public void setRepository(Repository repository) { this.repository = repository; } public void setWorkspace(String workspace) { this.workspace = workspace; } public void setCmsLogin(CmsLogin cmsLogin) { this.cmsLogin = cmsLogin; } public void setHeader(CmsUiProvider header) { this.header = header; } public void setPages(Map pages) { this.pages = pages; } public void setBasePath(String basePath) { this.basePath = 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 setEntryPoints( // Map entryPointFactories) { // this.entryPoints = entryPointFactories; // } 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; } class CmsExceptionHandler implements ExceptionHandler { @Override public void handleException(Throwable throwable) { CmsSession.current.get().exception(throwable); } } private class CmsEntryPointFactory implements EntryPointFactory { private final String page; public CmsEntryPointFactory(String page) { this.page = page; } @Override public EntryPoint create() { CmsEntryPoint entryPoint = new CmsEntryPoint(repository, workspace, pages.get(page)); entryPoint.setState(""); CmsSession.current.set(entryPoint); return entryPoint; } } private class CmsEntryPoint extends AbstractCmsEntryPoint { private Composite headerArea; private Composite bodyArea; private final CmsUiProvider uiProvider; public CmsEntryPoint(Repository repository, String workspace, CmsUiProvider uiProvider) { super(repository, workspace); this.uiProvider = uiProvider; } @Override protected void createContents(Composite parent) { try { getShell().getDisplay().setData(CmsSession.KEY, this); parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); parent.setLayout(CmsUtils.noSpaceGridLayout()); headerArea = new Composite(parent, SWT.NONE); headerArea.setLayout(new FillLayout()); GridData headerData = new GridData(SWT.FILL, SWT.FILL, false, false); headerData.heightHint = headerHeight; headerArea.setLayoutData(headerData); refreshHeader(); 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.setBackgroundMode(SWT.INHERIT_DEFAULT); bodyArea.setLayout(CmsUtils.noSpaceGridLayout()); refreshBody(); } catch (Exception e) { throw new CmsException("Cannot create entrypoint contents", e); } } @Override protected void refreshHeader() { if (headerArea == 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); } @Override protected void refreshBody() { if (bodyArea == null) return; // clear for (Control child : bodyArea.getChildren()) child.dispose(); bodyArea.setLayout(CmsUtils.noSpaceGridLayout()); // Exception Throwable exception = getException(); if (exception != null) { new Label(bodyArea, SWT.NONE).setText("Unreachable state : " + getState()); if (getNode() != null) new Label(bodyArea, SWT.NONE).setText("Context : " + getNode()); Text errorText = new Text(bodyArea, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); errorText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); StringWriter sw = new StringWriter(); exception.printStackTrace(new PrintWriter(sw)); errorText.setText(sw.toString()); IOUtils.closeQuietly(sw); resetException(); // TODO report } else { String state = getState(); try { if (state == null) throw new CmsException("State cannot be null"); uiProvider.createUi(bodyArea, getNode()); // if (page == null) // throw new CmsException("Page cannot be null"); // // else if (state.length() == 0) // // log.debug("empty state"); // else if (pages.containsKey(page)) // pages.get(page).createUi(bodyArea, getNode()); // else { // // try { // // RWT.getResponse().sendError(404); // // } catch (IOException e) { // // log.error("Cannot send 404 code", e); // // } // throw new CmsException("Unsupported state " + state); // } } catch (RepositoryException e) { throw new CmsException("Cannot refresh body", e); } } bodyArea.layout(true, true); } @Override protected void logAsAnonymous() { cmsLogin.logInAsAnonymous(); } @Override protected Node getDefaultNode(Session session) throws RepositoryException { if (!session.hasPermission(basePath, "read")) { if (session.getUserID().equals("anonymous")) throw new CmsLoginRequiredException(); else throw new CmsException("Unauthorized"); } return session.getNode(basePath); } @Override public CmsImageManager getImageManager() { return imageManager; } } private static ResourceLoader createResourceLoader(final String resourceName) { return new ResourceLoader() { public InputStream getResourceAsStream(String resourceName) throws IOException { return getClass().getClassLoader().getResourceAsStream( resourceName); } }; } /* * TEXTS */ private static String DEFAULT_LOADING_BODY = "" + "" + ""; }