X-Git-Url: https://git.argeo.org/?a=blobdiff_plain;f=org.argeo.cms%2Fsrc%2Forg%2Fargeo%2Fcms%2FAbstractCmsEntryPoint.java;h=00db13443b0cb44d6845f288471c4d53014e45eb;hb=998f2785e9571572c21117da28fbd1d681cc33a4;hp=6043980e90f8b58a927e45da360027dab298cad2;hpb=f26fa850fab8c3666e6cc27683991f2d11378e5b;p=lgpl%2Fargeo-commons.git diff --git a/org.argeo.cms/src/org/argeo/cms/AbstractCmsEntryPoint.java b/org.argeo.cms/src/org/argeo/cms/AbstractCmsEntryPoint.java index 6043980e9..00db13443 100644 --- a/org.argeo.cms/src/org/argeo/cms/AbstractCmsEntryPoint.java +++ b/org.argeo.cms/src/org/argeo/cms/AbstractCmsEntryPoint.java @@ -1,56 +1,89 @@ package org.argeo.cms; +import java.util.HashMap; import java.util.Locale; +import java.util.Map; import java.util.ResourceBundle; import javax.jcr.Node; +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.login.LoginException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.argeo.ArgeoException; +import org.argeo.cms.auth.ArgeoLoginContext; +import org.argeo.cms.auth.LoginRequiredException; +import org.argeo.cms.i18n.Msg; import org.argeo.jcr.JcrUtils; 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; -import org.springframework.security.core.context.SecurityContextHolder; /** Manages history and navigation */ public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint implements CmsSession { private final Log log = LogFactory.getLog(AbstractCmsEntryPoint.class); - private Repository repository; - private String workspace; - private Session session; + private final Subject subject = new Subject(); + + private final Repository repository; + private final String workspace; + private final String defaultPath; + private final Map factoryProperties; - // current state + // Current state + private Session session; private Node node; private String state; private String page; private Throwable exception; - private BrowserNavigation history; - - public AbstractCmsEntryPoint(Repository repository, String workspace) { - if (SecurityContextHolder.getContext().getAuthentication() == null) - logAsAnonymous(); + // Client services + private final JavaScriptExecutor jsExecutor; + private final BrowserNavigation browserNavigation; + public AbstractCmsEntryPoint(Repository repository, String workspace, + String defaultPath, Map factoryProperties) { this.repository = repository; this.workspace = workspace; - authChange(); + this.defaultPath = defaultPath; + this.factoryProperties = new HashMap(factoryProperties); - history = RWT.getClient().getService(BrowserNavigation.class); - if (history != null) - history.addBrowserNavigationListener(new CmsNavigationListener()); + // Initial login + try { + new ArgeoLoginContext(KernelHeader.LOGIN_CONTEXT_USER, subject) + .login(); + } catch (LoginException e) { + // if (log.isTraceEnabled()) + // log.trace("Cannot authenticate user", e); + try { + new ArgeoLoginContext(KernelHeader.LOGIN_CONTEXT_ANONYMOUS, + subject).login(); + } catch (LoginException eAnonymous) { + throw new ArgeoException("Cannot initialize subject", + eAnonymous); + } + } + authChange(); - // RWT.setLocale(Locale.FRANCE); + jsExecutor = RWT.getClient().getService(JavaScriptExecutor.class); + browserNavigation = RWT.getClient().getService(BrowserNavigation.class); + if (browserNavigation != null) + browserNavigation + .addBrowserNavigationListener(new CmsNavigationListener()); } @Override @@ -69,42 +102,52 @@ public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint return shell; } - /** Recreate header UI */ - protected abstract void refreshHeader(); + @Override + protected final void createContents(Composite parent) { + try { + getShell().getDisplay().setData(CmsSession.KEY, this); - /** Recreate body UI */ - protected abstract void refreshBody(); + createUi(parent); + } catch (Exception e) { + throw new CmsException("Cannot create entrypoint contents", e); + } + } - /** Log as anonymous */ - protected abstract void logAsAnonymous(); + /** Create UI */ + protected abstract void createUi(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) */ - protected abstract Node getDefaultNode(Session session) - throws RepositoryException; - - /** - * Reasonable default since it is a nt:hierarchyNode and is thus compatible - * with the obvious default folder type, nt:folder, conceptual equivalent of - * an empty text file in an operating system. To be overridden. - */ - protected String getDefaultNewNodeType() { - return CmsTypes.CMS_TEXT; + protected Node getDefaultNode(Session session) throws RepositoryException { + if (!session.hasPermission(defaultPath, "read")) { + if (session.getUserID().equals("anonymous")) + throw new LoginRequiredException(); + else + throw new CmsException("Unauthorized"); + } + return session.getNode(defaultPath); } - /** Default new folder type (used in mkdirs) is nt:folder. To be overridden. */ - protected String getDefaultNewFolderType() { - return NodeType.NT_FOLDER; + protected String getBaseTitle() { + return factoryProperties.get(WebClient.PAGE_TITLE); } public void navigateTo(String state) { exception = null; - setState(state); - refreshBody(); - if (history != null) - history.pushState(state, state); + String title = setState(state); + refresh(); + if (browserNavigation != null) + browserNavigation.pushState(state, title); + } + + @Override + public Subject getSubject() { + return subject; } @Override @@ -115,15 +158,31 @@ public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint currentPath = node.getPath(); JcrUtils.logoutQuietly(session); - if (SecurityContextHolder.getContext().getAuthentication() == null) - logAsAnonymous(); session = repository.login(workspace); if (currentPath != null) - node = session.getNode(currentPath); + try { + node = session.getNode(currentPath); + } catch (Exception e) { + try { + // TODO find a less hacky way to log out + new ArgeoLoginContext( + KernelHeader.LOGIN_CONTEXT_ANONYMOUS, subject) + .logout(); + new ArgeoLoginContext( + KernelHeader.LOGIN_CONTEXT_ANONYMOUS, subject) + .login(); + } catch (LoginException eAnonymous) { + throw new ArgeoException("Cannot reset to anonymous", + eAnonymous); + } + JcrUtils.logoutQuietly(session); + session = repository.login(workspace); + navigateTo("~"); + throw e; + } // refresh UI - refreshHeader(); - refreshBody(); + refresh(); } catch (RepositoryException e) { throw new CmsException("Cannot perform auth change", e); } @@ -134,7 +193,7 @@ public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint public void exception(Throwable e) { this.exception = e; log.error("Unexpected exception in CMS", e); - refreshBody(); + refresh(); } @Override @@ -150,91 +209,69 @@ public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint } /** Sets the state of the entry point and retrieve the related JCR node. */ - protected synchronized void setState(String newState) { + protected synchronized String setState(String newState) { String previousState = this.state; node = null; page = null; this.state = newState; + if (newState.equals("~")) + this.state = ""; try { int firstSlash = state.indexOf('/'); if (firstSlash == 0) { - if (!session.nodeExists(state)) - node = addNode(session, state, null); - else + if (session.nodeExists(state)) node = session.getNode(state); + else + throw new CmsException("Data " + state + " does not exist"); page = ""; } else if (firstSlash > 0) { String prefix = state.substring(0, firstSlash); String path = state.substring(firstSlash); - if (session.getWorkspace().getNodeTypeManager() - .hasNodeType(prefix)) { - String nodeType = prefix; - if (!session.nodeExists(path)) - node = addNode(session, path, nodeType); - else { - node = session.getNode(path); - if (!node.isNodeType(nodeType)) - throw new CmsException("Node " + path - + " not of type " + nodeType); - } - } else if ("delete".equals(prefix)) { - if (session.itemExists(path)) { - Node nodeToDelete = session.getNode(path); - // TODO "Are you sure?" - nodeToDelete.remove(); - session.save(); - log.debug("Deleted " + path); - navigateTo(previousState); - } else - throw new CmsException("Data " + path - + " does not exist"); - } else { - if (session.itemExists(path)) - node = session.getNode(path); - else - throw new CmsException("Data " + path - + " does not exist"); - } + if (session.nodeExists(path)) + node = session.getNode(path); + else + throw new CmsException("Data " + path + " does not exist"); page = prefix; } else { node = getDefaultNode(session); - if (state.equals("~")) - page = ""; - else - page = state; + page = state; } - if (log.isTraceEnabled()) - log.trace("page=" + page + ", node=" + node + ", state=" - + state); + // Title + String title; + if (node.isNodeType(NodeType.MIX_TITLE) + && node.hasProperty(Property.JCR_TITLE)) + title = node.getProperty(Property.JCR_TITLE).getString() + + " - " + getBaseTitle(); + else + title = getBaseTitle(); + jsExecutor.execute("document.title = \"" + title + "\""); - } catch (RepositoryException e) { - throw new CmsException("Cannot retrieve node", e); + if (log.isTraceEnabled()) + log.trace("node=" + node + ", state=" + state + " (page=" + + page + ", title=" + title + ")"); + + return title; + } catch (Exception e) { + log.error("Cannot set state '" + state + "'", e); + if (previousState.equals("")) + previousState = "~"; + navigateTo(previousState); + throw new CmsException("Unexpected issue when accessing #" + + newState, e); } } - protected Node addNode(Session session, String path, String nodeType) - throws RepositoryException { - return JcrUtils.mkdirs(session, path, nodeType != null ? nodeType - : getDefaultNewNodeType(), getDefaultNewFolderType(), false); - // not saved, so that the UI can discard it later on - } - protected Node getNode() { return node; } - @Override - public String getState() { + protected String getState() { return state; } - protected String getPage() { - return page; - } - protected Throwable getException() { return exception; } @@ -253,8 +290,7 @@ public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint @Override public void navigated(BrowserNavigationEvent event) { setState(event.getState()); - refreshBody(); + refresh(); } } - -} +} \ No newline at end of file