Introduce CMS E4
authorMathieu Baudier <mbaudier@argeo.org>
Fri, 16 Mar 2018 14:13:17 +0000 (15:13 +0100)
committerMathieu Baudier <mbaudier@argeo.org>
Fri, 16 Mar 2018 14:13:17 +0000 (15:13 +0100)
21 files changed:
.gitignore
demo/cms-e4-rap.properties [new file with mode: 0644]
org.argeo.cms.e4/.classpath [new file with mode: 0644]
org.argeo.cms.e4/.gitignore [new file with mode: 0644]
org.argeo.cms.e4/.project [new file with mode: 0644]
org.argeo.cms.e4/.settings/org.eclipse.jdt.core.prefs [new file with mode: 0644]
org.argeo.cms.e4/META-INF/.gitignore [new file with mode: 0644]
org.argeo.cms.e4/OSGI-INF/cms-admin-rap.xml [new file with mode: 0644]
org.argeo.cms.e4/bnd.bnd [new file with mode: 0644]
org.argeo.cms.e4/build.properties [new file with mode: 0644]
org.argeo.cms.e4/cms-admin.e4xmi [new file with mode: 0644]
org.argeo.cms.e4/pom.xml [new file with mode: 0644]
org.argeo.cms.e4/src/org/argeo/cms/e4/jcr/JcrBrowserView.java [new file with mode: 0644]
org.argeo.cms.e4/src/org/argeo/cms/e4/jcr/SimplePart.java [new file with mode: 0644]
org.argeo.cms.e4/src/org/argeo/cms/e4/rap/CmsE4AdminApp.java [new file with mode: 0644]
org.argeo.cms.e4/src/org/argeo/cms/e4/rap/CmsLoginLifecycle.java [new file with mode: 0644]
org.argeo.cms.e4/src/org/argeo/cms/e4/rap/LoginLifcecycle.java [new file with mode: 0644]
org.argeo.cms.ui/pom.xml
org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/OsgiRepositoryRegister.java [new file with mode: 0644]
org.argeo.cms.ui/src/org/argeo/cms/widgets/auth/CmsLogin.java
pom.xml

