From d4aea98e59c1754bdf557e43f19b9462053b59b2 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Fri, 16 Mar 2018 15:13:17 +0100 Subject: [PATCH] Introduce CMS E4 --- .gitignore | 1 - demo/cms-e4-rap.properties | 29 ++ org.argeo.cms.e4/.classpath | 7 + org.argeo.cms.e4/.gitignore | 2 + org.argeo.cms.e4/.project | 33 ++ .../.settings/org.eclipse.jdt.core.prefs | 7 + org.argeo.cms.e4/META-INF/.gitignore | 1 + org.argeo.cms.e4/OSGI-INF/cms-admin-rap.xml | 8 + org.argeo.cms.e4/bnd.bnd | 7 + org.argeo.cms.e4/build.properties | 5 + org.argeo.cms.e4/cms-admin.e4xmi | 13 + org.argeo.cms.e4/pom.xml | 35 ++ .../org/argeo/cms/e4/jcr/JcrBrowserView.java | 349 ++++++++++++++++++ .../src/org/argeo/cms/e4/jcr/SimplePart.java | 19 + .../org/argeo/cms/e4/rap/CmsE4AdminApp.java | 87 +++++ .../argeo/cms/e4/rap/CmsLoginLifecycle.java | 108 ++++++ .../org/argeo/cms/e4/rap/LoginLifcecycle.java | 90 +++++ org.argeo.cms.ui/pom.xml | 12 +- .../cms/ui/jcr/OsgiRepositoryRegister.java | 50 +++ .../org/argeo/cms/widgets/auth/CmsLogin.java | 13 +- pom.xml | 17 +- 21 files changed, 883 insertions(+), 10 deletions(-) create mode 100644 demo/cms-e4-rap.properties create mode 100644 org.argeo.cms.e4/.classpath create mode 100644 org.argeo.cms.e4/.gitignore create mode 100644 org.argeo.cms.e4/.project create mode 100644 org.argeo.cms.e4/.settings/org.eclipse.jdt.core.prefs create mode 100644 org.argeo.cms.e4/META-INF/.gitignore create mode 100644 org.argeo.cms.e4/OSGI-INF/cms-admin-rap.xml create mode 100644 org.argeo.cms.e4/bnd.bnd create mode 100644 org.argeo.cms.e4/build.properties create mode 100644 org.argeo.cms.e4/cms-admin.e4xmi create mode 100644 org.argeo.cms.e4/pom.xml create mode 100644 org.argeo.cms.e4/src/org/argeo/cms/e4/jcr/JcrBrowserView.java create mode 100644 org.argeo.cms.e4/src/org/argeo/cms/e4/jcr/SimplePart.java create mode 100644 org.argeo.cms.e4/src/org/argeo/cms/e4/rap/CmsE4AdminApp.java create mode 100644 org.argeo.cms.e4/src/org/argeo/cms/e4/rap/CmsLoginLifecycle.java create mode 100644 org.argeo.cms.e4/src/org/argeo/cms/e4/rap/LoginLifcecycle.java create mode 100644 org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/OsgiRepositoryRegister.java diff --git a/.gitignore b/.gitignore index 69b786d29..b83d22266 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ /target/ -/org.argeo.cms.e4.* \ No newline at end of file diff --git a/demo/cms-e4-rap.properties b/demo/cms-e4-rap.properties new file mode 100644 index 000000000..68db6f94b --- /dev/null +++ b/demo/cms-e4-rap.properties @@ -0,0 +1,29 @@ +argeo.osgi.start.2.node=\ +org.eclipse.equinox.http.servlet,\ +org.eclipse.equinox.http.jetty,\ +org.eclipse.equinox.metatype,\ +org.eclipse.equinox.cm,\ +org.eclipse.rap.rwt.osgi + +argeo.osgi.start.3.node=\ +org.argeo.cms + +argeo.osgi.start.5.node=\ +org.argeo.cms.e4 + +# Local +argeo.node.repo.type=h2 +org.osgi.service.http.port=7070 +#org.osgi.service.http.port.secure=7073 + +# Logging +log4j.configuration=file:../../log4j.properties + +# DON'T CHANGE BELOW +org.eclipse.equinox.http.jetty.autostart=false +org.osgi.framework.bootdelegation=com.sun.jndi.ldap,\ +com.sun.jndi.ldap.sasl,\ +com.sun.security.jgss,\ +com.sun.jndi.dns,\ +com.sun.nio.file,\ +com.sun.nio.sctp diff --git a/org.argeo.cms.e4/.classpath b/org.argeo.cms.e4/.classpath new file mode 100644 index 000000000..eca7bdba8 --- /dev/null +++ b/org.argeo.cms.e4/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.argeo.cms.e4/.gitignore b/org.argeo.cms.e4/.gitignore new file mode 100644 index 000000000..09e3bc9b2 --- /dev/null +++ b/org.argeo.cms.e4/.gitignore @@ -0,0 +1,2 @@ +/bin/ +/target/ diff --git a/org.argeo.cms.e4/.project b/org.argeo.cms.e4/.project new file mode 100644 index 000000000..0c0406952 --- /dev/null +++ b/org.argeo.cms.e4/.project @@ -0,0 +1,33 @@ + + + org.argeo.cms.e4 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + org.eclipse.pde.ds.core.builder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/org.argeo.cms.e4/.settings/org.eclipse.jdt.core.prefs b/org.argeo.cms.e4/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..0c68a61dc --- /dev/null +++ b/org.argeo.cms.e4/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/org.argeo.cms.e4/META-INF/.gitignore b/org.argeo.cms.e4/META-INF/.gitignore new file mode 100644 index 000000000..4854a41b9 --- /dev/null +++ b/org.argeo.cms.e4/META-INF/.gitignore @@ -0,0 +1 @@ +/MANIFEST.MF diff --git a/org.argeo.cms.e4/OSGI-INF/cms-admin-rap.xml b/org.argeo.cms.e4/OSGI-INF/cms-admin-rap.xml new file mode 100644 index 000000000..e54d613dc --- /dev/null +++ b/org.argeo.cms.e4/OSGI-INF/cms-admin-rap.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/org.argeo.cms.e4/bnd.bnd b/org.argeo.cms.e4/bnd.bnd new file mode 100644 index 000000000..5d1261fe7 --- /dev/null +++ b/org.argeo.cms.e4/bnd.bnd @@ -0,0 +1,7 @@ +Service-Component: OSGI-INF/cms-admin-rap.xml + +Import-Package: org.eclipse.swt,\ +org.argeo.node,\ +org.eclipse.rap.*;resolution:=optional,\ +org.eclipse.rap.rwt.client;resolution:=optional,\ +* diff --git a/org.argeo.cms.e4/build.properties b/org.argeo.cms.e4/build.properties new file mode 100644 index 000000000..0b085594e --- /dev/null +++ b/org.argeo.cms.e4/build.properties @@ -0,0 +1,5 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + OSGI-INF/,\ + . diff --git a/org.argeo.cms.e4/cms-admin.e4xmi b/org.argeo.cms.e4/cms-admin.e4xmi new file mode 100644 index 000000000..b9c37670f --- /dev/null +++ b/org.argeo.cms.e4/cms-admin.e4xmi @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/org.argeo.cms.e4/pom.xml b/org.argeo.cms.e4/pom.xml new file mode 100644 index 000000000..bf677e09e --- /dev/null +++ b/org.argeo.cms.e4/pom.xml @@ -0,0 +1,35 @@ + + + 4.0.0 + + org.argeo.commons + argeo-commons + 2.1.73-SNAPSHOT + .. + + org.argeo.cms.e4 + CMS E4 + jar + + + org.argeo.commons + org.argeo.cms.ui + 2.1.73-SNAPSHOT + + + org.argeo.commons + org.argeo.cms.ui.theme + 2.1.73-SNAPSHOT + + + + + org.argeo.tp + argeo-tp-rap-e4 + ${version.argeo-tp} + pom + provided + + + \ No newline at end of file diff --git a/org.argeo.cms.e4/src/org/argeo/cms/e4/jcr/JcrBrowserView.java b/org.argeo.cms.e4/src/org/argeo/cms/e4/jcr/JcrBrowserView.java new file mode 100644 index 000000000..0551e16b8 --- /dev/null +++ b/org.argeo.cms.e4/src/org/argeo/cms/e4/jcr/JcrBrowserView.java @@ -0,0 +1,349 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.cms.e4.jcr; + +import java.util.List; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.inject.Inject; +import javax.jcr.Property; +import javax.jcr.PropertyType; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.RepositoryFactory; +import javax.jcr.Session; +import javax.jcr.Value; +import javax.jcr.observation.Event; +import javax.jcr.observation.EventListener; +import javax.jcr.observation.ObservationManager; + +import org.argeo.cms.CmsException; +import org.argeo.cms.ui.jcr.JcrBrowserUtils; +import org.argeo.cms.ui.jcr.JcrDClickListener; +import org.argeo.cms.ui.jcr.NodeContentProvider; +import org.argeo.cms.ui.jcr.NodeLabelProvider; +import org.argeo.cms.ui.jcr.OsgiRepositoryRegister; +import org.argeo.cms.ui.jcr.PropertiesContentProvider; +import org.argeo.cms.ui.jcr.model.SingleJcrNodeElem; +import org.argeo.eclipse.ui.EclipseUiException; +import org.argeo.eclipse.ui.TreeParent; +import org.argeo.eclipse.ui.jcr.AsyncUiEventListener; +import org.argeo.eclipse.ui.jcr.utils.NodeViewerComparer; +import org.argeo.node.security.CryptoKeyring; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.viewers.ColumnLabelProvider; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.SashForm; +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.Display; +import org.eclipse.swt.widgets.Menu; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; + +/** + * Basic View to display a sash form to browse a JCR compliant multiple + * repository environment + */ +public class JcrBrowserView { + private static BundleContext bc = FrameworkUtil.getBundle(JcrBrowserView.class).getBundleContext(); + + private boolean sortChildNodes = true; + + /* DEPENDENCY INJECTION */ + private CryptoKeyring keyring; + @Inject + private RepositoryFactory repositoryFactory; + @Inject + private Repository nodeRepository; + + // Current user session on the "Argeo node" default workspace + private Session userSession; + + private OsgiRepositoryRegister repositoryRegister = new OsgiRepositoryRegister(bc); + + // This page widgets + private TreeViewer nodesViewer; + private NodeContentProvider nodeContentProvider; + private TableViewer propertiesViewer; + private EventListener resultsObserver; + + @PostConstruct + public void createPartControl(Composite parent) { + repositoryRegister.init(); + + parent.setLayout(new FillLayout()); + SashForm sashForm = new SashForm(parent, SWT.VERTICAL); + sashForm.setSashWidth(4); + sashForm.setLayout(new FillLayout()); + + // Create the tree on top of the view + Composite top = new Composite(sashForm, SWT.NONE); + GridLayout gl = new GridLayout(1, false); + top.setLayout(gl); + + try { + this.userSession = this.nodeRepository.login(); + } catch (RepositoryException e) { + throw new CmsException("Cannot open user session", e); + } + + nodeContentProvider = new NodeContentProvider(userSession, keyring, repositoryRegister, repositoryFactory, + sortChildNodes); + + // nodes viewer + nodesViewer = createNodeViewer(top, nodeContentProvider); + + // context menu : it is completely defined in the plugin.xml file. + MenuManager menuManager = new MenuManager(); + Menu menu = menuManager.createContextMenu(nodesViewer.getTree()); + + nodesViewer.getTree().setMenu(menu); + + nodesViewer.setInput(""); + + // Create the property viewer on the bottom + Composite bottom = new Composite(sashForm, SWT.NONE); + bottom.setLayout(new GridLayout(1, false)); + propertiesViewer = createPropertiesViewer(bottom); + + sashForm.setWeights(getWeights()); + nodesViewer.setComparer(new NodeViewerComparer()); + + // getSite().registerContextMenu(menuManager, nodesViewer); + // getSite().setSelectionProvider(nodesViewer); + } + + @PreDestroy + public void dispose() { + repositoryRegister.destroy(); + } + + public void refresh(Object obj) { + // Enable full refresh from a command when no element of the tree is + // selected + if (obj == null) { + Object[] elements = nodeContentProvider.getElements(null); + for (Object el : elements) { + if (el instanceof TreeParent) + JcrBrowserUtils.forceRefreshIfNeeded((TreeParent) el); + getNodeViewer().refresh(el); + } + } else + getNodeViewer().refresh(obj); + } + + /** + * To be overridden to adapt size of form and result frames. + */ + protected int[] getWeights() { + return new int[] { 70, 30 }; + } + + protected TreeViewer createNodeViewer(Composite parent, final ITreeContentProvider nodeContentProvider) { + + final TreeViewer tmpNodeViewer = new TreeViewer(parent, SWT.MULTI); + + tmpNodeViewer.getTree().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + tmpNodeViewer.setContentProvider(nodeContentProvider); + tmpNodeViewer.setLabelProvider(new NodeLabelProvider()); + tmpNodeViewer.addSelectionChangedListener(new ISelectionChangedListener() { + public void selectionChanged(SelectionChangedEvent event) { + if (!event.getSelection().isEmpty()) { + IStructuredSelection sel = (IStructuredSelection) event.getSelection(); + Object firstItem = sel.getFirstElement(); + if (firstItem instanceof SingleJcrNodeElem) + propertiesViewer.setInput(((SingleJcrNodeElem) firstItem).getNode()); + } else { + propertiesViewer.setInput(""); + } + } + }); + + resultsObserver = new TreeObserver(tmpNodeViewer.getTree().getDisplay()); + if (keyring != null) + try { + ObservationManager observationManager = userSession.getWorkspace().getObservationManager(); + observationManager.addEventListener(resultsObserver, Event.PROPERTY_ADDED | Event.PROPERTY_CHANGED, "/", + true, null, null, false); + } catch (RepositoryException e) { + throw new EclipseUiException("Cannot register listeners", e); + } + + tmpNodeViewer.addDoubleClickListener(new JcrDClickListener(tmpNodeViewer)); + return tmpNodeViewer; + } + + protected TableViewer createPropertiesViewer(Composite parent) { + propertiesViewer = new TableViewer(parent); + propertiesViewer.getTable().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + propertiesViewer.getTable().setHeaderVisible(true); + propertiesViewer.setContentProvider(new PropertiesContentProvider()); + TableViewerColumn col = new TableViewerColumn(propertiesViewer, SWT.NONE); + col.getColumn().setText("Name"); + col.getColumn().setWidth(200); + col.setLabelProvider(new ColumnLabelProvider() { + private static final long serialVersionUID = -6684361063107478595L; + + public String getText(Object element) { + try { + return ((Property) element).getName(); + } catch (RepositoryException e) { + throw new EclipseUiException("Unexpected exception in label provider", e); + } + } + }); + col = new TableViewerColumn(propertiesViewer, SWT.NONE); + col.getColumn().setText("Value"); + col.getColumn().setWidth(400); + col.setLabelProvider(new ColumnLabelProvider() { + private static final long serialVersionUID = -8201994187693336657L; + + public String getText(Object element) { + try { + Property property = (Property) element; + if (property.getType() == PropertyType.BINARY) + return ""; + else if (property.isMultiple()) { + StringBuffer buf = new StringBuffer("["); + Value[] values = property.getValues(); + for (int i = 0; i < values.length; i++) { + if (i != 0) + buf.append(", "); + buf.append(values[i].getString()); + } + buf.append(']'); + return buf.toString(); + } else + return property.getValue().getString(); + } catch (RepositoryException e) { + throw new EclipseUiException("Unexpected exception in label provider", e); + } + } + }); + col = new TableViewerColumn(propertiesViewer, SWT.NONE); + col.getColumn().setText("Type"); + col.getColumn().setWidth(200); + col.setLabelProvider(new ColumnLabelProvider() { + private static final long serialVersionUID = -6009599998150286070L; + + public String getText(Object element) { + return JcrBrowserUtils.getPropertyTypeAsString((Property) element); + } + }); + propertiesViewer.setInput(""); + return propertiesViewer; + } + + protected TreeViewer getNodeViewer() { + return nodesViewer; + } + + /** + * Resets the tree content provider + * + * @param sortChildNodes + * if true the content provider will use a comparer to sort nodes + * that might slow down the display + */ + public void setSortChildNodes(boolean sortChildNodes) { + this.sortChildNodes = sortChildNodes; + ((NodeContentProvider) nodesViewer.getContentProvider()).setSortChildren(sortChildNodes); + nodesViewer.setInput(""); + } + + /** Notifies the current view that a node has been added */ + public void nodeAdded(TreeParent parentNode) { + // insure that Ui objects have been correctly created: + JcrBrowserUtils.forceRefreshIfNeeded(parentNode); + getNodeViewer().refresh(parentNode); + getNodeViewer().expandToLevel(parentNode, 1); + } + + /** Notifies the current view that a node has been removed */ + public void nodeRemoved(TreeParent parentNode) { + IStructuredSelection newSel = new StructuredSelection(parentNode); + getNodeViewer().setSelection(newSel, true); + // Force refresh + IStructuredSelection tmpSel = (IStructuredSelection) getNodeViewer().getSelection(); + getNodeViewer().refresh(tmpSel.getFirstElement()); + } + + class TreeObserver extends AsyncUiEventListener { + + public TreeObserver(Display display) { + super(display); + } + + @Override + protected Boolean willProcessInUiThread(List events) throws RepositoryException { + for (Event event : events) { + if (getLog().isTraceEnabled()) + getLog().debug("Received event " + event); + String path = event.getPath(); + int index = path.lastIndexOf('/'); + String propertyName = path.substring(index + 1); + if (getLog().isTraceEnabled()) + getLog().debug("Concerned property " + propertyName); + } + return false; + } + + protected void onEventInUiThread(List events) throws RepositoryException { + if (getLog().isTraceEnabled()) + getLog().trace("Refresh result list"); + nodesViewer.refresh(); + } + + } + + public boolean getSortChildNodes() { + return sortChildNodes; + } + + public void setFocus() { + getNodeViewer().getTree().setFocus(); + } + + /* DEPENDENCY INJECTION */ + // public void setRepositoryRegister(RepositoryRegister repositoryRegister) { + // this.repositoryRegister = repositoryRegister; + // } + + public void setKeyring(CryptoKeyring keyring) { + this.keyring = keyring; + } + + public void setRepositoryFactory(RepositoryFactory repositoryFactory) { + this.repositoryFactory = repositoryFactory; + } + + public void setNodeRepository(Repository nodeRepository) { + this.nodeRepository = nodeRepository; + } +} diff --git a/org.argeo.cms.e4/src/org/argeo/cms/e4/jcr/SimplePart.java b/org.argeo.cms.e4/src/org/argeo/cms/e4/jcr/SimplePart.java new file mode 100644 index 000000000..17d8d2a23 --- /dev/null +++ b/org.argeo.cms.e4/src/org/argeo/cms/e4/jcr/SimplePart.java @@ -0,0 +1,19 @@ +package org.argeo.cms.e4.jcr; + +import javax.annotation.PostConstruct; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; + +public class SimplePart { + + @PostConstruct + void init(Composite parent) { + parent.setLayout(new GridLayout()); + Label label = new Label(parent, SWT.NONE); + label.setText("Hello e4 World"); + } + +} diff --git a/org.argeo.cms.e4/src/org/argeo/cms/e4/rap/CmsE4AdminApp.java b/org.argeo.cms.e4/src/org/argeo/cms/e4/rap/CmsE4AdminApp.java new file mode 100644 index 000000000..5b2adc0bb --- /dev/null +++ b/org.argeo.cms.e4/src/org/argeo/cms/e4/rap/CmsE4AdminApp.java @@ -0,0 +1,87 @@ +package org.argeo.cms.e4.rap; + +import java.security.PrivilegedAction; +import java.util.HashMap; +import java.util.Map; + +import javax.security.auth.Subject; + +import org.eclipse.rap.e4.E4ApplicationConfig; +import org.eclipse.rap.e4.E4EntryPointFactory; +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.client.WebClient; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; + +public class CmsE4AdminApp implements ApplicationConfiguration { + private final BundleContext bc = FrameworkUtil.getBundle(CmsE4AdminApp.class).getBundleContext(); + + String pageTitle = "CMS Admin"; + String e4Xmi = "/cms-admin.e4xmi"; + String path = "/admin"; + + public void configure(Application application) { + + Map properties = new HashMap(); + properties.put(WebClient.PAGE_TITLE, pageTitle); + Bundle bundle = bc.getBundle(); + String e4XmiUri = bundle.getSymbolicName() + e4Xmi; + E4ApplicationConfig config = E4ApplicationConfig.create(e4XmiUri, + "bundleclass://" + bundle.getSymbolicName() + "/" + CmsLoginLifecycle.class.getName()); + E4EntryPointFactory entryPointFactory = new E4EntryPointFactory(config) { + + @Override + public EntryPoint create() { + Subject subject = new Subject(); + // return Subject.doAs(subject, new PrivilegedAction() { + // + // @Override + // public EntryPoint run() { + EntryPoint ep = createEntryPoint(); + EntryPoint authEp = new EntryPoint() { + + @Override + public int createUI() { + return Subject.doAs(subject, new PrivilegedAction() { + + @Override + public Integer run() { + return ep.createUI(); + } + + }); + } + }; + // return authEp; + // } + // + // }); + return authEp; + } + + protected EntryPoint createEntryPoint() { + return super.create(); + } + + }; + application.addEntryPoint(path, entryPointFactory, properties); + application.setOperationMode(OperationMode.SWT_COMPATIBILITY); + } + + public void setPageTitle(String pageTitle) { + this.pageTitle = pageTitle; + } + + public void setE4Xmi(String e4Xmi) { + this.e4Xmi = e4Xmi; + } + + public void setPath(String path) { + this.path = path; + } + +} diff --git a/org.argeo.cms.e4/src/org/argeo/cms/e4/rap/CmsLoginLifecycle.java b/org.argeo.cms.e4/src/org/argeo/cms/e4/rap/CmsLoginLifecycle.java new file mode 100644 index 000000000..687290626 --- /dev/null +++ b/org.argeo.cms.e4/src/org/argeo/cms/e4/rap/CmsLoginLifecycle.java @@ -0,0 +1,108 @@ +package org.argeo.cms.e4.rap; + +import java.security.AccessController; + +import javax.security.auth.Subject; +import javax.security.auth.login.LoginContext; +import javax.security.auth.login.LoginException; + +import org.argeo.cms.CmsException; +import org.argeo.cms.auth.CurrentUser; +import org.argeo.cms.ui.CmsImageManager; +import org.argeo.cms.ui.CmsView; +import org.argeo.cms.ui.UxContext; +import org.argeo.cms.util.SimpleUxContext; +import org.argeo.cms.widgets.auth.CmsLoginShell; +import org.argeo.node.NodeConstants; +import org.eclipse.e4.ui.workbench.lifecycle.PostContextCreate; +import org.eclipse.swt.widgets.Display; + +@SuppressWarnings("restriction") +public class CmsLoginLifecycle implements CmsView { + private UxContext uxContext; + private LoginContext loginContext; + + @PostContextCreate + boolean login(Display d) { + Subject subject = Subject.getSubject(AccessController.getContext()); + Display display = Display.getCurrent(); + CmsLoginShell loginShell = new CmsLoginShell(this); + loginShell.setSubject(subject); + try { + // try pre-auth + loginContext = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, subject, loginShell); + loginContext.login(); + } catch (LoginException e) { + loginShell.createUi(); + loginShell.open(); + + while (!loginShell.getShell().isDisposed()) { + if (!display.readAndDispatch()) + display.sleep(); + } + } + if (CurrentUser.getUsername(getSubject()) == null) + return false; + uxContext = new SimpleUxContext(); + return true; + } + + @Override + public UxContext getUxContext() { + return uxContext; + } + + @Override + public void navigateTo(String state) { + // TODO Auto-generated method stub + + } + + @Override + public void authChange(LoginContext loginContext) { + if (loginContext == null) + throw new CmsException("Login context cannot be null"); + // logout previous login context +// if (this.loginContext != null) +// try { +// this.loginContext.logout(); +// } catch (LoginException e1) { +// System.err.println("Could not log out: " + e1); +// } + this.loginContext = loginContext; + } + + @Override + public void logout() { + if (loginContext == null) + throw new CmsException("Login context should not bet null"); + try { + CurrentUser.logoutCmsSession(loginContext.getSubject()); + loginContext.logout(); + } catch (LoginException e) { + throw new CmsException("Cannot log out", e); + } + } + + @Override + public void exception(Throwable e) { + // TODO Auto-generated method stub + + } + + @Override + public CmsImageManager getImageManager() { + // TODO Auto-generated method stub + return null; + } + + protected Subject getSubject() { + return loginContext.getSubject(); + } + + @Override + public boolean isAnonymous() { + return CurrentUser.isAnonymous(getSubject()); + } + +} diff --git a/org.argeo.cms.e4/src/org/argeo/cms/e4/rap/LoginLifcecycle.java b/org.argeo.cms.e4/src/org/argeo/cms/e4/rap/LoginLifcecycle.java new file mode 100644 index 000000000..5c6caaf8b --- /dev/null +++ b/org.argeo.cms.e4/src/org/argeo/cms/e4/rap/LoginLifcecycle.java @@ -0,0 +1,90 @@ +package org.argeo.cms.e4.rap; + +import java.util.concurrent.atomic.AtomicBoolean; + +import org.eclipse.e4.ui.workbench.lifecycle.PostContextCreate; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +@SuppressWarnings("restriction") +public class LoginLifcecycle { + @PostContextCreate + boolean login(Display d) { + final AtomicBoolean rv = new AtomicBoolean(false); + final Shell s = new Shell(d); + s.setText("Login"); + s.setLayout(new GridLayout(2, false)); + + { + Label l = new Label(s, SWT.NONE); + l.setText("Username"); + + Text t = new Text(s, SWT.BORDER); + t.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + } + + { + Label l = new Label(s, SWT.NONE); + l.setText("Password"); + + Text t = new Text(s, SWT.BORDER | SWT.PASSWORD); + t.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + } + + { + Composite buttonContainer = new Composite(s, SWT.NONE); + buttonContainer.setLayout(new GridLayout(2, true)); + buttonContainer.setLayoutData(new GridData(SWT.TRAIL, SWT.CENTER, false, false, 2, 1)); + + { + Button b = new Button(buttonContainer, SWT.PUSH); + b.setText("Abort"); + b.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + rv.set(false); + s.dispose(); + } + }); + } + + { + Button b = new Button(buttonContainer, SWT.PUSH); + b.setText("Login"); + b.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + rv.set(true); + s.dispose(); + } + }); + } + } + s.pack(); + s.setSize(300, s.getSize().y + 10); + Rectangle bounds = d.getPrimaryMonitor().getBounds(); + + Point size = s.getSize(); + s.setLocation(bounds.width / 2 - size.x / 2, bounds.height / 2 - size.y / 2); + + s.open(); + while (!s.isDisposed() && !d.isDisposed()) { + if (!d.readAndDispatch()) { + d.sleep(); + } + } + + return rv.get(); + } +} \ No newline at end of file diff --git a/org.argeo.cms.ui/pom.xml b/org.argeo.cms.ui/pom.xml index 719db68e1..774533326 100644 --- a/org.argeo.cms.ui/pom.xml +++ b/org.argeo.cms.ui/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 org.argeo.commons @@ -23,6 +24,13 @@ provided + + + org.argeo.commons + org.argeo.cms.ui.theme + 2.1.73-SNAPSHOT + + org.argeo.tp.rap.e4 @@ -39,7 +47,7 @@ org.eclipse.rap.jface provided - + org.argeo.tp.rap.e4 diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/OsgiRepositoryRegister.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/OsgiRepositoryRegister.java new file mode 100644 index 000000000..566b33d01 --- /dev/null +++ b/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/OsgiRepositoryRegister.java @@ -0,0 +1,50 @@ +package org.argeo.cms.ui.jcr; + +import java.util.HashMap; +import java.util.Map; + +import javax.jcr.Repository; + +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.util.tracker.ServiceTracker; + +public class OsgiRepositoryRegister extends DefaultRepositoryRegister { + private final ServiceTracker repositoryTracker; + + public OsgiRepositoryRegister(BundleContext bc) { + repositoryTracker = new ServiceTracker(bc, Repository.class, null) { + + @Override + public Repository addingService(ServiceReference reference) { + + Repository repository = super.addingService(reference); + Map props = new HashMap<>(); + for (String key : reference.getPropertyKeys()) { + props.put(key, reference.getProperty(key)); + } + register(repository, props); + return repository; + } + + @Override + public void removedService(ServiceReference reference, Repository service) { + Map props = new HashMap<>(); + for (String key : reference.getPropertyKeys()) { + props.put(key, reference.getProperty(key)); + } + unregister(service, props); + super.removedService(reference, service); + } + + }; + } + + public void init() { + repositoryTracker.open(); + } + + public void destroy() { + repositoryTracker.close(); + } +} diff --git a/org.argeo.cms.ui/src/org/argeo/cms/widgets/auth/CmsLogin.java b/org.argeo.cms.ui/src/org/argeo/cms/widgets/auth/CmsLogin.java index fc9b77689..e450bfa07 100644 --- a/org.argeo.cms.ui/src/org/argeo/cms/widgets/auth/CmsLogin.java +++ b/org.argeo.cms.ui/src/org/argeo/cms/widgets/auth/CmsLogin.java @@ -7,6 +7,7 @@ import java.io.IOException; import java.util.List; import java.util.Locale; +import javax.security.auth.Subject; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.LanguageCallback; @@ -57,6 +58,9 @@ public class CmsLogin implements CmsStyles, CallbackHandler { private final CmsView cmsView; + // optional subject to be set explicitly + private Subject subject = null; + public CmsLogin(CmsView cmsView) { this.cmsView = cmsView; defaultLocale = Activator.getNodeState().getDefaultLocale(); @@ -187,7 +191,7 @@ public class CmsLogin implements CmsStyles, CallbackHandler { } /** - * To be overridden in order to provide custome login button and other links. + * To be overridden in order to provide custom login button and other links. */ protected void extendsCredentialsBlock(Composite credentialsBlock, Locale selectedLocale, SelectionListener loginSelectionListener) { @@ -242,6 +246,7 @@ public class CmsLogin implements CmsStyles, CallbackHandler { } protected boolean login() { + // TODO use CmsVie in order to retrieve subject? // Subject subject = cmsView.getLoginContext().getSubject(); // LoginContext loginContext = cmsView.getLoginContext(); try { @@ -249,7 +254,7 @@ public class CmsLogin implements CmsStyles, CallbackHandler { // LOGIN // // loginContext.logout(); - LoginContext loginContext = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, this); + LoginContext loginContext = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, subject, this); loginContext.login(); cmsView.authChange(loginContext); return true; @@ -304,4 +309,8 @@ public class CmsLogin implements CmsStyles, CallbackHandler { } } + public void setSubject(Subject subject) { + this.subject = subject; + } + } diff --git a/pom.xml b/pom.xml index cab81d117..66f95773a 100644 --- a/pom.xml +++ b/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 org.argeo.commons argeo-commons @@ -33,6 +34,8 @@ org.argeo.cms org.argeo.cms.ui.theme org.argeo.cms.ui + + org.argeo.cms.e4 org.argeo.cms.ui.workbench org.argeo.cms.ui.workbench.rap @@ -608,8 +611,10 @@ limitations under the License. - - + + @@ -634,8 +639,10 @@ limitations under the License. - - + + -- 2.30.2