index 69b786d29977b930fcbb5b72022b4f47deaa740c..b83d22266ac8aa2f8df2edef68082c789727841d 100644 (file)
@@ -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 (file)
index 0000000..68db6f9
--- /dev/null
@@ -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 (file)
index 0000000..eca7bdb
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+       <classpathentry kind="src" path="src"/>
+       <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.argeo.cms.e4/.gitignore b/org.argeo.cms.e4/.gitignore
new file mode 100644 (file)
index 0000000..09e3bc9
--- /dev/null
@@ -0,0 +1,2 @@
+/bin/
+/target/
diff --git a/org.argeo.cms.e4/.project b/org.argeo.cms.e4/.project
new file mode 100644 (file)
index 0000000..0c04069
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>org.argeo.cms.e4</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.ManifestBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.SchemaBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.ds.core.builder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.pde.PluginNature</nature>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+       </natures>
+</projectDescription>
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 (file)
index 0000000..0c68a61
--- /dev/null
@@ -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 (file)
index 0000000..4854a41
--- /dev/null
@@ -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 (file)
index 0000000..e54d613
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" configuration-policy="optional" name="CMS Admin RAP">
+   <implementation class="org.argeo.cms.e4.rap.CmsE4AdminApp"/>
+   <service>
+      <provide interface="org.eclipse.rap.rwt.application.ApplicationConfiguration"/>
+      <property name="contextName" type="String" value="ui"/>
+   </service>
+</scr:component>
diff --git a/org.argeo.cms.e4/bnd.bnd b/org.argeo.cms.e4/bnd.bnd
new file mode 100644 (file)
index 0000000..5d1261f
--- /dev/null
@@ -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 (file)
index 0000000..0b08559
--- /dev/null
@@ -0,0 +1,5 @@
+source.. = src/\r
+output.. = bin/\r
+bin.includes = META-INF/,\\r
+               OSGI-INF/,\\r
+               .\r
diff --git a/org.argeo.cms.e4/cms-admin.e4xmi b/org.argeo.cms.e4/cms-admin.e4xmi
new file mode 100644 (file)
index 0000000..b9c3767
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="ASCII"?>
+<application:Application xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:application="http://www.eclipse.org/ui/2010/UIModel/application" xmlns:basic="http://www.eclipse.org/ui/2010/UIModel/application/ui/basic" xmi:id="_XqkCQKknEeObFrG_clJBYA" elementId="">
+  <children xsi:type="basic:TrimmedWindow" xmi:id="_Zdy6cKknEeObFrG_clJBYA" elementId="org.argeo.cms.e4.apps.admin.trimmedwindow.0" label="" x="10" y="10" width="500" height="500">
+    <children xsi:type="basic:Part" xmi:id="_WAjPkCkTEein5vuhpK-Dew" elementId="org.argeo.cms.e4.jcrbrowser" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.JcrBrowserView" label="JCR Browser"/>
+  </children>
+  <addons xmi:id="_XqkCQaknEeObFrG_clJBYA" elementId="org.eclipse.e4.core.commands.service" contributionURI="bundleclass://org.eclipse.e4.core.commands/org.eclipse.e4.core.commands.CommandServiceAddon"/>
+  <addons xmi:id="_XqkCQqknEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.contexts.service" contributionURI="bundleclass://org.eclipse.e4.ui.services/org.eclipse.e4.ui.services.ContextServiceAddon"/>
+  <addons xmi:id="_XqkCQ6knEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.bindings.service" contributionURI="bundleclass://org.eclipse.e4.ui.bindings/org.eclipse.e4.ui.bindings.BindingServiceAddon"/>
+  <addons xmi:id="_XqkCRKknEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.workbench.commands.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench/org.eclipse.e4.ui.internal.workbench.addons.CommandProcessingAddon"/>
+  <addons xmi:id="_XqkCRaknEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.workbench.contexts.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench/org.eclipse.e4.ui.internal.workbench.addons.ContextProcessingAddon"/>
+  <addons xmi:id="_XqkCRqknEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.workbench.bindings.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench.swt/org.eclipse.e4.ui.workbench.swt.util.BindingProcessingAddon"/>
+  <addons xmi:id="_XqkCR6knEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.workbench.handler.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench/org.eclipse.e4.ui.internal.workbench.addons.HandlerProcessingAddon"/>
+</application:Application>
diff --git a/org.argeo.cms.e4/pom.xml b/org.argeo.cms.e4/pom.xml
new file mode 100644 (file)
index 0000000..bf677e0
--- /dev/null
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+       <modelVersion>4.0.0</modelVersion>
+       <parent>
+               <groupId>org.argeo.commons</groupId>
+               <artifactId>argeo-commons</artifactId>
+               <version>2.1.73-SNAPSHOT</version>
+               <relativePath>..</relativePath>
+       </parent>
+       <artifactId>org.argeo.cms.e4</artifactId>
+       <name>CMS E4</name>
+       <packaging>jar</packaging>
+       <dependencies>
+               <dependency>
+                       <groupId>org.argeo.commons</groupId>
+                       <artifactId>org.argeo.cms.ui</artifactId>
+                       <version>2.1.73-SNAPSHOT</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.argeo.commons</groupId>
+                       <artifactId>org.argeo.cms.ui.theme</artifactId>
+                       <version>2.1.73-SNAPSHOT</version>
+               </dependency>
+
+               <!-- UI -->
+               <dependency>
+                       <groupId>org.argeo.tp</groupId>
+                       <artifactId>argeo-tp-rap-e4</artifactId>
+                       <version>${version.argeo-tp}</version>
+                       <type>pom</type>
+                       <scope>provided</scope>
+               </dependency>
+       </dependencies>
+</project>
\ 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 (file)
index 0000000..0551e16
--- /dev/null
@@ -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 "<binary>";
+                                       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<Event> 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<Event> 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 (file)
index 0000000..17d8d2a
--- /dev/null
@@ -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 (file)
index 0000000..5b2adc0
--- /dev/null
@@ -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<String, String> properties = new HashMap<String, String>();
+               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<EntryPoint>() {
+                               //
+                               // @Override
+                               // public EntryPoint run() {
+                               EntryPoint ep = createEntryPoint();
+                               EntryPoint authEp = new EntryPoint() {
+
+                                       @Override
+                                       public int createUI() {
+                                               return Subject.doAs(subject, new PrivilegedAction<Integer>() {
+
+                                                       @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 (file)
index 0000000..6872906
--- /dev/null
@@ -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 (file)
index 0000000..5c6caaf
--- /dev/null
@@ -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
index 719db68e1412742cb3f29339df533f4274a1b737..774533326beab7d27dd0cc4f489709aca91701d2 100644 (file)
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
                <groupId>org.argeo.commons</groupId>
                        <scope>provided</scope>
                </dependency>
 
+               <!-- Theme -->
+               <dependency>
+                       <groupId>org.argeo.commons</groupId>
+                       <artifactId>org.argeo.cms.ui.theme</artifactId>
+                       <version>2.1.73-SNAPSHOT</version>
+               </dependency>
+
                <!-- UI -->
                <dependency>
                        <groupId>org.argeo.tp.rap.e4</groupId>
@@ -39,7 +47,7 @@
                        <artifactId>org.eclipse.rap.jface</artifactId>
                        <scope>provided</scope>
                </dependency>
-               
+
                <!-- TODO move it to specific -->
                <dependency>
                        <groupId>org.argeo.tp.rap.e4</groupId>
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 (file)
index 0000000..566b33d
--- /dev/null
@@ -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<Repository, Repository> repositoryTracker;
+
+       public OsgiRepositoryRegister(BundleContext bc) {
+               repositoryTracker = new ServiceTracker<Repository, Repository>(bc, Repository.class, null) {
+
+                       @Override
+                       public Repository addingService(ServiceReference<Repository> reference) {
+
+                               Repository repository = super.addingService(reference);
+                               Map<String, Object> props = new HashMap<>();
+                               for (String key : reference.getPropertyKeys()) {
+                                       props.put(key, reference.getProperty(key));
+                               }
+                               register(repository, props);
+                               return repository;
+                       }
+
+                       @Override
+                       public void removedService(ServiceReference<Repository> reference, Repository service) {
+                               Map<String, Object> 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();
+       }
+}
index fc9b7768995e71387084f4f9fef5526effcd7dfb..e450bfa075040bb0f30926dfb1cd6225faa42711 100644 (file)
@@ -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 cab81d11715fa13905d17dd13a265b07bde5207e..66f95773a35fc63db6cc67da1d4b81aa5deeac20 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>org.argeo.commons</groupId>
        <artifactId>argeo-commons</artifactId>
@@ -33,6 +34,8 @@
                <module>org.argeo.cms</module>
                <module>org.argeo.cms.ui.theme</module>
                <module>org.argeo.cms.ui</module>
+               <!-- CMS E4 -->
+               <module>org.argeo.cms.e4</module>
                <!-- CMS Workbench -->
                <module>org.argeo.cms.ui.workbench</module>
                <module>org.argeo.cms.ui.workbench.rap</module>
@@ -608,8 +611,10 @@ limitations under the License.
                                                                </goals>
                                                                <configuration>
                                                                        <target>
-                                                                               <copy todir="${argeo.rpm.stagingRepository}" quiet="true" failonerror="false">
-                                                                                       <fileset dir="${project.build.directory}/rpm" includes="*/RPMS/**/*.rpm" />
+                                                                               <copy todir="${argeo.rpm.stagingRepository}" quiet="true"
+                                                                                       failonerror="false">
+                                                                                       <fileset dir="${project.build.directory}/rpm"
+                                                                                               includes="*/RPMS/**/*.rpm" />
                                                                                        <flattenmapper />
                                                                                </copy>
                                                                        </target>
@@ -634,8 +639,10 @@ limitations under the License.
                                                                </goals>
                                                                <configuration>
                                                                        <target>
-                                                                               <copy todir="${argeo.rpm.stagingRepository}" quiet="true" failonerror="false">
-                                                                                       <fileset dir="${project.build.directory}/rpm" includes="*/RPMS/**/*.rpm" />
+                                                                               <copy todir="${argeo.rpm.stagingRepository}" quiet="true"
+                                                                                       failonerror="false">
+                                                                                       <fileset dir="${project.build.directory}/rpm"
+                                                                                               includes="*/RPMS/**/*.rpm" />
                                                                                        <flattenmapper />
                                                                                </copy>
                                                                        </target>