From: Mathieu Baudier Date: Tue, 25 Nov 2014 14:07:12 +0000 (+0000) Subject: New project conventions (builds) X-Git-Tag: argeo-commons-2.1.30~508 X-Git-Url: http://git.argeo.org/?a=commitdiff_plain;h=d33e8191813f561cee96fbbbd3f74737070140d0;p=lgpl%2Fargeo-commons.git New project conventions (builds) git-svn-id: https://svn.argeo.org/commons/trunk@7540 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- diff --git a/org.argeo.jcr.ui.explorer/.classpath b/org.argeo.jcr.ui.explorer/.classpath index 527d8abab..d2953a684 100644 --- a/org.argeo.jcr.ui.explorer/.classpath +++ b/org.argeo.jcr.ui.explorer/.classpath @@ -1,8 +1,9 @@ - - - >> - - + + + + diff --git a/org.argeo.jcr.ui.explorer/.settings/org.eclipse.jdt.core.prefs b/org.argeo.jcr.ui.explorer/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 992c5d722..000000000 --- a/org.argeo.jcr.ui.explorer/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,8 +0,0 @@ -#Thu Feb 24 08:49:06 CET 2011 -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 -org.eclipse.jdt.core.compiler.compliance=1.5 -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.5 diff --git a/org.argeo.jcr.ui.explorer/build.properties b/org.argeo.jcr.ui.explorer/build.properties index 9b0c715ca..410bf3a8b 100644 --- a/org.argeo.jcr.ui.explorer/build.properties +++ b/org.argeo.jcr.ui.explorer/build.properties @@ -1,7 +1 @@ -source.. = src/main/java/,\ - src/main/resources -output.. = target/classes/ -bin.includes = META-INF/,\ - .,\ - plugin.xml,\ - plugin.properties +source.. = src/ diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/JcrExplorerConstants.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/JcrExplorerConstants.java deleted file mode 100644 index a9cb25841..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/JcrExplorerConstants.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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.jcr.ui.explorer; - -/** Constants used across the application. */ -public interface JcrExplorerConstants { - /* - * MISCEALLENEOUS - */ - public final static String DATE_TIME_FORMAT = "dd/MM/yyyy, HH:mm"; - - public final static String PARAM_PATH = "org.argeo.jcr.ui.explorer.nodePath"; - -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/JcrExplorerPerspective.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/JcrExplorerPerspective.java deleted file mode 100644 index 2626415fc..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/JcrExplorerPerspective.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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.jcr.ui.explorer; - -import org.eclipse.ui.IFolderLayout; -import org.eclipse.ui.IPageLayout; -import org.eclipse.ui.IPerspectiveFactory; - -/** Base perspective for JcrExplorer browser */ -public class JcrExplorerPerspective implements IPerspectiveFactory { - public static String BROWSER_VIEW_ID = JcrExplorerPlugin.ID - + ".browserView"; - - public void createInitialLayout(IPageLayout layout) { - layout.setEditorAreaVisible(true); - - IFolderLayout upperLeft = layout.createFolder(JcrExplorerPlugin.ID - + ".upperLeft", IPageLayout.LEFT, 0.4f, layout.getEditorArea()); - upperLeft.addView(BROWSER_VIEW_ID); - -// String editorArea = layout.getEditorArea(); -// String logViewId = "org.argeo.security.ui.logView"; -// IFolderLayout bottom = layout.createFolder("bottom", -// IPageLayout.BOTTOM, 0.50f, editorArea); -// bottom.addView(logViewId); - } - -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/JcrExplorerPlugin.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/JcrExplorerPlugin.java deleted file mode 100644 index 3bf9e7f7d..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/JcrExplorerPlugin.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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.jcr.ui.explorer; - -import java.util.ResourceBundle; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.ui.plugin.AbstractUIPlugin; -import org.osgi.framework.BundleContext; - -/** - * The activator class controls the plug-in life cycle - */ -public class JcrExplorerPlugin extends AbstractUIPlugin { - private final static Log log = LogFactory.getLog(JcrExplorerPlugin.class); - private ResourceBundle messages; - - // The plug-in ID - public static final String ID = "org.argeo.jcr.ui.explorer"; //$NON-NLS-1$ - - // The shared instance - private static JcrExplorerPlugin plugin; - - /** - * The constructor - */ - public JcrExplorerPlugin() { - } - - /* - * (non-Javadoc) - * - * @see - * org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext - * ) - */ - public void start(BundleContext context) throws Exception { - super.start(context); - plugin = this; - messages = ResourceBundle - .getBundle("org.argeo.jcr.ui.explorer.messages"); - - } - - /* - * (non-Javadoc) - * - * @see - * org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext - * ) - */ - public void stop(BundleContext context) throws Exception { - plugin = null; - super.stop(context); - } - - /** - * Returns the shared instance - * - * @return the shared instance - */ - public static JcrExplorerPlugin getDefault() { - return plugin; - } - - public static ImageDescriptor getImageDescriptor(String path) { - return imageDescriptorFromPlugin(ID, path); - } - - /** Returns the internationalized label for the given key */ - public static String getMessage(String key) { - try { - return getDefault().messages.getString(key); - } catch (NullPointerException npe) { - log.warn(key + " not found."); - return key; - } - } - - /** - * Gives access to the internationalization message bundle. Returns null in - * case the ClientUiPlugin is not started (for JUnit tests, by instance) - */ - public static ResourceBundle getMessagesBundle() { - if (getDefault() != null) - // To avoid NPE - return getDefault().messages; - else - return null; - } - -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/JcrExplorerView.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/JcrExplorerView.java deleted file mode 100644 index 01a957a96..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/JcrExplorerView.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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.jcr.ui.explorer; - -import org.argeo.jcr.ui.explorer.views.GenericJcrBrowser; - -public class JcrExplorerView extends GenericJcrBrowser { - -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/browser/NodeContentProvider.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/browser/NodeContentProvider.java deleted file mode 100644 index fb6bd1a15..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/browser/NodeContentProvider.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * 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.jcr.ui.explorer.browser; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; -import java.util.List; - -import javax.jcr.Node; -import javax.jcr.RepositoryException; -import javax.jcr.RepositoryFactory; -import javax.jcr.Session; -import javax.jcr.nodetype.NodeType; - -import org.argeo.eclipse.ui.TreeParent; -import org.argeo.jcr.ArgeoJcrConstants; -import org.argeo.jcr.RepositoryRegister; -import org.argeo.jcr.UserJcrUtils; -import org.argeo.jcr.ui.explorer.model.RepositoriesElem; -import org.argeo.jcr.ui.explorer.model.SingleJcrNodeElem; -import org.argeo.util.security.Keyring; -import org.eclipse.jface.viewers.ITreeContentProvider; -import org.eclipse.jface.viewers.Viewer; - -/** - * Implementation of the {@code ITreeContentProvider} to display multiple - * repository environment in a tree like structure - * - */ -public class NodeContentProvider implements ITreeContentProvider { - final private RepositoryRegister repositoryRegister; - final private RepositoryFactory repositoryFactory; - /** - * A session of the logged in user on the default workspace of the node - * repository. - */ - final private Session userSession; - final private Keyring keyring; - private boolean sortChildren; - - // reference for cleaning - private SingleJcrNodeElem homeNode = null; - private RepositoriesElem repositoriesNode = null; - - // Utils - private TreeBrowserComparator itemComparator = new TreeBrowserComparator(); - - public NodeContentProvider(Session userSession, Keyring keyring, - RepositoryRegister repositoryRegister, - RepositoryFactory repositoryFactory, Boolean sortChildren) { - this.userSession = userSession; - this.keyring = keyring; - this.repositoryRegister = repositoryRegister; - this.repositoryFactory = repositoryFactory; - this.sortChildren = sortChildren; - } - - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - if (newInput == null)// dispose - return; - - if (userSession != null) { - Node userHome = UserJcrUtils.getUserHome(userSession); - if (userHome != null) { - // TODO : find a way to dynamically get alias for the node - if (homeNode != null) - homeNode.dispose(); - homeNode = new SingleJcrNodeElem(null, userHome, - userSession.getUserID(), ArgeoJcrConstants.ALIAS_NODE); - } - } - if (repositoryRegister != null) { - if (repositoriesNode != null) - repositoriesNode.dispose(); - repositoriesNode = new RepositoriesElem("Repositories", - repositoryRegister, repositoryFactory, null, userSession, - keyring); - } - } - - /** - * Sends back the first level of the Tree. Independent from inputElement - * that can be null - */ - public Object[] getElements(Object inputElement) { - List objs = new ArrayList(); - if (homeNode != null) - objs.add(homeNode); - if (repositoriesNode != null) - objs.add(repositoriesNode); - return objs.toArray(); - } - - public Object[] getChildren(Object parentElement) { - if (parentElement instanceof TreeParent) { - if (sortChildren) { - // TreeParent[] arr = (TreeParent[]) ((TreeParent) - // parentElement) - // .getChildren(); - Object[] tmpArr = ((TreeParent) parentElement).getChildren(); - TreeParent[] arr = new TreeParent[tmpArr.length]; - for (int i = 0; i < tmpArr.length; i++) - arr[i] = (TreeParent) tmpArr[i]; - - Arrays.sort(arr, itemComparator); - return arr; - } else - return ((TreeParent) parentElement).getChildren(); - - } else { - return new Object[0]; - } - } - - /** - * Sets whether the content provider should order the children nodes or not. - * It is user duty to call a full refresh of the tree after changing this - * parameter. - */ - public void setSortChildren(boolean sortChildren) { - this.sortChildren = sortChildren; - } - - public Object getParent(Object element) { - if (element instanceof TreeParent) { - return ((TreeParent) element).getParent(); - } else - return null; - } - - public boolean hasChildren(Object element) { - if (element instanceof RepositoriesElem) { - RepositoryRegister rr = ((RepositoriesElem) element) - .getRepositoryRegister(); - return rr.getRepositories().size() > 0; - } else if (element instanceof TreeParent) { - TreeParent tp = (TreeParent) element; - return tp.hasChildren(); - } - return false; - } - - public void dispose() { - if (homeNode != null) - homeNode.dispose(); - if (repositoriesNode != null) { - // logs out open sessions - // see https://bugzilla.argeo.org/show_bug.cgi?id=23 - repositoriesNode.dispose(); - } - } - - /** - * Specific comparator for this view. See spec in BUG : - * https://www.argeo.org/bugzilla/show_bug.cgi?id=139 - */ - private class TreeBrowserComparator implements Comparator { - - public int category(TreeParent element) { - if (element instanceof SingleJcrNodeElem) { - Node node = ((SingleJcrNodeElem) element).getNode(); - try { - if (node.isNodeType(NodeType.NT_FOLDER)) - return 5; - } catch (RepositoryException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - return 10; - } - - public int compare(TreeParent o1, TreeParent o2) { - int cat1 = category(o1); - int cat2 = category(o2); - - if (cat1 != cat2) { - return cat1 - cat2; - } - return o1.getName().compareTo(o2.getName()); - } - } -} \ No newline at end of file diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/browser/NodeLabelProvider.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/browser/NodeLabelProvider.java deleted file mode 100644 index d6d593ce8..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/browser/NodeLabelProvider.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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.jcr.ui.explorer.browser; - -import javax.jcr.Node; -import javax.jcr.RepositoryException; -import javax.jcr.nodetype.NodeType; - -import org.argeo.ArgeoException; -import org.argeo.eclipse.ui.jcr.DefaultNodeLabelProvider; -import org.argeo.eclipse.ui.jcr.JcrImages; -import org.argeo.jcr.ui.explorer.model.RemoteRepositoryElem; -import org.argeo.jcr.ui.explorer.model.RepositoriesElem; -import org.argeo.jcr.ui.explorer.model.RepositoryElem; -import org.argeo.jcr.ui.explorer.model.SingleJcrNodeElem; -import org.argeo.jcr.ui.explorer.model.WorkspaceElem; -import org.eclipse.swt.graphics.Image; - -public class NodeLabelProvider extends DefaultNodeLabelProvider { - // Images - - public String getText(Object element) { - try { - if (element instanceof SingleJcrNodeElem) { - SingleJcrNodeElem sjn = (SingleJcrNodeElem) element; - return getText(sjn.getNode()); - } else - return super.getText(element); - } catch (RepositoryException e) { - throw new ArgeoException( - "Unexpected JCR error while getting node name."); - } - } - - protected String getText(Node node) throws RepositoryException { - String label = node.getName(); - StringBuffer mixins = new StringBuffer(""); - for (NodeType type : node.getMixinNodeTypes()) - mixins.append(' ').append(type.getName()); - - return label + " [" + node.getPrimaryNodeType().getName() + mixins - + "]"; - } - - @Override - public Image getImage(Object element) { - if (element instanceof RemoteRepositoryElem) { - if (((RemoteRepositoryElem) element).isConnected()) - return JcrImages.REMOTE_CONNECTED; - else - return JcrImages.REMOTE_DISCONNECTED; - } else if (element instanceof RepositoryElem) { - if (((RepositoryElem) element).isConnected()) - return JcrImages.REPOSITORY_CONNECTED; - else - return JcrImages.REPOSITORY_DISCONNECTED; - } else if (element instanceof WorkspaceElem) { - if (((WorkspaceElem) element).isConnected()) - return JcrImages.WORKSPACE_CONNECTED; - else - return JcrImages.WORKSPACE_DISCONNECTED; - } else if (element instanceof RepositoriesElem) { - return JcrImages.REPOSITORIES; - } else if (element instanceof SingleJcrNodeElem) - try { - return super.getImage(((SingleJcrNodeElem) element).getNode()); - } catch (RepositoryException e) { - return null; - } - return super.getImage(element); - } - -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/browser/PropertiesContentProvider.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/browser/PropertiesContentProvider.java deleted file mode 100644 index d39f3195e..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/browser/PropertiesContentProvider.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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.jcr.ui.explorer.browser; - -import java.util.Set; -import java.util.TreeSet; - -import javax.jcr.Node; -import javax.jcr.Property; -import javax.jcr.PropertyIterator; -import javax.jcr.RepositoryException; - -import org.argeo.ArgeoException; -import org.argeo.eclipse.ui.jcr.utils.JcrItemsComparator; -import org.eclipse.jface.viewers.IStructuredContentProvider; -import org.eclipse.jface.viewers.Viewer; - -public class PropertiesContentProvider implements IStructuredContentProvider { - private JcrItemsComparator itemComparator = new JcrItemsComparator(); - - public void dispose() { - } - - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - } - - public Object[] getElements(Object inputElement) { - try { - if (inputElement instanceof Node) { - Set props = new TreeSet(itemComparator); - PropertyIterator pit = ((Node) inputElement).getProperties(); - while (pit.hasNext()) - props.add(pit.nextProperty()); - return props.toArray(); - } - return new Object[] {}; - } catch (RepositoryException e) { - throw new ArgeoException("Cannot get element for " + inputElement, - e); - } - } - -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/AddFolderNode.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/AddFolderNode.java deleted file mode 100644 index 0389aeec0..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/AddFolderNode.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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.jcr.ui.explorer.commands; - -import javax.jcr.Node; -import javax.jcr.RepositoryException; -import javax.jcr.nodetype.NodeType; - -import org.argeo.eclipse.ui.ErrorFeedback; -import org.argeo.eclipse.ui.TreeParent; -import org.argeo.eclipse.ui.dialogs.SingleValue; -import org.argeo.eclipse.ui.jcr.JcrUiPlugin; -import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; -import org.argeo.jcr.ui.explorer.model.SingleJcrNodeElem; -import org.argeo.jcr.ui.explorer.model.WorkspaceElem; -import org.argeo.jcr.ui.explorer.views.GenericJcrBrowser; -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.ui.handlers.HandlerUtil; - -/** - * Adds a node of type nt:folder, only on {@link SingleJcrNodeElem} and - * {@link WorkspaceElem} TreeObject types. - * - * - * This handler assumes that a selection provider is available and picks only - * first selected item. It is UI's job to enable the command only when the - * selection contains one and only one element. Thus no parameter is passed - * through the command. - * - * This handler is still 'hard linked' to a GenericJcrBrowser view to enable - * correct tree refresh when a node is added. This must be corrected in future - * versions. - */ -public class AddFolderNode extends AbstractHandler { - - public final static String ID = JcrExplorerPlugin.ID + ".addFolderNode"; - - // public final static String DEFAULT_LABEL = JcrExplorerPlugin - // .getMessage("addFolderNodeCmdLbl"); - // public final static String DEFAULT_ICON_REL_PATH = "icons/addRepo.gif"; - - public Object execute(ExecutionEvent event) throws ExecutionException { - - ISelection selection = HandlerUtil.getActiveWorkbenchWindow(event) - .getActivePage().getSelection(); - - GenericJcrBrowser view = (GenericJcrBrowser) HandlerUtil - .getActiveWorkbenchWindow(event).getActivePage() - .findView(HandlerUtil.getActivePartId(event)); - - if (selection != null && !selection.isEmpty() - && selection instanceof IStructuredSelection) { - Object obj = ((IStructuredSelection) selection).getFirstElement(); - TreeParent treeParentNode = null; - Node jcrParentNode = null; - - if (obj instanceof SingleJcrNodeElem) { - treeParentNode = (TreeParent) obj; - jcrParentNode = ((SingleJcrNodeElem) treeParentNode).getNode(); - } else if (obj instanceof WorkspaceElem) { - treeParentNode = (TreeParent) obj; - jcrParentNode = ((WorkspaceElem) treeParentNode).getRootNode(); - } else - return null; - - String folderName = SingleValue.ask("Folder name", - "Enter folder name"); - if (folderName != null) { - try { - jcrParentNode.addNode(folderName, NodeType.NT_FOLDER); - jcrParentNode.getSession().save(); - view.nodeAdded(treeParentNode); - } catch (RepositoryException e) { - ErrorFeedback.show("Cannot create folder " + folderName - + " under " + treeParentNode, e); - } - } - } else { - ErrorFeedback.show(JcrUiPlugin - .getMessage("errorUnvalidNtFolderNodeType")); - } - return null; - } -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/AddPrivileges.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/AddPrivileges.java deleted file mode 100644 index 829290ebe..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/AddPrivileges.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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.jcr.ui.explorer.commands; - -import javax.jcr.Node; -import javax.jcr.RepositoryException; - -import org.argeo.ArgeoException; -import org.argeo.eclipse.ui.ErrorFeedback; -import org.argeo.eclipse.ui.TreeParent; -import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; -import org.argeo.jcr.ui.explorer.model.SingleJcrNodeElem; -import org.argeo.jcr.ui.explorer.model.WorkspaceElem; -import org.argeo.jcr.ui.explorer.wizards.ChangeRightsWizard; -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.wizard.WizardDialog; -import org.eclipse.ui.handlers.HandlerUtil; - -/** - * Open a dialog to change rights on the selected node. - */ - -public class AddPrivileges extends AbstractHandler { - public final static String ID = JcrExplorerPlugin.ID + ".addPrivileges"; - - public Object execute(ExecutionEvent event) throws ExecutionException { - - ISelection selection = HandlerUtil.getActiveWorkbenchWindow(event) - .getActivePage().getSelection(); - if (selection != null && !selection.isEmpty() - && selection instanceof IStructuredSelection) { - Object obj = ((IStructuredSelection) selection).getFirstElement(); - TreeParent treeParentNode = null; - Node jcrParentNode = null; - - if (obj instanceof SingleJcrNodeElem) { - treeParentNode = (TreeParent) obj; - jcrParentNode = ((SingleJcrNodeElem) treeParentNode).getNode(); - } else if (obj instanceof WorkspaceElem) { - treeParentNode = (TreeParent) obj; - jcrParentNode = ((WorkspaceElem) treeParentNode).getRootNode(); - } else - return null; - - try { - ChangeRightsWizard wizard = new ChangeRightsWizard( - jcrParentNode.getSession(), jcrParentNode.getPath()); - WizardDialog dialog = new WizardDialog( - HandlerUtil.getActiveShell(event), wizard); - dialog.open(); - return null; - } catch (RepositoryException re) { - throw new ArgeoException( - "Unexpected error while creating the new workspace.", - re); - } - } else { - ErrorFeedback.show("Cannot add privileges"); - } - return null; - } -} \ No newline at end of file diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/AddRemoteRepository.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/AddRemoteRepository.java deleted file mode 100644 index e41edfca8..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/AddRemoteRepository.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * 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.jcr.ui.explorer.commands; - -import java.net.URI; -import java.util.Hashtable; - -import javax.jcr.Node; -import javax.jcr.Repository; -import javax.jcr.RepositoryFactory; -import javax.jcr.Session; -import javax.jcr.SimpleCredentials; - -import org.argeo.ArgeoException; -import org.argeo.eclipse.ui.ErrorFeedback; -import org.argeo.eclipse.ui.utils.CommandUtils; -import org.argeo.jcr.ArgeoJcrConstants; -import org.argeo.jcr.ArgeoNames; -import org.argeo.jcr.ArgeoTypes; -import org.argeo.jcr.JcrUtils; -import org.argeo.jcr.UserJcrUtils; -import org.argeo.jcr.ui.explorer.JcrExplorerConstants; -import org.argeo.util.security.Keyring; -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import org.eclipse.jface.dialogs.Dialog; -import org.eclipse.jface.dialogs.IMessageProvider; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.dialogs.TitleAreaDialog; -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.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.Control; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Text; - -/** - * Connect to a remote repository and, if successful publish it as an OSGi - * service. - */ -public class AddRemoteRepository extends AbstractHandler implements - JcrExplorerConstants, ArgeoNames { - - private RepositoryFactory repositoryFactory; - private Repository nodeRepository; - private Keyring keyring; - - public Object execute(ExecutionEvent event) throws ExecutionException { - RemoteRepositoryLoginDialog dlg = new RemoteRepositoryLoginDialog( - Display.getDefault().getActiveShell()); - if (dlg.open() == Dialog.OK) { - CommandUtils.callCommand(Refresh.ID); - } - return null; - } - - public void setRepositoryFactory(RepositoryFactory repositoryFactory) { - this.repositoryFactory = repositoryFactory; - } - - public void setKeyring(Keyring keyring) { - this.keyring = keyring; - } - - public void setNodeRepository(Repository nodeRepository) { - this.nodeRepository = nodeRepository; - } - - class RemoteRepositoryLoginDialog extends TitleAreaDialog { - private Text name; - private Text uri; - private Text username; - private Text password; - private Button saveInKeyring; - - public RemoteRepositoryLoginDialog(Shell parentShell) { - super(parentShell); - } - - protected Point getInitialSize() { - return new Point(600, 400); - } - - protected Control createDialogArea(Composite parent) { - Composite dialogarea = (Composite) super.createDialogArea(parent); - dialogarea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, - true)); - Composite composite = new Composite(dialogarea, SWT.NONE); - composite.setLayout(new GridLayout(2, false)); - composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, - false)); - setMessage("Login to remote repository", IMessageProvider.NONE); - name = createLT(composite, "Name", "remoteRepository"); - uri = createLT(composite, "URI", - "http://localhost:7070/data/jcr/node"); - username = createLT(composite, "User", ""); - password = createLP(composite, "Password"); - - saveInKeyring = createLC(composite, "Remember password", false); - parent.pack(); - return composite; - } - - @Override - protected void createButtonsForButtonBar(Composite parent) { - super.createButtonsForButtonBar(parent); - Button test = createButton(parent, 2, "Test", false); - test.addSelectionListener(new SelectionAdapter() { - public void widgetSelected(SelectionEvent arg0) { - testConnection(); - } - }); - } - - void testConnection() { - Session session = null; - try { - URI checkedUri = new URI(uri.getText()); - String checkedUriStr = checkedUri.toString(); - - Hashtable params = new Hashtable(); - params.put(ArgeoJcrConstants.JCR_REPOSITORY_URI, checkedUriStr); - Repository repository = repositoryFactory.getRepository(params); - if (username.getText().trim().equals("")) {// anonymous - session = repository.login(); - } else { - // FIXME use getTextChars() when upgrading to 3.7 - // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=297412 - char[] pwd = password.getText().toCharArray(); - SimpleCredentials sc = new SimpleCredentials( - username.getText(), pwd); - session = repository.login(sc); - MessageDialog.openInformation(getParentShell(), "Success", - "Connection to '" + uri.getText() + "' successful"); - } - } catch (Exception e) { - ErrorFeedback.show( - "Connection test failed for " + uri.getText(), e); - } finally { - JcrUtils.logoutQuietly(session); - } - } - - @Override - protected void okPressed() { - Session nodeSession = null; - try { - nodeSession = nodeRepository.login(); - Node home = UserJcrUtils.getUserHome(nodeSession); - - Node remote = home.hasNode(ARGEO_REMOTE) ? home - .getNode(ARGEO_REMOTE) : home.addNode(ARGEO_REMOTE); - if (remote.hasNode(name.getText())) - throw new ArgeoException( - "There is already a remote repository named " - + name.getText()); - Node remoteRepository = remote.addNode(name.getText(), - ArgeoTypes.ARGEO_REMOTE_REPOSITORY); - remoteRepository.setProperty(ARGEO_URI, uri.getText()); - remoteRepository.setProperty(ARGEO_USER_ID, username.getText()); - nodeSession.save(); - if (saveInKeyring.getSelection()) { - String pwdPath = remoteRepository.getPath() + '/' - + ARGEO_PASSWORD; - keyring.set(pwdPath, password.getText().toCharArray()); - } - nodeSession.save(); - MessageDialog.openInformation( - getParentShell(), - "Repository Added", - "Remote repository '" + username.getText() + "@" - + uri.getText() + "' added"); - - super.okPressed(); - } catch (Exception e) { - ErrorFeedback.show("Cannot add remote repository", e); - } finally { - JcrUtils.logoutQuietly(nodeSession); - } - } - - /** Creates label and text. */ - protected Text createLT(Composite parent, String label, String initial) { - new Label(parent, SWT.NONE).setText(label); - Text text = new Text(parent, SWT.SINGLE | SWT.LEAD | SWT.BORDER); - text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - text.setText(initial); - return text; - } - - /** Creates label and check. */ - protected Button createLC(Composite parent, String label, - Boolean initial) { - new Label(parent, SWT.NONE).setText(label); - Button check = new Button(parent, SWT.CHECK); - check.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - check.setSelection(initial); - return check; - } - - protected Text createLP(Composite parent, String label) { - new Label(parent, SWT.NONE).setText(label); - Text text = new Text(parent, SWT.SINGLE | SWT.LEAD | SWT.BORDER - | SWT.PASSWORD); - text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - return text; - } - } -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/CreateWorkspace.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/CreateWorkspace.java deleted file mode 100644 index e579630ce..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/CreateWorkspace.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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.jcr.ui.explorer.commands; - -import java.util.Arrays; - -import org.argeo.eclipse.ui.ErrorFeedback; -import org.argeo.eclipse.ui.dialogs.SingleValue; -import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; -import org.argeo.jcr.ui.explorer.model.RepositoryElem; -import org.argeo.jcr.ui.explorer.views.GenericJcrBrowser; -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.ui.handlers.HandlerUtil; - -/** Creates a new JCR workspace */ -public class CreateWorkspace extends AbstractHandler { - - public final static String ID = JcrExplorerPlugin.ID + ".addFolderNode"; - - public Object execute(ExecutionEvent event) throws ExecutionException { - - ISelection selection = HandlerUtil.getActiveWorkbenchWindow(event) - .getActivePage().getSelection(); - - GenericJcrBrowser view = (GenericJcrBrowser) HandlerUtil - .getActiveWorkbenchWindow(event).getActivePage() - .findView(HandlerUtil.getActivePartId(event)); - - if (selection != null && !selection.isEmpty() - && selection instanceof IStructuredSelection) { - Object obj = ((IStructuredSelection) selection).getFirstElement(); - if (!(obj instanceof RepositoryElem)) - return null; - - RepositoryElem repositoryNode = (RepositoryElem) obj; - String workspaceName = SingleValue.ask("Workspace name", - "Enter workspace name"); - if (workspaceName != null) { - if (Arrays.asList(repositoryNode.getAccessibleWorkspaceNames()) - .contains(workspaceName)) { - ErrorFeedback.show("Workspace " + workspaceName - + " already exists."); - } else { - repositoryNode.createWorkspace(workspaceName); - view.nodeAdded(repositoryNode); - } - } - } else { - ErrorFeedback.show("Cannot create workspace"); - } - return null; - } -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/DeleteNodes.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/DeleteNodes.java deleted file mode 100644 index 26d4cdd43..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/DeleteNodes.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * 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.jcr.ui.explorer.commands; - -import java.util.Iterator; - -import javax.jcr.Node; -import javax.jcr.RepositoryException; - -import org.argeo.ArgeoException; -import org.argeo.eclipse.ui.ErrorFeedback; -import org.argeo.eclipse.ui.TreeParent; -import org.argeo.jcr.ui.explorer.model.SingleJcrNodeElem; -import org.argeo.jcr.ui.explorer.model.WorkspaceElem; -import org.argeo.jcr.ui.explorer.views.GenericJcrBrowser; -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.ui.handlers.HandlerUtil; - -/** - * Deletes the selected nodes: both in the JCR repository and in the UI view. - * Warning no check is done, except implementation dependent native checks, - * handle with care. - * - * This handler is still 'hard linked' to a GenericJcrBrowser view to enable - * correct tree refresh when a node is added. This must be corrected in future - * versions. - */ -public class DeleteNodes extends AbstractHandler { - public Object execute(ExecutionEvent event) throws ExecutionException { - ISelection selection = HandlerUtil.getActiveWorkbenchWindow(event) - .getActivePage().getSelection(); - if (selection == null || !(selection instanceof IStructuredSelection)) - return null; - - GenericJcrBrowser view = (GenericJcrBrowser) HandlerUtil - .getActiveWorkbenchWindow(event).getActivePage() - .findView(HandlerUtil.getActivePartId(event)); - - // confirmation - StringBuffer buf = new StringBuffer(""); - Iterator lst = ((IStructuredSelection) selection).iterator(); - while (lst.hasNext()) { - SingleJcrNodeElem sjn = ((SingleJcrNodeElem) lst.next()); - buf.append(sjn.getName()).append(' '); - } - Boolean ok = MessageDialog.openConfirm( - HandlerUtil.getActiveShell(event), "Confirm deletion", - "Do you want to delete " + buf + "?"); - - // operation - if (ok) { - Iterator it = ((IStructuredSelection) selection).iterator(); - Object obj = null; - SingleJcrNodeElem ancestor = null; - WorkspaceElem rootAncestor = null; - try { - while (it.hasNext()) { - obj = it.next(); - if (obj instanceof SingleJcrNodeElem) { - // Cache objects - SingleJcrNodeElem sjn = (SingleJcrNodeElem) obj; - TreeParent tp = (TreeParent) sjn.getParent(); - Node node = sjn.getNode(); - - // Jcr Remove - node.remove(); - node.getSession().save(); - // UI remove - tp.removeChild(sjn); - - // Check if the parent is the root node - if (tp instanceof WorkspaceElem) - rootAncestor = (WorkspaceElem) tp; - else - ancestor = getOlder(ancestor, (SingleJcrNodeElem) tp); - } - } - if (rootAncestor != null) - view.nodeRemoved(rootAncestor); - else if (ancestor != null) - view.nodeRemoved(ancestor); - } catch (Exception e) { - ErrorFeedback.show("Cannot delete selected node ", e); - } - } - return null; - } - - private SingleJcrNodeElem getOlder(SingleJcrNodeElem A, SingleJcrNodeElem B) { - try { - if (A == null) - return B == null ? null : B; - // Todo enhanced this method - else - return A.getNode().getDepth() <= B.getNode().getDepth() ? A : B; - } catch (RepositoryException re) { - throw new ArgeoException("Cannot find ancestor", re); - } - } -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/DumpNode.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/DumpNode.java deleted file mode 100644 index c8a235d73..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/DumpNode.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * 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.jcr.ui.explorer.commands; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import javax.jcr.Node; -import javax.jcr.RepositoryException; - -import org.argeo.ArgeoException; -import org.argeo.eclipse.ui.specific.OpenFile; -import org.argeo.eclipse.ui.utils.CommandUtils; -import org.argeo.jcr.JcrUtils; -import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; -import org.argeo.jcr.ui.explorer.model.SingleJcrNodeElem; -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.ui.handlers.HandlerUtil; - -/** - * If the method - * HandlerUtil.getActiveWorkbenchWindow(event).getActivePage().getSelection() - * exits and has a SingleJcrNodeElem as first element, it canonically calls the - * JCR Session.exportSystemView() method on the underlying node with both - * skipBinary & noRecurse boolean flags set to false. - * - * Resulting stream is saved in a tmp file and opened via the "open file" - * single-sourced command. - */ -public class DumpNode extends AbstractHandler { - public final static String ID = JcrExplorerPlugin.ID + ".dumpNode"; - - private final static DateFormat df = new SimpleDateFormat( - "yyyy-MM-dd_HH-mm"); - - public Object execute(ExecutionEvent event) throws ExecutionException { - ISelection selection = HandlerUtil.getActiveWorkbenchWindow(event) - .getActivePage().getSelection(); - if (selection == null || !(selection instanceof IStructuredSelection)) - return null; - - Iterator lst = ((IStructuredSelection) selection).iterator(); - if (lst.hasNext()) { - Object element = lst.next(); - if (element instanceof SingleJcrNodeElem) { - SingleJcrNodeElem sjn = (SingleJcrNodeElem) element; - Node node = sjn.getNode(); - - // TODO add a dialog to configure the export and ask for - // confirmation - // Boolean ok = MessageDialog.openConfirm( - // HandlerUtil.getActiveShell(event), "Confirm deletion", - // "Do you want to delete " + buf + "?"); - - File tmpFile; - FileOutputStream fos; - try { - tmpFile = File.createTempFile("JcrExport", ".xml"); - tmpFile.deleteOnExit(); - fos = new FileOutputStream(tmpFile); - String dateVal = df.format(new GregorianCalendar() - .getTime()); - node.getSession().exportSystemView(node.getPath(), fos, - true, false); - openGeneratedFile(tmpFile.getAbsolutePath(), - "Dump-" + JcrUtils.replaceInvalidChars(node.getName())+ "-" + dateVal + ".xml"); - } catch (RepositoryException e) { - throw new ArgeoException( - "Unable to perform SystemExport on " + node, e); - } catch (IOException e) { - throw new ArgeoException("Unable to SystemExport " + node, - e); - } - } - } - return null; - } - - private synchronized void openGeneratedFile(String path, String fileName) { - Map params = new HashMap(); - params.put(OpenFile.PARAM_FILE_NAME, fileName); - params.put(OpenFile.PARAM_FILE_URI, "file://" + path); - CommandUtils.callCommand("org.argeo.security.ui.specific.openFile", - params); - } -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/EditNode.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/EditNode.java deleted file mode 100644 index e98973e47..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/EditNode.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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.jcr.ui.explorer.commands; - -import java.util.HashMap; -import java.util.Map; - -import javax.jcr.Property; -import javax.jcr.nodetype.NodeType; - -import org.argeo.eclipse.ui.ErrorFeedback; -import org.argeo.eclipse.ui.jcr.editors.NodeEditorInput; -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.handlers.HandlerUtil; - -/** Generic command to open a path in an editor. */ -public class EditNode extends AbstractHandler { - public final static String EDITOR_PARAM = "editor"; - - private String defaultEditorId; - - private Map nodeTypeToEditor = new HashMap(); - - public Object execute(ExecutionEvent event) throws ExecutionException { - String path = event.getParameter(Property.JCR_PATH); - - String type = event.getParameter(NodeType.NT_NODE_TYPE); - if (type == null) - type = NodeType.NT_UNSTRUCTURED; - - String editorId = event.getParameter(NodeType.NT_NODE_TYPE); - if (editorId == null) - editorId = nodeTypeToEditor.containsKey(type) ? nodeTypeToEditor - .get(type) : defaultEditorId; - - NodeEditorInput nei = new NodeEditorInput(path); - - try { - HandlerUtil.getActiveWorkbenchWindow(event).getActivePage() - .openEditor(nei, editorId); - } catch (PartInitException e) { - ErrorFeedback.show("Cannot open " + editorId + " with " + path - + " of type " + type, e); - } - // TODO Auto-generated method stub - return null; - } - - public void setDefaultEditorId(String defaultEditorId) { - this.defaultEditorId = defaultEditorId; - } - -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/GetNodeSize.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/GetNodeSize.java deleted file mode 100644 index cfcac1354..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/GetNodeSize.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * 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.jcr.ui.explorer.commands; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import javax.jcr.Node; - -import org.argeo.eclipse.ui.ErrorFeedback; -import org.argeo.jcr.JcrUtils; -import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; -import org.argeo.jcr.ui.explorer.model.SingleJcrNodeElem; -import org.argeo.jcr.ui.explorer.model.WorkspaceElem; -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.ui.handlers.HandlerUtil; - -/** Opens the generic node editor. */ -public class GetNodeSize extends AbstractHandler { - // private final static Log log = LogFactory.getLog(GetNodeSize.class); - - public final static String ID = JcrExplorerPlugin.ID + ".getNodeSize"; - - // public final static String DEFAULT_ICON_REL_PATH = "icons/getSize.gif"; - // public final static String DEFAULT_LABEL = JcrExplorerPlugin - // .getMessage("getNodeSizeCmdLbl"); - - public Object execute(ExecutionEvent event) throws ExecutionException { - // JcrUtils.getRepositoryByAlias(repositoryRegister, - // ArgeoJcrConstants.ALIAS_NODE); - - ISelection selection = HandlerUtil.getActiveWorkbenchWindow(event) - .getActivePage().getSelection(); - - if (selection != null && !selection.isEmpty() - && selection instanceof IStructuredSelection) { - - // IStructuredSelection iss = (IStructuredSelection) selection; - // if (iss.size() > 1) - // ErrorFeedback.show(JcrExplorerPlugin - // .getMessage("warningInvalidMultipleSelection"), null); - - long size = 0; - - Iterator it = ((IStructuredSelection) selection).iterator(); - - // as the size method is recursive, we keep track of nodes for which - // we already have computed size so that we don't count them twice. - // In a first approximation, we assume that the structure selection - // keep the nodes ordered. - // TODO : enhance that. - List importedPathes = new ArrayList(); - try { - nodesIt: while (it.hasNext()) { - Object obj = it.next(); - String curPath; - Node node; - if (obj instanceof SingleJcrNodeElem) { - node = ((SingleJcrNodeElem) obj).getNode(); - curPath = node.getSession().getWorkspace().getName(); - curPath += "/" + node.getPath(); - } else if (obj instanceof WorkspaceElem) { - node = ((WorkspaceElem) obj).getRootNode(); - curPath = node.getSession().getWorkspace().getName(); - } else - // unvalid object type - continue nodesIt; - - Iterator itPath = importedPathes.iterator(); - while (itPath.hasNext()) { - String refPath = itPath.next(); - if (curPath.startsWith(refPath)) - // Already done : skip node - continue nodesIt; - } - size += JcrUtils.getNodeApproxSize(node); - importedPathes.add(curPath); - } - } catch (Exception e) { - ErrorFeedback.show("Cannot Get size of selected node ", e); - } - - String[] labels = { "OK" }; - Shell shell = HandlerUtil.getActiveWorkbenchWindow(event) - .getShell(); - MessageDialog md = new MessageDialog(shell, "Node size", null, - "Node size is: " + size / 1024 + " KB", - MessageDialog.INFORMATION, labels, 0); - md.open(); - } - return null; - } -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/ImportFileSystem.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/ImportFileSystem.java deleted file mode 100644 index 5c4bf7e6b..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/ImportFileSystem.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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.jcr.ui.explorer.commands; - -import javax.jcr.Node; - -import org.argeo.eclipse.ui.ErrorFeedback; -import org.argeo.eclipse.ui.TreeParent; -import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; -import org.argeo.jcr.ui.explorer.model.SingleJcrNodeElem; -import org.argeo.jcr.ui.explorer.model.WorkspaceElem; -import org.argeo.jcr.ui.explorer.views.GenericJcrBrowser; -import org.argeo.jcr.ui.explorer.wizards.ImportFileSystemWizard; -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.wizard.WizardDialog; -import org.eclipse.ui.handlers.HandlerUtil; - -/** Import a local file system directory tree. */ -public class ImportFileSystem extends AbstractHandler { - public Object execute(ExecutionEvent event) throws ExecutionException { - ISelection selection = HandlerUtil.getActiveWorkbenchWindow(event) - .getActivePage().getSelection(); - GenericJcrBrowser view = (GenericJcrBrowser) HandlerUtil - .getActiveWorkbenchWindow(event).getActivePage() - .findView(HandlerUtil.getActivePartId(event)); - if (selection != null && !selection.isEmpty() - && selection instanceof IStructuredSelection) { - Object obj = ((IStructuredSelection) selection).getFirstElement(); - try { - Node folder = null; - if (obj instanceof SingleJcrNodeElem) { - folder = ((SingleJcrNodeElem) obj).getNode(); - } else if (obj instanceof WorkspaceElem) { - folder = ((WorkspaceElem) obj).getRootNode(); - } else { - ErrorFeedback.show(JcrExplorerPlugin - .getMessage("warningInvalidNodeToImport")); - } - if (folder != null) { - ImportFileSystemWizard wizard = new ImportFileSystemWizard( - folder); - WizardDialog dialog = new WizardDialog( - HandlerUtil.getActiveShell(event), wizard); - dialog.open(); - view.nodeAdded((TreeParent) obj); - } - } catch (Exception e) { - ErrorFeedback.show("Cannot import files to " + obj, e); - } - } - return null; - } -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/OpenGenericNodeEditor.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/OpenGenericNodeEditor.java deleted file mode 100644 index 6799d1706..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/OpenGenericNodeEditor.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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.jcr.ui.explorer.commands; - -import org.argeo.ArgeoException; -import org.argeo.eclipse.ui.jcr.editors.NodeEditorInput; -import org.argeo.jcr.ui.explorer.JcrExplorerConstants; -import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; -import org.argeo.jcr.ui.explorer.editors.GenericNodeEditor; -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import org.eclipse.ui.handlers.HandlerUtil; - -/** Opens the generic node editor. */ -public class OpenGenericNodeEditor extends AbstractHandler { - public final static String ID = JcrExplorerPlugin.ID + ".openGenericNodeEditor"; - - public Object execute(ExecutionEvent event) throws ExecutionException { - String path = event.getParameter(JcrExplorerConstants.PARAM_PATH); - try { - NodeEditorInput nei = new NodeEditorInput(path); - HandlerUtil.getActiveWorkbenchWindow(event).getActivePage() - .openEditor(nei, GenericNodeEditor.ID); - } catch (Exception e) { - throw new ArgeoException("Cannot open editor", e); - } - return null; - } - -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/Refresh.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/Refresh.java deleted file mode 100644 index 21ce25658..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/Refresh.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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.jcr.ui.explorer.commands; - -import java.util.Iterator; - -import org.argeo.eclipse.ui.TreeParent; -import org.argeo.eclipse.ui.jcr.views.AbstractJcrBrowser; -import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; -import org.argeo.jcr.ui.explorer.utils.JcrUiUtils; -import org.argeo.jcr.ui.explorer.views.GenericJcrBrowser; -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredSelection; - -/** - * Force the selected objects of the active view to be refreshed doing the - * following: - *
    - *
  1. The model objects are recomputed
  2. - *
  3. the view is refreshed
  4. - *
- */ -public class Refresh extends AbstractHandler { - - public final static String ID = JcrExplorerPlugin.ID + ".refresh"; - - public Object execute(ExecutionEvent event) throws ExecutionException { - - AbstractJcrBrowser view = (AbstractJcrBrowser) JcrExplorerPlugin - .getDefault().getWorkbench().getActiveWorkbenchWindow() - .getActivePage().getActivePart();// - - ISelection selection = JcrExplorerPlugin.getDefault().getWorkbench() - .getActiveWorkbenchWindow().getActivePage().getSelection(); - - if (selection != null && selection instanceof IStructuredSelection - && !selection.isEmpty()) { - Iterator it = ((IStructuredSelection) selection).iterator(); - while (it.hasNext()) { - Object obj = it.next(); - if (obj instanceof TreeParent) { - TreeParent tp = (TreeParent) obj; - JcrUiUtils.forceRefreshIfNeeded(tp); - view.refresh(obj); - } - } - } else if (view instanceof GenericJcrBrowser) - ((GenericJcrBrowser) view).refresh(null); // force full refresh - - return null; - } -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/RemoveRemoteRepository.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/RemoveRemoteRepository.java deleted file mode 100644 index ec23dd08c..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/RemoveRemoteRepository.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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.jcr.ui.explorer.commands; - -import org.argeo.jcr.ui.explorer.model.RemoteRepositoryElem; -import org.argeo.jcr.ui.explorer.views.GenericJcrBrowser; -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.ui.handlers.HandlerUtil; - -/** Remove a registered remote repository */ -public class RemoveRemoteRepository extends AbstractHandler { - - public Object execute(ExecutionEvent event) throws ExecutionException { - - ISelection selection = HandlerUtil.getActiveWorkbenchWindow(event) - .getActivePage().getSelection(); - - GenericJcrBrowser view = (GenericJcrBrowser) HandlerUtil - .getActiveWorkbenchWindow(event).getActivePage() - .findView(HandlerUtil.getActivePartId(event)); - - if (selection != null && !selection.isEmpty() - && selection instanceof IStructuredSelection) { - Object obj = ((IStructuredSelection) selection).getFirstElement(); - - if (obj instanceof RemoteRepositoryElem) { - ((RemoteRepositoryElem) obj).remove(); - view.refresh(null); - } - } - return null; - } - -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/SortChildNodes.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/SortChildNodes.java deleted file mode 100644 index 2961529d8..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/commands/SortChildNodes.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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.jcr.ui.explorer.commands; - -import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; -import org.argeo.jcr.ui.explorer.views.GenericJcrBrowser; -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.Command; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import org.eclipse.core.commands.State; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.commands.ICommandService; -import org.eclipse.ui.handlers.HandlerUtil; - -/** - * Change isSorted state of the JcrExplorer Browser - */ -public class SortChildNodes extends AbstractHandler { - public final static String ID = JcrExplorerPlugin.ID + ".sortChildNodes"; - - public Object execute(ExecutionEvent event) throws ExecutionException { - GenericJcrBrowser view = (GenericJcrBrowser) HandlerUtil - .getActiveWorkbenchWindow(event).getActivePage() - .findView(GenericJcrBrowser.ID); - - ICommandService service = (ICommandService) PlatformUI.getWorkbench() - .getService(ICommandService.class); - Command command = service.getCommand(ID); - State state = command.getState(ID + ".toggleState"); - - boolean wasSorted = (Boolean) state.getValue(); - view.setSortChildNodes(!wasSorted); - state.setValue(!wasSorted); - return null; - } -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/dialogs/ChooseNameDialog.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/dialogs/ChooseNameDialog.java deleted file mode 100644 index d4a5cc757..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/dialogs/ChooseNameDialog.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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.jcr.ui.explorer.dialogs; - -import org.eclipse.jface.dialogs.IMessageProvider; -import org.eclipse.jface.dialogs.TitleAreaDialog; -import org.eclipse.swt.SWT; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Text; - -/** Dialog to change the current user password */ -public class ChooseNameDialog extends TitleAreaDialog { - private Text nameT; - - public ChooseNameDialog(Shell parentShell) { - super(parentShell); - setTitle("Choose name"); - } - - protected Point getInitialSize() { - return new Point(300, 250); - } - - protected Control createDialogArea(Composite parent) { - Composite dialogarea = (Composite) super.createDialogArea(parent); - dialogarea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - Composite composite = new Composite(dialogarea, SWT.NONE); - composite.setLayout(new GridLayout(2, false)); - composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); - nameT = createLT(composite, "Name"); - - setMessage("Choose name", IMessageProvider.INFORMATION); - parent.pack(); - return composite; - } - - /** Creates label and text. */ - protected Text createLT(Composite parent, String label) { - new Label(parent, SWT.NONE).setText(label); - Text text = new Text(parent, SWT.SINGLE | SWT.LEAD | SWT.BORDER); - text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); - return text; - } - - public String getName() { - return nameT.getText(); - } -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/editors/ChildNodesPage.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/editors/ChildNodesPage.java deleted file mode 100644 index 682254a48..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/editors/ChildNodesPage.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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.jcr.ui.explorer.editors; - -import javax.jcr.Node; - -import org.argeo.ArgeoException; -import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; -import org.argeo.jcr.ui.explorer.browser.NodeLabelProvider; -import org.argeo.jcr.ui.explorer.providers.SingleNodeAsTreeContentProvider; -import org.argeo.jcr.ui.explorer.utils.GenericNodeDoubleClickListener; -import org.eclipse.jface.viewers.ITreeContentProvider; -import org.eclipse.jface.viewers.TreeViewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.editor.FormEditor; -import org.eclipse.ui.forms.editor.FormPage; -import org.eclipse.ui.forms.widgets.ScrolledForm; - -/** - * List all childs of the current node and brings some browsing capabilities - * accross the repository - */ -public class ChildNodesPage extends FormPage { - // private final static Log log = LogFactory.getLog(ChildNodesPage.class); - - // business objects - private Node currentNode; - - // this page UI components - private SingleNodeAsTreeContentProvider nodeContentProvider; - private TreeViewer nodesViewer; - - public ChildNodesPage(FormEditor editor, String title, Node currentNode) { - super(editor, "ChildNodesPage", title); - this.currentNode = currentNode; - } - - protected void createFormContent(IManagedForm managedForm) { - try { - ScrolledForm form = managedForm.getForm(); - form.setText(JcrExplorerPlugin.getMessage("childNodesPageTitle")); - Composite body = form.getBody(); - GridLayout twt = new GridLayout(1, false); - twt.marginWidth = twt.marginHeight = 5; - body.setLayout(twt); - if (!currentNode.hasNodes()) { - managedForm.getToolkit().createLabel(body, - JcrExplorerPlugin.getMessage("warningNoChildNode")); - } else { - - nodeContentProvider = new SingleNodeAsTreeContentProvider(); - nodesViewer = createNodeViewer(body, nodeContentProvider); - nodesViewer.setInput(currentNode); - } - } catch (Exception e) { - throw new ArgeoException( - "Unexpected error while creating child node page", e); - } - } - - 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 - .addDoubleClickListener(new GenericNodeDoubleClickListener( - tmpNodeViewer)); - return tmpNodeViewer; - } -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/editors/EmptyNodePage.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/editors/EmptyNodePage.java deleted file mode 100644 index 322c7ebd2..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/editors/EmptyNodePage.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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.jcr.ui.explorer.editors; - -import org.eclipse.swt.SWT; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Label; -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.editor.FormEditor; -import org.eclipse.ui.forms.editor.FormPage; -import org.eclipse.ui.forms.widgets.ScrolledForm; - -/** - * This page is only used at editor's creation time when current node has not - * yet been set - */ -public class EmptyNodePage extends FormPage { - // private final static Log log = LogFactory.getLog(EmptyNodePage.class); - - public EmptyNodePage(FormEditor editor, String title) { - super(editor, "Empty Page", title); - } - - protected void createFormContent(IManagedForm managedForm) { - try { - ScrolledForm form = managedForm.getForm(); - GridLayout twt = new GridLayout(1, false); - twt.marginWidth = twt.marginHeight = 0; - form.getBody().setLayout(twt); - Label lbl = new Label(form.getBody(), SWT.NONE); - lbl.setText("Empty page"); - } catch (Exception e) { - e.printStackTrace(); - } - } -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/editors/GenericJcrQueryEditor.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/editors/GenericJcrQueryEditor.java deleted file mode 100644 index 3b98ed137..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/editors/GenericJcrQueryEditor.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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.jcr.ui.explorer.editors; - -import org.argeo.eclipse.ui.jcr.editors.AbstractJcrQueryEditor; -import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; -import org.eclipse.swt.SWT; -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.Event; -import org.eclipse.swt.widgets.Listener; -import org.eclipse.swt.widgets.Text; - -/** Enables end user to type and execute any JCR query. */ -public class GenericJcrQueryEditor extends AbstractJcrQueryEditor { - public final static String ID = JcrExplorerPlugin.ID + ".genericJcrQueryEditor"; - - private Text queryField; - - @Override - public void createQueryForm(Composite parent) { - parent.setLayout(new GridLayout(1, false)); - - queryField = new Text(parent, SWT.BORDER | SWT.MULTI | SWT.WRAP); - queryField.setText(initialQuery); - queryField.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - - Button execute = new Button(parent, SWT.PUSH); - execute.setText("Execute"); - - Listener executeListener = new Listener() { - public void handleEvent(Event event) { - executeQuery(queryField.getText()); - } - }; - - execute.addListener(SWT.Selection, executeListener); - // queryField.addListener(SWT.DefaultSelection, executeListener); - } - - @Override - public void setFocus() { - queryField.setFocus(); - } -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/editors/GenericNodeEditor.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/editors/GenericNodeEditor.java deleted file mode 100644 index 57f3aa236..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/editors/GenericNodeEditor.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * 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.jcr.ui.explorer.editors; - -import javax.jcr.Node; - -import org.argeo.ArgeoException; -import org.argeo.jcr.JcrUtils; -import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.ui.IEditorInput; -import org.eclipse.ui.IEditorSite; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.forms.editor.FormEditor; - -/** - * Container for the node editor page. At creation time, it takes a JCR Node - * that cannot be changed afterwards. - */ -public class GenericNodeEditor extends FormEditor { - - // private final static Log log = - // LogFactory.getLog(GenericNodeEditor.class); - public final static String ID = JcrExplorerPlugin.ID + ".genericNodeEditor"; - - private Node currentNode; - - private GenericPropertyPage genericPropertyPage; - private ChildNodesPage childNodesPage; - private NodeRightsManagementPage nodeRightsManagementPage; - private NodeVersionHistoryPage nodeVersionHistoryPage; - - public void init(IEditorSite site, IEditorInput input) - throws PartInitException { - super.init(site, input); - GenericNodeEditorInput nei = (GenericNodeEditorInput) getEditorInput(); - currentNode = nei.getCurrentNode(); - this.setPartName(JcrUtils.lastPathElement(nei.getPath())); - } - - @Override - protected void addPages() { - try { - // genericNodePage = new GenericNodePage(this, - // JcrExplorerPlugin.getMessage("genericNodePageTitle"), - // currentNode); - // addPage(genericNodePage); - - genericPropertyPage = new GenericPropertyPage(this, - JcrExplorerPlugin.getMessage("genericNodePageTitle"), - currentNode); - addPage(genericPropertyPage); - - childNodesPage = new ChildNodesPage(this, - JcrExplorerPlugin.getMessage("childNodesPageTitle"), - currentNode); - addPage(childNodesPage); - - nodeRightsManagementPage = new NodeRightsManagementPage(this, - JcrExplorerPlugin - .getMessage("nodeRightsManagementPageTitle"), - currentNode); - addPage(nodeRightsManagementPage); - - nodeVersionHistoryPage = new NodeVersionHistoryPage( - this, - JcrExplorerPlugin.getMessage("nodeVersionHistoryPageTitle"), - currentNode); - addPage(nodeVersionHistoryPage); - } catch (PartInitException e) { - throw new ArgeoException("Not able to add an empty page ", e); - } - } - - @Override - public void doSaveAs() { - // unused compulsory method - } - - @Override - public void doSave(IProgressMonitor monitor) { - try { - // Automatically commit all pages of the editor - commitPages(true); - firePropertyChange(PROP_DIRTY); - } catch (Exception e) { - throw new ArgeoException("Error while saving node", e); - } - - } - - @Override - public boolean isSaveAsAllowed() { - return true; - } - - Node getCurrentNode() { - return currentNode; - } -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/editors/GenericNodeEditorInput.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/editors/GenericNodeEditorInput.java deleted file mode 100644 index 45e337e5d..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/editors/GenericNodeEditorInput.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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.jcr.ui.explorer.editors; - -import javax.jcr.Node; -import javax.jcr.RepositoryException; - -import org.argeo.ArgeoException; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.ui.IEditorInput; -import org.eclipse.ui.IPersistableElement; - -/** - * An editor input based the JCR node object. - * */ - -public class GenericNodeEditorInput implements IEditorInput { - private final Node currentNode; - - // cache key properties at creation time to avoid Exception at recoring time - // when the session has been closed - private String path; - private String uid; - private String name; - - public GenericNodeEditorInput(Node currentNode) { - this.currentNode = currentNode; - try { - name = currentNode.getName(); - uid = currentNode.getIdentifier(); - path = currentNode.getPath(); - } catch (RepositoryException re) { - throw new ArgeoException( - "unexpected error while getting node key values at creation time", - re); - } - } - - public Node getCurrentNode() { - return currentNode; - } - - public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) { - return null; - } - - public boolean exists() { - return true; - } - - public ImageDescriptor getImageDescriptor() { - return null; - } - - public String getName() { - return name; - } - - public String getUid() { - return uid; - } - - public String getToolTipText() { - return path; - } - - public String getPath() { - return path; - } - - public IPersistableElement getPersistable() { - return null; - } - - /** - * equals method based on UID that is unique within a workspace and path of - * the node, thus 2 shared node that have same UID as defined in the spec - * but 2 different pathes will open two distinct editors. - * - * TODO enhance this method to support multirepository and multiworkspace - * environments - */ - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - - GenericNodeEditorInput other = (GenericNodeEditorInput) obj; - if (!getUid().equals(other.getUid())) - return false; - if (!getPath().equals(other.getPath())) - return false; - return true; - } -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/editors/GenericNodePage.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/editors/GenericNodePage.java deleted file mode 100644 index fd4dafe76..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/editors/GenericNodePage.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * 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.jcr.ui.explorer.editors; - -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.ListIterator; - -import javax.jcr.Node; -import javax.jcr.Property; -import javax.jcr.PropertyIterator; -import javax.jcr.PropertyType; -import javax.jcr.RepositoryException; - -import org.argeo.ArgeoException; -import org.argeo.jcr.JcrUtils; -import org.argeo.jcr.ui.explorer.JcrExplorerConstants; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.forms.AbstractFormPart; -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.editor.FormEditor; -import org.eclipse.ui.forms.editor.FormPage; -import org.eclipse.ui.forms.widgets.FormToolkit; -import org.eclipse.ui.forms.widgets.ScrolledForm; - -/** - * Main node editor page. Lists all properties of the current node and enable - * access and editing for some of them. - */ - -public class GenericNodePage extends FormPage implements JcrExplorerConstants { - // private final static Log log = LogFactory.getLog(GenericNodePage.class); - - // local constants - private final static String JCR_PROPERTY_NAME = "jcr:name"; - - // Utils - protected DateFormat timeFormatter = new SimpleDateFormat(DATE_TIME_FORMAT); - - // Main business Objects - private Node currentNode; - - // This page widgets - private FormToolkit tk; - private List modifyableProperties = new ArrayList(); - - public GenericNodePage(FormEditor editor, String title, Node currentNode) { - super(editor, "id", title); - this.currentNode = currentNode; - } - - protected void createFormContent(IManagedForm managedForm) { - tk = managedForm.getToolkit(); - ScrolledForm form = managedForm.getForm(); - GridLayout twt = new GridLayout(3, false); - twt.marginWidth = twt.marginHeight = 5; - - form.getBody().setLayout(twt); - createPropertiesPart(form.getBody()); - } - - private void createPropertiesPart(Composite parent) { - try { - - PropertyIterator pi = currentNode.getProperties(); - - // Initializes form part - AbstractFormPart part = new AbstractFormPart() { - public void commit(boolean onSave) { - try { - if (onSave) { - ListIterator it = modifyableProperties - .listIterator(); - while (it.hasNext()) { - // we only support Text controls for the time - // being - Text curControl = (Text) it.next(); - String value = curControl.getText(); - currentNode.setProperty((String) curControl - .getData(JCR_PROPERTY_NAME), value); - } - - // We only commit when onSave = true, - // thus it is still possible to save after a tab - // change. - super.commit(onSave); - } - } catch (RepositoryException re) { - throw new ArgeoException( - "Unexpected error while saving properties", re); - } - } - }; - - while (pi.hasNext()) { - Property prop = pi.nextProperty(); - addPropertyLine(parent, part, prop); - } - - getManagedForm().addPart(part); - } catch (RepositoryException re) { - throw new ArgeoException( - "Error during creation of network details section", re); - } - - } - - private void addPropertyLine(Composite parent, AbstractFormPart part, - Property prop) { - try { - tk.createLabel(parent, prop.getName()); - tk.createLabel(parent, - "[" + JcrUtils.getPropertyDefinitionAsString(prop) + "]"); - - if (prop.getDefinition().isProtected()) { - tk.createLabel(parent, formatReadOnlyPropertyValue(prop)); - } else - addModifyableValueWidget(parent, part, prop); - } catch (RepositoryException re) { - throw new ArgeoException("Cannot get property " + prop, re); - } - } - - private String formatReadOnlyPropertyValue(Property prop) { - try { - String strValue; - - if (prop.getType() == PropertyType.BINARY) - strValue = ""; - else if (prop.isMultiple()) - strValue = Arrays.asList(prop.getValues()).toString(); - else if (prop.getType() == PropertyType.DATE) - strValue = timeFormatter.format(prop.getValue().getDate() - .getTime()); - else - strValue = prop.getValue().getString(); - - return strValue; - } catch (RepositoryException re) { - throw new ArgeoException( - "Unexpected error while formatting read only property value", - re); - } - } - - private Control addModifyableValueWidget(Composite parent, - AbstractFormPart part, Property prop) { - GridData gd; - try { - if (prop.getType() == PropertyType.STRING) { - Text txt = tk.createText(parent, prop.getString()); - gd = new GridData(GridData.FILL_HORIZONTAL); - txt.setLayoutData(gd); - txt.addModifyListener(new ModifiedFieldListener(part)); - txt.setData(JCR_PROPERTY_NAME, prop.getName()); - modifyableProperties.add(txt); - } else { - // unsupported property type for editing, we create a read only - // label. - return tk - .createLabel(parent, formatReadOnlyPropertyValue(prop)); - } - return null; - } catch (RepositoryException re) { - throw new ArgeoException( - "Unexpected error while formatting read only property value", - re); - } - - } - - // - // LISTENERS - // - - private class ModifiedFieldListener implements ModifyListener { - - private AbstractFormPart formPart; - - public ModifiedFieldListener(AbstractFormPart generalPart) { - this.formPart = generalPart; - } - - public void modifyText(ModifyEvent e) { - formPart.markDirty(); - } - } - -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/editors/GenericPropertyPage.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/editors/GenericPropertyPage.java deleted file mode 100644 index 3aec4538c..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/editors/GenericPropertyPage.java +++ /dev/null @@ -1,306 +0,0 @@ -/* - * 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.jcr.ui.explorer.editors; - -import java.util.ArrayList; -import java.util.List; - -import javax.jcr.Node; -import javax.jcr.Property; -import javax.jcr.PropertyIterator; -import javax.jcr.RepositoryException; -import javax.jcr.Value; - -import org.argeo.ArgeoException; -import org.argeo.jcr.ui.explorer.JcrExplorerConstants; -import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; -import org.argeo.jcr.ui.explorer.providers.PropertyLabelProvider; -import org.eclipse.jface.viewers.ITreeContentProvider; -import org.eclipse.jface.viewers.TreeViewer; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.layout.FillLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Tree; -import org.eclipse.swt.widgets.TreeColumn; -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.editor.FormEditor; -import org.eclipse.ui.forms.editor.FormPage; -import org.eclipse.ui.forms.widgets.ScrolledForm; - -/** - * Generic editor property page. Lists all properties of current node as a - * complex tree. TODO: enable editing - */ - -public class GenericPropertyPage extends FormPage implements - JcrExplorerConstants { - // private final static Log log = - // LogFactory.getLog(GenericPropertyPage.class); - - // Main business Objects - private Node currentNode; - - public GenericPropertyPage(FormEditor editor, String title, Node currentNode) { - super(editor, "id", title); - this.currentNode = currentNode; - } - - protected void createFormContent(IManagedForm managedForm) { - ScrolledForm form = managedForm.getForm(); - form.setText(JcrExplorerPlugin.getMessage("genericNodePageTitle")); - FillLayout layout = new FillLayout(); - layout.marginHeight = 5; - layout.marginWidth = 5; - form.getBody().setLayout(layout); - - createComplexTree(form.getBody()); - - // TODO remove following - // createPropertiesPart(form.getBody()); - } - - private TreeViewer createComplexTree(Composite parent) { - int style = SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION; - Tree tree = new Tree(parent, style); - createColumn(tree, "Property", SWT.LEFT, 200); - createColumn(tree, "Value(s)", SWT.LEFT, 300); - createColumn(tree, "Attributes", SWT.LEFT, 65); - tree.setLinesVisible(true); - tree.setHeaderVisible(true); - - TreeViewer result = new TreeViewer(tree); - result.setContentProvider(new TreeContentProvider()); - result.setLabelProvider(new PropertyLabelProvider()); - result.setInput(currentNode); - result.expandAll(); - return result; - } - - private static TreeColumn createColumn(Tree parent, String name, int style, - int width) { - TreeColumn result = new TreeColumn(parent, style); - result.setText(name); - result.setWidth(width); - result.setMoveable(true); - result.setResizable(true); - return result; - } - - // - // private void createPropertiesPart(Composite parent) { - // try { - // - // PropertyIterator pi = currentNode.getProperties(); - // - // // Initializes form part - // AbstractFormPart part = new AbstractFormPart() { - // public void commit(boolean onSave) { - // try { - // if (onSave) { - // ListIterator it = modifyableProperties - // .listIterator(); - // while (it.hasNext()) { - // // we only support Text controls for the time - // // being - // Text curControl = (Text) it.next(); - // String value = curControl.getText(); - // currentNode.setProperty((String) curControl - // .getData(JCR_PROPERTY_NAME), value); - // } - // - // // We only commit when onSave = true, - // // thus it is still possible to save after a tab - // // change. - // super.commit(onSave); - // } - // } catch (RepositoryException re) { - // throw new ArgeoException( - // "Unexpected error while saving properties", re); - // } - // } - // }; - // - // while (pi.hasNext()) { - // Property prop = pi.nextProperty(); - // addPropertyLine(parent, part, prop); - // } - // - // getManagedForm().addPart(part); - // } catch (RepositoryException re) { - // throw new ArgeoException( - // "Error during creation of network details section", re); - // } - // - // } - // - // private void addPropertyLine(Composite parent, AbstractFormPart part, - // Property prop) { - // try { - // tk.createLabel(parent, prop.getName()); - // tk.createLabel(parent, - // "[" + JcrUtils.getPropertyDefinitionAsString(prop) + "]"); - // - // if (prop.getDefinition().isProtected()) { - // tk.createLabel(parent, formatReadOnlyPropertyValue(prop)); - // } else - // addModifyableValueWidget(parent, part, prop); - // } catch (RepositoryException re) { - // throw new ArgeoException("Cannot get property " + prop, re); - // } - // } - // - // private String formatReadOnlyPropertyValue(Property prop) { - // try { - // String strValue; - // - // if (prop.getType() == PropertyType.BINARY) - // strValue = ""; - // else if (prop.isMultiple()) - // strValue = Arrays.asList(prop.getValues()).toString(); - // else if (prop.getType() == PropertyType.DATE) - // strValue = timeFormatter.format(prop.getValue().getDate() - // .getTime()); - // else - // strValue = prop.getValue().getString(); - // - // return strValue; - // } catch (RepositoryException re) { - // throw new ArgeoException( - // "Unexpected error while formatting read only property value", - // re); - // } - // } - // - // private Control addModifyableValueWidget(Composite parent, - // AbstractFormPart part, Property prop) { - // GridData gd; - // try { - // if (prop.getType() == PropertyType.STRING) { - // Text txt = tk.createText(parent, prop.getString()); - // gd = new GridData(GridData.FILL_HORIZONTAL); - // txt.setLayoutData(gd); - // txt.addModifyListener(new ModifiedFieldListener(part)); - // txt.setData(JCR_PROPERTY_NAME, prop.getName()); - // modifyableProperties.add(txt); - // } else { - // // unsupported property type for editing, we create a read only - // // label. - // return tk - // .createLabel(parent, formatReadOnlyPropertyValue(prop)); - // } - // return null; - // } catch (RepositoryException re) { - // throw new ArgeoException( - // "Unexpected error while formatting read only property value", - // re); - // } - // - // } - - // Multiple Value Model - // protected class MultipleValueItem { - // private int index; - // private Value value; - // - // public MultipleValueItem(int index, Value value) { - // this.index = index; - // this.value = value; - // } - // - // public int getIndex() { - // return index; - // } - // - // public Object getValue() { - // return value; - // } - // } - - private class TreeContentProvider implements ITreeContentProvider { - public Object[] getElements(Object parent) { - Object[] props = null; - try { - - if (parent instanceof Node) { - Node node = (Node) parent; - PropertyIterator pi; - pi = node.getProperties(); - List propList = new ArrayList(); - while (pi.hasNext()) { - propList.add(pi.nextProperty()); - } - props = propList.toArray(); - } - } catch (RepositoryException e) { - throw new ArgeoException( - "Unexpected exception while listing node properties", e); - } - return props; - } - - public Object getParent(Object child) { - return null; - } - - public Object[] getChildren(Object parent) { - Object[] result = null; - if (parent instanceof Property) { - Property prop = (Property) parent; - try { - - if (prop.isMultiple()) { - Value[] values = prop.getValues(); - // List list = new - // ArrayList(); - // for (int i = 0; i < values.length; i++) { - // MultipleValueItem mvi = new MultipleValueItem(i, - // values[i]); - // list.add(mvi); - // } - - return values; - } - } catch (RepositoryException e) { - throw new ArgeoException( - "Unexpected error getting multiple values property.", - e); - } - } - return result; - } - - public boolean hasChildren(Object parent) { - try { - if (parent instanceof Property - && ((Property) parent).isMultiple()) { - return true; - } - } catch (RepositoryException e) { - throw new ArgeoException( - "Unexpected exception while checking if property is multiple", - e); - } - return false; - } - - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - } - - public void dispose() { - } - } -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/editors/NodeRightsManagementPage.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/editors/NodeRightsManagementPage.java deleted file mode 100644 index cc5efb5f9..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/editors/NodeRightsManagementPage.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * 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.jcr.ui.explorer.editors; - -import javax.jcr.Node; -import javax.jcr.security.AccessControlManager; -import javax.jcr.security.Privilege; - -import org.argeo.ArgeoException; -import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; -import org.eclipse.jface.viewers.ColumnLabelProvider; -import org.eclipse.jface.viewers.IStructuredContentProvider; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.jface.viewers.TableViewerColumn; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.layout.FillLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableColumn; -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.editor.FormEditor; -import org.eclipse.ui.forms.editor.FormPage; -import org.eclipse.ui.forms.widgets.ScrolledForm; - -/** - * This comments will be nicely fill by mbaudier in. - */ -public class NodeRightsManagementPage extends FormPage { - // private final static Log log = - // LogFactory.getLog(NodeRightsManagementPage.class); - - private Node currentNode; - - private TableViewer viewer; - - public NodeRightsManagementPage(FormEditor editor, String title, - Node currentNode) { - super(editor, "NodeRightsManagementPage", title); - this.currentNode = currentNode; - } - - protected void createFormContent(IManagedForm managedForm) { - ScrolledForm form = managedForm.getForm(); - form.setText(JcrExplorerPlugin - .getMessage("nodeRightsManagementPageTitle")); - FillLayout layout = new FillLayout(); - layout.marginHeight = 5; - layout.marginWidth = 5; - form.getBody().setLayout(layout); - createRightsPart(form.getBody()); - } - - /** Creates the rights part */ - protected void createRightsPart(Composite parent) { - Table table = new Table(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); - table.setLinesVisible(true); - table.setHeaderVisible(true); - viewer = new TableViewer(table); - - // check column - TableViewerColumn column = createTableViewerColumn(viewer, "checked", - 20); - column.setLabelProvider(new ColumnLabelProvider() { - public String getText(Object element) { - return null; - } - - public Image getImage(Object element) { - return null; - } - }); - // column.setEditingSupport(new RoleEditingSupport(rolesViewer, part)); - - // role column - column = createTableViewerColumn(viewer, "Role", 200); - column.setLabelProvider(new ColumnLabelProvider() { - public String getText(Object element) { - Privilege p = (Privilege) element; - return p.getName(); - } - - public Image getImage(Object element) { - return null; - } - }); - viewer.setContentProvider(new RightsContentProvider()); - viewer.setInput(getEditorSite()); - } - - protected TableViewerColumn createTableViewerColumn(TableViewer viewer, - String title, int bound) { - final TableViewerColumn viewerColumn = new TableViewerColumn(viewer, - SWT.NONE); - final TableColumn column = viewerColumn.getColumn(); - column.setText(title); - column.setWidth(bound); - column.setResizable(true); - column.setMoveable(true); - return viewerColumn; - } - - private class RightsContentProvider implements IStructuredContentProvider { - - public void dispose() { - } - - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - } - - public Object[] getElements(Object inputElement) { - try { - AccessControlManager accessControlManager = currentNode - .getSession().getAccessControlManager(); - Privilege[] privileges = accessControlManager - .getPrivileges(currentNode.getPath()); - return privileges; - } catch (Exception e) { - throw new ArgeoException("Cannot retrieve rights", e); - } - } - - } -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/editors/NodeVersionHistoryPage.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/editors/NodeVersionHistoryPage.java deleted file mode 100644 index 59fff5e59..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/editors/NodeVersionHistoryPage.java +++ /dev/null @@ -1,319 +0,0 @@ -/* - * 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.jcr.ui.explorer.editors; - -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.List; -import java.util.Map; - -import javax.jcr.Node; -import javax.jcr.Property; -import javax.jcr.PropertyType; -import javax.jcr.RepositoryException; -import javax.jcr.Value; -import javax.jcr.nodetype.NodeType; -import javax.jcr.version.Version; -import javax.jcr.version.VersionHistory; -import javax.jcr.version.VersionIterator; -import javax.jcr.version.VersionManager; - -import org.argeo.ArgeoException; -import org.argeo.jcr.JcrUtils; -import org.argeo.jcr.PropertyDiff; -import org.argeo.jcr.VersionDiff; -import org.argeo.jcr.ui.explorer.JcrExplorerConstants; -import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; -import org.argeo.jcr.ui.explorer.providers.FullVersioningTreeContentProvider; -import org.argeo.jcr.ui.explorer.providers.VersionLabelProvider; -import org.argeo.jcr.ui.explorer.utils.GenericNodeDoubleClickListener; -import org.eclipse.jface.viewers.ITreeContentProvider; -import org.eclipse.jface.viewers.TreeViewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.forms.AbstractFormPart; -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.editor.FormEditor; -import org.eclipse.ui.forms.editor.FormPage; -import org.eclipse.ui.forms.widgets.FormToolkit; -import org.eclipse.ui.forms.widgets.ScrolledForm; -import org.eclipse.ui.forms.widgets.Section; -import org.eclipse.ui.forms.widgets.TableWrapData; -import org.eclipse.ui.forms.widgets.TableWrapLayout; - -/** - * Offers two main sections : one to display a text area with a summary of all - * variations between a version and its predecessor and one tree view that - * enable browsing - * */ -public class NodeVersionHistoryPage extends FormPage implements - JcrExplorerConstants { - // private final static Log log = LogFactory - // .getLog(NodeVersionHistoryPage.class); - - // Utils - protected DateFormat timeFormatter = new SimpleDateFormat(DATE_TIME_FORMAT); - - // business objects - private Node currentNode; - - // this page UI components - private FullVersioningTreeContentProvider nodeContentProvider; - private TreeViewer nodesViewer; - private FormToolkit tk; - - public NodeVersionHistoryPage(FormEditor editor, String title, - Node currentNode) { - super(editor, "NodeVersionHistoryPage", title); - this.currentNode = currentNode; - } - - protected void createFormContent(IManagedForm managedForm) { - ScrolledForm form = managedForm.getForm(); - form.setText(JcrExplorerPlugin - .getMessage("nodeVersionHistoryPageTitle")); - tk = managedForm.getToolkit(); - GridLayout twt = new GridLayout(1, false); - twt.marginWidth = twt.marginHeight = 5; - Composite body = form.getBody(); - body.setLayout(twt); - - try { - if (!currentNode.isNodeType(NodeType.MIX_VERSIONABLE)) { - tk.createLabel(body, JcrExplorerPlugin - .getMessage("warningUnversionableNode")); - } else { - createHistorySection(form.getBody()); - createTreeSection(form.getBody()); - } - } catch (RepositoryException e) { - throw new ArgeoException( - "Unexpected error while checking if node is versionable", e); - } - } - - protected void createTreeSection(Composite parent) { - // Section Layout & MetaData - Section section = tk.createSection(parent, Section.TWISTIE); - section.setLayoutData(new GridData(GridData.FILL_BOTH)); - section.setText(JcrExplorerPlugin.getMessage("versionTreeSectionTitle")); - - // Section Body - Composite body = tk.createComposite(section, SWT.FILL); - // WARNING : 2 following lines are compulsory or body won't be - // displayed. - body.setLayout(new GridLayout()); - section.setClient(body); - - body.setLayoutData(new GridData(GridData.FILL_BOTH)); - section.setExpanded(true); - - nodeContentProvider = new FullVersioningTreeContentProvider(); - nodesViewer = createNodeViewer(body, nodeContentProvider); - nodesViewer.setInput(currentNode); - } - - 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 VersionLabelProvider()); - tmpNodeViewer - .addDoubleClickListener(new GenericNodeDoubleClickListener( - tmpNodeViewer)); - return tmpNodeViewer; - } - - protected void createHistorySection(Composite parent) { - - // Section Layout - Section section = tk.createSection(parent, Section.TWISTIE); - section.setLayoutData(new GridData(TableWrapData.FILL_GRAB)); - TableWrapLayout twt = new TableWrapLayout(); - section.setLayout(twt); - - // Set title of the section - section.setText(JcrExplorerPlugin - .getMessage("versionHistorySectionTitle")); - - final Text styledText = tk.createText(section, "", SWT.FULL_SELECTION - | SWT.BORDER | SWT.MULTI | SWT.WRAP | SWT.V_SCROLL); - styledText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - section.setClient(styledText); - refreshHistory(styledText); - styledText.setEditable(false); - section.setExpanded(false); - - AbstractFormPart part = new AbstractFormPart() { - public void commit(boolean onSave) { - } - - public void refresh() { - super.refresh(); - refreshHistory(styledText); - } - }; - getManagedForm().addPart(part); - } - - protected void refreshHistory(Text styledText) { - try { - List lst = listHistoryDiff(); - StringBuffer main = new StringBuffer(""); - - for (int i = lst.size() - 1; i >= 0; i--) { - if (i == 0) - main.append("Creation ("); - else - main.append("Update " + i + " ("); - - if (lst.get(i).getUserId() != null) - main.append("UserId : " + lst.get(i).getUserId()); - - if (lst.get(i).getUserId() != null - && lst.get(i).getUpdateTime() != null) - main.append(", "); - - if (lst.get(i).getUpdateTime() != null) - main.append("Date : " - + timeFormatter.format(lst.get(i).getUpdateTime() - .getTime()) + ")\n"); - - StringBuffer buf = new StringBuffer(""); - Map diffs = lst.get(i).getDiffs(); - for (String prop : diffs.keySet()) { - PropertyDiff pd = diffs.get(prop); - // String propName = pd.getRelPath(); - Value refValue = pd.getReferenceValue(); - Value newValue = pd.getNewValue(); - String refValueStr = ""; - String newValueStr = ""; - - if (refValue != null) { - if (refValue.getType() == PropertyType.DATE) { - refValueStr = timeFormatter.format(refValue - .getDate().getTime()); - } else - refValueStr = refValue.getString(); - } - if (newValue != null) { - if (newValue.getType() == PropertyType.DATE) { - newValueStr = timeFormatter.format(newValue - .getDate().getTime()); - } else - newValueStr = newValue.getString(); - } - - if (pd.getType() == PropertyDiff.MODIFIED) { - buf.append(prop).append(": "); - buf.append(refValueStr); - buf.append(" > "); - buf.append(newValueStr); - buf.append("\n"); - } else if (pd.getType() == PropertyDiff.ADDED - && !"".equals(newValueStr)) { - // we don't list property that have been added with an - // empty string as value - buf.append(prop).append(": "); - buf.append(" + "); - buf.append(newValueStr); - buf.append("\n"); - } else if (pd.getType() == PropertyDiff.REMOVED) { - buf.append(prop).append(": "); - buf.append(" - "); - buf.append(refValueStr); - buf.append("\n"); - } - } - buf.append("\n"); - main.append(buf); - } - styledText.setText(main.toString()); - } catch (RepositoryException e) { - throw new ArgeoException("Cannot generate history for node", e); - } - - } - - public List listHistoryDiff() { - try { - List res = new ArrayList(); - VersionManager versionManager = currentNode.getSession() - .getWorkspace().getVersionManager(); - VersionHistory versionHistory = versionManager - .getVersionHistory(currentNode.getPath()); - - VersionIterator vit = versionHistory.getAllLinearVersions(); - while (vit.hasNext()) { - Version version = vit.nextVersion(); - Node node = version.getFrozenNode(); - Version predecessor = null; - try { - predecessor = version.getLinearPredecessor(); - } catch (Exception e) { - // no predecessor seems to throw an exception even if it - // shouldn't... - } - if (predecessor == null) {// original - } else { - Map diffs = JcrUtils.diffProperties( - predecessor.getFrozenNode(), node); - if (!diffs.isEmpty()) { - String lastUserName = null; - Calendar lastUpdate = null; - try { - if (currentNode - .isNodeType(NodeType.MIX_LAST_MODIFIED)) { - lastUserName = node.getProperty( - Property.JCR_LAST_MODIFIED_BY) - .getString(); - lastUpdate = node.getProperty( - Property.JCR_LAST_MODIFIED).getDate(); - } else - lastUpdate = version.getProperty( - Property.JCR_CREATED).getDate(); - - } catch (Exception e) { - // Silent that info is optional - } - VersionDiff vd = new VersionDiff(lastUserName, - lastUpdate, diffs); - res.add(vd); - } - } - } - return res; - } catch (RepositoryException e) { - throw new ArgeoException("Cannot generate history for node "); - } - - } - - @Override - public void setActive(boolean active) { - super.setActive(active); - } -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/editors/StringNodeEditorInput.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/editors/StringNodeEditorInput.java deleted file mode 100644 index 654b2aeea..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/editors/StringNodeEditorInput.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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.jcr.ui.explorer.editors; - -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.ui.IEditorInput; -import org.eclipse.ui.IPersistableElement; - -/** - * An editor input based on three strings define a node : - *
    - *
  • complete path to the node
  • - *
  • the workspace name
  • - *
  • the repository alias
  • - *
- * In a single workspace and/or repository environment, name and alias can be - * null. - * - * Note : unused for the time being. - */ - -public class StringNodeEditorInput implements IEditorInput { - private final String path; - private final String repositoryAlias; - private final String workspaceName; - - /** - * In order to implement a generic explorer that supports remote and multi - * workspaces repositories, node path can be detailed by these strings. - * - * @param repositoryAlias - * : can be null - * @param workspaceName - * : can be null - * @param path - */ - public StringNodeEditorInput(String repositoryAlias, String workspaceName, - String path) { - this.path = path; - this.repositoryAlias = repositoryAlias; - this.workspaceName = workspaceName; - } - - public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) { - return null; - } - - public boolean exists() { - return true; - } - - public ImageDescriptor getImageDescriptor() { - return null; - } - - public String getName() { - return path; - } - - public String getRepositoryAlias() { - return repositoryAlias; - } - - public String getWorkspaceName() { - return workspaceName; - } - - public IPersistableElement getPersistable() { - return null; - } - - public String getToolTipText() { - return path; - } - - public String getPath() { - return path; - } - - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - - StringNodeEditorInput other = (StringNodeEditorInput) obj; - - if (!path.equals(other.getPath())) - return false; - - String own = other.getWorkspaceName(); - if ((workspaceName == null && own != null) - || (workspaceName != null && (own == null || !workspaceName - .equals(own)))) - return false; - - String ora = other.getRepositoryAlias(); - if ((repositoryAlias == null && ora != null) - || (repositoryAlias != null && (ora == null || !repositoryAlias - .equals(ora)))) - return false; - - return true; - } -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/model/MaintainedRepositoryElem.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/model/MaintainedRepositoryElem.java deleted file mode 100644 index abb97a9e8..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/model/MaintainedRepositoryElem.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.argeo.jcr.ui.explorer.model; - -import javax.jcr.Repository; - -import org.argeo.ArgeoException; -import org.argeo.eclipse.ui.TreeParent; -import org.argeo.jcr.MaintainedRepository; - -/** Wraps a {@link MaintainedRepository} */ -public class MaintainedRepositoryElem extends RepositoryElem { - - public MaintainedRepositoryElem(String alias, Repository repository, - TreeParent parent) { - super(alias, repository, parent); - if (!(repository instanceof MaintainedRepository)) { - throw new ArgeoException("Repository " + alias - + " is not amiantained repository"); - } - } - - protected MaintainedRepository getMaintainedRepository() { - return (MaintainedRepository) getRepository(); - } -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/model/RemoteRepositoryElem.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/model/RemoteRepositoryElem.java deleted file mode 100644 index 0be69781c..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/model/RemoteRepositoryElem.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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.jcr.ui.explorer.model; - -import java.util.Arrays; - -import javax.jcr.Node; -import javax.jcr.Repository; -import javax.jcr.RepositoryException; -import javax.jcr.RepositoryFactory; -import javax.jcr.Session; -import javax.jcr.SimpleCredentials; - -import org.argeo.ArgeoException; -import org.argeo.eclipse.ui.TreeParent; -import org.argeo.jcr.ArgeoJcrUtils; -import org.argeo.jcr.ArgeoNames; -import org.argeo.util.security.Keyring; - -/** Root of a remote repository */ -public class RemoteRepositoryElem extends RepositoryElem { - private final Keyring keyring; - /** - * A session of the logged in user on the default workspace of the node - * repository. - */ - private final Session userSession; - private final String remoteNodePath; - - private final RepositoryFactory repositoryFactory; - private final String uri; - - public RemoteRepositoryElem(String alias, - RepositoryFactory repositoryFactory, String uri, TreeParent parent, - Session userSession, Keyring keyring, String remoteNodePath) { - super(alias, null, parent); - this.repositoryFactory = repositoryFactory; - this.uri = uri; - this.keyring = keyring; - this.userSession = userSession; - this.remoteNodePath = remoteNodePath; - } - - @Override - protected Session repositoryLogin(String workspaceName) - throws RepositoryException { - Node remoteRepository = userSession.getNode(remoteNodePath); - String userID = remoteRepository.getProperty(ArgeoNames.ARGEO_USER_ID) - .getString(); - String pwdPath = remoteRepository.getPath() + '/' - + ArgeoNames.ARGEO_PASSWORD; - char[] password = keyring.getAsChars(pwdPath); - - try { - SimpleCredentials credentials = new SimpleCredentials(userID, - password); - return getRepository().login(credentials, workspaceName); - } finally { - Arrays.fill(password, 0, password.length, ' '); - } - } - - @Override - public Repository getRepository() { - if (repository == null) - repository = ArgeoJcrUtils.getRepositoryByUri(repositoryFactory, - uri); - return super.getRepository(); - } - - public void remove() { - try { - Node remoteNode = userSession.getNode(remoteNodePath); - remoteNode.remove(); - remoteNode.getSession().save(); - } catch (RepositoryException e) { - throw new ArgeoException("Cannot remove " + remoteNodePath, e); - } - } - -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/model/RepositoriesElem.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/model/RepositoriesElem.java deleted file mode 100644 index b123727bc..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/model/RepositoriesElem.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * 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.jcr.ui.explorer.model; - -import java.util.Map; - -import javax.jcr.Node; -import javax.jcr.NodeIterator; -import javax.jcr.Repository; -import javax.jcr.RepositoryException; -import javax.jcr.RepositoryFactory; -import javax.jcr.Session; - -import org.argeo.ArgeoException; -import org.argeo.eclipse.ui.ErrorFeedback; -import org.argeo.eclipse.ui.TreeParent; -import org.argeo.jcr.ArgeoNames; -import org.argeo.jcr.MaintainedRepository; -import org.argeo.jcr.RepositoryRegister; -import org.argeo.jcr.UserJcrUtils; -import org.argeo.util.security.Keyring; - -/** - * UI Tree component. Implements the Argeo abstraction of a - * {@link RepositoryFactory} that enable a user to "mount" various repositories - * in a single Tree like View. It is usually meant to be at the root of the UI - * Tree and thus {@link getParent()} method will return null. - * - * The {@link RepositoryFactory} is injected at instantiation time and must be - * use get or register new {@link Repository} objects upon which a reference is - * kept here. - */ - -public class RepositoriesElem extends TreeParent implements ArgeoNames { - private final RepositoryRegister repositoryRegister; - private final RepositoryFactory repositoryFactory; - - /** - * A session of the logged in user on the default workspace of the node - * repository. - */ - private final Session userSession; - private final Keyring keyring; - - public RepositoriesElem(String name, RepositoryRegister repositoryRegister, - RepositoryFactory repositoryFactory, TreeParent parent, - Session userSession, Keyring keyring) { - super(name); - this.repositoryRegister = repositoryRegister; - this.repositoryFactory = repositoryFactory; - this.userSession = userSession; - this.keyring = keyring; - } - - /** - * Override normal behavior to initialize the various repositories only at - * request time - */ - @Override - public synchronized Object[] getChildren() { - if (isLoaded()) { - return super.getChildren(); - } else { - // initialize current object - Map refRepos = repositoryRegister - .getRepositories(); - for (String name : refRepos.keySet()) { - Repository repository = refRepos.get(name); - if (repository instanceof MaintainedRepository) - super.addChild(new MaintainedRepositoryElem(name, - repository, this)); - else - super.addChild(new RepositoryElem(name, repository, this)); - } - - // remote - if (keyring != null) { - try { - addRemoteRepositories(keyring); - } catch (RepositoryException e) { - throw new ArgeoException( - "Cannot browse remote repositories", e); - } - } - return super.getChildren(); - } - } - - protected void addRemoteRepositories(Keyring jcrKeyring) - throws RepositoryException { - Node userHome = UserJcrUtils.getUserHome(userSession); - if (userHome != null && userHome.hasNode(ARGEO_REMOTE)) { - NodeIterator it = userHome.getNode(ARGEO_REMOTE).getNodes(); - while (it.hasNext()) { - Node remoteNode = it.nextNode(); - String uri = remoteNode.getProperty(ARGEO_URI).getString(); - try { - RemoteRepositoryElem remoteRepositoryNode = new RemoteRepositoryElem( - remoteNode.getName(), repositoryFactory, uri, this, - userSession, jcrKeyring, remoteNode.getPath()); - super.addChild(remoteRepositoryNode); - } catch (Exception e) { - ErrorFeedback.show("Cannot add remote repository " - + remoteNode, e); - } - } - } - } - - public void registerNewRepository(String alias, Repository repository) { - // TODO: implement this - // Create a new RepositoryNode Object - // add it - // super.addChild(new RepositoriesNode(...)); - } - - /** Returns the {@link RepositoryRegister} wrapped by this object. */ - public RepositoryRegister getRepositoryRegister() { - return repositoryRegister; - } -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/model/RepositoryElem.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/model/RepositoryElem.java deleted file mode 100644 index 935bac12b..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/model/RepositoryElem.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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.jcr.ui.explorer.model; - -import javax.jcr.Repository; -import javax.jcr.RepositoryException; -import javax.jcr.Session; - -import org.argeo.ArgeoException; -import org.argeo.eclipse.ui.TreeParent; - -/** - * UI Tree component. Wraps a JCR {@link Repository}. It also keeps a reference - * to its parent Tree Ui component; typically the unique {@link Repositories} - * object of the current view to enable bi-directionnal browsing in the tree. - */ - -public class RepositoryElem extends TreeParent { - private String alias; - protected Repository repository; - private Session defaultSession = null; - - /** Create a new repository with distinct name & alias */ - public RepositoryElem(String alias, Repository repository, TreeParent parent) { - super(alias); - this.repository = repository; - setParent(parent); - this.alias = alias; - } - - public void login() { - try { - defaultSession = repositoryLogin(null); - String[] wkpNames = defaultSession.getWorkspace() - .getAccessibleWorkspaceNames(); - for (String wkpName : wkpNames) { - if (wkpName.equals(defaultSession.getWorkspace().getName())) - addChild(new WorkspaceElem(this, wkpName, defaultSession)); - else - addChild(new WorkspaceElem(this, wkpName)); - } - } catch (RepositoryException e) { - throw new ArgeoException("Cannot connect to repository " + alias, e); - } - } - - /** - * Actual call to the - * {@link Repository#login(javax.jcr.Credentials, String)} method. To be - * overridden. - */ - protected Session repositoryLogin(String workspaceName) - throws RepositoryException { - return repository.login(workspaceName); - } - - public String[] getAccessibleWorkspaceNames() { - try { - return defaultSession.getWorkspace().getAccessibleWorkspaceNames(); - } catch (RepositoryException e) { - throw new ArgeoException("Cannot retrieve workspace names", e); - } - } - - public void createWorkspace(String workspaceName) { - if (!isConnected()) - login(); - try { - defaultSession.getWorkspace().createWorkspace(workspaceName); - } catch (RepositoryException e) { - throw new ArgeoException("Cannot create workspace", e); - } - } - - /** returns the {@link Repository} referenced by the current UI Node */ - public Repository getRepository() { - return repository; - } - - public String getAlias() { - return alias; - } - - public Boolean isConnected() { - if (defaultSession != null && defaultSession.isLive()) - return true; - else - return false; - } -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/model/SingleJcrNodeElem.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/model/SingleJcrNodeElem.java deleted file mode 100644 index 7b588f83b..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/model/SingleJcrNodeElem.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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.jcr.ui.explorer.model; - -import javax.jcr.Node; -import javax.jcr.NodeIterator; -import javax.jcr.RepositoryException; -import javax.jcr.Workspace; - -import org.argeo.ArgeoException; -import org.argeo.eclipse.ui.TreeParent; - -/** - * UI Tree component. Wraps a node of a JCR {@link Workspace}. It also keeps a - * reference to its parent node that can either be a {@link WorkspaceElem}, a - * {@link SingleJcrNodeElem} or null if the node is "mounted" as the root of the UI - * tree. - */ - -public class SingleJcrNodeElem extends TreeParent { - - private final Node node; - private String alias = null; - - // keeps a local reference to the node's name to avoid exception when the - // session is lost - // private final String name; - - /** Creates a new UiNode in the UI Tree */ - public SingleJcrNodeElem(TreeParent parent, Node node, String name) { - super(name); - setParent(parent); - this.node = node; - } - - /** - * Creates a new UiNode in the UI Tree, keeping a reference to the alias of - * the corresponding repository in the current UI environment. It is useful - * to be able to mount nodes as roots of the UI tree. - */ - public SingleJcrNodeElem(TreeParent parent, Node node, String name, String alias) { - super(name); - setParent(parent); - this.node = node; - this.alias = alias; - } - - /** returns the node wrapped by the current Ui object */ - public Node getNode() { - return node; - } - - protected String getRepositoryAlias() { - return alias; - } - - /** - * Override normal behavior to initialize children only when first requested - */ - @Override - public synchronized Object[] getChildren() { - if (isLoaded()) { - return super.getChildren(); - } else { - // initialize current object - try { - NodeIterator ni = node.getNodes(); - while (ni.hasNext()) { - Node curNode = ni.nextNode(); - addChild(new SingleJcrNodeElem(this, curNode, curNode.getName())); - } - return super.getChildren(); - } catch (RepositoryException re) { - throw new ArgeoException( - "Unexcpected error while initializing children SingleJcrNode", - re); - } - } - } - - @Override - public boolean hasChildren() { - try { - if (node.getSession().isLive()) - return node.hasNodes(); - else - return false; - } catch (RepositoryException re) { - throw new ArgeoException( - "Unexpected error while checking children node existence", - re); - } - } - -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/model/WorkspaceElem.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/model/WorkspaceElem.java deleted file mode 100644 index bb9b69caf..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/model/WorkspaceElem.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * 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.jcr.ui.explorer.model; - -import javax.jcr.Node; -import javax.jcr.NodeIterator; -import javax.jcr.RepositoryException; -import javax.jcr.Session; -import javax.jcr.Workspace; - -import org.argeo.ArgeoException; -import org.argeo.eclipse.ui.TreeParent; -import org.argeo.jcr.JcrUtils; - -/** - * UI Tree component. Wraps the root node of a JCR {@link Workspace}. It also - * keeps a reference to its parent {@link RepositoryElem}, to be able to - * retrieve alias of the current used repository - */ -public class WorkspaceElem extends TreeParent { - private Session session = null; - - public WorkspaceElem(RepositoryElem parent, String name) { - this(parent, name, null); - } - - public WorkspaceElem(RepositoryElem parent, String name, Session session) { - super(name); - this.session = session; - setParent(parent); - } - - public Session getSession() { - return session; - } - - public Node getRootNode() { - try { - if (session != null) - return session.getRootNode(); - else - return null; - } catch (RepositoryException e) { - throw new ArgeoException("Cannot get root node of workspace " - + getName(), e); - } - } - - public void login() { - try { - session = ((RepositoryElem) getParent()).repositoryLogin(getName()); - } catch (RepositoryException e) { - throw new ArgeoException("Cannot connect to repository " - + getName(), e); - } - } - - public Boolean isConnected() { - if (session != null && session.isLive()) - return true; - else - return false; - } - - @Override - public synchronized void dispose() { - logout(); - super.dispose(); - } - - /** Logouts the session, does not nothing if there is no live session. */ - public void logout() { - clearChildren(); - JcrUtils.logoutQuietly(session); - } - - @Override - public boolean hasChildren() { - try { - if (isConnected()) - return session.getRootNode().hasNodes(); - else - return false; - } catch (RepositoryException re) { - throw new ArgeoException( - "Unexpected error while checking children node existence", - re); - } - } - - /** Override normal behaviour to initialize display of the workspace */ - @Override - public synchronized Object[] getChildren() { - if (isLoaded()) { - return super.getChildren(); - } else { - // initialize current object - try { - Node rootNode; - if (session == null) - return null; - else - rootNode = session.getRootNode(); - NodeIterator ni = rootNode.getNodes(); - while (ni.hasNext()) { - Node node = ni.nextNode(); - addChild(new SingleJcrNodeElem(this, node, node.getName())); - } - return super.getChildren(); - } catch (RepositoryException e) { - throw new ArgeoException( - "Cannot initialize WorkspaceNode UI object." - + getName(), e); - } - } - } -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/providers/FullVersioningTreeContentProvider.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/providers/FullVersioningTreeContentProvider.java deleted file mode 100644 index 736a5aa2f..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/providers/FullVersioningTreeContentProvider.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * 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.jcr.ui.explorer.providers; - -import java.util.ArrayList; -import java.util.List; - -import javax.jcr.Node; -import javax.jcr.RepositoryException; -import javax.jcr.nodetype.NodeType; -import javax.jcr.version.Version; -import javax.jcr.version.VersionHistory; -import javax.jcr.version.VersionIterator; -import javax.jcr.version.VersionManager; - -import org.argeo.ArgeoException; -import org.eclipse.jface.viewers.ITreeContentProvider; -import org.eclipse.jface.viewers.Viewer; - -/** - * Implementation of the {@code ITreeContentProvider} in order to display some - * version informations of a JCR full versionable node in a tree like structure - * - */ -public class FullVersioningTreeContentProvider implements ITreeContentProvider { - // private Node rootNode; - // private ItemComparator itemComparator = new ItemComparator(); - - /** - * Sends back the first level of the Tree. input element must be a single - * node object - */ - public Object[] getElements(Object inputElement) { - try { - Node rootNode = (Node) inputElement; - String curPath = rootNode.getPath(); - VersionManager vm = rootNode.getSession().getWorkspace() - .getVersionManager(); - - VersionHistory vh = vm.getVersionHistory(curPath); - List result = new ArrayList(); - VersionIterator vi = vh.getAllLinearVersions(); - - while (vi.hasNext()) { - result.add(vi.nextVersion()); - } - return result.toArray(); - } catch (RepositoryException re) { - throw new ArgeoException( - "Unexpected error while getting version elements", re); - } - } - - public Object[] getChildren(Object parentElement) { - try { - if (parentElement instanceof Version) { - List tmp = new ArrayList(); - tmp.add(((Version) parentElement).getFrozenNode()); - return tmp.toArray(); - } - } catch (RepositoryException re) { - throw new ArgeoException("Unexpected error while getting child " - + "node for version element", re); - } - return null; - } - - public Object getParent(Object element) { - try { - // this will not work in a simpleVersionning environment, parent is - // not a node. - if (element instanceof Node - && ((Node) element).isNodeType(NodeType.NT_FROZEN_NODE)) { - Node node = (Node) element; - return node.getParent(); - } else - return null; - } catch (RepositoryException e) { - return null; - } - } - - public boolean hasChildren(Object element) { - try { - if (element instanceof Version) - return true; - else if (element instanceof Node) - return ((Node) element).hasNodes(); - else - return false; - } catch (RepositoryException e) { - throw new ArgeoException("Cannot check children of " + element, e); - } - } - - public void dispose() { - } - - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - } - -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/providers/PropertyLabelProvider.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/providers/PropertyLabelProvider.java deleted file mode 100644 index decbe6338..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/providers/PropertyLabelProvider.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * 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.jcr.ui.explorer.providers; - -import java.text.DateFormat; -import java.text.SimpleDateFormat; - -import javax.jcr.Property; -import javax.jcr.PropertyType; -import javax.jcr.RepositoryException; -import javax.jcr.Value; - -import org.argeo.ArgeoException; -import org.argeo.jcr.JcrUtils; -import org.argeo.jcr.ui.explorer.JcrExplorerConstants; -import org.eclipse.jface.viewers.ColumnLabelProvider; -import org.eclipse.jface.viewers.ViewerCell; - -public class PropertyLabelProvider extends ColumnLabelProvider implements - JcrExplorerConstants { - - // To be able to change column order easily - public static final int COLUMN_PROPERTY = 0; - public static final int COLUMN_VALUE = 1; - public static final int COLUMN_ATTRIBUTES = 2; - - // Utils - protected DateFormat timeFormatter = new SimpleDateFormat(DATE_TIME_FORMAT); - - public void update(ViewerCell cell) { - Object element = cell.getElement(); - cell.setText(getColumnText(element, cell.getColumnIndex())); - // Image image = getImage(element); - // cell.setImage(image); - // cell.setBackground(getBackground(element)); - // cell.setForeground(getForeground(element)); - // cell.setFont(getFont(element)); - } - - public String getColumnText(Object element, int columnIndex) { - try { - if (element instanceof Property) { - Property prop = (Property) element; - if (prop.isMultiple()) { - switch (columnIndex) { - case COLUMN_PROPERTY: - return prop.getName(); - case COLUMN_VALUE: - // Corresponding values are listed on children - return ""; - case COLUMN_ATTRIBUTES: - return JcrUtils.getPropertyDefinitionAsString(prop); - } - } else { - switch (columnIndex) { - case COLUMN_PROPERTY: - return prop.getName(); - case COLUMN_VALUE: - return formatValueAsString(prop.getValue()); - case COLUMN_ATTRIBUTES: - return JcrUtils.getPropertyDefinitionAsString(prop); - } - } - } else if (element instanceof Value) { - Value val = (Value) element; - - switch (columnIndex) { - case COLUMN_PROPERTY: - // Nothing to show - return ""; - case COLUMN_VALUE: - return formatValueAsString(val); - case COLUMN_ATTRIBUTES: - // Corresponding attributes are listed on the parent - return ""; - } - } - - } catch (RepositoryException re) { - throw new ArgeoException( - "Unexepected error while getting property values", re); - } - return null; - } - - private String formatValueAsString(Value value) { - // TODO enhance this method - try { - String strValue; - - if (value.getType() == PropertyType.BINARY) - strValue = ""; - else if (value.getType() == PropertyType.DATE) - strValue = timeFormatter.format(value.getDate().getTime()); - else - strValue = value.getString(); - return strValue; - } catch (RepositoryException e) { - throw new ArgeoException("unexpected error while formatting value", - e); - } - } -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/providers/SingleNodeAsTreeContentProvider.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/providers/SingleNodeAsTreeContentProvider.java deleted file mode 100644 index 8c69b6b9c..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/providers/SingleNodeAsTreeContentProvider.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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.jcr.ui.explorer.providers; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import javax.jcr.Node; -import javax.jcr.NodeIterator; -import javax.jcr.RepositoryException; - -import org.argeo.ArgeoException; -import org.argeo.eclipse.ui.jcr.utils.JcrItemsComparator; -import org.eclipse.jface.viewers.ITreeContentProvider; -import org.eclipse.jface.viewers.Viewer; - -/** - * Implementation of the {@code ITreeContentProvider} in order to display a - * single JCR node and its children in a tree like structure - * - */ -public class SingleNodeAsTreeContentProvider implements ITreeContentProvider { - // private Node rootNode; - private JcrItemsComparator itemComparator = new JcrItemsComparator(); - - /** - * Sends back the first level of the Tree. input element must be a single - * node object - */ - public Object[] getElements(Object inputElement) { - try { - Node rootNode = (Node) inputElement; - List result = new ArrayList(); - NodeIterator ni = rootNode.getNodes(); - while (ni.hasNext()) { - result.add(ni.nextNode()); - } - - return result.toArray(); - } catch (RepositoryException re) { - throw new ArgeoException( - "Unexpected error while getting child nodes for children editor page ", - re); - } - } - - public Object[] getChildren(Object parentElement) { - return childrenNodes((Node) parentElement); - } - - public Object getParent(Object element) { - try { - Node node = (Node) element; - if (!node.getPath().equals("/")) - return node.getParent(); - else - return null; - } catch (RepositoryException e) { - return null; - } - } - - public boolean hasChildren(Object element) { - try { - return ((Node) element).hasNodes(); - } catch (RepositoryException e) { - throw new ArgeoException("Cannot check children of " + element, e); - } - } - - public void dispose() { - } - - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - } - - protected Object[] childrenNodes(Node parentNode) { - try { - List children = new ArrayList(); - NodeIterator nit = parentNode.getNodes(); - while (nit.hasNext()) { - Node node = nit.nextNode(); - children.add(node); - } - Node[] arr = children.toArray(new Node[children.size()]); - Arrays.sort(arr, itemComparator); - return arr; - } catch (RepositoryException e) { - throw new ArgeoException("Cannot list children of " + parentNode, e); - } - } -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/providers/VersionLabelProvider.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/providers/VersionLabelProvider.java deleted file mode 100644 index 69b35ebb5..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/providers/VersionLabelProvider.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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.jcr.ui.explorer.providers; - -import javax.jcr.Node; -import javax.jcr.RepositoryException; -import javax.jcr.version.Version; - -import org.argeo.ArgeoException; -import org.eclipse.jface.viewers.ColumnLabelProvider; - -/** - * simple wrapping of the ColumnLabelProvider class to provide text display in - * order to build a tree for version. The Get text method does not assume that - * Version extends Node class to respect JCR 2.0 specification - * - */ -public class VersionLabelProvider extends ColumnLabelProvider { - - public String getText(Object element) { - try { - if (element instanceof Version) { - Version version = (Version) element; - return version.getName(); - } else if (element instanceof Node) { - return ((Node) element).getName(); - } - } catch (RepositoryException re) { - throw new ArgeoException( - "Unexpected error while getting element name", re); - } - return super.getText(element); - } -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/utils/GenericNodeDoubleClickListener.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/utils/GenericNodeDoubleClickListener.java deleted file mode 100644 index 0f93450eb..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/utils/GenericNodeDoubleClickListener.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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.jcr.ui.explorer.utils; - -import javax.jcr.Node; -import javax.jcr.RepositoryException; -import javax.jcr.nodetype.NodeType; - -import org.argeo.ArgeoException; -import org.argeo.eclipse.ui.jcr.utils.JcrFileProvider; -import org.argeo.eclipse.ui.specific.FileHandler; -import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; -import org.argeo.jcr.ui.explorer.editors.GenericNodeEditor; -import org.argeo.jcr.ui.explorer.editors.GenericNodeEditorInput; -import org.argeo.jcr.ui.explorer.model.RepositoryElem; -import org.argeo.jcr.ui.explorer.model.SingleJcrNodeElem; -import org.argeo.jcr.ui.explorer.model.WorkspaceElem; -import org.eclipse.jface.viewers.DoubleClickEvent; -import org.eclipse.jface.viewers.IDoubleClickListener; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.viewers.TreeViewer; -import org.eclipse.ui.PartInitException; - -/** - * Centralizes the management of double click on a NodeTreeViewer - */ -public class GenericNodeDoubleClickListener implements IDoubleClickListener { - - // private final static Log log = LogFactory - // .getLog(GenericNodeDoubleClickListener.class); - - private TreeViewer nodeViewer; - private JcrFileProvider jfp; - private FileHandler fileHandler; - - public GenericNodeDoubleClickListener(TreeViewer nodeViewer) { - this.nodeViewer = nodeViewer; - jfp = new JcrFileProvider(); - // Commented out. see https://www.argeo.org/bugzilla/show_bug.cgi?id=188 - fileHandler = null; - // fileHandler = new FileHandler(jfp); - } - - public void doubleClick(DoubleClickEvent event) { - if (event.getSelection() == null || event.getSelection().isEmpty()) - return; - Object obj = ((IStructuredSelection) event.getSelection()) - .getFirstElement(); - if (obj instanceof RepositoryElem) { - RepositoryElem rpNode = (RepositoryElem) obj; - if (!rpNode.isConnected()) { - rpNode.login(); - nodeViewer.refresh(obj); - } - // else do nothing - } else if (obj instanceof WorkspaceElem) { - WorkspaceElem wn = (WorkspaceElem) obj; - if (wn.isConnected()) - wn.logout(); - else - wn.login(); - nodeViewer.refresh(obj); - } else if (obj instanceof SingleJcrNodeElem) { - SingleJcrNodeElem sjn = (SingleJcrNodeElem) obj; - Node node = sjn.getNode(); - try { - if (node.isNodeType(NodeType.NT_FILE)) { - // double click on a file node triggers its opening - String name = node.getName(); - String id = node.getIdentifier(); - - // For the file provider to be able to browse the - // various - // repository. - // TODO : enhanced that. - // ITreeContentProvider itcp = (ITreeContentProvider) - // nodeViewer - // .getContentProvider(); - jfp.setReferenceNode(node); - if (fileHandler != null) - fileHandler.openFile(name, id); - } - GenericNodeEditorInput gnei = new GenericNodeEditorInput(node); - JcrExplorerPlugin.getDefault().getWorkbench() - .getActiveWorkbenchWindow().getActivePage() - .openEditor(gnei, GenericNodeEditor.ID); - } catch (RepositoryException re) { - throw new ArgeoException( - "Repository error while getting node info", re); - } catch (PartInitException pie) { - throw new ArgeoException( - "Unexepected exception while opening node editor", pie); - } - } - } -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/utils/JcrUiUtils.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/utils/JcrUiUtils.java deleted file mode 100644 index ca32113ed..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/utils/JcrUiUtils.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * 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.jcr.ui.explorer.utils; - -import javax.jcr.Node; -import javax.jcr.RepositoryException; - -import org.argeo.ArgeoException; -import org.argeo.eclipse.ui.TreeParent; -import org.argeo.jcr.ui.explorer.model.RepositoriesElem; -import org.argeo.jcr.ui.explorer.model.RepositoryElem; -import org.argeo.jcr.ui.explorer.model.SingleJcrNodeElem; -import org.argeo.jcr.ui.explorer.model.WorkspaceElem; - -/** Centralizes some useful methods to build UIs with JCR */ -public class JcrUiUtils { - - /** Insure that the UI component is not stale, refresh if needed */ - public static void forceRefreshIfNeeded(TreeParent element) { - Node curNode = null; - - boolean doRefresh = false; - - try { - if (element instanceof SingleJcrNodeElem) { - curNode = ((SingleJcrNodeElem) element).getNode(); - } else if (element instanceof WorkspaceElem) { - curNode = ((WorkspaceElem) element).getRootNode(); - } - - if (curNode != null - && element.getChildren().length != curNode.getNodes() - .getSize()) - doRefresh = true; - else if (element instanceof RepositoryElem) { - RepositoryElem rn = (RepositoryElem) element; - if (rn.isConnected()) { - String[] wkpNames = rn.getAccessibleWorkspaceNames(); - if (element.getChildren().length != wkpNames.length) - doRefresh = true; - } - } else if (element instanceof RepositoriesElem) { - doRefresh = true; - // Always force refresh for RepositoriesElem : the condition - // below does not take remote repository into account and it is - // not trivial to do so. - - // RepositoriesElem rn = (RepositoriesElem) element; - // if (element.getChildren().length != - // rn.getRepositoryRegister() - // .getRepositories().size()) - // doRefresh = true; - } - if (doRefresh) { - element.clearChildren(); - element.getChildren(); - } - } catch (RepositoryException re) { - throw new ArgeoException( - "Unexpected error while synchronising the UI with the JCR repository", - re); - } - } - - /** - * Insure that a model element is inline with the underlying data by - * cleaning the corresponding subtree and building it again. - */ - public static void forceRebuild(TreeParent element) { - // TODO implement this method if needed. - } - /** - * Workaround to get the alias of the repository that contains the given - * element. As we cannot browse the UI tree upward we recursively browse it - * downward until we find the given element - * */ - // public static String getRepositoryAliasFromITreeElement( - // NodeContentProvider ncp, Object element) { - // RepositoryNode repositoryNode = null; - // if (element instanceof RepositoryNode) - // return ((RepositoryNode) element).getName(); - // else if (element instanceof RepositoryRegister) - // throw new ArgeoException( - // "Cannot get alias for a repository register"); - // - // // Get root elements - // Object[] elements = ncp.getElements(null); - // - // try { - // for (int i = 0; i < elements.length; i++) { - // if (elements[i] instanceof Node) { - // Node curNode = (Node) elements[i]; - // if (curNode.isNodeType(ArgeoTypes.ARGEO_USER_HOME)) { - // // Do nothing, we'll find the node in the "normal" tree - // // and - // // get corresponding alias this way round - // } else - // throw new ArgeoException( - // "Normal nodes should not be at the root of NodeTreeViewer"); - // } else if (elements[i] instanceof RepositoryRegister) { - // RepositoryRegister repositoryRegister = (RepositoryRegister) elements[i]; - // Map repositories = repositoryRegister - // .getRepositories(); - // - // for (String name : repositories.keySet()) { - // boolean found = isElementInCurrentTreePart( - // ncp, - // new RepositoryNode(name, repositories.get(name)), - // (Node) element); - // if (found) - // return name; - // } - // } else - // throw new ArgeoException( - // "Unexpected object class at the root of NodeTreeViewer"); - // } - // } catch (RepositoryException re) { - // throw new ArgeoException( - // "Unexpected error while retrieving Alias name", re); - // } - // return null; - // } - // - // /** implements the recursivity */ - // private static boolean isElementInCurrentTreePart(NodeContentProvider - // ncp, - // Object parentElement, NodParente searchedElement) { - // boolean found = false; - // if (parentElement instanceof WorkspaceNode) { - // WorkspaceNode wn = (WorkspaceNode) parentElement; - // Object[] children = wn.getChildren(); - // int i = children.length - 1; - // while (!found && i >= 0) { - // found = isElementInCurrentTreePart(ncp, children[i], - // searchedElement); - // } - // return found; - // } else if (parentElement instanceof RepositoryNode) { - // RepositoryNode rn = (RepositoryNode) parentElement; - // Object[] children = rn.getChildren(); - // int i = children.length - 1; - // while (!found && i >= 0) { - // found = isElementInCurrentTreePart(ncp, children[i], - // searchedElement); - // } - // return found; - // } else { - // Node node = (Node) parentElement; - // if (node.equals(searchedElement)) - // return true; - // NodeIterator ni; - // try { - // ni = node.getNodes(); - // while (!found && ni.hasNext()) { - // found = isElementInCurrentTreePart(ncp, ni.nextNode(), - // searchedElement); - // } - // } catch (RepositoryException e) { - // throw new ArgeoException("unexpected erreur while recursively" - // + " recovering RepositoryNode for selected object", e); - // } - // - // return found; - // } - // } -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/utils/TreeObjectsComparator.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/utils/TreeObjectsComparator.java deleted file mode 100644 index 02450d6ed..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/utils/TreeObjectsComparator.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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.jcr.ui.explorer.utils; - -import java.util.Comparator; - -import org.argeo.eclipse.ui.TreeParent; - -public class TreeObjectsComparator implements Comparator { - public int compare(TreeParent o1, TreeParent o2) { - return o1.getName().compareTo(o2.getName()); - } -} \ No newline at end of file diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/views/GenericJcrBrowser.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/views/GenericJcrBrowser.java deleted file mode 100644 index f401ae8fe..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/views/GenericJcrBrowser.java +++ /dev/null @@ -1,357 +0,0 @@ -/* - * 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.jcr.ui.explorer.views; - -import java.util.List; - -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.ArgeoException; -import org.argeo.eclipse.ui.TreeParent; -import org.argeo.eclipse.ui.jcr.AsyncUiEventListener; -import org.argeo.eclipse.ui.jcr.utils.NodeViewerComparer; -import org.argeo.eclipse.ui.jcr.views.AbstractJcrBrowser; -import org.argeo.jcr.RepositoryRegister; -import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; -import org.argeo.jcr.ui.explorer.browser.NodeContentProvider; -import org.argeo.jcr.ui.explorer.browser.NodeLabelProvider; -import org.argeo.jcr.ui.explorer.browser.PropertiesContentProvider; -import org.argeo.jcr.ui.explorer.model.SingleJcrNodeElem; -import org.argeo.jcr.ui.explorer.utils.GenericNodeDoubleClickListener; -import org.argeo.jcr.ui.explorer.utils.JcrUiUtils; -import org.argeo.util.security.Keyring; -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; - -/** - * Basic View to display a sash form to browse a JCR compliant multirepository - * environment - */ -public class GenericJcrBrowser extends AbstractJcrBrowser { - public final static String ID = JcrExplorerPlugin.ID + ".browserView"; - private boolean sortChildNodes = true; - - /* DEPENDENCY INJECTION */ - private Keyring keyring; - private RepositoryRegister repositoryRegister; - private RepositoryFactory repositoryFactory; - private Repository nodeRepository; - /** - * A session of the logged in user on the default workspace of the node - * repository. - */ - private Session userSession; - - // This page widgets - private TreeViewer nodesViewer; - private NodeContentProvider nodeContentProvider; - private TableViewer propertiesViewer; - private EventListener resultsObserver; - - @Override - public void createPartControl(Composite parent) { - 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 ArgeoException("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); - getSite().registerContextMenu(menuManager, nodesViewer); - getSite().setSelectionProvider(nodesViewer); - - nodesViewer.setInput(getViewSite()); - - // 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()); - } - - @Override - 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) - JcrUiUtils.forceRefreshIfNeeded((TreeParent) el); - getNodeViewer().refresh(el); - } - } - super.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(getViewSite()); - } - } - }); - - 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 ArgeoException("Cannot register listeners", e); - } - - tmpNodeViewer - .addDoubleClickListener(new GenericNodeDoubleClickListener( - 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() { - public String getText(Object element) { - try { - return ((Property) element).getName(); - } catch (RepositoryException e) { - throw new ArgeoException( - "Unexpected exception in label provider", e); - } - } - }); - col = new TableViewerColumn(propertiesViewer, SWT.NONE); - col.getColumn().setText("Value"); - col.getColumn().setWidth(400); - col.setLabelProvider(new ColumnLabelProvider() { - 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 ArgeoException( - "Unexpected exception in label provider", e); - } - } - }); - col = new TableViewerColumn(propertiesViewer, SWT.NONE); - col.getColumn().setText("Type"); - col.getColumn().setWidth(200); - col.setLabelProvider(new ColumnLabelProvider() { - public String getText(Object element) { - try { - return PropertyType.nameFromValue(((Property) element) - .getType()); - } catch (RepositoryException e) { - throw new ArgeoException( - "Unexpected exception in label provider", e); - } - } - }); - propertiesViewer.setInput(getViewSite()); - return propertiesViewer; - } - - @Override - public void dispose() { - super.dispose(); - } - - @Override - 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(getViewSite()); - } - - /** Notifies the current view that a node has been added */ - public void nodeAdded(TreeParent parentNode) { - // insure that Ui objects have been correctly created: - JcrUiUtils.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; - } - - /* DEPENDENCY INJECTION */ - public void setRepositoryRegister(RepositoryRegister repositoryRegister) { - this.repositoryRegister = repositoryRegister; - } - - public void setKeyring(Keyring 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.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/wizards/ChangeRightsWizard.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/wizards/ChangeRightsWizard.java deleted file mode 100644 index 4381837e4..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/wizards/ChangeRightsWizard.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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.jcr.ui.explorer.wizards; - -import javax.jcr.RepositoryException; -import javax.jcr.Session; - -import org.argeo.ArgeoException; -import org.argeo.jcr.JcrUtils; -import org.eclipse.jface.wizard.Wizard; - -/** - * Small wizard to manage authorizations on the root node of the current - * workspace - */ -public class ChangeRightsWizard extends Wizard { - - private Session currentSession; - private String path; - - // This page widget - private ChooseRightsPage page; - - public ChangeRightsWizard(Session currentSession, String path) { - super(); - this.currentSession = currentSession; - this.path = path; - } - - @Override - public void addPages() { - try { - page = new ChooseRightsPage(path); - addPage(page); - } catch (Exception e) { - throw new ArgeoException("Cannot add page to wizard ", e); - } - } - - @Override - public boolean performFinish() { - if (!canFinish()) - return false; - try { - JcrUtils.addPrivilege(currentSession, path, page.getGroupName(), - page.getAuthTypeStr()); - } catch (RepositoryException re) { - throw new ArgeoException( - "Unexpected error while setting privileges", re); - } - return true; - } -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/wizards/ChooseRightsPage.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/wizards/ChooseRightsPage.java deleted file mode 100644 index 69948ce83..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/wizards/ChooseRightsPage.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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.jcr.ui.explorer.wizards; - -import javax.jcr.security.Privilege; - -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Text; - -public class ChooseRightsPage extends WizardPage implements ModifyListener { - - // This page widget - private Text groupNameTxt; - private Combo authorizationCmb; - - // USABLE SHORTCUTS - protected final static String[] validAuthType = { Privilege.JCR_READ, - Privilege.JCR_WRITE, Privilege.JCR_ALL }; - - public ChooseRightsPage(String path) { - super("Main"); - setTitle("Add privilege to " + path); - } - - public void createControl(Composite parent) { - // specify subject - Composite composite = new Composite(parent, SWT.NONE); - composite.setLayout(new GridLayout(2, false)); - Label lbl = new Label(composite, SWT.LEAD); - lbl.setText("Group or user name (no blank, no special chars)"); - lbl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false)); - groupNameTxt = new Text(composite, SWT.LEAD | SWT.BORDER); - groupNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, - false)); - if (groupNameTxt != null) - groupNameTxt.addModifyListener(this); - - // Choose rigths - new Label(composite, SWT.NONE).setText("Choose corresponding rights"); - authorizationCmb = new Combo(composite, SWT.BORDER | SWT.V_SCROLL); - authorizationCmb.setItems(validAuthType); - GridData gd = new GridData(GridData.FILL_HORIZONTAL); - authorizationCmb.setLayoutData(gd); - - authorizationCmb.select(0); - - // Compulsory - setControl(composite); - } - - protected String getGroupName() { - return groupNameTxt.getText(); - } - - protected String getAuthTypeStr() { - return authorizationCmb.getItem(authorizationCmb.getSelectionIndex()); - } - - public void modifyText(ModifyEvent event) { - String message = checkComplete(); - if (message != null) - setMessage(message, WizardPage.ERROR); - else { - setMessage("Complete", WizardPage.INFORMATION); - setPageComplete(true); - } - } - - /** @return error message or null if complete */ - protected String checkComplete() { - String groupStr = groupNameTxt.getText(); - if (groupStr == null || "".equals(groupStr)) - return "Please enter the name of the corresponding group."; - // Remove regexp check for the time being. - // else if (!match(groupStr)) - // return - // "Please use only alphanumerical chars for the short technical name."; - return null; - } -} diff --git a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/wizards/ImportFileSystemWizard.java b/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/wizards/ImportFileSystemWizard.java deleted file mode 100644 index 127c2cd54..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/wizards/ImportFileSystemWizard.java +++ /dev/null @@ -1,237 +0,0 @@ -/* - * 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.jcr.ui.explorer.wizards; - -import java.io.File; -import java.io.FileInputStream; - -import javax.jcr.Binary; -import javax.jcr.Node; -import javax.jcr.Property; -import javax.jcr.nodetype.NodeType; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.ArgeoException; -import org.argeo.eclipse.ui.ErrorFeedback; -import org.argeo.eclipse.ui.specific.ImportToServerWizardPage; -import org.argeo.eclipse.ui.specific.UploadFileWizardPage; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.operation.IRunnableWithProgress; -import org.eclipse.jface.wizard.Wizard; - -public class ImportFileSystemWizard extends Wizard { - private final static Log log = LogFactory - .getLog(ImportFileSystemWizard.class); - - private UploadFileWizardPage importPage; - private final Node folder; - - public ImportFileSystemWizard(Node folder) { - this.folder = folder; - setWindowTitle("Import from file system"); - } - - @Override - public void addPages() { - importPage = new UploadFileWizardPage(); - addPage(importPage); - setNeedsProgressMonitor(importPage.getNeedsProgressMonitor()); - } - - /** - * Called when the user click on 'Finish' in the wizard. The real upload to - * the JCR repository is done here. - */ - @Override - public boolean performFinish() { - - // Initialization - final String objectType = importPage.getObjectType(); - final String objectPath = importPage.getObjectPath(); - - // We do not display a progress bar for one file only - if (ImportToServerWizardPage.FILE_ITEM_TYPE.equals(objectType)) { - // In Rap we must force the "real" upload of the file - importPage.performFinish(); - try { - Node fileNode = folder.addNode(importPage.getObjectName(), - NodeType.NT_FILE); - Node resNode = fileNode.addNode(Property.JCR_CONTENT, - NodeType.NT_RESOURCE); - Binary binary = null; - try { - binary = folder.getSession().getValueFactory() - .createBinary(importPage.getFileInputStream()); - resNode.setProperty(Property.JCR_DATA, binary); - } finally { - if (binary != null) - binary.dispose(); - IOUtils.closeQuietly(importPage.getFileInputStream()); - } - folder.getSession().save(); - } catch (Exception e) { - e.printStackTrace(); - return false; - } - return true; - } else if (ImportToServerWizardPage.FOLDER_ITEM_TYPE.equals(objectType)) { - if (objectPath == null || !new File(objectPath).exists()) { - ErrorFeedback.show("Directory " + objectPath - + " does not exist"); - return false; - } - - Boolean failed = false; - final File dir = new File(objectPath).getAbsoluteFile(); - final Long sizeB = directorySize(dir, 0l); - final Stats stats = new Stats(); - Long begin = System.currentTimeMillis(); - try { - getContainer().run(true, true, new IRunnableWithProgress() { - public void run(IProgressMonitor monitor) { - try { - Integer sizeKB = (int) (sizeB / FileUtils.ONE_KB); - monitor.beginTask("", sizeKB); - importDirectory(folder, dir, monitor, stats); - monitor.done(); - } catch (Exception e) { - if (e instanceof RuntimeException) - throw (RuntimeException) e; - else - throw new ArgeoException("Cannot import " - + objectPath, e); - } - } - }); - } catch (Exception e) { - ErrorFeedback.show("Cannot import " + objectPath, e); - failed = true; - } - - Long duration = System.currentTimeMillis() - begin; - Long durationS = duration / 1000l; - String durationStr = (durationS / 60) + " min " + (durationS % 60) - + " s"; - StringBuffer message = new StringBuffer("Imported\n"); - message.append(stats.fileCount).append(" files\n"); - message.append(stats.dirCount).append(" directories\n"); - message.append(FileUtils.byteCountToDisplaySize(stats.sizeB)); - if (failed) - message.append(" of planned ").append( - FileUtils.byteCountToDisplaySize(sizeB)); - message.append("\n"); - message.append("in ").append(durationStr).append("\n"); - if (failed) - MessageDialog.openError(getShell(), "Import failed", - message.toString()); - else - MessageDialog.openInformation(getShell(), "Import successful", - message.toString()); - - return true; - } - return false; - - } - - /** Recursively computes the size of the directory in bytes. */ - protected Long directorySize(File dir, Long currentSize) { - Long size = currentSize; - File[] files = dir.listFiles(); - for (File file : files) { - if (file.isDirectory()) { - size = directorySize(file, size); - } else { - size = size + file.length(); - } - } - return size; - } - - /** - * Import recursively a directory and its content to the repository. - */ - protected void importDirectory(Node folder, File dir, - IProgressMonitor monitor, Stats stats) { - try { - File[] files = dir.listFiles(); - for (File file : files) { - if (file.isDirectory()) { - Node childFolder = folder.addNode(file.getName(), - NodeType.NT_FOLDER); - importDirectory(childFolder, file, monitor, stats); - folder.getSession().save(); - stats.dirCount++; - } else { - Long fileSize = file.length(); - - // we skip tempory files that are created by apps when a - // file is being edited. - // TODO : make this configurable. - if (file.getName().lastIndexOf('~') != file.getName() - .length() - 1) { - - monitor.subTask(file.getName() + " (" - + FileUtils.byteCountToDisplaySize(fileSize) - + ") " + file.getCanonicalPath()); - try { - Node fileNode = folder.addNode(file.getName(), - NodeType.NT_FILE); - Node resNode = fileNode.addNode( - Property.JCR_CONTENT, NodeType.NT_RESOURCE); - Binary binary = null; - try { - binary = folder - .getSession() - .getValueFactory() - .createBinary(new FileInputStream(file)); - resNode.setProperty(Property.JCR_DATA, binary); - } finally { - if (binary != null) - binary.dispose(); - } - folder.getSession().save(); - stats.fileCount++; - stats.sizeB = stats.sizeB + fileSize; - } catch (Exception e) { - log.warn("Import of " - + file - + " (" - + FileUtils - .byteCountToDisplaySize(fileSize) - + ") failed: " + e); - folder.getSession().refresh(false); - } - monitor.worked((int) (fileSize / FileUtils.ONE_KB)); - } - } - } - } catch (Exception e) { - throw new ArgeoException("Cannot import " + dir + " to " + folder, - e); - } - } - - static class Stats { - public Long fileCount = 0l; - public Long dirCount = 0l; - public Long sizeB = 0l; - } -} diff --git a/org.argeo.jcr.ui.explorer/src/main/resources/org/argeo/jcr/ui/explorer/messages.properties b/org.argeo.jcr.ui.explorer/src/main/resources/org/argeo/jcr/ui/explorer/messages.properties deleted file mode 100644 index 3023c523f..000000000 --- a/org.argeo.jcr.ui.explorer/src/main/resources/org/argeo/jcr/ui/explorer/messages.properties +++ /dev/null @@ -1,28 +0,0 @@ -## English labels for Agreo JCR UI application - -## Generic labels - -## Errors & warnings -errorUnvalidNtFolderNodeType= Error: folder can only be created on a Jcr Node -warningInvalidNodeToImport=Can only import to a node -warningInvalidMultipleSelection=This functionality is implemented only on a single node for the time being. -warningUnversionableNode= Current node is not versionable. -warningNoChildNode= Current node has no child. - -## Commands -getNodeSizeCmdLbl= Get approx. size -addFolderNodeCmdLbl= Add Folder - -## GenericNodeEditor -nodeEditorLbl=Generic node editor -genericNodePageTitle=Properties -childNodesPageTitle=Children -nodeRightsManagementPageTitle=Rights -nodeVersionHistoryPageTitle=History - -# History -versionTreeSectionTitle=Version list -versionHistorySectionTitle=History - -## Dummy ones -testLbl=Internationalizations of messages seems to work properly. diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/JcrExplorerConstants.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/JcrExplorerConstants.java new file mode 100644 index 000000000..a9cb25841 --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/JcrExplorerConstants.java @@ -0,0 +1,27 @@ +/* + * 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.jcr.ui.explorer; + +/** Constants used across the application. */ +public interface JcrExplorerConstants { + /* + * MISCEALLENEOUS + */ + public final static String DATE_TIME_FORMAT = "dd/MM/yyyy, HH:mm"; + + public final static String PARAM_PATH = "org.argeo.jcr.ui.explorer.nodePath"; + +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/JcrExplorerPerspective.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/JcrExplorerPerspective.java new file mode 100644 index 000000000..2626415fc --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/JcrExplorerPerspective.java @@ -0,0 +1,41 @@ +/* + * 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.jcr.ui.explorer; + +import org.eclipse.ui.IFolderLayout; +import org.eclipse.ui.IPageLayout; +import org.eclipse.ui.IPerspectiveFactory; + +/** Base perspective for JcrExplorer browser */ +public class JcrExplorerPerspective implements IPerspectiveFactory { + public static String BROWSER_VIEW_ID = JcrExplorerPlugin.ID + + ".browserView"; + + public void createInitialLayout(IPageLayout layout) { + layout.setEditorAreaVisible(true); + + IFolderLayout upperLeft = layout.createFolder(JcrExplorerPlugin.ID + + ".upperLeft", IPageLayout.LEFT, 0.4f, layout.getEditorArea()); + upperLeft.addView(BROWSER_VIEW_ID); + +// String editorArea = layout.getEditorArea(); +// String logViewId = "org.argeo.security.ui.logView"; +// IFolderLayout bottom = layout.createFolder("bottom", +// IPageLayout.BOTTOM, 0.50f, editorArea); +// bottom.addView(logViewId); + } + +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/JcrExplorerPlugin.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/JcrExplorerPlugin.java new file mode 100644 index 000000000..3bf9e7f7d --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/JcrExplorerPlugin.java @@ -0,0 +1,107 @@ +/* + * 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.jcr.ui.explorer; + +import java.util.ResourceBundle; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + */ +public class JcrExplorerPlugin extends AbstractUIPlugin { + private final static Log log = LogFactory.getLog(JcrExplorerPlugin.class); + private ResourceBundle messages; + + // The plug-in ID + public static final String ID = "org.argeo.jcr.ui.explorer"; //$NON-NLS-1$ + + // The shared instance + private static JcrExplorerPlugin plugin; + + /** + * The constructor + */ + public JcrExplorerPlugin() { + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext + * ) + */ + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + messages = ResourceBundle + .getBundle("org.argeo.jcr.ui.explorer.messages"); + + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext + * ) + */ + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static JcrExplorerPlugin getDefault() { + return plugin; + } + + public static ImageDescriptor getImageDescriptor(String path) { + return imageDescriptorFromPlugin(ID, path); + } + + /** Returns the internationalized label for the given key */ + public static String getMessage(String key) { + try { + return getDefault().messages.getString(key); + } catch (NullPointerException npe) { + log.warn(key + " not found."); + return key; + } + } + + /** + * Gives access to the internationalization message bundle. Returns null in + * case the ClientUiPlugin is not started (for JUnit tests, by instance) + */ + public static ResourceBundle getMessagesBundle() { + if (getDefault() != null) + // To avoid NPE + return getDefault().messages; + else + return null; + } + +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/JcrExplorerView.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/JcrExplorerView.java new file mode 100644 index 000000000..01a957a96 --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/JcrExplorerView.java @@ -0,0 +1,22 @@ +/* + * 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.jcr.ui.explorer; + +import org.argeo.jcr.ui.explorer.views.GenericJcrBrowser; + +public class JcrExplorerView extends GenericJcrBrowser { + +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/browser/NodeContentProvider.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/browser/NodeContentProvider.java new file mode 100644 index 000000000..fb6bd1a15 --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/browser/NodeContentProvider.java @@ -0,0 +1,197 @@ +/* + * 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.jcr.ui.explorer.browser; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; + +import javax.jcr.Node; +import javax.jcr.RepositoryException; +import javax.jcr.RepositoryFactory; +import javax.jcr.Session; +import javax.jcr.nodetype.NodeType; + +import org.argeo.eclipse.ui.TreeParent; +import org.argeo.jcr.ArgeoJcrConstants; +import org.argeo.jcr.RepositoryRegister; +import org.argeo.jcr.UserJcrUtils; +import org.argeo.jcr.ui.explorer.model.RepositoriesElem; +import org.argeo.jcr.ui.explorer.model.SingleJcrNodeElem; +import org.argeo.util.security.Keyring; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.Viewer; + +/** + * Implementation of the {@code ITreeContentProvider} to display multiple + * repository environment in a tree like structure + * + */ +public class NodeContentProvider implements ITreeContentProvider { + final private RepositoryRegister repositoryRegister; + final private RepositoryFactory repositoryFactory; + /** + * A session of the logged in user on the default workspace of the node + * repository. + */ + final private Session userSession; + final private Keyring keyring; + private boolean sortChildren; + + // reference for cleaning + private SingleJcrNodeElem homeNode = null; + private RepositoriesElem repositoriesNode = null; + + // Utils + private TreeBrowserComparator itemComparator = new TreeBrowserComparator(); + + public NodeContentProvider(Session userSession, Keyring keyring, + RepositoryRegister repositoryRegister, + RepositoryFactory repositoryFactory, Boolean sortChildren) { + this.userSession = userSession; + this.keyring = keyring; + this.repositoryRegister = repositoryRegister; + this.repositoryFactory = repositoryFactory; + this.sortChildren = sortChildren; + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + if (newInput == null)// dispose + return; + + if (userSession != null) { + Node userHome = UserJcrUtils.getUserHome(userSession); + if (userHome != null) { + // TODO : find a way to dynamically get alias for the node + if (homeNode != null) + homeNode.dispose(); + homeNode = new SingleJcrNodeElem(null, userHome, + userSession.getUserID(), ArgeoJcrConstants.ALIAS_NODE); + } + } + if (repositoryRegister != null) { + if (repositoriesNode != null) + repositoriesNode.dispose(); + repositoriesNode = new RepositoriesElem("Repositories", + repositoryRegister, repositoryFactory, null, userSession, + keyring); + } + } + + /** + * Sends back the first level of the Tree. Independent from inputElement + * that can be null + */ + public Object[] getElements(Object inputElement) { + List objs = new ArrayList(); + if (homeNode != null) + objs.add(homeNode); + if (repositoriesNode != null) + objs.add(repositoriesNode); + return objs.toArray(); + } + + public Object[] getChildren(Object parentElement) { + if (parentElement instanceof TreeParent) { + if (sortChildren) { + // TreeParent[] arr = (TreeParent[]) ((TreeParent) + // parentElement) + // .getChildren(); + Object[] tmpArr = ((TreeParent) parentElement).getChildren(); + TreeParent[] arr = new TreeParent[tmpArr.length]; + for (int i = 0; i < tmpArr.length; i++) + arr[i] = (TreeParent) tmpArr[i]; + + Arrays.sort(arr, itemComparator); + return arr; + } else + return ((TreeParent) parentElement).getChildren(); + + } else { + return new Object[0]; + } + } + + /** + * Sets whether the content provider should order the children nodes or not. + * It is user duty to call a full refresh of the tree after changing this + * parameter. + */ + public void setSortChildren(boolean sortChildren) { + this.sortChildren = sortChildren; + } + + public Object getParent(Object element) { + if (element instanceof TreeParent) { + return ((TreeParent) element).getParent(); + } else + return null; + } + + public boolean hasChildren(Object element) { + if (element instanceof RepositoriesElem) { + RepositoryRegister rr = ((RepositoriesElem) element) + .getRepositoryRegister(); + return rr.getRepositories().size() > 0; + } else if (element instanceof TreeParent) { + TreeParent tp = (TreeParent) element; + return tp.hasChildren(); + } + return false; + } + + public void dispose() { + if (homeNode != null) + homeNode.dispose(); + if (repositoriesNode != null) { + // logs out open sessions + // see https://bugzilla.argeo.org/show_bug.cgi?id=23 + repositoriesNode.dispose(); + } + } + + /** + * Specific comparator for this view. See spec in BUG : + * https://www.argeo.org/bugzilla/show_bug.cgi?id=139 + */ + private class TreeBrowserComparator implements Comparator { + + public int category(TreeParent element) { + if (element instanceof SingleJcrNodeElem) { + Node node = ((SingleJcrNodeElem) element).getNode(); + try { + if (node.isNodeType(NodeType.NT_FOLDER)) + return 5; + } catch (RepositoryException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + return 10; + } + + public int compare(TreeParent o1, TreeParent o2) { + int cat1 = category(o1); + int cat2 = category(o2); + + if (cat1 != cat2) { + return cat1 - cat2; + } + return o1.getName().compareTo(o2.getName()); + } + } +} \ No newline at end of file diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/browser/NodeLabelProvider.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/browser/NodeLabelProvider.java new file mode 100644 index 000000000..d6d593ce8 --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/browser/NodeLabelProvider.java @@ -0,0 +1,86 @@ +/* + * 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.jcr.ui.explorer.browser; + +import javax.jcr.Node; +import javax.jcr.RepositoryException; +import javax.jcr.nodetype.NodeType; + +import org.argeo.ArgeoException; +import org.argeo.eclipse.ui.jcr.DefaultNodeLabelProvider; +import org.argeo.eclipse.ui.jcr.JcrImages; +import org.argeo.jcr.ui.explorer.model.RemoteRepositoryElem; +import org.argeo.jcr.ui.explorer.model.RepositoriesElem; +import org.argeo.jcr.ui.explorer.model.RepositoryElem; +import org.argeo.jcr.ui.explorer.model.SingleJcrNodeElem; +import org.argeo.jcr.ui.explorer.model.WorkspaceElem; +import org.eclipse.swt.graphics.Image; + +public class NodeLabelProvider extends DefaultNodeLabelProvider { + // Images + + public String getText(Object element) { + try { + if (element instanceof SingleJcrNodeElem) { + SingleJcrNodeElem sjn = (SingleJcrNodeElem) element; + return getText(sjn.getNode()); + } else + return super.getText(element); + } catch (RepositoryException e) { + throw new ArgeoException( + "Unexpected JCR error while getting node name."); + } + } + + protected String getText(Node node) throws RepositoryException { + String label = node.getName(); + StringBuffer mixins = new StringBuffer(""); + for (NodeType type : node.getMixinNodeTypes()) + mixins.append(' ').append(type.getName()); + + return label + " [" + node.getPrimaryNodeType().getName() + mixins + + "]"; + } + + @Override + public Image getImage(Object element) { + if (element instanceof RemoteRepositoryElem) { + if (((RemoteRepositoryElem) element).isConnected()) + return JcrImages.REMOTE_CONNECTED; + else + return JcrImages.REMOTE_DISCONNECTED; + } else if (element instanceof RepositoryElem) { + if (((RepositoryElem) element).isConnected()) + return JcrImages.REPOSITORY_CONNECTED; + else + return JcrImages.REPOSITORY_DISCONNECTED; + } else if (element instanceof WorkspaceElem) { + if (((WorkspaceElem) element).isConnected()) + return JcrImages.WORKSPACE_CONNECTED; + else + return JcrImages.WORKSPACE_DISCONNECTED; + } else if (element instanceof RepositoriesElem) { + return JcrImages.REPOSITORIES; + } else if (element instanceof SingleJcrNodeElem) + try { + return super.getImage(((SingleJcrNodeElem) element).getNode()); + } catch (RepositoryException e) { + return null; + } + return super.getImage(element); + } + +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/browser/PropertiesContentProvider.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/browser/PropertiesContentProvider.java new file mode 100644 index 000000000..d39f3195e --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/browser/PropertiesContentProvider.java @@ -0,0 +1,56 @@ +/* + * 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.jcr.ui.explorer.browser; + +import java.util.Set; +import java.util.TreeSet; + +import javax.jcr.Node; +import javax.jcr.Property; +import javax.jcr.PropertyIterator; +import javax.jcr.RepositoryException; + +import org.argeo.ArgeoException; +import org.argeo.eclipse.ui.jcr.utils.JcrItemsComparator; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.Viewer; + +public class PropertiesContentProvider implements IStructuredContentProvider { + private JcrItemsComparator itemComparator = new JcrItemsComparator(); + + public void dispose() { + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + } + + public Object[] getElements(Object inputElement) { + try { + if (inputElement instanceof Node) { + Set props = new TreeSet(itemComparator); + PropertyIterator pit = ((Node) inputElement).getProperties(); + while (pit.hasNext()) + props.add(pit.nextProperty()); + return props.toArray(); + } + return new Object[] {}; + } catch (RepositoryException e) { + throw new ArgeoException("Cannot get element for " + inputElement, + e); + } + } + +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/AddFolderNode.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/AddFolderNode.java new file mode 100644 index 000000000..0389aeec0 --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/AddFolderNode.java @@ -0,0 +1,101 @@ +/* + * 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.jcr.ui.explorer.commands; + +import javax.jcr.Node; +import javax.jcr.RepositoryException; +import javax.jcr.nodetype.NodeType; + +import org.argeo.eclipse.ui.ErrorFeedback; +import org.argeo.eclipse.ui.TreeParent; +import org.argeo.eclipse.ui.dialogs.SingleValue; +import org.argeo.eclipse.ui.jcr.JcrUiPlugin; +import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; +import org.argeo.jcr.ui.explorer.model.SingleJcrNodeElem; +import org.argeo.jcr.ui.explorer.model.WorkspaceElem; +import org.argeo.jcr.ui.explorer.views.GenericJcrBrowser; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * Adds a node of type nt:folder, only on {@link SingleJcrNodeElem} and + * {@link WorkspaceElem} TreeObject types. + * + * + * This handler assumes that a selection provider is available and picks only + * first selected item. It is UI's job to enable the command only when the + * selection contains one and only one element. Thus no parameter is passed + * through the command. + * + * This handler is still 'hard linked' to a GenericJcrBrowser view to enable + * correct tree refresh when a node is added. This must be corrected in future + * versions. + */ +public class AddFolderNode extends AbstractHandler { + + public final static String ID = JcrExplorerPlugin.ID + ".addFolderNode"; + + // public final static String DEFAULT_LABEL = JcrExplorerPlugin + // .getMessage("addFolderNodeCmdLbl"); + // public final static String DEFAULT_ICON_REL_PATH = "icons/addRepo.gif"; + + public Object execute(ExecutionEvent event) throws ExecutionException { + + ISelection selection = HandlerUtil.getActiveWorkbenchWindow(event) + .getActivePage().getSelection(); + + GenericJcrBrowser view = (GenericJcrBrowser) HandlerUtil + .getActiveWorkbenchWindow(event).getActivePage() + .findView(HandlerUtil.getActivePartId(event)); + + if (selection != null && !selection.isEmpty() + && selection instanceof IStructuredSelection) { + Object obj = ((IStructuredSelection) selection).getFirstElement(); + TreeParent treeParentNode = null; + Node jcrParentNode = null; + + if (obj instanceof SingleJcrNodeElem) { + treeParentNode = (TreeParent) obj; + jcrParentNode = ((SingleJcrNodeElem) treeParentNode).getNode(); + } else if (obj instanceof WorkspaceElem) { + treeParentNode = (TreeParent) obj; + jcrParentNode = ((WorkspaceElem) treeParentNode).getRootNode(); + } else + return null; + + String folderName = SingleValue.ask("Folder name", + "Enter folder name"); + if (folderName != null) { + try { + jcrParentNode.addNode(folderName, NodeType.NT_FOLDER); + jcrParentNode.getSession().save(); + view.nodeAdded(treeParentNode); + } catch (RepositoryException e) { + ErrorFeedback.show("Cannot create folder " + folderName + + " under " + treeParentNode, e); + } + } + } else { + ErrorFeedback.show(JcrUiPlugin + .getMessage("errorUnvalidNtFolderNodeType")); + } + return null; + } +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/AddPrivileges.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/AddPrivileges.java new file mode 100644 index 000000000..829290ebe --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/AddPrivileges.java @@ -0,0 +1,79 @@ +/* + * 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.jcr.ui.explorer.commands; + +import javax.jcr.Node; +import javax.jcr.RepositoryException; + +import org.argeo.ArgeoException; +import org.argeo.eclipse.ui.ErrorFeedback; +import org.argeo.eclipse.ui.TreeParent; +import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; +import org.argeo.jcr.ui.explorer.model.SingleJcrNodeElem; +import org.argeo.jcr.ui.explorer.model.WorkspaceElem; +import org.argeo.jcr.ui.explorer.wizards.ChangeRightsWizard; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.wizard.WizardDialog; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * Open a dialog to change rights on the selected node. + */ + +public class AddPrivileges extends AbstractHandler { + public final static String ID = JcrExplorerPlugin.ID + ".addPrivileges"; + + public Object execute(ExecutionEvent event) throws ExecutionException { + + ISelection selection = HandlerUtil.getActiveWorkbenchWindow(event) + .getActivePage().getSelection(); + if (selection != null && !selection.isEmpty() + && selection instanceof IStructuredSelection) { + Object obj = ((IStructuredSelection) selection).getFirstElement(); + TreeParent treeParentNode = null; + Node jcrParentNode = null; + + if (obj instanceof SingleJcrNodeElem) { + treeParentNode = (TreeParent) obj; + jcrParentNode = ((SingleJcrNodeElem) treeParentNode).getNode(); + } else if (obj instanceof WorkspaceElem) { + treeParentNode = (TreeParent) obj; + jcrParentNode = ((WorkspaceElem) treeParentNode).getRootNode(); + } else + return null; + + try { + ChangeRightsWizard wizard = new ChangeRightsWizard( + jcrParentNode.getSession(), jcrParentNode.getPath()); + WizardDialog dialog = new WizardDialog( + HandlerUtil.getActiveShell(event), wizard); + dialog.open(); + return null; + } catch (RepositoryException re) { + throw new ArgeoException( + "Unexpected error while creating the new workspace.", + re); + } + } else { + ErrorFeedback.show("Cannot add privileges"); + } + return null; + } +} \ No newline at end of file diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/AddRemoteRepository.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/AddRemoteRepository.java new file mode 100644 index 000000000..e41edfca8 --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/AddRemoteRepository.java @@ -0,0 +1,230 @@ +/* + * 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.jcr.ui.explorer.commands; + +import java.net.URI; +import java.util.Hashtable; + +import javax.jcr.Node; +import javax.jcr.Repository; +import javax.jcr.RepositoryFactory; +import javax.jcr.Session; +import javax.jcr.SimpleCredentials; + +import org.argeo.ArgeoException; +import org.argeo.eclipse.ui.ErrorFeedback; +import org.argeo.eclipse.ui.utils.CommandUtils; +import org.argeo.jcr.ArgeoJcrConstants; +import org.argeo.jcr.ArgeoNames; +import org.argeo.jcr.ArgeoTypes; +import org.argeo.jcr.JcrUtils; +import org.argeo.jcr.UserJcrUtils; +import org.argeo.jcr.ui.explorer.JcrExplorerConstants; +import org.argeo.util.security.Keyring; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.dialogs.TitleAreaDialog; +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.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.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +/** + * Connect to a remote repository and, if successful publish it as an OSGi + * service. + */ +public class AddRemoteRepository extends AbstractHandler implements + JcrExplorerConstants, ArgeoNames { + + private RepositoryFactory repositoryFactory; + private Repository nodeRepository; + private Keyring keyring; + + public Object execute(ExecutionEvent event) throws ExecutionException { + RemoteRepositoryLoginDialog dlg = new RemoteRepositoryLoginDialog( + Display.getDefault().getActiveShell()); + if (dlg.open() == Dialog.OK) { + CommandUtils.callCommand(Refresh.ID); + } + return null; + } + + public void setRepositoryFactory(RepositoryFactory repositoryFactory) { + this.repositoryFactory = repositoryFactory; + } + + public void setKeyring(Keyring keyring) { + this.keyring = keyring; + } + + public void setNodeRepository(Repository nodeRepository) { + this.nodeRepository = nodeRepository; + } + + class RemoteRepositoryLoginDialog extends TitleAreaDialog { + private Text name; + private Text uri; + private Text username; + private Text password; + private Button saveInKeyring; + + public RemoteRepositoryLoginDialog(Shell parentShell) { + super(parentShell); + } + + protected Point getInitialSize() { + return new Point(600, 400); + } + + protected Control createDialogArea(Composite parent) { + Composite dialogarea = (Composite) super.createDialogArea(parent); + dialogarea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, + true)); + Composite composite = new Composite(dialogarea, SWT.NONE); + composite.setLayout(new GridLayout(2, false)); + composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, + false)); + setMessage("Login to remote repository", IMessageProvider.NONE); + name = createLT(composite, "Name", "remoteRepository"); + uri = createLT(composite, "URI", + "http://localhost:7070/data/jcr/node"); + username = createLT(composite, "User", ""); + password = createLP(composite, "Password"); + + saveInKeyring = createLC(composite, "Remember password", false); + parent.pack(); + return composite; + } + + @Override + protected void createButtonsForButtonBar(Composite parent) { + super.createButtonsForButtonBar(parent); + Button test = createButton(parent, 2, "Test", false); + test.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent arg0) { + testConnection(); + } + }); + } + + void testConnection() { + Session session = null; + try { + URI checkedUri = new URI(uri.getText()); + String checkedUriStr = checkedUri.toString(); + + Hashtable params = new Hashtable(); + params.put(ArgeoJcrConstants.JCR_REPOSITORY_URI, checkedUriStr); + Repository repository = repositoryFactory.getRepository(params); + if (username.getText().trim().equals("")) {// anonymous + session = repository.login(); + } else { + // FIXME use getTextChars() when upgrading to 3.7 + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=297412 + char[] pwd = password.getText().toCharArray(); + SimpleCredentials sc = new SimpleCredentials( + username.getText(), pwd); + session = repository.login(sc); + MessageDialog.openInformation(getParentShell(), "Success", + "Connection to '" + uri.getText() + "' successful"); + } + } catch (Exception e) { + ErrorFeedback.show( + "Connection test failed for " + uri.getText(), e); + } finally { + JcrUtils.logoutQuietly(session); + } + } + + @Override + protected void okPressed() { + Session nodeSession = null; + try { + nodeSession = nodeRepository.login(); + Node home = UserJcrUtils.getUserHome(nodeSession); + + Node remote = home.hasNode(ARGEO_REMOTE) ? home + .getNode(ARGEO_REMOTE) : home.addNode(ARGEO_REMOTE); + if (remote.hasNode(name.getText())) + throw new ArgeoException( + "There is already a remote repository named " + + name.getText()); + Node remoteRepository = remote.addNode(name.getText(), + ArgeoTypes.ARGEO_REMOTE_REPOSITORY); + remoteRepository.setProperty(ARGEO_URI, uri.getText()); + remoteRepository.setProperty(ARGEO_USER_ID, username.getText()); + nodeSession.save(); + if (saveInKeyring.getSelection()) { + String pwdPath = remoteRepository.getPath() + '/' + + ARGEO_PASSWORD; + keyring.set(pwdPath, password.getText().toCharArray()); + } + nodeSession.save(); + MessageDialog.openInformation( + getParentShell(), + "Repository Added", + "Remote repository '" + username.getText() + "@" + + uri.getText() + "' added"); + + super.okPressed(); + } catch (Exception e) { + ErrorFeedback.show("Cannot add remote repository", e); + } finally { + JcrUtils.logoutQuietly(nodeSession); + } + } + + /** Creates label and text. */ + protected Text createLT(Composite parent, String label, String initial) { + new Label(parent, SWT.NONE).setText(label); + Text text = new Text(parent, SWT.SINGLE | SWT.LEAD | SWT.BORDER); + text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + text.setText(initial); + return text; + } + + /** Creates label and check. */ + protected Button createLC(Composite parent, String label, + Boolean initial) { + new Label(parent, SWT.NONE).setText(label); + Button check = new Button(parent, SWT.CHECK); + check.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + check.setSelection(initial); + return check; + } + + protected Text createLP(Composite parent, String label) { + new Label(parent, SWT.NONE).setText(label); + Text text = new Text(parent, SWT.SINGLE | SWT.LEAD | SWT.BORDER + | SWT.PASSWORD); + text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + return text; + } + } +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/CreateWorkspace.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/CreateWorkspace.java new file mode 100644 index 000000000..e579630ce --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/CreateWorkspace.java @@ -0,0 +1,70 @@ +/* + * 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.jcr.ui.explorer.commands; + +import java.util.Arrays; + +import org.argeo.eclipse.ui.ErrorFeedback; +import org.argeo.eclipse.ui.dialogs.SingleValue; +import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; +import org.argeo.jcr.ui.explorer.model.RepositoryElem; +import org.argeo.jcr.ui.explorer.views.GenericJcrBrowser; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.handlers.HandlerUtil; + +/** Creates a new JCR workspace */ +public class CreateWorkspace extends AbstractHandler { + + public final static String ID = JcrExplorerPlugin.ID + ".addFolderNode"; + + public Object execute(ExecutionEvent event) throws ExecutionException { + + ISelection selection = HandlerUtil.getActiveWorkbenchWindow(event) + .getActivePage().getSelection(); + + GenericJcrBrowser view = (GenericJcrBrowser) HandlerUtil + .getActiveWorkbenchWindow(event).getActivePage() + .findView(HandlerUtil.getActivePartId(event)); + + if (selection != null && !selection.isEmpty() + && selection instanceof IStructuredSelection) { + Object obj = ((IStructuredSelection) selection).getFirstElement(); + if (!(obj instanceof RepositoryElem)) + return null; + + RepositoryElem repositoryNode = (RepositoryElem) obj; + String workspaceName = SingleValue.ask("Workspace name", + "Enter workspace name"); + if (workspaceName != null) { + if (Arrays.asList(repositoryNode.getAccessibleWorkspaceNames()) + .contains(workspaceName)) { + ErrorFeedback.show("Workspace " + workspaceName + + " already exists."); + } else { + repositoryNode.createWorkspace(workspaceName); + view.nodeAdded(repositoryNode); + } + } + } else { + ErrorFeedback.show("Cannot create workspace"); + } + return null; + } +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/DeleteNodes.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/DeleteNodes.java new file mode 100644 index 000000000..26d4cdd43 --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/DeleteNodes.java @@ -0,0 +1,118 @@ +/* + * 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.jcr.ui.explorer.commands; + +import java.util.Iterator; + +import javax.jcr.Node; +import javax.jcr.RepositoryException; + +import org.argeo.ArgeoException; +import org.argeo.eclipse.ui.ErrorFeedback; +import org.argeo.eclipse.ui.TreeParent; +import org.argeo.jcr.ui.explorer.model.SingleJcrNodeElem; +import org.argeo.jcr.ui.explorer.model.WorkspaceElem; +import org.argeo.jcr.ui.explorer.views.GenericJcrBrowser; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * Deletes the selected nodes: both in the JCR repository and in the UI view. + * Warning no check is done, except implementation dependent native checks, + * handle with care. + * + * This handler is still 'hard linked' to a GenericJcrBrowser view to enable + * correct tree refresh when a node is added. This must be corrected in future + * versions. + */ +public class DeleteNodes extends AbstractHandler { + public Object execute(ExecutionEvent event) throws ExecutionException { + ISelection selection = HandlerUtil.getActiveWorkbenchWindow(event) + .getActivePage().getSelection(); + if (selection == null || !(selection instanceof IStructuredSelection)) + return null; + + GenericJcrBrowser view = (GenericJcrBrowser) HandlerUtil + .getActiveWorkbenchWindow(event).getActivePage() + .findView(HandlerUtil.getActivePartId(event)); + + // confirmation + StringBuffer buf = new StringBuffer(""); + Iterator lst = ((IStructuredSelection) selection).iterator(); + while (lst.hasNext()) { + SingleJcrNodeElem sjn = ((SingleJcrNodeElem) lst.next()); + buf.append(sjn.getName()).append(' '); + } + Boolean ok = MessageDialog.openConfirm( + HandlerUtil.getActiveShell(event), "Confirm deletion", + "Do you want to delete " + buf + "?"); + + // operation + if (ok) { + Iterator it = ((IStructuredSelection) selection).iterator(); + Object obj = null; + SingleJcrNodeElem ancestor = null; + WorkspaceElem rootAncestor = null; + try { + while (it.hasNext()) { + obj = it.next(); + if (obj instanceof SingleJcrNodeElem) { + // Cache objects + SingleJcrNodeElem sjn = (SingleJcrNodeElem) obj; + TreeParent tp = (TreeParent) sjn.getParent(); + Node node = sjn.getNode(); + + // Jcr Remove + node.remove(); + node.getSession().save(); + // UI remove + tp.removeChild(sjn); + + // Check if the parent is the root node + if (tp instanceof WorkspaceElem) + rootAncestor = (WorkspaceElem) tp; + else + ancestor = getOlder(ancestor, (SingleJcrNodeElem) tp); + } + } + if (rootAncestor != null) + view.nodeRemoved(rootAncestor); + else if (ancestor != null) + view.nodeRemoved(ancestor); + } catch (Exception e) { + ErrorFeedback.show("Cannot delete selected node ", e); + } + } + return null; + } + + private SingleJcrNodeElem getOlder(SingleJcrNodeElem A, SingleJcrNodeElem B) { + try { + if (A == null) + return B == null ? null : B; + // Todo enhanced this method + else + return A.getNode().getDepth() <= B.getNode().getDepth() ? A : B; + } catch (RepositoryException re) { + throw new ArgeoException("Cannot find ancestor", re); + } + } +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/DumpNode.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/DumpNode.java new file mode 100644 index 000000000..c8a235d73 --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/DumpNode.java @@ -0,0 +1,110 @@ +/* + * 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.jcr.ui.explorer.commands; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import javax.jcr.Node; +import javax.jcr.RepositoryException; + +import org.argeo.ArgeoException; +import org.argeo.eclipse.ui.specific.OpenFile; +import org.argeo.eclipse.ui.utils.CommandUtils; +import org.argeo.jcr.JcrUtils; +import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; +import org.argeo.jcr.ui.explorer.model.SingleJcrNodeElem; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * If the method + * HandlerUtil.getActiveWorkbenchWindow(event).getActivePage().getSelection() + * exits and has a SingleJcrNodeElem as first element, it canonically calls the + * JCR Session.exportSystemView() method on the underlying node with both + * skipBinary & noRecurse boolean flags set to false. + * + * Resulting stream is saved in a tmp file and opened via the "open file" + * single-sourced command. + */ +public class DumpNode extends AbstractHandler { + public final static String ID = JcrExplorerPlugin.ID + ".dumpNode"; + + private final static DateFormat df = new SimpleDateFormat( + "yyyy-MM-dd_HH-mm"); + + public Object execute(ExecutionEvent event) throws ExecutionException { + ISelection selection = HandlerUtil.getActiveWorkbenchWindow(event) + .getActivePage().getSelection(); + if (selection == null || !(selection instanceof IStructuredSelection)) + return null; + + Iterator lst = ((IStructuredSelection) selection).iterator(); + if (lst.hasNext()) { + Object element = lst.next(); + if (element instanceof SingleJcrNodeElem) { + SingleJcrNodeElem sjn = (SingleJcrNodeElem) element; + Node node = sjn.getNode(); + + // TODO add a dialog to configure the export and ask for + // confirmation + // Boolean ok = MessageDialog.openConfirm( + // HandlerUtil.getActiveShell(event), "Confirm deletion", + // "Do you want to delete " + buf + "?"); + + File tmpFile; + FileOutputStream fos; + try { + tmpFile = File.createTempFile("JcrExport", ".xml"); + tmpFile.deleteOnExit(); + fos = new FileOutputStream(tmpFile); + String dateVal = df.format(new GregorianCalendar() + .getTime()); + node.getSession().exportSystemView(node.getPath(), fos, + true, false); + openGeneratedFile(tmpFile.getAbsolutePath(), + "Dump-" + JcrUtils.replaceInvalidChars(node.getName())+ "-" + dateVal + ".xml"); + } catch (RepositoryException e) { + throw new ArgeoException( + "Unable to perform SystemExport on " + node, e); + } catch (IOException e) { + throw new ArgeoException("Unable to SystemExport " + node, + e); + } + } + } + return null; + } + + private synchronized void openGeneratedFile(String path, String fileName) { + Map params = new HashMap(); + params.put(OpenFile.PARAM_FILE_NAME, fileName); + params.put(OpenFile.PARAM_FILE_URI, "file://" + path); + CommandUtils.callCommand("org.argeo.security.ui.specific.openFile", + params); + } +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/EditNode.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/EditNode.java new file mode 100644 index 000000000..e98973e47 --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/EditNode.java @@ -0,0 +1,69 @@ +/* + * 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.jcr.ui.explorer.commands; + +import java.util.HashMap; +import java.util.Map; + +import javax.jcr.Property; +import javax.jcr.nodetype.NodeType; + +import org.argeo.eclipse.ui.ErrorFeedback; +import org.argeo.eclipse.ui.jcr.editors.NodeEditorInput; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.handlers.HandlerUtil; + +/** Generic command to open a path in an editor. */ +public class EditNode extends AbstractHandler { + public final static String EDITOR_PARAM = "editor"; + + private String defaultEditorId; + + private Map nodeTypeToEditor = new HashMap(); + + public Object execute(ExecutionEvent event) throws ExecutionException { + String path = event.getParameter(Property.JCR_PATH); + + String type = event.getParameter(NodeType.NT_NODE_TYPE); + if (type == null) + type = NodeType.NT_UNSTRUCTURED; + + String editorId = event.getParameter(NodeType.NT_NODE_TYPE); + if (editorId == null) + editorId = nodeTypeToEditor.containsKey(type) ? nodeTypeToEditor + .get(type) : defaultEditorId; + + NodeEditorInput nei = new NodeEditorInput(path); + + try { + HandlerUtil.getActiveWorkbenchWindow(event).getActivePage() + .openEditor(nei, editorId); + } catch (PartInitException e) { + ErrorFeedback.show("Cannot open " + editorId + " with " + path + + " of type " + type, e); + } + // TODO Auto-generated method stub + return null; + } + + public void setDefaultEditorId(String defaultEditorId) { + this.defaultEditorId = defaultEditorId; + } + +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/GetNodeSize.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/GetNodeSize.java new file mode 100644 index 000000000..cfcac1354 --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/GetNodeSize.java @@ -0,0 +1,113 @@ +/* + * 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.jcr.ui.explorer.commands; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import javax.jcr.Node; + +import org.argeo.eclipse.ui.ErrorFeedback; +import org.argeo.jcr.JcrUtils; +import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; +import org.argeo.jcr.ui.explorer.model.SingleJcrNodeElem; +import org.argeo.jcr.ui.explorer.model.WorkspaceElem; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.handlers.HandlerUtil; + +/** Opens the generic node editor. */ +public class GetNodeSize extends AbstractHandler { + // private final static Log log = LogFactory.getLog(GetNodeSize.class); + + public final static String ID = JcrExplorerPlugin.ID + ".getNodeSize"; + + // public final static String DEFAULT_ICON_REL_PATH = "icons/getSize.gif"; + // public final static String DEFAULT_LABEL = JcrExplorerPlugin + // .getMessage("getNodeSizeCmdLbl"); + + public Object execute(ExecutionEvent event) throws ExecutionException { + // JcrUtils.getRepositoryByAlias(repositoryRegister, + // ArgeoJcrConstants.ALIAS_NODE); + + ISelection selection = HandlerUtil.getActiveWorkbenchWindow(event) + .getActivePage().getSelection(); + + if (selection != null && !selection.isEmpty() + && selection instanceof IStructuredSelection) { + + // IStructuredSelection iss = (IStructuredSelection) selection; + // if (iss.size() > 1) + // ErrorFeedback.show(JcrExplorerPlugin + // .getMessage("warningInvalidMultipleSelection"), null); + + long size = 0; + + Iterator it = ((IStructuredSelection) selection).iterator(); + + // as the size method is recursive, we keep track of nodes for which + // we already have computed size so that we don't count them twice. + // In a first approximation, we assume that the structure selection + // keep the nodes ordered. + // TODO : enhance that. + List importedPathes = new ArrayList(); + try { + nodesIt: while (it.hasNext()) { + Object obj = it.next(); + String curPath; + Node node; + if (obj instanceof SingleJcrNodeElem) { + node = ((SingleJcrNodeElem) obj).getNode(); + curPath = node.getSession().getWorkspace().getName(); + curPath += "/" + node.getPath(); + } else if (obj instanceof WorkspaceElem) { + node = ((WorkspaceElem) obj).getRootNode(); + curPath = node.getSession().getWorkspace().getName(); + } else + // unvalid object type + continue nodesIt; + + Iterator itPath = importedPathes.iterator(); + while (itPath.hasNext()) { + String refPath = itPath.next(); + if (curPath.startsWith(refPath)) + // Already done : skip node + continue nodesIt; + } + size += JcrUtils.getNodeApproxSize(node); + importedPathes.add(curPath); + } + } catch (Exception e) { + ErrorFeedback.show("Cannot Get size of selected node ", e); + } + + String[] labels = { "OK" }; + Shell shell = HandlerUtil.getActiveWorkbenchWindow(event) + .getShell(); + MessageDialog md = new MessageDialog(shell, "Node size", null, + "Node size is: " + size / 1024 + " KB", + MessageDialog.INFORMATION, labels, 0); + md.open(); + } + return null; + } +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/ImportFileSystem.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/ImportFileSystem.java new file mode 100644 index 000000000..5c4bf7e6b --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/ImportFileSystem.java @@ -0,0 +1,70 @@ +/* + * 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.jcr.ui.explorer.commands; + +import javax.jcr.Node; + +import org.argeo.eclipse.ui.ErrorFeedback; +import org.argeo.eclipse.ui.TreeParent; +import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; +import org.argeo.jcr.ui.explorer.model.SingleJcrNodeElem; +import org.argeo.jcr.ui.explorer.model.WorkspaceElem; +import org.argeo.jcr.ui.explorer.views.GenericJcrBrowser; +import org.argeo.jcr.ui.explorer.wizards.ImportFileSystemWizard; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.wizard.WizardDialog; +import org.eclipse.ui.handlers.HandlerUtil; + +/** Import a local file system directory tree. */ +public class ImportFileSystem extends AbstractHandler { + public Object execute(ExecutionEvent event) throws ExecutionException { + ISelection selection = HandlerUtil.getActiveWorkbenchWindow(event) + .getActivePage().getSelection(); + GenericJcrBrowser view = (GenericJcrBrowser) HandlerUtil + .getActiveWorkbenchWindow(event).getActivePage() + .findView(HandlerUtil.getActivePartId(event)); + if (selection != null && !selection.isEmpty() + && selection instanceof IStructuredSelection) { + Object obj = ((IStructuredSelection) selection).getFirstElement(); + try { + Node folder = null; + if (obj instanceof SingleJcrNodeElem) { + folder = ((SingleJcrNodeElem) obj).getNode(); + } else if (obj instanceof WorkspaceElem) { + folder = ((WorkspaceElem) obj).getRootNode(); + } else { + ErrorFeedback.show(JcrExplorerPlugin + .getMessage("warningInvalidNodeToImport")); + } + if (folder != null) { + ImportFileSystemWizard wizard = new ImportFileSystemWizard( + folder); + WizardDialog dialog = new WizardDialog( + HandlerUtil.getActiveShell(event), wizard); + dialog.open(); + view.nodeAdded((TreeParent) obj); + } + } catch (Exception e) { + ErrorFeedback.show("Cannot import files to " + obj, e); + } + } + return null; + } +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/OpenGenericNodeEditor.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/OpenGenericNodeEditor.java new file mode 100644 index 000000000..6799d1706 --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/OpenGenericNodeEditor.java @@ -0,0 +1,44 @@ +/* + * 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.jcr.ui.explorer.commands; + +import org.argeo.ArgeoException; +import org.argeo.eclipse.ui.jcr.editors.NodeEditorInput; +import org.argeo.jcr.ui.explorer.JcrExplorerConstants; +import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; +import org.argeo.jcr.ui.explorer.editors.GenericNodeEditor; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.ui.handlers.HandlerUtil; + +/** Opens the generic node editor. */ +public class OpenGenericNodeEditor extends AbstractHandler { + public final static String ID = JcrExplorerPlugin.ID + ".openGenericNodeEditor"; + + public Object execute(ExecutionEvent event) throws ExecutionException { + String path = event.getParameter(JcrExplorerConstants.PARAM_PATH); + try { + NodeEditorInput nei = new NodeEditorInput(path); + HandlerUtil.getActiveWorkbenchWindow(event).getActivePage() + .openEditor(nei, GenericNodeEditor.ID); + } catch (Exception e) { + throw new ArgeoException("Cannot open editor", e); + } + return null; + } + +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/Refresh.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/Refresh.java new file mode 100644 index 000000000..21ce25658 --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/Refresh.java @@ -0,0 +1,68 @@ +/* + * 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.jcr.ui.explorer.commands; + +import java.util.Iterator; + +import org.argeo.eclipse.ui.TreeParent; +import org.argeo.eclipse.ui.jcr.views.AbstractJcrBrowser; +import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; +import org.argeo.jcr.ui.explorer.utils.JcrUiUtils; +import org.argeo.jcr.ui.explorer.views.GenericJcrBrowser; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; + +/** + * Force the selected objects of the active view to be refreshed doing the + * following: + *
    + *
  1. The model objects are recomputed
  2. + *
  3. the view is refreshed
  4. + *
+ */ +public class Refresh extends AbstractHandler { + + public final static String ID = JcrExplorerPlugin.ID + ".refresh"; + + public Object execute(ExecutionEvent event) throws ExecutionException { + + AbstractJcrBrowser view = (AbstractJcrBrowser) JcrExplorerPlugin + .getDefault().getWorkbench().getActiveWorkbenchWindow() + .getActivePage().getActivePart();// + + ISelection selection = JcrExplorerPlugin.getDefault().getWorkbench() + .getActiveWorkbenchWindow().getActivePage().getSelection(); + + if (selection != null && selection instanceof IStructuredSelection + && !selection.isEmpty()) { + Iterator it = ((IStructuredSelection) selection).iterator(); + while (it.hasNext()) { + Object obj = it.next(); + if (obj instanceof TreeParent) { + TreeParent tp = (TreeParent) obj; + JcrUiUtils.forceRefreshIfNeeded(tp); + view.refresh(obj); + } + } + } else if (view instanceof GenericJcrBrowser) + ((GenericJcrBrowser) view).refresh(null); // force full refresh + + return null; + } +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/RemoveRemoteRepository.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/RemoveRemoteRepository.java new file mode 100644 index 000000000..ec23dd08c --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/RemoveRemoteRepository.java @@ -0,0 +1,51 @@ +/* + * 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.jcr.ui.explorer.commands; + +import org.argeo.jcr.ui.explorer.model.RemoteRepositoryElem; +import org.argeo.jcr.ui.explorer.views.GenericJcrBrowser; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.handlers.HandlerUtil; + +/** Remove a registered remote repository */ +public class RemoveRemoteRepository extends AbstractHandler { + + public Object execute(ExecutionEvent event) throws ExecutionException { + + ISelection selection = HandlerUtil.getActiveWorkbenchWindow(event) + .getActivePage().getSelection(); + + GenericJcrBrowser view = (GenericJcrBrowser) HandlerUtil + .getActiveWorkbenchWindow(event).getActivePage() + .findView(HandlerUtil.getActivePartId(event)); + + if (selection != null && !selection.isEmpty() + && selection instanceof IStructuredSelection) { + Object obj = ((IStructuredSelection) selection).getFirstElement(); + + if (obj instanceof RemoteRepositoryElem) { + ((RemoteRepositoryElem) obj).remove(); + view.refresh(null); + } + } + return null; + } + +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/SortChildNodes.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/SortChildNodes.java new file mode 100644 index 000000000..2961529d8 --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/commands/SortChildNodes.java @@ -0,0 +1,50 @@ +/* + * 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.jcr.ui.explorer.commands; + +import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; +import org.argeo.jcr.ui.explorer.views.GenericJcrBrowser; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.Command; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.commands.State; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.commands.ICommandService; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * Change isSorted state of the JcrExplorer Browser + */ +public class SortChildNodes extends AbstractHandler { + public final static String ID = JcrExplorerPlugin.ID + ".sortChildNodes"; + + public Object execute(ExecutionEvent event) throws ExecutionException { + GenericJcrBrowser view = (GenericJcrBrowser) HandlerUtil + .getActiveWorkbenchWindow(event).getActivePage() + .findView(GenericJcrBrowser.ID); + + ICommandService service = (ICommandService) PlatformUI.getWorkbench() + .getService(ICommandService.class); + Command command = service.getCommand(ID); + State state = command.getState(ID + ".toggleState"); + + boolean wasSorted = (Boolean) state.getValue(); + view.setSortChildNodes(!wasSorted); + state.setValue(!wasSorted); + return null; + } +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/dialogs/ChooseNameDialog.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/dialogs/ChooseNameDialog.java new file mode 100644 index 000000000..d4a5cc757 --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/dialogs/ChooseNameDialog.java @@ -0,0 +1,67 @@ +/* + * 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.jcr.ui.explorer.dialogs; + +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.dialogs.TitleAreaDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +/** Dialog to change the current user password */ +public class ChooseNameDialog extends TitleAreaDialog { + private Text nameT; + + public ChooseNameDialog(Shell parentShell) { + super(parentShell); + setTitle("Choose name"); + } + + protected Point getInitialSize() { + return new Point(300, 250); + } + + protected Control createDialogArea(Composite parent) { + Composite dialogarea = (Composite) super.createDialogArea(parent); + dialogarea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + Composite composite = new Composite(dialogarea, SWT.NONE); + composite.setLayout(new GridLayout(2, false)); + composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + nameT = createLT(composite, "Name"); + + setMessage("Choose name", IMessageProvider.INFORMATION); + parent.pack(); + return composite; + } + + /** Creates label and text. */ + protected Text createLT(Composite parent, String label) { + new Label(parent, SWT.NONE).setText(label); + Text text = new Text(parent, SWT.SINGLE | SWT.LEAD | SWT.BORDER); + text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + return text; + } + + public String getName() { + return nameT.getText(); + } +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/editors/ChildNodesPage.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/editors/ChildNodesPage.java new file mode 100644 index 000000000..682254a48 --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/editors/ChildNodesPage.java @@ -0,0 +1,93 @@ +/* + * 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.jcr.ui.explorer.editors; + +import javax.jcr.Node; + +import org.argeo.ArgeoException; +import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; +import org.argeo.jcr.ui.explorer.browser.NodeLabelProvider; +import org.argeo.jcr.ui.explorer.providers.SingleNodeAsTreeContentProvider; +import org.argeo.jcr.ui.explorer.utils.GenericNodeDoubleClickListener; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.forms.IManagedForm; +import org.eclipse.ui.forms.editor.FormEditor; +import org.eclipse.ui.forms.editor.FormPage; +import org.eclipse.ui.forms.widgets.ScrolledForm; + +/** + * List all childs of the current node and brings some browsing capabilities + * accross the repository + */ +public class ChildNodesPage extends FormPage { + // private final static Log log = LogFactory.getLog(ChildNodesPage.class); + + // business objects + private Node currentNode; + + // this page UI components + private SingleNodeAsTreeContentProvider nodeContentProvider; + private TreeViewer nodesViewer; + + public ChildNodesPage(FormEditor editor, String title, Node currentNode) { + super(editor, "ChildNodesPage", title); + this.currentNode = currentNode; + } + + protected void createFormContent(IManagedForm managedForm) { + try { + ScrolledForm form = managedForm.getForm(); + form.setText(JcrExplorerPlugin.getMessage("childNodesPageTitle")); + Composite body = form.getBody(); + GridLayout twt = new GridLayout(1, false); + twt.marginWidth = twt.marginHeight = 5; + body.setLayout(twt); + if (!currentNode.hasNodes()) { + managedForm.getToolkit().createLabel(body, + JcrExplorerPlugin.getMessage("warningNoChildNode")); + } else { + + nodeContentProvider = new SingleNodeAsTreeContentProvider(); + nodesViewer = createNodeViewer(body, nodeContentProvider); + nodesViewer.setInput(currentNode); + } + } catch (Exception e) { + throw new ArgeoException( + "Unexpected error while creating child node page", e); + } + } + + 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 + .addDoubleClickListener(new GenericNodeDoubleClickListener( + tmpNodeViewer)); + return tmpNodeViewer; + } +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/editors/EmptyNodePage.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/editors/EmptyNodePage.java new file mode 100644 index 000000000..322c7ebd2 --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/editors/EmptyNodePage.java @@ -0,0 +1,49 @@ +/* + * 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.jcr.ui.explorer.editors; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Label; +import org.eclipse.ui.forms.IManagedForm; +import org.eclipse.ui.forms.editor.FormEditor; +import org.eclipse.ui.forms.editor.FormPage; +import org.eclipse.ui.forms.widgets.ScrolledForm; + +/** + * This page is only used at editor's creation time when current node has not + * yet been set + */ +public class EmptyNodePage extends FormPage { + // private final static Log log = LogFactory.getLog(EmptyNodePage.class); + + public EmptyNodePage(FormEditor editor, String title) { + super(editor, "Empty Page", title); + } + + protected void createFormContent(IManagedForm managedForm) { + try { + ScrolledForm form = managedForm.getForm(); + GridLayout twt = new GridLayout(1, false); + twt.marginWidth = twt.marginHeight = 0; + form.getBody().setLayout(twt); + Label lbl = new Label(form.getBody(), SWT.NONE); + lbl.setText("Empty page"); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/editors/GenericJcrQueryEditor.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/editors/GenericJcrQueryEditor.java new file mode 100644 index 000000000..3b98ed137 --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/editors/GenericJcrQueryEditor.java @@ -0,0 +1,60 @@ +/* + * 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.jcr.ui.explorer.editors; + +import org.argeo.eclipse.ui.jcr.editors.AbstractJcrQueryEditor; +import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; +import org.eclipse.swt.SWT; +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.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Text; + +/** Enables end user to type and execute any JCR query. */ +public class GenericJcrQueryEditor extends AbstractJcrQueryEditor { + public final static String ID = JcrExplorerPlugin.ID + ".genericJcrQueryEditor"; + + private Text queryField; + + @Override + public void createQueryForm(Composite parent) { + parent.setLayout(new GridLayout(1, false)); + + queryField = new Text(parent, SWT.BORDER | SWT.MULTI | SWT.WRAP); + queryField.setText(initialQuery); + queryField.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + Button execute = new Button(parent, SWT.PUSH); + execute.setText("Execute"); + + Listener executeListener = new Listener() { + public void handleEvent(Event event) { + executeQuery(queryField.getText()); + } + }; + + execute.addListener(SWT.Selection, executeListener); + // queryField.addListener(SWT.DefaultSelection, executeListener); + } + + @Override + public void setFocus() { + queryField.setFocus(); + } +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/editors/GenericNodeEditor.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/editors/GenericNodeEditor.java new file mode 100644 index 000000000..57f3aa236 --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/editors/GenericNodeEditor.java @@ -0,0 +1,113 @@ +/* + * 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.jcr.ui.explorer.editors; + +import javax.jcr.Node; + +import org.argeo.ArgeoException; +import org.argeo.jcr.JcrUtils; +import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorSite; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.forms.editor.FormEditor; + +/** + * Container for the node editor page. At creation time, it takes a JCR Node + * that cannot be changed afterwards. + */ +public class GenericNodeEditor extends FormEditor { + + // private final static Log log = + // LogFactory.getLog(GenericNodeEditor.class); + public final static String ID = JcrExplorerPlugin.ID + ".genericNodeEditor"; + + private Node currentNode; + + private GenericPropertyPage genericPropertyPage; + private ChildNodesPage childNodesPage; + private NodeRightsManagementPage nodeRightsManagementPage; + private NodeVersionHistoryPage nodeVersionHistoryPage; + + public void init(IEditorSite site, IEditorInput input) + throws PartInitException { + super.init(site, input); + GenericNodeEditorInput nei = (GenericNodeEditorInput) getEditorInput(); + currentNode = nei.getCurrentNode(); + this.setPartName(JcrUtils.lastPathElement(nei.getPath())); + } + + @Override + protected void addPages() { + try { + // genericNodePage = new GenericNodePage(this, + // JcrExplorerPlugin.getMessage("genericNodePageTitle"), + // currentNode); + // addPage(genericNodePage); + + genericPropertyPage = new GenericPropertyPage(this, + JcrExplorerPlugin.getMessage("genericNodePageTitle"), + currentNode); + addPage(genericPropertyPage); + + childNodesPage = new ChildNodesPage(this, + JcrExplorerPlugin.getMessage("childNodesPageTitle"), + currentNode); + addPage(childNodesPage); + + nodeRightsManagementPage = new NodeRightsManagementPage(this, + JcrExplorerPlugin + .getMessage("nodeRightsManagementPageTitle"), + currentNode); + addPage(nodeRightsManagementPage); + + nodeVersionHistoryPage = new NodeVersionHistoryPage( + this, + JcrExplorerPlugin.getMessage("nodeVersionHistoryPageTitle"), + currentNode); + addPage(nodeVersionHistoryPage); + } catch (PartInitException e) { + throw new ArgeoException("Not able to add an empty page ", e); + } + } + + @Override + public void doSaveAs() { + // unused compulsory method + } + + @Override + public void doSave(IProgressMonitor monitor) { + try { + // Automatically commit all pages of the editor + commitPages(true); + firePropertyChange(PROP_DIRTY); + } catch (Exception e) { + throw new ArgeoException("Error while saving node", e); + } + + } + + @Override + public boolean isSaveAsAllowed() { + return true; + } + + Node getCurrentNode() { + return currentNode; + } +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/editors/GenericNodeEditorInput.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/editors/GenericNodeEditorInput.java new file mode 100644 index 000000000..45e337e5d --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/editors/GenericNodeEditorInput.java @@ -0,0 +1,111 @@ +/* + * 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.jcr.ui.explorer.editors; + +import javax.jcr.Node; +import javax.jcr.RepositoryException; + +import org.argeo.ArgeoException; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IPersistableElement; + +/** + * An editor input based the JCR node object. + * */ + +public class GenericNodeEditorInput implements IEditorInput { + private final Node currentNode; + + // cache key properties at creation time to avoid Exception at recoring time + // when the session has been closed + private String path; + private String uid; + private String name; + + public GenericNodeEditorInput(Node currentNode) { + this.currentNode = currentNode; + try { + name = currentNode.getName(); + uid = currentNode.getIdentifier(); + path = currentNode.getPath(); + } catch (RepositoryException re) { + throw new ArgeoException( + "unexpected error while getting node key values at creation time", + re); + } + } + + public Node getCurrentNode() { + return currentNode; + } + + public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) { + return null; + } + + public boolean exists() { + return true; + } + + public ImageDescriptor getImageDescriptor() { + return null; + } + + public String getName() { + return name; + } + + public String getUid() { + return uid; + } + + public String getToolTipText() { + return path; + } + + public String getPath() { + return path; + } + + public IPersistableElement getPersistable() { + return null; + } + + /** + * equals method based on UID that is unique within a workspace and path of + * the node, thus 2 shared node that have same UID as defined in the spec + * but 2 different pathes will open two distinct editors. + * + * TODO enhance this method to support multirepository and multiworkspace + * environments + */ + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + + GenericNodeEditorInput other = (GenericNodeEditorInput) obj; + if (!getUid().equals(other.getUid())) + return false; + if (!getPath().equals(other.getPath())) + return false; + return true; + } +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/editors/GenericNodePage.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/editors/GenericNodePage.java new file mode 100644 index 000000000..fd4dafe76 --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/editors/GenericNodePage.java @@ -0,0 +1,211 @@ +/* + * 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.jcr.ui.explorer.editors; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.ListIterator; + +import javax.jcr.Node; +import javax.jcr.Property; +import javax.jcr.PropertyIterator; +import javax.jcr.PropertyType; +import javax.jcr.RepositoryException; + +import org.argeo.ArgeoException; +import org.argeo.jcr.JcrUtils; +import org.argeo.jcr.ui.explorer.JcrExplorerConstants; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.forms.AbstractFormPart; +import org.eclipse.ui.forms.IManagedForm; +import org.eclipse.ui.forms.editor.FormEditor; +import org.eclipse.ui.forms.editor.FormPage; +import org.eclipse.ui.forms.widgets.FormToolkit; +import org.eclipse.ui.forms.widgets.ScrolledForm; + +/** + * Main node editor page. Lists all properties of the current node and enable + * access and editing for some of them. + */ + +public class GenericNodePage extends FormPage implements JcrExplorerConstants { + // private final static Log log = LogFactory.getLog(GenericNodePage.class); + + // local constants + private final static String JCR_PROPERTY_NAME = "jcr:name"; + + // Utils + protected DateFormat timeFormatter = new SimpleDateFormat(DATE_TIME_FORMAT); + + // Main business Objects + private Node currentNode; + + // This page widgets + private FormToolkit tk; + private List modifyableProperties = new ArrayList(); + + public GenericNodePage(FormEditor editor, String title, Node currentNode) { + super(editor, "id", title); + this.currentNode = currentNode; + } + + protected void createFormContent(IManagedForm managedForm) { + tk = managedForm.getToolkit(); + ScrolledForm form = managedForm.getForm(); + GridLayout twt = new GridLayout(3, false); + twt.marginWidth = twt.marginHeight = 5; + + form.getBody().setLayout(twt); + createPropertiesPart(form.getBody()); + } + + private void createPropertiesPart(Composite parent) { + try { + + PropertyIterator pi = currentNode.getProperties(); + + // Initializes form part + AbstractFormPart part = new AbstractFormPart() { + public void commit(boolean onSave) { + try { + if (onSave) { + ListIterator it = modifyableProperties + .listIterator(); + while (it.hasNext()) { + // we only support Text controls for the time + // being + Text curControl = (Text) it.next(); + String value = curControl.getText(); + currentNode.setProperty((String) curControl + .getData(JCR_PROPERTY_NAME), value); + } + + // We only commit when onSave = true, + // thus it is still possible to save after a tab + // change. + super.commit(onSave); + } + } catch (RepositoryException re) { + throw new ArgeoException( + "Unexpected error while saving properties", re); + } + } + }; + + while (pi.hasNext()) { + Property prop = pi.nextProperty(); + addPropertyLine(parent, part, prop); + } + + getManagedForm().addPart(part); + } catch (RepositoryException re) { + throw new ArgeoException( + "Error during creation of network details section", re); + } + + } + + private void addPropertyLine(Composite parent, AbstractFormPart part, + Property prop) { + try { + tk.createLabel(parent, prop.getName()); + tk.createLabel(parent, + "[" + JcrUtils.getPropertyDefinitionAsString(prop) + "]"); + + if (prop.getDefinition().isProtected()) { + tk.createLabel(parent, formatReadOnlyPropertyValue(prop)); + } else + addModifyableValueWidget(parent, part, prop); + } catch (RepositoryException re) { + throw new ArgeoException("Cannot get property " + prop, re); + } + } + + private String formatReadOnlyPropertyValue(Property prop) { + try { + String strValue; + + if (prop.getType() == PropertyType.BINARY) + strValue = ""; + else if (prop.isMultiple()) + strValue = Arrays.asList(prop.getValues()).toString(); + else if (prop.getType() == PropertyType.DATE) + strValue = timeFormatter.format(prop.getValue().getDate() + .getTime()); + else + strValue = prop.getValue().getString(); + + return strValue; + } catch (RepositoryException re) { + throw new ArgeoException( + "Unexpected error while formatting read only property value", + re); + } + } + + private Control addModifyableValueWidget(Composite parent, + AbstractFormPart part, Property prop) { + GridData gd; + try { + if (prop.getType() == PropertyType.STRING) { + Text txt = tk.createText(parent, prop.getString()); + gd = new GridData(GridData.FILL_HORIZONTAL); + txt.setLayoutData(gd); + txt.addModifyListener(new ModifiedFieldListener(part)); + txt.setData(JCR_PROPERTY_NAME, prop.getName()); + modifyableProperties.add(txt); + } else { + // unsupported property type for editing, we create a read only + // label. + return tk + .createLabel(parent, formatReadOnlyPropertyValue(prop)); + } + return null; + } catch (RepositoryException re) { + throw new ArgeoException( + "Unexpected error while formatting read only property value", + re); + } + + } + + // + // LISTENERS + // + + private class ModifiedFieldListener implements ModifyListener { + + private AbstractFormPart formPart; + + public ModifiedFieldListener(AbstractFormPart generalPart) { + this.formPart = generalPart; + } + + public void modifyText(ModifyEvent e) { + formPart.markDirty(); + } + } + +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/editors/GenericPropertyPage.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/editors/GenericPropertyPage.java new file mode 100644 index 000000000..3aec4538c --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/editors/GenericPropertyPage.java @@ -0,0 +1,306 @@ +/* + * 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.jcr.ui.explorer.editors; + +import java.util.ArrayList; +import java.util.List; + +import javax.jcr.Node; +import javax.jcr.Property; +import javax.jcr.PropertyIterator; +import javax.jcr.RepositoryException; +import javax.jcr.Value; + +import org.argeo.ArgeoException; +import org.argeo.jcr.ui.explorer.JcrExplorerConstants; +import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; +import org.argeo.jcr.ui.explorer.providers.PropertyLabelProvider; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.TreeColumn; +import org.eclipse.ui.forms.IManagedForm; +import org.eclipse.ui.forms.editor.FormEditor; +import org.eclipse.ui.forms.editor.FormPage; +import org.eclipse.ui.forms.widgets.ScrolledForm; + +/** + * Generic editor property page. Lists all properties of current node as a + * complex tree. TODO: enable editing + */ + +public class GenericPropertyPage extends FormPage implements + JcrExplorerConstants { + // private final static Log log = + // LogFactory.getLog(GenericPropertyPage.class); + + // Main business Objects + private Node currentNode; + + public GenericPropertyPage(FormEditor editor, String title, Node currentNode) { + super(editor, "id", title); + this.currentNode = currentNode; + } + + protected void createFormContent(IManagedForm managedForm) { + ScrolledForm form = managedForm.getForm(); + form.setText(JcrExplorerPlugin.getMessage("genericNodePageTitle")); + FillLayout layout = new FillLayout(); + layout.marginHeight = 5; + layout.marginWidth = 5; + form.getBody().setLayout(layout); + + createComplexTree(form.getBody()); + + // TODO remove following + // createPropertiesPart(form.getBody()); + } + + private TreeViewer createComplexTree(Composite parent) { + int style = SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION; + Tree tree = new Tree(parent, style); + createColumn(tree, "Property", SWT.LEFT, 200); + createColumn(tree, "Value(s)", SWT.LEFT, 300); + createColumn(tree, "Attributes", SWT.LEFT, 65); + tree.setLinesVisible(true); + tree.setHeaderVisible(true); + + TreeViewer result = new TreeViewer(tree); + result.setContentProvider(new TreeContentProvider()); + result.setLabelProvider(new PropertyLabelProvider()); + result.setInput(currentNode); + result.expandAll(); + return result; + } + + private static TreeColumn createColumn(Tree parent, String name, int style, + int width) { + TreeColumn result = new TreeColumn(parent, style); + result.setText(name); + result.setWidth(width); + result.setMoveable(true); + result.setResizable(true); + return result; + } + + // + // private void createPropertiesPart(Composite parent) { + // try { + // + // PropertyIterator pi = currentNode.getProperties(); + // + // // Initializes form part + // AbstractFormPart part = new AbstractFormPart() { + // public void commit(boolean onSave) { + // try { + // if (onSave) { + // ListIterator it = modifyableProperties + // .listIterator(); + // while (it.hasNext()) { + // // we only support Text controls for the time + // // being + // Text curControl = (Text) it.next(); + // String value = curControl.getText(); + // currentNode.setProperty((String) curControl + // .getData(JCR_PROPERTY_NAME), value); + // } + // + // // We only commit when onSave = true, + // // thus it is still possible to save after a tab + // // change. + // super.commit(onSave); + // } + // } catch (RepositoryException re) { + // throw new ArgeoException( + // "Unexpected error while saving properties", re); + // } + // } + // }; + // + // while (pi.hasNext()) { + // Property prop = pi.nextProperty(); + // addPropertyLine(parent, part, prop); + // } + // + // getManagedForm().addPart(part); + // } catch (RepositoryException re) { + // throw new ArgeoException( + // "Error during creation of network details section", re); + // } + // + // } + // + // private void addPropertyLine(Composite parent, AbstractFormPart part, + // Property prop) { + // try { + // tk.createLabel(parent, prop.getName()); + // tk.createLabel(parent, + // "[" + JcrUtils.getPropertyDefinitionAsString(prop) + "]"); + // + // if (prop.getDefinition().isProtected()) { + // tk.createLabel(parent, formatReadOnlyPropertyValue(prop)); + // } else + // addModifyableValueWidget(parent, part, prop); + // } catch (RepositoryException re) { + // throw new ArgeoException("Cannot get property " + prop, re); + // } + // } + // + // private String formatReadOnlyPropertyValue(Property prop) { + // try { + // String strValue; + // + // if (prop.getType() == PropertyType.BINARY) + // strValue = ""; + // else if (prop.isMultiple()) + // strValue = Arrays.asList(prop.getValues()).toString(); + // else if (prop.getType() == PropertyType.DATE) + // strValue = timeFormatter.format(prop.getValue().getDate() + // .getTime()); + // else + // strValue = prop.getValue().getString(); + // + // return strValue; + // } catch (RepositoryException re) { + // throw new ArgeoException( + // "Unexpected error while formatting read only property value", + // re); + // } + // } + // + // private Control addModifyableValueWidget(Composite parent, + // AbstractFormPart part, Property prop) { + // GridData gd; + // try { + // if (prop.getType() == PropertyType.STRING) { + // Text txt = tk.createText(parent, prop.getString()); + // gd = new GridData(GridData.FILL_HORIZONTAL); + // txt.setLayoutData(gd); + // txt.addModifyListener(new ModifiedFieldListener(part)); + // txt.setData(JCR_PROPERTY_NAME, prop.getName()); + // modifyableProperties.add(txt); + // } else { + // // unsupported property type for editing, we create a read only + // // label. + // return tk + // .createLabel(parent, formatReadOnlyPropertyValue(prop)); + // } + // return null; + // } catch (RepositoryException re) { + // throw new ArgeoException( + // "Unexpected error while formatting read only property value", + // re); + // } + // + // } + + // Multiple Value Model + // protected class MultipleValueItem { + // private int index; + // private Value value; + // + // public MultipleValueItem(int index, Value value) { + // this.index = index; + // this.value = value; + // } + // + // public int getIndex() { + // return index; + // } + // + // public Object getValue() { + // return value; + // } + // } + + private class TreeContentProvider implements ITreeContentProvider { + public Object[] getElements(Object parent) { + Object[] props = null; + try { + + if (parent instanceof Node) { + Node node = (Node) parent; + PropertyIterator pi; + pi = node.getProperties(); + List propList = new ArrayList(); + while (pi.hasNext()) { + propList.add(pi.nextProperty()); + } + props = propList.toArray(); + } + } catch (RepositoryException e) { + throw new ArgeoException( + "Unexpected exception while listing node properties", e); + } + return props; + } + + public Object getParent(Object child) { + return null; + } + + public Object[] getChildren(Object parent) { + Object[] result = null; + if (parent instanceof Property) { + Property prop = (Property) parent; + try { + + if (prop.isMultiple()) { + Value[] values = prop.getValues(); + // List list = new + // ArrayList(); + // for (int i = 0; i < values.length; i++) { + // MultipleValueItem mvi = new MultipleValueItem(i, + // values[i]); + // list.add(mvi); + // } + + return values; + } + } catch (RepositoryException e) { + throw new ArgeoException( + "Unexpected error getting multiple values property.", + e); + } + } + return result; + } + + public boolean hasChildren(Object parent) { + try { + if (parent instanceof Property + && ((Property) parent).isMultiple()) { + return true; + } + } catch (RepositoryException e) { + throw new ArgeoException( + "Unexpected exception while checking if property is multiple", + e); + } + return false; + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + } + + public void dispose() { + } + } +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/editors/NodeRightsManagementPage.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/editors/NodeRightsManagementPage.java new file mode 100644 index 000000000..cc5efb5f9 --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/editors/NodeRightsManagementPage.java @@ -0,0 +1,138 @@ +/* + * 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.jcr.ui.explorer.editors; + +import javax.jcr.Node; +import javax.jcr.security.AccessControlManager; +import javax.jcr.security.Privilege; + +import org.argeo.ArgeoException; +import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; +import org.eclipse.jface.viewers.ColumnLabelProvider; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.ui.forms.IManagedForm; +import org.eclipse.ui.forms.editor.FormEditor; +import org.eclipse.ui.forms.editor.FormPage; +import org.eclipse.ui.forms.widgets.ScrolledForm; + +/** + * This comments will be nicely fill by mbaudier in. + */ +public class NodeRightsManagementPage extends FormPage { + // private final static Log log = + // LogFactory.getLog(NodeRightsManagementPage.class); + + private Node currentNode; + + private TableViewer viewer; + + public NodeRightsManagementPage(FormEditor editor, String title, + Node currentNode) { + super(editor, "NodeRightsManagementPage", title); + this.currentNode = currentNode; + } + + protected void createFormContent(IManagedForm managedForm) { + ScrolledForm form = managedForm.getForm(); + form.setText(JcrExplorerPlugin + .getMessage("nodeRightsManagementPageTitle")); + FillLayout layout = new FillLayout(); + layout.marginHeight = 5; + layout.marginWidth = 5; + form.getBody().setLayout(layout); + createRightsPart(form.getBody()); + } + + /** Creates the rights part */ + protected void createRightsPart(Composite parent) { + Table table = new Table(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); + table.setLinesVisible(true); + table.setHeaderVisible(true); + viewer = new TableViewer(table); + + // check column + TableViewerColumn column = createTableViewerColumn(viewer, "checked", + 20); + column.setLabelProvider(new ColumnLabelProvider() { + public String getText(Object element) { + return null; + } + + public Image getImage(Object element) { + return null; + } + }); + // column.setEditingSupport(new RoleEditingSupport(rolesViewer, part)); + + // role column + column = createTableViewerColumn(viewer, "Role", 200); + column.setLabelProvider(new ColumnLabelProvider() { + public String getText(Object element) { + Privilege p = (Privilege) element; + return p.getName(); + } + + public Image getImage(Object element) { + return null; + } + }); + viewer.setContentProvider(new RightsContentProvider()); + viewer.setInput(getEditorSite()); + } + + protected TableViewerColumn createTableViewerColumn(TableViewer viewer, + String title, int bound) { + final TableViewerColumn viewerColumn = new TableViewerColumn(viewer, + SWT.NONE); + final TableColumn column = viewerColumn.getColumn(); + column.setText(title); + column.setWidth(bound); + column.setResizable(true); + column.setMoveable(true); + return viewerColumn; + } + + private class RightsContentProvider implements IStructuredContentProvider { + + public void dispose() { + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + } + + public Object[] getElements(Object inputElement) { + try { + AccessControlManager accessControlManager = currentNode + .getSession().getAccessControlManager(); + Privilege[] privileges = accessControlManager + .getPrivileges(currentNode.getPath()); + return privileges; + } catch (Exception e) { + throw new ArgeoException("Cannot retrieve rights", e); + } + } + + } +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/editors/NodeVersionHistoryPage.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/editors/NodeVersionHistoryPage.java new file mode 100644 index 000000000..59fff5e59 --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/editors/NodeVersionHistoryPage.java @@ -0,0 +1,319 @@ +/* + * 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.jcr.ui.explorer.editors; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.List; +import java.util.Map; + +import javax.jcr.Node; +import javax.jcr.Property; +import javax.jcr.PropertyType; +import javax.jcr.RepositoryException; +import javax.jcr.Value; +import javax.jcr.nodetype.NodeType; +import javax.jcr.version.Version; +import javax.jcr.version.VersionHistory; +import javax.jcr.version.VersionIterator; +import javax.jcr.version.VersionManager; + +import org.argeo.ArgeoException; +import org.argeo.jcr.JcrUtils; +import org.argeo.jcr.PropertyDiff; +import org.argeo.jcr.VersionDiff; +import org.argeo.jcr.ui.explorer.JcrExplorerConstants; +import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; +import org.argeo.jcr.ui.explorer.providers.FullVersioningTreeContentProvider; +import org.argeo.jcr.ui.explorer.providers.VersionLabelProvider; +import org.argeo.jcr.ui.explorer.utils.GenericNodeDoubleClickListener; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.forms.AbstractFormPart; +import org.eclipse.ui.forms.IManagedForm; +import org.eclipse.ui.forms.editor.FormEditor; +import org.eclipse.ui.forms.editor.FormPage; +import org.eclipse.ui.forms.widgets.FormToolkit; +import org.eclipse.ui.forms.widgets.ScrolledForm; +import org.eclipse.ui.forms.widgets.Section; +import org.eclipse.ui.forms.widgets.TableWrapData; +import org.eclipse.ui.forms.widgets.TableWrapLayout; + +/** + * Offers two main sections : one to display a text area with a summary of all + * variations between a version and its predecessor and one tree view that + * enable browsing + * */ +public class NodeVersionHistoryPage extends FormPage implements + JcrExplorerConstants { + // private final static Log log = LogFactory + // .getLog(NodeVersionHistoryPage.class); + + // Utils + protected DateFormat timeFormatter = new SimpleDateFormat(DATE_TIME_FORMAT); + + // business objects + private Node currentNode; + + // this page UI components + private FullVersioningTreeContentProvider nodeContentProvider; + private TreeViewer nodesViewer; + private FormToolkit tk; + + public NodeVersionHistoryPage(FormEditor editor, String title, + Node currentNode) { + super(editor, "NodeVersionHistoryPage", title); + this.currentNode = currentNode; + } + + protected void createFormContent(IManagedForm managedForm) { + ScrolledForm form = managedForm.getForm(); + form.setText(JcrExplorerPlugin + .getMessage("nodeVersionHistoryPageTitle")); + tk = managedForm.getToolkit(); + GridLayout twt = new GridLayout(1, false); + twt.marginWidth = twt.marginHeight = 5; + Composite body = form.getBody(); + body.setLayout(twt); + + try { + if (!currentNode.isNodeType(NodeType.MIX_VERSIONABLE)) { + tk.createLabel(body, JcrExplorerPlugin + .getMessage("warningUnversionableNode")); + } else { + createHistorySection(form.getBody()); + createTreeSection(form.getBody()); + } + } catch (RepositoryException e) { + throw new ArgeoException( + "Unexpected error while checking if node is versionable", e); + } + } + + protected void createTreeSection(Composite parent) { + // Section Layout & MetaData + Section section = tk.createSection(parent, Section.TWISTIE); + section.setLayoutData(new GridData(GridData.FILL_BOTH)); + section.setText(JcrExplorerPlugin.getMessage("versionTreeSectionTitle")); + + // Section Body + Composite body = tk.createComposite(section, SWT.FILL); + // WARNING : 2 following lines are compulsory or body won't be + // displayed. + body.setLayout(new GridLayout()); + section.setClient(body); + + body.setLayoutData(new GridData(GridData.FILL_BOTH)); + section.setExpanded(true); + + nodeContentProvider = new FullVersioningTreeContentProvider(); + nodesViewer = createNodeViewer(body, nodeContentProvider); + nodesViewer.setInput(currentNode); + } + + 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 VersionLabelProvider()); + tmpNodeViewer + .addDoubleClickListener(new GenericNodeDoubleClickListener( + tmpNodeViewer)); + return tmpNodeViewer; + } + + protected void createHistorySection(Composite parent) { + + // Section Layout + Section section = tk.createSection(parent, Section.TWISTIE); + section.setLayoutData(new GridData(TableWrapData.FILL_GRAB)); + TableWrapLayout twt = new TableWrapLayout(); + section.setLayout(twt); + + // Set title of the section + section.setText(JcrExplorerPlugin + .getMessage("versionHistorySectionTitle")); + + final Text styledText = tk.createText(section, "", SWT.FULL_SELECTION + | SWT.BORDER | SWT.MULTI | SWT.WRAP | SWT.V_SCROLL); + styledText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + section.setClient(styledText); + refreshHistory(styledText); + styledText.setEditable(false); + section.setExpanded(false); + + AbstractFormPart part = new AbstractFormPart() { + public void commit(boolean onSave) { + } + + public void refresh() { + super.refresh(); + refreshHistory(styledText); + } + }; + getManagedForm().addPart(part); + } + + protected void refreshHistory(Text styledText) { + try { + List lst = listHistoryDiff(); + StringBuffer main = new StringBuffer(""); + + for (int i = lst.size() - 1; i >= 0; i--) { + if (i == 0) + main.append("Creation ("); + else + main.append("Update " + i + " ("); + + if (lst.get(i).getUserId() != null) + main.append("UserId : " + lst.get(i).getUserId()); + + if (lst.get(i).getUserId() != null + && lst.get(i).getUpdateTime() != null) + main.append(", "); + + if (lst.get(i).getUpdateTime() != null) + main.append("Date : " + + timeFormatter.format(lst.get(i).getUpdateTime() + .getTime()) + ")\n"); + + StringBuffer buf = new StringBuffer(""); + Map diffs = lst.get(i).getDiffs(); + for (String prop : diffs.keySet()) { + PropertyDiff pd = diffs.get(prop); + // String propName = pd.getRelPath(); + Value refValue = pd.getReferenceValue(); + Value newValue = pd.getNewValue(); + String refValueStr = ""; + String newValueStr = ""; + + if (refValue != null) { + if (refValue.getType() == PropertyType.DATE) { + refValueStr = timeFormatter.format(refValue + .getDate().getTime()); + } else + refValueStr = refValue.getString(); + } + if (newValue != null) { + if (newValue.getType() == PropertyType.DATE) { + newValueStr = timeFormatter.format(newValue + .getDate().getTime()); + } else + newValueStr = newValue.getString(); + } + + if (pd.getType() == PropertyDiff.MODIFIED) { + buf.append(prop).append(": "); + buf.append(refValueStr); + buf.append(" > "); + buf.append(newValueStr); + buf.append("\n"); + } else if (pd.getType() == PropertyDiff.ADDED + && !"".equals(newValueStr)) { + // we don't list property that have been added with an + // empty string as value + buf.append(prop).append(": "); + buf.append(" + "); + buf.append(newValueStr); + buf.append("\n"); + } else if (pd.getType() == PropertyDiff.REMOVED) { + buf.append(prop).append(": "); + buf.append(" - "); + buf.append(refValueStr); + buf.append("\n"); + } + } + buf.append("\n"); + main.append(buf); + } + styledText.setText(main.toString()); + } catch (RepositoryException e) { + throw new ArgeoException("Cannot generate history for node", e); + } + + } + + public List listHistoryDiff() { + try { + List res = new ArrayList(); + VersionManager versionManager = currentNode.getSession() + .getWorkspace().getVersionManager(); + VersionHistory versionHistory = versionManager + .getVersionHistory(currentNode.getPath()); + + VersionIterator vit = versionHistory.getAllLinearVersions(); + while (vit.hasNext()) { + Version version = vit.nextVersion(); + Node node = version.getFrozenNode(); + Version predecessor = null; + try { + predecessor = version.getLinearPredecessor(); + } catch (Exception e) { + // no predecessor seems to throw an exception even if it + // shouldn't... + } + if (predecessor == null) {// original + } else { + Map diffs = JcrUtils.diffProperties( + predecessor.getFrozenNode(), node); + if (!diffs.isEmpty()) { + String lastUserName = null; + Calendar lastUpdate = null; + try { + if (currentNode + .isNodeType(NodeType.MIX_LAST_MODIFIED)) { + lastUserName = node.getProperty( + Property.JCR_LAST_MODIFIED_BY) + .getString(); + lastUpdate = node.getProperty( + Property.JCR_LAST_MODIFIED).getDate(); + } else + lastUpdate = version.getProperty( + Property.JCR_CREATED).getDate(); + + } catch (Exception e) { + // Silent that info is optional + } + VersionDiff vd = new VersionDiff(lastUserName, + lastUpdate, diffs); + res.add(vd); + } + } + } + return res; + } catch (RepositoryException e) { + throw new ArgeoException("Cannot generate history for node "); + } + + } + + @Override + public void setActive(boolean active) { + super.setActive(active); + } +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/editors/StringNodeEditorInput.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/editors/StringNodeEditorInput.java new file mode 100644 index 000000000..654b2aeea --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/editors/StringNodeEditorInput.java @@ -0,0 +1,120 @@ +/* + * 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.jcr.ui.explorer.editors; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IPersistableElement; + +/** + * An editor input based on three strings define a node : + *
    + *
  • complete path to the node
  • + *
  • the workspace name
  • + *
  • the repository alias
  • + *
+ * In a single workspace and/or repository environment, name and alias can be + * null. + * + * Note : unused for the time being. + */ + +public class StringNodeEditorInput implements IEditorInput { + private final String path; + private final String repositoryAlias; + private final String workspaceName; + + /** + * In order to implement a generic explorer that supports remote and multi + * workspaces repositories, node path can be detailed by these strings. + * + * @param repositoryAlias + * : can be null + * @param workspaceName + * : can be null + * @param path + */ + public StringNodeEditorInput(String repositoryAlias, String workspaceName, + String path) { + this.path = path; + this.repositoryAlias = repositoryAlias; + this.workspaceName = workspaceName; + } + + public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) { + return null; + } + + public boolean exists() { + return true; + } + + public ImageDescriptor getImageDescriptor() { + return null; + } + + public String getName() { + return path; + } + + public String getRepositoryAlias() { + return repositoryAlias; + } + + public String getWorkspaceName() { + return workspaceName; + } + + public IPersistableElement getPersistable() { + return null; + } + + public String getToolTipText() { + return path; + } + + public String getPath() { + return path; + } + + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + + StringNodeEditorInput other = (StringNodeEditorInput) obj; + + if (!path.equals(other.getPath())) + return false; + + String own = other.getWorkspaceName(); + if ((workspaceName == null && own != null) + || (workspaceName != null && (own == null || !workspaceName + .equals(own)))) + return false; + + String ora = other.getRepositoryAlias(); + if ((repositoryAlias == null && ora != null) + || (repositoryAlias != null && (ora == null || !repositoryAlias + .equals(ora)))) + return false; + + return true; + } +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/messages.properties b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/messages.properties new file mode 100644 index 000000000..3023c523f --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/messages.properties @@ -0,0 +1,28 @@ +## English labels for Agreo JCR UI application + +## Generic labels + +## Errors & warnings +errorUnvalidNtFolderNodeType= Error: folder can only be created on a Jcr Node +warningInvalidNodeToImport=Can only import to a node +warningInvalidMultipleSelection=This functionality is implemented only on a single node for the time being. +warningUnversionableNode= Current node is not versionable. +warningNoChildNode= Current node has no child. + +## Commands +getNodeSizeCmdLbl= Get approx. size +addFolderNodeCmdLbl= Add Folder + +## GenericNodeEditor +nodeEditorLbl=Generic node editor +genericNodePageTitle=Properties +childNodesPageTitle=Children +nodeRightsManagementPageTitle=Rights +nodeVersionHistoryPageTitle=History + +# History +versionTreeSectionTitle=Version list +versionHistorySectionTitle=History + +## Dummy ones +testLbl=Internationalizations of messages seems to work properly. diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/model/MaintainedRepositoryElem.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/model/MaintainedRepositoryElem.java new file mode 100644 index 000000000..abb97a9e8 --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/model/MaintainedRepositoryElem.java @@ -0,0 +1,24 @@ +package org.argeo.jcr.ui.explorer.model; + +import javax.jcr.Repository; + +import org.argeo.ArgeoException; +import org.argeo.eclipse.ui.TreeParent; +import org.argeo.jcr.MaintainedRepository; + +/** Wraps a {@link MaintainedRepository} */ +public class MaintainedRepositoryElem extends RepositoryElem { + + public MaintainedRepositoryElem(String alias, Repository repository, + TreeParent parent) { + super(alias, repository, parent); + if (!(repository instanceof MaintainedRepository)) { + throw new ArgeoException("Repository " + alias + + " is not amiantained repository"); + } + } + + protected MaintainedRepository getMaintainedRepository() { + return (MaintainedRepository) getRepository(); + } +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/model/RemoteRepositoryElem.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/model/RemoteRepositoryElem.java new file mode 100644 index 000000000..0be69781c --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/model/RemoteRepositoryElem.java @@ -0,0 +1,94 @@ +/* + * 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.jcr.ui.explorer.model; + +import java.util.Arrays; + +import javax.jcr.Node; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.RepositoryFactory; +import javax.jcr.Session; +import javax.jcr.SimpleCredentials; + +import org.argeo.ArgeoException; +import org.argeo.eclipse.ui.TreeParent; +import org.argeo.jcr.ArgeoJcrUtils; +import org.argeo.jcr.ArgeoNames; +import org.argeo.util.security.Keyring; + +/** Root of a remote repository */ +public class RemoteRepositoryElem extends RepositoryElem { + private final Keyring keyring; + /** + * A session of the logged in user on the default workspace of the node + * repository. + */ + private final Session userSession; + private final String remoteNodePath; + + private final RepositoryFactory repositoryFactory; + private final String uri; + + public RemoteRepositoryElem(String alias, + RepositoryFactory repositoryFactory, String uri, TreeParent parent, + Session userSession, Keyring keyring, String remoteNodePath) { + super(alias, null, parent); + this.repositoryFactory = repositoryFactory; + this.uri = uri; + this.keyring = keyring; + this.userSession = userSession; + this.remoteNodePath = remoteNodePath; + } + + @Override + protected Session repositoryLogin(String workspaceName) + throws RepositoryException { + Node remoteRepository = userSession.getNode(remoteNodePath); + String userID = remoteRepository.getProperty(ArgeoNames.ARGEO_USER_ID) + .getString(); + String pwdPath = remoteRepository.getPath() + '/' + + ArgeoNames.ARGEO_PASSWORD; + char[] password = keyring.getAsChars(pwdPath); + + try { + SimpleCredentials credentials = new SimpleCredentials(userID, + password); + return getRepository().login(credentials, workspaceName); + } finally { + Arrays.fill(password, 0, password.length, ' '); + } + } + + @Override + public Repository getRepository() { + if (repository == null) + repository = ArgeoJcrUtils.getRepositoryByUri(repositoryFactory, + uri); + return super.getRepository(); + } + + public void remove() { + try { + Node remoteNode = userSession.getNode(remoteNodePath); + remoteNode.remove(); + remoteNode.getSession().save(); + } catch (RepositoryException e) { + throw new ArgeoException("Cannot remove " + remoteNodePath, e); + } + } + +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/model/RepositoriesElem.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/model/RepositoriesElem.java new file mode 100644 index 000000000..b123727bc --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/model/RepositoriesElem.java @@ -0,0 +1,134 @@ +/* + * 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.jcr.ui.explorer.model; + +import java.util.Map; + +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.RepositoryFactory; +import javax.jcr.Session; + +import org.argeo.ArgeoException; +import org.argeo.eclipse.ui.ErrorFeedback; +import org.argeo.eclipse.ui.TreeParent; +import org.argeo.jcr.ArgeoNames; +import org.argeo.jcr.MaintainedRepository; +import org.argeo.jcr.RepositoryRegister; +import org.argeo.jcr.UserJcrUtils; +import org.argeo.util.security.Keyring; + +/** + * UI Tree component. Implements the Argeo abstraction of a + * {@link RepositoryFactory} that enable a user to "mount" various repositories + * in a single Tree like View. It is usually meant to be at the root of the UI + * Tree and thus {@link getParent()} method will return null. + * + * The {@link RepositoryFactory} is injected at instantiation time and must be + * use get or register new {@link Repository} objects upon which a reference is + * kept here. + */ + +public class RepositoriesElem extends TreeParent implements ArgeoNames { + private final RepositoryRegister repositoryRegister; + private final RepositoryFactory repositoryFactory; + + /** + * A session of the logged in user on the default workspace of the node + * repository. + */ + private final Session userSession; + private final Keyring keyring; + + public RepositoriesElem(String name, RepositoryRegister repositoryRegister, + RepositoryFactory repositoryFactory, TreeParent parent, + Session userSession, Keyring keyring) { + super(name); + this.repositoryRegister = repositoryRegister; + this.repositoryFactory = repositoryFactory; + this.userSession = userSession; + this.keyring = keyring; + } + + /** + * Override normal behavior to initialize the various repositories only at + * request time + */ + @Override + public synchronized Object[] getChildren() { + if (isLoaded()) { + return super.getChildren(); + } else { + // initialize current object + Map refRepos = repositoryRegister + .getRepositories(); + for (String name : refRepos.keySet()) { + Repository repository = refRepos.get(name); + if (repository instanceof MaintainedRepository) + super.addChild(new MaintainedRepositoryElem(name, + repository, this)); + else + super.addChild(new RepositoryElem(name, repository, this)); + } + + // remote + if (keyring != null) { + try { + addRemoteRepositories(keyring); + } catch (RepositoryException e) { + throw new ArgeoException( + "Cannot browse remote repositories", e); + } + } + return super.getChildren(); + } + } + + protected void addRemoteRepositories(Keyring jcrKeyring) + throws RepositoryException { + Node userHome = UserJcrUtils.getUserHome(userSession); + if (userHome != null && userHome.hasNode(ARGEO_REMOTE)) { + NodeIterator it = userHome.getNode(ARGEO_REMOTE).getNodes(); + while (it.hasNext()) { + Node remoteNode = it.nextNode(); + String uri = remoteNode.getProperty(ARGEO_URI).getString(); + try { + RemoteRepositoryElem remoteRepositoryNode = new RemoteRepositoryElem( + remoteNode.getName(), repositoryFactory, uri, this, + userSession, jcrKeyring, remoteNode.getPath()); + super.addChild(remoteRepositoryNode); + } catch (Exception e) { + ErrorFeedback.show("Cannot add remote repository " + + remoteNode, e); + } + } + } + } + + public void registerNewRepository(String alias, Repository repository) { + // TODO: implement this + // Create a new RepositoryNode Object + // add it + // super.addChild(new RepositoriesNode(...)); + } + + /** Returns the {@link RepositoryRegister} wrapped by this object. */ + public RepositoryRegister getRepositoryRegister() { + return repositoryRegister; + } +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/model/RepositoryElem.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/model/RepositoryElem.java new file mode 100644 index 000000000..935bac12b --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/model/RepositoryElem.java @@ -0,0 +1,103 @@ +/* + * 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.jcr.ui.explorer.model; + +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.Session; + +import org.argeo.ArgeoException; +import org.argeo.eclipse.ui.TreeParent; + +/** + * UI Tree component. Wraps a JCR {@link Repository}. It also keeps a reference + * to its parent Tree Ui component; typically the unique {@link Repositories} + * object of the current view to enable bi-directionnal browsing in the tree. + */ + +public class RepositoryElem extends TreeParent { + private String alias; + protected Repository repository; + private Session defaultSession = null; + + /** Create a new repository with distinct name & alias */ + public RepositoryElem(String alias, Repository repository, TreeParent parent) { + super(alias); + this.repository = repository; + setParent(parent); + this.alias = alias; + } + + public void login() { + try { + defaultSession = repositoryLogin(null); + String[] wkpNames = defaultSession.getWorkspace() + .getAccessibleWorkspaceNames(); + for (String wkpName : wkpNames) { + if (wkpName.equals(defaultSession.getWorkspace().getName())) + addChild(new WorkspaceElem(this, wkpName, defaultSession)); + else + addChild(new WorkspaceElem(this, wkpName)); + } + } catch (RepositoryException e) { + throw new ArgeoException("Cannot connect to repository " + alias, e); + } + } + + /** + * Actual call to the + * {@link Repository#login(javax.jcr.Credentials, String)} method. To be + * overridden. + */ + protected Session repositoryLogin(String workspaceName) + throws RepositoryException { + return repository.login(workspaceName); + } + + public String[] getAccessibleWorkspaceNames() { + try { + return defaultSession.getWorkspace().getAccessibleWorkspaceNames(); + } catch (RepositoryException e) { + throw new ArgeoException("Cannot retrieve workspace names", e); + } + } + + public void createWorkspace(String workspaceName) { + if (!isConnected()) + login(); + try { + defaultSession.getWorkspace().createWorkspace(workspaceName); + } catch (RepositoryException e) { + throw new ArgeoException("Cannot create workspace", e); + } + } + + /** returns the {@link Repository} referenced by the current UI Node */ + public Repository getRepository() { + return repository; + } + + public String getAlias() { + return alias; + } + + public Boolean isConnected() { + if (defaultSession != null && defaultSession.isLive()) + return true; + else + return false; + } +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/model/SingleJcrNodeElem.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/model/SingleJcrNodeElem.java new file mode 100644 index 000000000..7b588f83b --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/model/SingleJcrNodeElem.java @@ -0,0 +1,108 @@ +/* + * 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.jcr.ui.explorer.model; + +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.RepositoryException; +import javax.jcr.Workspace; + +import org.argeo.ArgeoException; +import org.argeo.eclipse.ui.TreeParent; + +/** + * UI Tree component. Wraps a node of a JCR {@link Workspace}. It also keeps a + * reference to its parent node that can either be a {@link WorkspaceElem}, a + * {@link SingleJcrNodeElem} or null if the node is "mounted" as the root of the UI + * tree. + */ + +public class SingleJcrNodeElem extends TreeParent { + + private final Node node; + private String alias = null; + + // keeps a local reference to the node's name to avoid exception when the + // session is lost + // private final String name; + + /** Creates a new UiNode in the UI Tree */ + public SingleJcrNodeElem(TreeParent parent, Node node, String name) { + super(name); + setParent(parent); + this.node = node; + } + + /** + * Creates a new UiNode in the UI Tree, keeping a reference to the alias of + * the corresponding repository in the current UI environment. It is useful + * to be able to mount nodes as roots of the UI tree. + */ + public SingleJcrNodeElem(TreeParent parent, Node node, String name, String alias) { + super(name); + setParent(parent); + this.node = node; + this.alias = alias; + } + + /** returns the node wrapped by the current Ui object */ + public Node getNode() { + return node; + } + + protected String getRepositoryAlias() { + return alias; + } + + /** + * Override normal behavior to initialize children only when first requested + */ + @Override + public synchronized Object[] getChildren() { + if (isLoaded()) { + return super.getChildren(); + } else { + // initialize current object + try { + NodeIterator ni = node.getNodes(); + while (ni.hasNext()) { + Node curNode = ni.nextNode(); + addChild(new SingleJcrNodeElem(this, curNode, curNode.getName())); + } + return super.getChildren(); + } catch (RepositoryException re) { + throw new ArgeoException( + "Unexcpected error while initializing children SingleJcrNode", + re); + } + } + } + + @Override + public boolean hasChildren() { + try { + if (node.getSession().isLive()) + return node.hasNodes(); + else + return false; + } catch (RepositoryException re) { + throw new ArgeoException( + "Unexpected error while checking children node existence", + re); + } + } + +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/model/WorkspaceElem.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/model/WorkspaceElem.java new file mode 100644 index 000000000..bb9b69caf --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/model/WorkspaceElem.java @@ -0,0 +1,130 @@ +/* + * 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.jcr.ui.explorer.model; + +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.Workspace; + +import org.argeo.ArgeoException; +import org.argeo.eclipse.ui.TreeParent; +import org.argeo.jcr.JcrUtils; + +/** + * UI Tree component. Wraps the root node of a JCR {@link Workspace}. It also + * keeps a reference to its parent {@link RepositoryElem}, to be able to + * retrieve alias of the current used repository + */ +public class WorkspaceElem extends TreeParent { + private Session session = null; + + public WorkspaceElem(RepositoryElem parent, String name) { + this(parent, name, null); + } + + public WorkspaceElem(RepositoryElem parent, String name, Session session) { + super(name); + this.session = session; + setParent(parent); + } + + public Session getSession() { + return session; + } + + public Node getRootNode() { + try { + if (session != null) + return session.getRootNode(); + else + return null; + } catch (RepositoryException e) { + throw new ArgeoException("Cannot get root node of workspace " + + getName(), e); + } + } + + public void login() { + try { + session = ((RepositoryElem) getParent()).repositoryLogin(getName()); + } catch (RepositoryException e) { + throw new ArgeoException("Cannot connect to repository " + + getName(), e); + } + } + + public Boolean isConnected() { + if (session != null && session.isLive()) + return true; + else + return false; + } + + @Override + public synchronized void dispose() { + logout(); + super.dispose(); + } + + /** Logouts the session, does not nothing if there is no live session. */ + public void logout() { + clearChildren(); + JcrUtils.logoutQuietly(session); + } + + @Override + public boolean hasChildren() { + try { + if (isConnected()) + return session.getRootNode().hasNodes(); + else + return false; + } catch (RepositoryException re) { + throw new ArgeoException( + "Unexpected error while checking children node existence", + re); + } + } + + /** Override normal behaviour to initialize display of the workspace */ + @Override + public synchronized Object[] getChildren() { + if (isLoaded()) { + return super.getChildren(); + } else { + // initialize current object + try { + Node rootNode; + if (session == null) + return null; + else + rootNode = session.getRootNode(); + NodeIterator ni = rootNode.getNodes(); + while (ni.hasNext()) { + Node node = ni.nextNode(); + addChild(new SingleJcrNodeElem(this, node, node.getName())); + } + return super.getChildren(); + } catch (RepositoryException e) { + throw new ArgeoException( + "Cannot initialize WorkspaceNode UI object." + + getName(), e); + } + } + } +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/providers/FullVersioningTreeContentProvider.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/providers/FullVersioningTreeContentProvider.java new file mode 100644 index 000000000..736a5aa2f --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/providers/FullVersioningTreeContentProvider.java @@ -0,0 +1,115 @@ +/* + * 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.jcr.ui.explorer.providers; + +import java.util.ArrayList; +import java.util.List; + +import javax.jcr.Node; +import javax.jcr.RepositoryException; +import javax.jcr.nodetype.NodeType; +import javax.jcr.version.Version; +import javax.jcr.version.VersionHistory; +import javax.jcr.version.VersionIterator; +import javax.jcr.version.VersionManager; + +import org.argeo.ArgeoException; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.Viewer; + +/** + * Implementation of the {@code ITreeContentProvider} in order to display some + * version informations of a JCR full versionable node in a tree like structure + * + */ +public class FullVersioningTreeContentProvider implements ITreeContentProvider { + // private Node rootNode; + // private ItemComparator itemComparator = new ItemComparator(); + + /** + * Sends back the first level of the Tree. input element must be a single + * node object + */ + public Object[] getElements(Object inputElement) { + try { + Node rootNode = (Node) inputElement; + String curPath = rootNode.getPath(); + VersionManager vm = rootNode.getSession().getWorkspace() + .getVersionManager(); + + VersionHistory vh = vm.getVersionHistory(curPath); + List result = new ArrayList(); + VersionIterator vi = vh.getAllLinearVersions(); + + while (vi.hasNext()) { + result.add(vi.nextVersion()); + } + return result.toArray(); + } catch (RepositoryException re) { + throw new ArgeoException( + "Unexpected error while getting version elements", re); + } + } + + public Object[] getChildren(Object parentElement) { + try { + if (parentElement instanceof Version) { + List tmp = new ArrayList(); + tmp.add(((Version) parentElement).getFrozenNode()); + return tmp.toArray(); + } + } catch (RepositoryException re) { + throw new ArgeoException("Unexpected error while getting child " + + "node for version element", re); + } + return null; + } + + public Object getParent(Object element) { + try { + // this will not work in a simpleVersionning environment, parent is + // not a node. + if (element instanceof Node + && ((Node) element).isNodeType(NodeType.NT_FROZEN_NODE)) { + Node node = (Node) element; + return node.getParent(); + } else + return null; + } catch (RepositoryException e) { + return null; + } + } + + public boolean hasChildren(Object element) { + try { + if (element instanceof Version) + return true; + else if (element instanceof Node) + return ((Node) element).hasNodes(); + else + return false; + } catch (RepositoryException e) { + throw new ArgeoException("Cannot check children of " + element, e); + } + } + + public void dispose() { + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + } + +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/providers/PropertyLabelProvider.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/providers/PropertyLabelProvider.java new file mode 100644 index 000000000..decbe6338 --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/providers/PropertyLabelProvider.java @@ -0,0 +1,116 @@ +/* + * 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.jcr.ui.explorer.providers; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; + +import javax.jcr.Property; +import javax.jcr.PropertyType; +import javax.jcr.RepositoryException; +import javax.jcr.Value; + +import org.argeo.ArgeoException; +import org.argeo.jcr.JcrUtils; +import org.argeo.jcr.ui.explorer.JcrExplorerConstants; +import org.eclipse.jface.viewers.ColumnLabelProvider; +import org.eclipse.jface.viewers.ViewerCell; + +public class PropertyLabelProvider extends ColumnLabelProvider implements + JcrExplorerConstants { + + // To be able to change column order easily + public static final int COLUMN_PROPERTY = 0; + public static final int COLUMN_VALUE = 1; + public static final int COLUMN_ATTRIBUTES = 2; + + // Utils + protected DateFormat timeFormatter = new SimpleDateFormat(DATE_TIME_FORMAT); + + public void update(ViewerCell cell) { + Object element = cell.getElement(); + cell.setText(getColumnText(element, cell.getColumnIndex())); + // Image image = getImage(element); + // cell.setImage(image); + // cell.setBackground(getBackground(element)); + // cell.setForeground(getForeground(element)); + // cell.setFont(getFont(element)); + } + + public String getColumnText(Object element, int columnIndex) { + try { + if (element instanceof Property) { + Property prop = (Property) element; + if (prop.isMultiple()) { + switch (columnIndex) { + case COLUMN_PROPERTY: + return prop.getName(); + case COLUMN_VALUE: + // Corresponding values are listed on children + return ""; + case COLUMN_ATTRIBUTES: + return JcrUtils.getPropertyDefinitionAsString(prop); + } + } else { + switch (columnIndex) { + case COLUMN_PROPERTY: + return prop.getName(); + case COLUMN_VALUE: + return formatValueAsString(prop.getValue()); + case COLUMN_ATTRIBUTES: + return JcrUtils.getPropertyDefinitionAsString(prop); + } + } + } else if (element instanceof Value) { + Value val = (Value) element; + + switch (columnIndex) { + case COLUMN_PROPERTY: + // Nothing to show + return ""; + case COLUMN_VALUE: + return formatValueAsString(val); + case COLUMN_ATTRIBUTES: + // Corresponding attributes are listed on the parent + return ""; + } + } + + } catch (RepositoryException re) { + throw new ArgeoException( + "Unexepected error while getting property values", re); + } + return null; + } + + private String formatValueAsString(Value value) { + // TODO enhance this method + try { + String strValue; + + if (value.getType() == PropertyType.BINARY) + strValue = ""; + else if (value.getType() == PropertyType.DATE) + strValue = timeFormatter.format(value.getDate().getTime()); + else + strValue = value.getString(); + return strValue; + } catch (RepositoryException e) { + throw new ArgeoException("unexpected error while formatting value", + e); + } + } +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/providers/SingleNodeAsTreeContentProvider.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/providers/SingleNodeAsTreeContentProvider.java new file mode 100644 index 000000000..8c69b6b9c --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/providers/SingleNodeAsTreeContentProvider.java @@ -0,0 +1,106 @@ +/* + * 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.jcr.ui.explorer.providers; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.RepositoryException; + +import org.argeo.ArgeoException; +import org.argeo.eclipse.ui.jcr.utils.JcrItemsComparator; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.Viewer; + +/** + * Implementation of the {@code ITreeContentProvider} in order to display a + * single JCR node and its children in a tree like structure + * + */ +public class SingleNodeAsTreeContentProvider implements ITreeContentProvider { + // private Node rootNode; + private JcrItemsComparator itemComparator = new JcrItemsComparator(); + + /** + * Sends back the first level of the Tree. input element must be a single + * node object + */ + public Object[] getElements(Object inputElement) { + try { + Node rootNode = (Node) inputElement; + List result = new ArrayList(); + NodeIterator ni = rootNode.getNodes(); + while (ni.hasNext()) { + result.add(ni.nextNode()); + } + + return result.toArray(); + } catch (RepositoryException re) { + throw new ArgeoException( + "Unexpected error while getting child nodes for children editor page ", + re); + } + } + + public Object[] getChildren(Object parentElement) { + return childrenNodes((Node) parentElement); + } + + public Object getParent(Object element) { + try { + Node node = (Node) element; + if (!node.getPath().equals("/")) + return node.getParent(); + else + return null; + } catch (RepositoryException e) { + return null; + } + } + + public boolean hasChildren(Object element) { + try { + return ((Node) element).hasNodes(); + } catch (RepositoryException e) { + throw new ArgeoException("Cannot check children of " + element, e); + } + } + + public void dispose() { + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + } + + protected Object[] childrenNodes(Node parentNode) { + try { + List children = new ArrayList(); + NodeIterator nit = parentNode.getNodes(); + while (nit.hasNext()) { + Node node = nit.nextNode(); + children.add(node); + } + Node[] arr = children.toArray(new Node[children.size()]); + Arrays.sort(arr, itemComparator); + return arr; + } catch (RepositoryException e) { + throw new ArgeoException("Cannot list children of " + parentNode, e); + } + } +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/providers/VersionLabelProvider.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/providers/VersionLabelProvider.java new file mode 100644 index 000000000..69b35ebb5 --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/providers/VersionLabelProvider.java @@ -0,0 +1,47 @@ +/* + * 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.jcr.ui.explorer.providers; + +import javax.jcr.Node; +import javax.jcr.RepositoryException; +import javax.jcr.version.Version; + +import org.argeo.ArgeoException; +import org.eclipse.jface.viewers.ColumnLabelProvider; + +/** + * simple wrapping of the ColumnLabelProvider class to provide text display in + * order to build a tree for version. The Get text method does not assume that + * Version extends Node class to respect JCR 2.0 specification + * + */ +public class VersionLabelProvider extends ColumnLabelProvider { + + public String getText(Object element) { + try { + if (element instanceof Version) { + Version version = (Version) element; + return version.getName(); + } else if (element instanceof Node) { + return ((Node) element).getName(); + } + } catch (RepositoryException re) { + throw new ArgeoException( + "Unexpected error while getting element name", re); + } + return super.getText(element); + } +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/utils/GenericNodeDoubleClickListener.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/utils/GenericNodeDoubleClickListener.java new file mode 100644 index 000000000..0f93450eb --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/utils/GenericNodeDoubleClickListener.java @@ -0,0 +1,109 @@ +/* + * 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.jcr.ui.explorer.utils; + +import javax.jcr.Node; +import javax.jcr.RepositoryException; +import javax.jcr.nodetype.NodeType; + +import org.argeo.ArgeoException; +import org.argeo.eclipse.ui.jcr.utils.JcrFileProvider; +import org.argeo.eclipse.ui.specific.FileHandler; +import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; +import org.argeo.jcr.ui.explorer.editors.GenericNodeEditor; +import org.argeo.jcr.ui.explorer.editors.GenericNodeEditorInput; +import org.argeo.jcr.ui.explorer.model.RepositoryElem; +import org.argeo.jcr.ui.explorer.model.SingleJcrNodeElem; +import org.argeo.jcr.ui.explorer.model.WorkspaceElem; +import org.eclipse.jface.viewers.DoubleClickEvent; +import org.eclipse.jface.viewers.IDoubleClickListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.ui.PartInitException; + +/** + * Centralizes the management of double click on a NodeTreeViewer + */ +public class GenericNodeDoubleClickListener implements IDoubleClickListener { + + // private final static Log log = LogFactory + // .getLog(GenericNodeDoubleClickListener.class); + + private TreeViewer nodeViewer; + private JcrFileProvider jfp; + private FileHandler fileHandler; + + public GenericNodeDoubleClickListener(TreeViewer nodeViewer) { + this.nodeViewer = nodeViewer; + jfp = new JcrFileProvider(); + // Commented out. see https://www.argeo.org/bugzilla/show_bug.cgi?id=188 + fileHandler = null; + // fileHandler = new FileHandler(jfp); + } + + public void doubleClick(DoubleClickEvent event) { + if (event.getSelection() == null || event.getSelection().isEmpty()) + return; + Object obj = ((IStructuredSelection) event.getSelection()) + .getFirstElement(); + if (obj instanceof RepositoryElem) { + RepositoryElem rpNode = (RepositoryElem) obj; + if (!rpNode.isConnected()) { + rpNode.login(); + nodeViewer.refresh(obj); + } + // else do nothing + } else if (obj instanceof WorkspaceElem) { + WorkspaceElem wn = (WorkspaceElem) obj; + if (wn.isConnected()) + wn.logout(); + else + wn.login(); + nodeViewer.refresh(obj); + } else if (obj instanceof SingleJcrNodeElem) { + SingleJcrNodeElem sjn = (SingleJcrNodeElem) obj; + Node node = sjn.getNode(); + try { + if (node.isNodeType(NodeType.NT_FILE)) { + // double click on a file node triggers its opening + String name = node.getName(); + String id = node.getIdentifier(); + + // For the file provider to be able to browse the + // various + // repository. + // TODO : enhanced that. + // ITreeContentProvider itcp = (ITreeContentProvider) + // nodeViewer + // .getContentProvider(); + jfp.setReferenceNode(node); + if (fileHandler != null) + fileHandler.openFile(name, id); + } + GenericNodeEditorInput gnei = new GenericNodeEditorInput(node); + JcrExplorerPlugin.getDefault().getWorkbench() + .getActiveWorkbenchWindow().getActivePage() + .openEditor(gnei, GenericNodeEditor.ID); + } catch (RepositoryException re) { + throw new ArgeoException( + "Repository error while getting node info", re); + } catch (PartInitException pie) { + throw new ArgeoException( + "Unexepected exception while opening node editor", pie); + } + } + } +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/utils/JcrUiUtils.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/utils/JcrUiUtils.java new file mode 100644 index 000000000..ca32113ed --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/utils/JcrUiUtils.java @@ -0,0 +1,179 @@ +/* + * 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.jcr.ui.explorer.utils; + +import javax.jcr.Node; +import javax.jcr.RepositoryException; + +import org.argeo.ArgeoException; +import org.argeo.eclipse.ui.TreeParent; +import org.argeo.jcr.ui.explorer.model.RepositoriesElem; +import org.argeo.jcr.ui.explorer.model.RepositoryElem; +import org.argeo.jcr.ui.explorer.model.SingleJcrNodeElem; +import org.argeo.jcr.ui.explorer.model.WorkspaceElem; + +/** Centralizes some useful methods to build UIs with JCR */ +public class JcrUiUtils { + + /** Insure that the UI component is not stale, refresh if needed */ + public static void forceRefreshIfNeeded(TreeParent element) { + Node curNode = null; + + boolean doRefresh = false; + + try { + if (element instanceof SingleJcrNodeElem) { + curNode = ((SingleJcrNodeElem) element).getNode(); + } else if (element instanceof WorkspaceElem) { + curNode = ((WorkspaceElem) element).getRootNode(); + } + + if (curNode != null + && element.getChildren().length != curNode.getNodes() + .getSize()) + doRefresh = true; + else if (element instanceof RepositoryElem) { + RepositoryElem rn = (RepositoryElem) element; + if (rn.isConnected()) { + String[] wkpNames = rn.getAccessibleWorkspaceNames(); + if (element.getChildren().length != wkpNames.length) + doRefresh = true; + } + } else if (element instanceof RepositoriesElem) { + doRefresh = true; + // Always force refresh for RepositoriesElem : the condition + // below does not take remote repository into account and it is + // not trivial to do so. + + // RepositoriesElem rn = (RepositoriesElem) element; + // if (element.getChildren().length != + // rn.getRepositoryRegister() + // .getRepositories().size()) + // doRefresh = true; + } + if (doRefresh) { + element.clearChildren(); + element.getChildren(); + } + } catch (RepositoryException re) { + throw new ArgeoException( + "Unexpected error while synchronising the UI with the JCR repository", + re); + } + } + + /** + * Insure that a model element is inline with the underlying data by + * cleaning the corresponding subtree and building it again. + */ + public static void forceRebuild(TreeParent element) { + // TODO implement this method if needed. + } + /** + * Workaround to get the alias of the repository that contains the given + * element. As we cannot browse the UI tree upward we recursively browse it + * downward until we find the given element + * */ + // public static String getRepositoryAliasFromITreeElement( + // NodeContentProvider ncp, Object element) { + // RepositoryNode repositoryNode = null; + // if (element instanceof RepositoryNode) + // return ((RepositoryNode) element).getName(); + // else if (element instanceof RepositoryRegister) + // throw new ArgeoException( + // "Cannot get alias for a repository register"); + // + // // Get root elements + // Object[] elements = ncp.getElements(null); + // + // try { + // for (int i = 0; i < elements.length; i++) { + // if (elements[i] instanceof Node) { + // Node curNode = (Node) elements[i]; + // if (curNode.isNodeType(ArgeoTypes.ARGEO_USER_HOME)) { + // // Do nothing, we'll find the node in the "normal" tree + // // and + // // get corresponding alias this way round + // } else + // throw new ArgeoException( + // "Normal nodes should not be at the root of NodeTreeViewer"); + // } else if (elements[i] instanceof RepositoryRegister) { + // RepositoryRegister repositoryRegister = (RepositoryRegister) elements[i]; + // Map repositories = repositoryRegister + // .getRepositories(); + // + // for (String name : repositories.keySet()) { + // boolean found = isElementInCurrentTreePart( + // ncp, + // new RepositoryNode(name, repositories.get(name)), + // (Node) element); + // if (found) + // return name; + // } + // } else + // throw new ArgeoException( + // "Unexpected object class at the root of NodeTreeViewer"); + // } + // } catch (RepositoryException re) { + // throw new ArgeoException( + // "Unexpected error while retrieving Alias name", re); + // } + // return null; + // } + // + // /** implements the recursivity */ + // private static boolean isElementInCurrentTreePart(NodeContentProvider + // ncp, + // Object parentElement, NodParente searchedElement) { + // boolean found = false; + // if (parentElement instanceof WorkspaceNode) { + // WorkspaceNode wn = (WorkspaceNode) parentElement; + // Object[] children = wn.getChildren(); + // int i = children.length - 1; + // while (!found && i >= 0) { + // found = isElementInCurrentTreePart(ncp, children[i], + // searchedElement); + // } + // return found; + // } else if (parentElement instanceof RepositoryNode) { + // RepositoryNode rn = (RepositoryNode) parentElement; + // Object[] children = rn.getChildren(); + // int i = children.length - 1; + // while (!found && i >= 0) { + // found = isElementInCurrentTreePart(ncp, children[i], + // searchedElement); + // } + // return found; + // } else { + // Node node = (Node) parentElement; + // if (node.equals(searchedElement)) + // return true; + // NodeIterator ni; + // try { + // ni = node.getNodes(); + // while (!found && ni.hasNext()) { + // found = isElementInCurrentTreePart(ncp, ni.nextNode(), + // searchedElement); + // } + // } catch (RepositoryException e) { + // throw new ArgeoException("unexpected erreur while recursively" + // + " recovering RepositoryNode for selected object", e); + // } + // + // return found; + // } + // } +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/utils/TreeObjectsComparator.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/utils/TreeObjectsComparator.java new file mode 100644 index 000000000..02450d6ed --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/utils/TreeObjectsComparator.java @@ -0,0 +1,26 @@ +/* + * 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.jcr.ui.explorer.utils; + +import java.util.Comparator; + +import org.argeo.eclipse.ui.TreeParent; + +public class TreeObjectsComparator implements Comparator { + public int compare(TreeParent o1, TreeParent o2) { + return o1.getName().compareTo(o2.getName()); + } +} \ No newline at end of file diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/views/GenericJcrBrowser.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/views/GenericJcrBrowser.java new file mode 100644 index 000000000..f401ae8fe --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/views/GenericJcrBrowser.java @@ -0,0 +1,357 @@ +/* + * 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.jcr.ui.explorer.views; + +import java.util.List; + +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.ArgeoException; +import org.argeo.eclipse.ui.TreeParent; +import org.argeo.eclipse.ui.jcr.AsyncUiEventListener; +import org.argeo.eclipse.ui.jcr.utils.NodeViewerComparer; +import org.argeo.eclipse.ui.jcr.views.AbstractJcrBrowser; +import org.argeo.jcr.RepositoryRegister; +import org.argeo.jcr.ui.explorer.JcrExplorerPlugin; +import org.argeo.jcr.ui.explorer.browser.NodeContentProvider; +import org.argeo.jcr.ui.explorer.browser.NodeLabelProvider; +import org.argeo.jcr.ui.explorer.browser.PropertiesContentProvider; +import org.argeo.jcr.ui.explorer.model.SingleJcrNodeElem; +import org.argeo.jcr.ui.explorer.utils.GenericNodeDoubleClickListener; +import org.argeo.jcr.ui.explorer.utils.JcrUiUtils; +import org.argeo.util.security.Keyring; +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; + +/** + * Basic View to display a sash form to browse a JCR compliant multirepository + * environment + */ +public class GenericJcrBrowser extends AbstractJcrBrowser { + public final static String ID = JcrExplorerPlugin.ID + ".browserView"; + private boolean sortChildNodes = true; + + /* DEPENDENCY INJECTION */ + private Keyring keyring; + private RepositoryRegister repositoryRegister; + private RepositoryFactory repositoryFactory; + private Repository nodeRepository; + /** + * A session of the logged in user on the default workspace of the node + * repository. + */ + private Session userSession; + + // This page widgets + private TreeViewer nodesViewer; + private NodeContentProvider nodeContentProvider; + private TableViewer propertiesViewer; + private EventListener resultsObserver; + + @Override + public void createPartControl(Composite parent) { + 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 ArgeoException("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); + getSite().registerContextMenu(menuManager, nodesViewer); + getSite().setSelectionProvider(nodesViewer); + + nodesViewer.setInput(getViewSite()); + + // 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()); + } + + @Override + 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) + JcrUiUtils.forceRefreshIfNeeded((TreeParent) el); + getNodeViewer().refresh(el); + } + } + super.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(getViewSite()); + } + } + }); + + 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 ArgeoException("Cannot register listeners", e); + } + + tmpNodeViewer + .addDoubleClickListener(new GenericNodeDoubleClickListener( + 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() { + public String getText(Object element) { + try { + return ((Property) element).getName(); + } catch (RepositoryException e) { + throw new ArgeoException( + "Unexpected exception in label provider", e); + } + } + }); + col = new TableViewerColumn(propertiesViewer, SWT.NONE); + col.getColumn().setText("Value"); + col.getColumn().setWidth(400); + col.setLabelProvider(new ColumnLabelProvider() { + 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 ArgeoException( + "Unexpected exception in label provider", e); + } + } + }); + col = new TableViewerColumn(propertiesViewer, SWT.NONE); + col.getColumn().setText("Type"); + col.getColumn().setWidth(200); + col.setLabelProvider(new ColumnLabelProvider() { + public String getText(Object element) { + try { + return PropertyType.nameFromValue(((Property) element) + .getType()); + } catch (RepositoryException e) { + throw new ArgeoException( + "Unexpected exception in label provider", e); + } + } + }); + propertiesViewer.setInput(getViewSite()); + return propertiesViewer; + } + + @Override + public void dispose() { + super.dispose(); + } + + @Override + 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(getViewSite()); + } + + /** Notifies the current view that a node has been added */ + public void nodeAdded(TreeParent parentNode) { + // insure that Ui objects have been correctly created: + JcrUiUtils.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; + } + + /* DEPENDENCY INJECTION */ + public void setRepositoryRegister(RepositoryRegister repositoryRegister) { + this.repositoryRegister = repositoryRegister; + } + + public void setKeyring(Keyring 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.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/wizards/ChangeRightsWizard.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/wizards/ChangeRightsWizard.java new file mode 100644 index 000000000..4381837e4 --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/wizards/ChangeRightsWizard.java @@ -0,0 +1,66 @@ +/* + * 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.jcr.ui.explorer.wizards; + +import javax.jcr.RepositoryException; +import javax.jcr.Session; + +import org.argeo.ArgeoException; +import org.argeo.jcr.JcrUtils; +import org.eclipse.jface.wizard.Wizard; + +/** + * Small wizard to manage authorizations on the root node of the current + * workspace + */ +public class ChangeRightsWizard extends Wizard { + + private Session currentSession; + private String path; + + // This page widget + private ChooseRightsPage page; + + public ChangeRightsWizard(Session currentSession, String path) { + super(); + this.currentSession = currentSession; + this.path = path; + } + + @Override + public void addPages() { + try { + page = new ChooseRightsPage(path); + addPage(page); + } catch (Exception e) { + throw new ArgeoException("Cannot add page to wizard ", e); + } + } + + @Override + public boolean performFinish() { + if (!canFinish()) + return false; + try { + JcrUtils.addPrivilege(currentSession, path, page.getGroupName(), + page.getAuthTypeStr()); + } catch (RepositoryException re) { + throw new ArgeoException( + "Unexpected error while setting privileges", re); + } + return true; + } +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/wizards/ChooseRightsPage.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/wizards/ChooseRightsPage.java new file mode 100644 index 000000000..69948ce83 --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/wizards/ChooseRightsPage.java @@ -0,0 +1,101 @@ +/* + * 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.jcr.ui.explorer.wizards; + +import javax.jcr.security.Privilege; + +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; + +public class ChooseRightsPage extends WizardPage implements ModifyListener { + + // This page widget + private Text groupNameTxt; + private Combo authorizationCmb; + + // USABLE SHORTCUTS + protected final static String[] validAuthType = { Privilege.JCR_READ, + Privilege.JCR_WRITE, Privilege.JCR_ALL }; + + public ChooseRightsPage(String path) { + super("Main"); + setTitle("Add privilege to " + path); + } + + public void createControl(Composite parent) { + // specify subject + Composite composite = new Composite(parent, SWT.NONE); + composite.setLayout(new GridLayout(2, false)); + Label lbl = new Label(composite, SWT.LEAD); + lbl.setText("Group or user name (no blank, no special chars)"); + lbl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false)); + groupNameTxt = new Text(composite, SWT.LEAD | SWT.BORDER); + groupNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, + false)); + if (groupNameTxt != null) + groupNameTxt.addModifyListener(this); + + // Choose rigths + new Label(composite, SWT.NONE).setText("Choose corresponding rights"); + authorizationCmb = new Combo(composite, SWT.BORDER | SWT.V_SCROLL); + authorizationCmb.setItems(validAuthType); + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + authorizationCmb.setLayoutData(gd); + + authorizationCmb.select(0); + + // Compulsory + setControl(composite); + } + + protected String getGroupName() { + return groupNameTxt.getText(); + } + + protected String getAuthTypeStr() { + return authorizationCmb.getItem(authorizationCmb.getSelectionIndex()); + } + + public void modifyText(ModifyEvent event) { + String message = checkComplete(); + if (message != null) + setMessage(message, WizardPage.ERROR); + else { + setMessage("Complete", WizardPage.INFORMATION); + setPageComplete(true); + } + } + + /** @return error message or null if complete */ + protected String checkComplete() { + String groupStr = groupNameTxt.getText(); + if (groupStr == null || "".equals(groupStr)) + return "Please enter the name of the corresponding group."; + // Remove regexp check for the time being. + // else if (!match(groupStr)) + // return + // "Please use only alphanumerical chars for the short technical name."; + return null; + } +} diff --git a/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/wizards/ImportFileSystemWizard.java b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/wizards/ImportFileSystemWizard.java new file mode 100644 index 000000000..127c2cd54 --- /dev/null +++ b/org.argeo.jcr.ui.explorer/src/org/argeo/jcr/ui/explorer/wizards/ImportFileSystemWizard.java @@ -0,0 +1,237 @@ +/* + * 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.jcr.ui.explorer.wizards; + +import java.io.File; +import java.io.FileInputStream; + +import javax.jcr.Binary; +import javax.jcr.Node; +import javax.jcr.Property; +import javax.jcr.nodetype.NodeType; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.ArgeoException; +import org.argeo.eclipse.ui.ErrorFeedback; +import org.argeo.eclipse.ui.specific.ImportToServerWizardPage; +import org.argeo.eclipse.ui.specific.UploadFileWizardPage; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.wizard.Wizard; + +public class ImportFileSystemWizard extends Wizard { + private final static Log log = LogFactory + .getLog(ImportFileSystemWizard.class); + + private UploadFileWizardPage importPage; + private final Node folder; + + public ImportFileSystemWizard(Node folder) { + this.folder = folder; + setWindowTitle("Import from file system"); + } + + @Override + public void addPages() { + importPage = new UploadFileWizardPage(); + addPage(importPage); + setNeedsProgressMonitor(importPage.getNeedsProgressMonitor()); + } + + /** + * Called when the user click on 'Finish' in the wizard. The real upload to + * the JCR repository is done here. + */ + @Override + public boolean performFinish() { + + // Initialization + final String objectType = importPage.getObjectType(); + final String objectPath = importPage.getObjectPath(); + + // We do not display a progress bar for one file only + if (ImportToServerWizardPage.FILE_ITEM_TYPE.equals(objectType)) { + // In Rap we must force the "real" upload of the file + importPage.performFinish(); + try { + Node fileNode = folder.addNode(importPage.getObjectName(), + NodeType.NT_FILE); + Node resNode = fileNode.addNode(Property.JCR_CONTENT, + NodeType.NT_RESOURCE); + Binary binary = null; + try { + binary = folder.getSession().getValueFactory() + .createBinary(importPage.getFileInputStream()); + resNode.setProperty(Property.JCR_DATA, binary); + } finally { + if (binary != null) + binary.dispose(); + IOUtils.closeQuietly(importPage.getFileInputStream()); + } + folder.getSession().save(); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + return true; + } else if (ImportToServerWizardPage.FOLDER_ITEM_TYPE.equals(objectType)) { + if (objectPath == null || !new File(objectPath).exists()) { + ErrorFeedback.show("Directory " + objectPath + + " does not exist"); + return false; + } + + Boolean failed = false; + final File dir = new File(objectPath).getAbsoluteFile(); + final Long sizeB = directorySize(dir, 0l); + final Stats stats = new Stats(); + Long begin = System.currentTimeMillis(); + try { + getContainer().run(true, true, new IRunnableWithProgress() { + public void run(IProgressMonitor monitor) { + try { + Integer sizeKB = (int) (sizeB / FileUtils.ONE_KB); + monitor.beginTask("", sizeKB); + importDirectory(folder, dir, monitor, stats); + monitor.done(); + } catch (Exception e) { + if (e instanceof RuntimeException) + throw (RuntimeException) e; + else + throw new ArgeoException("Cannot import " + + objectPath, e); + } + } + }); + } catch (Exception e) { + ErrorFeedback.show("Cannot import " + objectPath, e); + failed = true; + } + + Long duration = System.currentTimeMillis() - begin; + Long durationS = duration / 1000l; + String durationStr = (durationS / 60) + " min " + (durationS % 60) + + " s"; + StringBuffer message = new StringBuffer("Imported\n"); + message.append(stats.fileCount).append(" files\n"); + message.append(stats.dirCount).append(" directories\n"); + message.append(FileUtils.byteCountToDisplaySize(stats.sizeB)); + if (failed) + message.append(" of planned ").append( + FileUtils.byteCountToDisplaySize(sizeB)); + message.append("\n"); + message.append("in ").append(durationStr).append("\n"); + if (failed) + MessageDialog.openError(getShell(), "Import failed", + message.toString()); + else + MessageDialog.openInformation(getShell(), "Import successful", + message.toString()); + + return true; + } + return false; + + } + + /** Recursively computes the size of the directory in bytes. */ + protected Long directorySize(File dir, Long currentSize) { + Long size = currentSize; + File[] files = dir.listFiles(); + for (File file : files) { + if (file.isDirectory()) { + size = directorySize(file, size); + } else { + size = size + file.length(); + } + } + return size; + } + + /** + * Import recursively a directory and its content to the repository. + */ + protected void importDirectory(Node folder, File dir, + IProgressMonitor monitor, Stats stats) { + try { + File[] files = dir.listFiles(); + for (File file : files) { + if (file.isDirectory()) { + Node childFolder = folder.addNode(file.getName(), + NodeType.NT_FOLDER); + importDirectory(childFolder, file, monitor, stats); + folder.getSession().save(); + stats.dirCount++; + } else { + Long fileSize = file.length(); + + // we skip tempory files that are created by apps when a + // file is being edited. + // TODO : make this configurable. + if (file.getName().lastIndexOf('~') != file.getName() + .length() - 1) { + + monitor.subTask(file.getName() + " (" + + FileUtils.byteCountToDisplaySize(fileSize) + + ") " + file.getCanonicalPath()); + try { + Node fileNode = folder.addNode(file.getName(), + NodeType.NT_FILE); + Node resNode = fileNode.addNode( + Property.JCR_CONTENT, NodeType.NT_RESOURCE); + Binary binary = null; + try { + binary = folder + .getSession() + .getValueFactory() + .createBinary(new FileInputStream(file)); + resNode.setProperty(Property.JCR_DATA, binary); + } finally { + if (binary != null) + binary.dispose(); + } + folder.getSession().save(); + stats.fileCount++; + stats.sizeB = stats.sizeB + fileSize; + } catch (Exception e) { + log.warn("Import of " + + file + + " (" + + FileUtils + .byteCountToDisplaySize(fileSize) + + ") failed: " + e); + folder.getSession().refresh(false); + } + monitor.worked((int) (fileSize / FileUtils.ONE_KB)); + } + } + } + } catch (Exception e) { + throw new ArgeoException("Cannot import " + dir + " to " + folder, + e); + } + } + + static class Stats { + public Long fileCount = 0l; + public Long dirCount = 0l; + public Long sizeB = 0l; + } +} diff --git a/org.argeo.osgi.ui.explorer/.classpath b/org.argeo.osgi.ui.explorer/.classpath index c5931a083..d2953a684 100644 --- a/org.argeo.osgi.ui.explorer/.classpath +++ b/org.argeo.osgi.ui.explorer/.classpath @@ -1,7 +1,9 @@ - >> - - - + + + + diff --git a/org.argeo.osgi.ui.explorer/src/main/java/org/argeo/osgi/ui/explorer/OsgiExplorerImages.java b/org.argeo.osgi.ui.explorer/src/main/java/org/argeo/osgi/ui/explorer/OsgiExplorerImages.java deleted file mode 100644 index 77bdfe946..000000000 --- a/org.argeo.osgi.ui.explorer/src/main/java/org/argeo/osgi/ui/explorer/OsgiExplorerImages.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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.osgi.ui.explorer; - -import org.eclipse.swt.graphics.Image; - -/** Shared icons. */ -public class OsgiExplorerImages { - public final static Image INSTALLED = OsgiExplorerPlugin - .getImageDescriptor("icons/installed.gif").createImage(); - public final static Image RESOLVED = OsgiExplorerPlugin.getImageDescriptor( - "icons/resolved.gif").createImage(); - public final static Image STARTING = OsgiExplorerPlugin.getImageDescriptor( - "icons/starting.gif").createImage(); - public final static Image ACTIVE = OsgiExplorerPlugin.getImageDescriptor( - "icons/active.gif").createImage(); -} diff --git a/org.argeo.osgi.ui.explorer/src/main/java/org/argeo/osgi/ui/explorer/OsgiExplorerPerspective.java b/org.argeo.osgi.ui.explorer/src/main/java/org/argeo/osgi/ui/explorer/OsgiExplorerPerspective.java deleted file mode 100644 index 153abcda2..000000000 --- a/org.argeo.osgi.ui.explorer/src/main/java/org/argeo/osgi/ui/explorer/OsgiExplorerPerspective.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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.osgi.ui.explorer; - -import org.eclipse.ui.IPageLayout; -import org.eclipse.ui.IPerspectiveFactory; - -/** OSGi explorer perspective (to be enriched declaratively) */ -public class OsgiExplorerPerspective implements IPerspectiveFactory { - - public void createInitialLayout(IPageLayout layout) { - layout.setEditorAreaVisible(true); - layout.setFixed(false); - - } - -} diff --git a/org.argeo.osgi.ui.explorer/src/main/java/org/argeo/osgi/ui/explorer/OsgiExplorerPlugin.java b/org.argeo.osgi.ui.explorer/src/main/java/org/argeo/osgi/ui/explorer/OsgiExplorerPlugin.java deleted file mode 100644 index 80146d198..000000000 --- a/org.argeo.osgi.ui.explorer/src/main/java/org/argeo/osgi/ui/explorer/OsgiExplorerPlugin.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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.osgi.ui.explorer; - -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.ui.plugin.AbstractUIPlugin; -import org.osgi.framework.BundleContext; - -/** - * The activator class controls the plug-in life cycle - */ -public class OsgiExplorerPlugin extends AbstractUIPlugin { - - // The plug-in ID - public static final String PLUGIN_ID = "org.argeo.osgi.ui.explorer"; //$NON-NLS-1$ - - // The shared instance - private static OsgiExplorerPlugin plugin; - - /** - * The constructor - */ - public OsgiExplorerPlugin() { - } - - /* - * (non-Javadoc) - * - * @see - * org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext - * ) - */ - public void start(BundleContext context) throws Exception { - super.start(context); - plugin = this; - } - - /* - * (non-Javadoc) - * - * @see - * org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext - * ) - */ - public void stop(BundleContext context) throws Exception { - plugin = null; - super.stop(context); - } - - /** - * Returns the shared instance - * - * @return the shared instance - */ - public static OsgiExplorerPlugin getDefault() { - return plugin; - } - - public static ImageDescriptor getImageDescriptor(String path) { - return imageDescriptorFromPlugin(PLUGIN_ID, path); - } - -} diff --git a/org.argeo.osgi.ui.explorer/src/main/java/org/argeo/osgi/ui/explorer/views/BundlesView.java b/org.argeo.osgi.ui.explorer/src/main/java/org/argeo/osgi/ui/explorer/views/BundlesView.java deleted file mode 100644 index 98d74a6a7..000000000 --- a/org.argeo.osgi.ui.explorer/src/main/java/org/argeo/osgi/ui/explorer/views/BundlesView.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * 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.osgi.ui.explorer.views; - -import java.util.Comparator; - -import org.argeo.eclipse.ui.ColumnViewerComparator; -import org.argeo.eclipse.ui.specific.EclipseUiSpecificUtils; -import org.argeo.osgi.ui.explorer.OsgiExplorerImages; -import org.argeo.osgi.ui.explorer.OsgiExplorerPlugin; -import org.eclipse.jface.viewers.ColumnLabelProvider; -import org.eclipse.jface.viewers.IStructuredContentProvider; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.jface.viewers.TableViewerColumn; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.ui.part.ViewPart; -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleContext; -import org.osgi.framework.Constants; - -/** - * Overview of the bundles as a table. Equivalent to Equinox 'ss' console - * command. - */ -public class BundlesView extends ViewPart { - private TableViewer viewer; - - @Override - public void createPartControl(Composite parent) { - viewer = new TableViewer(parent); - viewer.setContentProvider(new BundleContentProvider()); - viewer.getTable().setHeaderVisible(true); - - EclipseUiSpecificUtils.enableToolTipSupport(viewer); - - // ID - TableViewerColumn column = new TableViewerColumn(viewer, SWT.NONE); - column.getColumn().setWidth(30); - column.getColumn().setText("ID"); - column.getColumn().setAlignment(SWT.RIGHT); - column.setLabelProvider(new ColumnLabelProvider() { - public String getText(Object element) { - return Long.toString(((Bundle) element).getBundleId()); - } - }); - new ColumnViewerComparator(column, new Comparator() { - public int compare(Bundle o1, Bundle o2) { - return (int) (o1.getBundleId() - o2.getBundleId()); - } - }); - - // State - column = new TableViewerColumn(viewer, SWT.NONE); - column.getColumn().setWidth(18); - column.getColumn().setText("State"); - column.setLabelProvider(new StateLabelProvider()); - new ColumnViewerComparator(column, new Comparator() { - public int compare(Bundle o1, Bundle o2) { - return o1.getState() - o2.getState(); - } - }); - - // Symbolic name - column = new TableViewerColumn(viewer, SWT.NONE); - column.getColumn().setWidth(300); - column.getColumn().setText("Symbolic Name"); - column.setLabelProvider(new ColumnLabelProvider() { - public String getText(Object element) { - return ((Bundle) element).getSymbolicName(); - } - }); - new ColumnViewerComparator(column, new Comparator() { - public int compare(Bundle o1, Bundle o2) { - return o1.getSymbolicName().compareTo(o2.getSymbolicName()); - } - }); - - // Version - column = new TableViewerColumn(viewer, SWT.NONE); - column.getColumn().setWidth(150); - column.getColumn().setText("Version"); - column.setLabelProvider(new ColumnLabelProvider() { - public String getText(Object element) { - return ((Bundle) element).getVersion().toString(); - } - }); - new ColumnViewerComparator(column, new Comparator() { - public int compare(Bundle o1, Bundle o2) { - return o1.getVersion().compareTo(o2.getVersion()); - } - }); - - viewer.setInput(OsgiExplorerPlugin.getDefault().getBundle() - .getBundleContext()); - - } - - @Override - public void setFocus() { - if (viewer != null) - viewer.getControl().setFocus(); - } - - /** Content provider managing the array of bundles */ - private static class BundleContentProvider implements - IStructuredContentProvider { - public Object[] getElements(Object inputElement) { - if (inputElement instanceof BundleContext) { - BundleContext bc = (BundleContext) inputElement; - return bc.getBundles(); - } - return null; - } - - public void dispose() { - } - - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - } - - } - - /** Label provider for the state column */ - private static class StateLabelProvider extends ColumnLabelProvider { - @Override - public Image getImage(Object element) { - Integer state = ((Bundle) element).getState(); - switch (state) { - case Bundle.UNINSTALLED: - return OsgiExplorerImages.INSTALLED; - case Bundle.INSTALLED: - return OsgiExplorerImages.INSTALLED; - case Bundle.RESOLVED: - return OsgiExplorerImages.RESOLVED; - case Bundle.STARTING: - return OsgiExplorerImages.STARTING; - case Bundle.STOPPING: - return OsgiExplorerImages.STARTING; - case Bundle.ACTIVE: - return OsgiExplorerImages.ACTIVE; - default: - return null; - } - } - - @Override - public String getText(Object element) { - return null; - } - - @Override - public String getToolTipText(Object element) { - Bundle bundle = (Bundle) element; - Integer state = bundle.getState(); - switch (state) { - case Bundle.UNINSTALLED: - return "UNINSTALLED"; - case Bundle.INSTALLED: - return "INSTALLED"; - case Bundle.RESOLVED: - return "RESOLVED"; - case Bundle.STARTING: - String activationPolicy = bundle.getHeaders() - .get(Constants.BUNDLE_ACTIVATIONPOLICY).toString(); - if (activationPolicy != null - && activationPolicy.equals(Constants.ACTIVATION_LAZY)) - return "<>"; - return "STARTING"; - case Bundle.STOPPING: - return "STOPPING"; - case Bundle.ACTIVE: - return "ACTIVE"; - default: - return null; - } - } - - } -} diff --git a/org.argeo.osgi.ui.explorer/src/main/java/org/argeo/osgi/ui/explorer/views/ModulesView.java b/org.argeo.osgi.ui.explorer/src/main/java/org/argeo/osgi/ui/explorer/views/ModulesView.java deleted file mode 100644 index 5d67bd458..000000000 --- a/org.argeo.osgi.ui.explorer/src/main/java/org/argeo/osgi/ui/explorer/views/ModulesView.java +++ /dev/null @@ -1,379 +0,0 @@ -/* - * 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.osgi.ui.explorer.views; - -import java.util.Comparator; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; -import java.util.TreeSet; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.eclipse.ui.TreeParent; -import org.argeo.osgi.ui.explorer.OsgiExplorerPlugin; -import org.eclipse.jface.viewers.ITableLabelProvider; -import org.eclipse.jface.viewers.ITreeContentProvider; -import org.eclipse.jface.viewers.LabelProvider; -import org.eclipse.jface.viewers.TreeViewer; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.ui.part.ViewPart; -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; -import org.osgi.service.packageadmin.ExportedPackage; -import org.osgi.service.packageadmin.PackageAdmin; - -/** Experimental The OSGi runtime from a module perspective. */ -public class ModulesView extends ViewPart { - private final static Log log = LogFactory.getLog(ModulesView.class); - - private TreeViewer viewer; - - private PackageAdmin packageAdmin; - - private Comparator exportedPackageComparator = new Comparator() { - - public int compare(ExportedPackage o1, ExportedPackage o2) { - if (!o1.getName().equals(o2.getName())) - return o1.getName().compareTo(o2.getName()); - else - return o1.getVersion().compareTo(o2.getVersion()); - } - }; - - @Override - public void createPartControl(Composite parent) { - viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); - viewer.setContentProvider(new ModulesContentProvider()); - viewer.setLabelProvider(new ModulesLabelProvider()); - viewer.setInput(OsgiExplorerPlugin.getDefault().getBundle() - .getBundleContext()); - } - - @Override - public void setFocus() { - viewer.getTree().setFocus(); - } - - private class ModulesContentProvider implements ITreeContentProvider { - - public Object[] getElements(Object inputElement) { - return getChildren(inputElement); - } - - public Object[] getChildren(Object parentElement) { - if (parentElement instanceof BundleContext) { - BundleContext bundleContext = (BundleContext) parentElement; - Bundle[] bundles = bundleContext.getBundles(); - - TreeParent bundlesNode = new TreeParent("Bundles"); - for (Bundle bundle : bundles) { - if (bundle.getState() == Bundle.ACTIVE) - bundlesNode.addChild(new BundleNode(bundle)); - } - - // scan packages - ServiceReference paSr = bundleContext - .getServiceReference(PackageAdmin.class.getName()); - // TODO: make a cleaner referencing - packageAdmin = (PackageAdmin) bundleContext.getService(paSr); - - Bundle bundle1 = null; - Bundle bundle2 = null; - - Map> importedPackages = new HashMap>(); - Map> packages = new TreeMap>(); - for (Bundle bundle : bundles) { - if (bundle.getSymbolicName() - .equals("org.argeo.security.ui")) - bundle1 = bundle; - if (bundle.getSymbolicName().equals( - "org.argeo.security.equinox")) - bundle2 = bundle; - - ExportedPackage[] pkgs = packageAdmin - .getExportedPackages(bundle); - if (pkgs != null) - for (ExportedPackage pkg : pkgs) { - if (!packages.containsKey(pkg.getName())) - packages.put(pkg.getName(), - new TreeSet( - exportedPackageComparator)); - Set expPackages = (Set) packages - .get(pkg.getName()); - expPackages.add(pkg); - - // imported - for (Bundle b : pkg.getImportingBundles()) { - if (bundle.getBundleId() != b.getBundleId()) { - if (!importedPackages.containsKey(b)) - importedPackages - .put(b, - new TreeSet( - exportedPackageComparator)); - Set impPackages = (Set) importedPackages - .get(b); - impPackages.add(pkg); - } - } - } - } - - TreeParent mPackageNode = new TreeParent("Multiple Packages"); - // TreeParent aPackageNode = new TreeParent("All Packages"); - for (String packageName : packages.keySet()) { - Set pkgs = packages.get(packageName); - if (pkgs.size() > 1) { - MultiplePackagesNode mpn = new MultiplePackagesNode( - packageName, pkgs); - mPackageNode.addChild(mpn); - // aPackageNode.addChild(mpn); - } else { - // aPackageNode.addChild(new ExportedPackageNode(pkgs - // .iterator().next())); - } - } - - return new Object[] { bundlesNode, mPackageNode };// , - // aPackageNode - // }; - } else if (parentElement instanceof TreeParent) { - return ((TreeParent) parentElement).getChildren(); - } else { - return null; - } - } - - public Object getParent(Object element) { - // TODO Auto-generated method stub - return null; - } - - public boolean hasChildren(Object element) { - if (element instanceof TreeParent) { - return ((TreeParent) element).hasChildren(); - } - return false; - } - - public void dispose() { - // TODO Auto-generated method stub - - } - - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - // TODO Auto-generated method stub - - } - - } - - protected Map dependencySpace(Bundle bundle, - Map> importedPackages, - Map> traces) { - log.debug("Dependency space for " + bundle.getSymbolicName()); - Map space = new TreeMap(); - fillDependencySpace(space, bundle, importedPackages, - bundle.getSymbolicName(), traces); - return space; - } - - /** Recursive */ - protected void fillDependencySpace(Map space, - Bundle bundle, Map> importedPackages, - String currTrace, Map> traces) { - if (importedPackages.containsKey(bundle)) { - Set imports = importedPackages.get(bundle); - // log.debug("## Fill dependency space for " + bundle + " : "); - for (ExportedPackage pkg : imports) { - if (!traces.containsKey(pkg.getName())) - traces.put(pkg.getName(), new TreeSet()); - traces.get(pkg.getName()).add(currTrace); - if (!space.containsKey(pkg.getName())) { - space.put(pkg.getName(), pkg); - Bundle exportingBundle = pkg.getExportingBundle(); - // if (bundle.getBundleId() != - // exportingBundle.getBundleId()) - fillDependencySpace(space, exportingBundle, - importedPackages, currTrace + " > " - + exportingBundle.getSymbolicName(), traces); - } - } - } - } - - private class ModulesLabelProvider extends LabelProvider implements - ITableLabelProvider { - - public Image getColumnImage(Object element, int columnIndex) { - // TODO Auto-generated method stub - return null; - } - - public String getColumnText(Object element, int columnIndex) { - return getText(element); - } - - } - - class BundleNode extends TreeParent { - private final Bundle bundle; - - public BundleNode(Bundle bundle) { - super(bundle.getSymbolicName()); - this.bundle = bundle; - - // Registered services - ServiceReference[] registeredServices = bundle - .getRegisteredServices(); - if (registeredServices != null) { - TreeParent registeredServicesNode = new TreeParent( - "Registered Services"); - addChild(registeredServicesNode); - for (ServiceReference sr : registeredServices) { - if (sr != null) - registeredServicesNode - .addChild(new ServiceReferenceNode(sr)); - } - } - - // Used services - ServiceReference[] usedServices = bundle.getRegisteredServices(); - if (usedServices != null) { - TreeParent usedServicesNode = new TreeParent("Used Services"); - addChild(usedServicesNode); - for (ServiceReference sr : usedServices) { - if (sr != null) - usedServicesNode.addChild(new ServiceReferenceNode(sr)); - } - } - } - - public Bundle getBundle() { - return bundle; - } - - } - - class ServiceReferenceNode extends TreeParent { - private final ServiceReference serviceReference; - - public ServiceReferenceNode(ServiceReference serviceReference) { - super(serviceReference.toString()); - this.serviceReference = serviceReference; - - Bundle[] usedBundles = serviceReference.getUsingBundles(); - if (usedBundles != null) { - TreeParent usingBundles = new TreeParent("Using Bundles"); - addChild(usingBundles); - for (Bundle b : usedBundles) { - if (b != null) - usingBundles.addChild(new TreeParent(b - .getSymbolicName())); - } - } - - TreeParent properties = new TreeParent("Properties"); - addChild(properties); - for (String key : serviceReference.getPropertyKeys()) { - properties.addChild(new TreeParent(key + "=" - + serviceReference.getProperty(key))); - } - - } - - public ServiceReference getServiceReference() { - return serviceReference; - } - - } - - class MultiplePackagesNode extends TreeParent { - private String packageName; - private Set exportedPackages; - - public MultiplePackagesNode(String packageName, - Set exportedPackages) { - super(packageName); - this.packageName = packageName; - this.exportedPackages = exportedPackages; - for (ExportedPackage pkg : exportedPackages) { - addChild(new ExportedPackageNode(pkg)); - } - } - - } - - class ConflictingPackageNode extends TreeParent { - private ExportedPackage exportedPackage; - - public ConflictingPackageNode(ExportedPackage exportedPackage) { - super(exportedPackage.getName() + " - " - + exportedPackage.getVersion() + " (" - + exportedPackage.getExportingBundle() + ")"); - this.exportedPackage = exportedPackage; - - TreeParent bundlesNode = new TreeParent("Dependent Bundles"); - this.addChild(bundlesNode); - Map bundles = new TreeMap(); - for (Bundle b : exportedPackage.getImportingBundles()) { - bundles.put(b.getSymbolicName(), b); - } - for (String key : bundles.keySet()) { - addDependentBundles(bundlesNode, bundles.get(key)); - } - } - } - - protected void addDependentBundles(TreeParent parent, Bundle bundle) { - TreeParent bundleNode = new TreeParent(bundle.toString()); - parent.addChild(bundleNode); - Map bundles = new TreeMap(); - ExportedPackage[] pkgs = packageAdmin.getExportedPackages(bundle); - if (pkgs != null) - for (ExportedPackage pkg : pkgs) { - for (Bundle b : pkg.getImportingBundles()) { - if (!bundles.containsKey(b.getSymbolicName()) - && b.getBundleId() != bundle.getBundleId()) { - bundles.put(b.getSymbolicName(), b); - } - } - } - - for (String key : bundles.keySet()) { - addDependentBundles(bundleNode, bundles.get(key)); - } - } - - class ExportedPackageNode extends TreeParent { - private ExportedPackage exportedPackage; - - public ExportedPackageNode(ExportedPackage exportedPackage) { - super(exportedPackage.getName() + " - " - + exportedPackage.getVersion() + " (" - + exportedPackage.getExportingBundle() + ")"); - this.exportedPackage = exportedPackage; - for (Bundle bundle : exportedPackage.getImportingBundles()) { - addChild(new BundleNode(bundle)); - } - } - } -} diff --git a/org.argeo.osgi.ui.explorer/src/org/argeo/osgi/ui/explorer/OsgiExplorerImages.java b/org.argeo.osgi.ui.explorer/src/org/argeo/osgi/ui/explorer/OsgiExplorerImages.java new file mode 100644 index 000000000..77bdfe946 --- /dev/null +++ b/org.argeo.osgi.ui.explorer/src/org/argeo/osgi/ui/explorer/OsgiExplorerImages.java @@ -0,0 +1,30 @@ +/* + * 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.osgi.ui.explorer; + +import org.eclipse.swt.graphics.Image; + +/** Shared icons. */ +public class OsgiExplorerImages { + public final static Image INSTALLED = OsgiExplorerPlugin + .getImageDescriptor("icons/installed.gif").createImage(); + public final static Image RESOLVED = OsgiExplorerPlugin.getImageDescriptor( + "icons/resolved.gif").createImage(); + public final static Image STARTING = OsgiExplorerPlugin.getImageDescriptor( + "icons/starting.gif").createImage(); + public final static Image ACTIVE = OsgiExplorerPlugin.getImageDescriptor( + "icons/active.gif").createImage(); +} diff --git a/org.argeo.osgi.ui.explorer/src/org/argeo/osgi/ui/explorer/OsgiExplorerPerspective.java b/org.argeo.osgi.ui.explorer/src/org/argeo/osgi/ui/explorer/OsgiExplorerPerspective.java new file mode 100644 index 000000000..153abcda2 --- /dev/null +++ b/org.argeo.osgi.ui.explorer/src/org/argeo/osgi/ui/explorer/OsgiExplorerPerspective.java @@ -0,0 +1,30 @@ +/* + * 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.osgi.ui.explorer; + +import org.eclipse.ui.IPageLayout; +import org.eclipse.ui.IPerspectiveFactory; + +/** OSGi explorer perspective (to be enriched declaratively) */ +public class OsgiExplorerPerspective implements IPerspectiveFactory { + + public void createInitialLayout(IPageLayout layout) { + layout.setEditorAreaVisible(true); + layout.setFixed(false); + + } + +} diff --git a/org.argeo.osgi.ui.explorer/src/org/argeo/osgi/ui/explorer/OsgiExplorerPlugin.java b/org.argeo.osgi.ui.explorer/src/org/argeo/osgi/ui/explorer/OsgiExplorerPlugin.java new file mode 100644 index 000000000..80146d198 --- /dev/null +++ b/org.argeo.osgi.ui.explorer/src/org/argeo/osgi/ui/explorer/OsgiExplorerPlugin.java @@ -0,0 +1,76 @@ +/* + * 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.osgi.ui.explorer; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + */ +public class OsgiExplorerPlugin extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "org.argeo.osgi.ui.explorer"; //$NON-NLS-1$ + + // The shared instance + private static OsgiExplorerPlugin plugin; + + /** + * The constructor + */ + public OsgiExplorerPlugin() { + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext + * ) + */ + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext + * ) + */ + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static OsgiExplorerPlugin getDefault() { + return plugin; + } + + public static ImageDescriptor getImageDescriptor(String path) { + return imageDescriptorFromPlugin(PLUGIN_ID, path); + } + +} diff --git a/org.argeo.osgi.ui.explorer/src/org/argeo/osgi/ui/explorer/views/BundlesView.java b/org.argeo.osgi.ui.explorer/src/org/argeo/osgi/ui/explorer/views/BundlesView.java new file mode 100644 index 000000000..98d74a6a7 --- /dev/null +++ b/org.argeo.osgi.ui.explorer/src/org/argeo/osgi/ui/explorer/views/BundlesView.java @@ -0,0 +1,195 @@ +/* + * 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.osgi.ui.explorer.views; + +import java.util.Comparator; + +import org.argeo.eclipse.ui.ColumnViewerComparator; +import org.argeo.eclipse.ui.specific.EclipseUiSpecificUtils; +import org.argeo.osgi.ui.explorer.OsgiExplorerImages; +import org.argeo.osgi.ui.explorer.OsgiExplorerPlugin; +import org.eclipse.jface.viewers.ColumnLabelProvider; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.part.ViewPart; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.Constants; + +/** + * Overview of the bundles as a table. Equivalent to Equinox 'ss' console + * command. + */ +public class BundlesView extends ViewPart { + private TableViewer viewer; + + @Override + public void createPartControl(Composite parent) { + viewer = new TableViewer(parent); + viewer.setContentProvider(new BundleContentProvider()); + viewer.getTable().setHeaderVisible(true); + + EclipseUiSpecificUtils.enableToolTipSupport(viewer); + + // ID + TableViewerColumn column = new TableViewerColumn(viewer, SWT.NONE); + column.getColumn().setWidth(30); + column.getColumn().setText("ID"); + column.getColumn().setAlignment(SWT.RIGHT); + column.setLabelProvider(new ColumnLabelProvider() { + public String getText(Object element) { + return Long.toString(((Bundle) element).getBundleId()); + } + }); + new ColumnViewerComparator(column, new Comparator() { + public int compare(Bundle o1, Bundle o2) { + return (int) (o1.getBundleId() - o2.getBundleId()); + } + }); + + // State + column = new TableViewerColumn(viewer, SWT.NONE); + column.getColumn().setWidth(18); + column.getColumn().setText("State"); + column.setLabelProvider(new StateLabelProvider()); + new ColumnViewerComparator(column, new Comparator() { + public int compare(Bundle o1, Bundle o2) { + return o1.getState() - o2.getState(); + } + }); + + // Symbolic name + column = new TableViewerColumn(viewer, SWT.NONE); + column.getColumn().setWidth(300); + column.getColumn().setText("Symbolic Name"); + column.setLabelProvider(new ColumnLabelProvider() { + public String getText(Object element) { + return ((Bundle) element).getSymbolicName(); + } + }); + new ColumnViewerComparator(column, new Comparator() { + public int compare(Bundle o1, Bundle o2) { + return o1.getSymbolicName().compareTo(o2.getSymbolicName()); + } + }); + + // Version + column = new TableViewerColumn(viewer, SWT.NONE); + column.getColumn().setWidth(150); + column.getColumn().setText("Version"); + column.setLabelProvider(new ColumnLabelProvider() { + public String getText(Object element) { + return ((Bundle) element).getVersion().toString(); + } + }); + new ColumnViewerComparator(column, new Comparator() { + public int compare(Bundle o1, Bundle o2) { + return o1.getVersion().compareTo(o2.getVersion()); + } + }); + + viewer.setInput(OsgiExplorerPlugin.getDefault().getBundle() + .getBundleContext()); + + } + + @Override + public void setFocus() { + if (viewer != null) + viewer.getControl().setFocus(); + } + + /** Content provider managing the array of bundles */ + private static class BundleContentProvider implements + IStructuredContentProvider { + public Object[] getElements(Object inputElement) { + if (inputElement instanceof BundleContext) { + BundleContext bc = (BundleContext) inputElement; + return bc.getBundles(); + } + return null; + } + + public void dispose() { + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + } + + } + + /** Label provider for the state column */ + private static class StateLabelProvider extends ColumnLabelProvider { + @Override + public Image getImage(Object element) { + Integer state = ((Bundle) element).getState(); + switch (state) { + case Bundle.UNINSTALLED: + return OsgiExplorerImages.INSTALLED; + case Bundle.INSTALLED: + return OsgiExplorerImages.INSTALLED; + case Bundle.RESOLVED: + return OsgiExplorerImages.RESOLVED; + case Bundle.STARTING: + return OsgiExplorerImages.STARTING; + case Bundle.STOPPING: + return OsgiExplorerImages.STARTING; + case Bundle.ACTIVE: + return OsgiExplorerImages.ACTIVE; + default: + return null; + } + } + + @Override + public String getText(Object element) { + return null; + } + + @Override + public String getToolTipText(Object element) { + Bundle bundle = (Bundle) element; + Integer state = bundle.getState(); + switch (state) { + case Bundle.UNINSTALLED: + return "UNINSTALLED"; + case Bundle.INSTALLED: + return "INSTALLED"; + case Bundle.RESOLVED: + return "RESOLVED"; + case Bundle.STARTING: + String activationPolicy = bundle.getHeaders() + .get(Constants.BUNDLE_ACTIVATIONPOLICY).toString(); + if (activationPolicy != null + && activationPolicy.equals(Constants.ACTIVATION_LAZY)) + return "<>"; + return "STARTING"; + case Bundle.STOPPING: + return "STOPPING"; + case Bundle.ACTIVE: + return "ACTIVE"; + default: + return null; + } + } + + } +} diff --git a/org.argeo.osgi.ui.explorer/src/org/argeo/osgi/ui/explorer/views/ModulesView.java b/org.argeo.osgi.ui.explorer/src/org/argeo/osgi/ui/explorer/views/ModulesView.java new file mode 100644 index 000000000..5d67bd458 --- /dev/null +++ b/org.argeo.osgi.ui.explorer/src/org/argeo/osgi/ui/explorer/views/ModulesView.java @@ -0,0 +1,379 @@ +/* + * 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.osgi.ui.explorer.views; + +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.eclipse.ui.TreeParent; +import org.argeo.osgi.ui.explorer.OsgiExplorerPlugin; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.part.ViewPart; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.service.packageadmin.ExportedPackage; +import org.osgi.service.packageadmin.PackageAdmin; + +/** Experimental The OSGi runtime from a module perspective. */ +public class ModulesView extends ViewPart { + private final static Log log = LogFactory.getLog(ModulesView.class); + + private TreeViewer viewer; + + private PackageAdmin packageAdmin; + + private Comparator exportedPackageComparator = new Comparator() { + + public int compare(ExportedPackage o1, ExportedPackage o2) { + if (!o1.getName().equals(o2.getName())) + return o1.getName().compareTo(o2.getName()); + else + return o1.getVersion().compareTo(o2.getVersion()); + } + }; + + @Override + public void createPartControl(Composite parent) { + viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); + viewer.setContentProvider(new ModulesContentProvider()); + viewer.setLabelProvider(new ModulesLabelProvider()); + viewer.setInput(OsgiExplorerPlugin.getDefault().getBundle() + .getBundleContext()); + } + + @Override + public void setFocus() { + viewer.getTree().setFocus(); + } + + private class ModulesContentProvider implements ITreeContentProvider { + + public Object[] getElements(Object inputElement) { + return getChildren(inputElement); + } + + public Object[] getChildren(Object parentElement) { + if (parentElement instanceof BundleContext) { + BundleContext bundleContext = (BundleContext) parentElement; + Bundle[] bundles = bundleContext.getBundles(); + + TreeParent bundlesNode = new TreeParent("Bundles"); + for (Bundle bundle : bundles) { + if (bundle.getState() == Bundle.ACTIVE) + bundlesNode.addChild(new BundleNode(bundle)); + } + + // scan packages + ServiceReference paSr = bundleContext + .getServiceReference(PackageAdmin.class.getName()); + // TODO: make a cleaner referencing + packageAdmin = (PackageAdmin) bundleContext.getService(paSr); + + Bundle bundle1 = null; + Bundle bundle2 = null; + + Map> importedPackages = new HashMap>(); + Map> packages = new TreeMap>(); + for (Bundle bundle : bundles) { + if (bundle.getSymbolicName() + .equals("org.argeo.security.ui")) + bundle1 = bundle; + if (bundle.getSymbolicName().equals( + "org.argeo.security.equinox")) + bundle2 = bundle; + + ExportedPackage[] pkgs = packageAdmin + .getExportedPackages(bundle); + if (pkgs != null) + for (ExportedPackage pkg : pkgs) { + if (!packages.containsKey(pkg.getName())) + packages.put(pkg.getName(), + new TreeSet( + exportedPackageComparator)); + Set expPackages = (Set) packages + .get(pkg.getName()); + expPackages.add(pkg); + + // imported + for (Bundle b : pkg.getImportingBundles()) { + if (bundle.getBundleId() != b.getBundleId()) { + if (!importedPackages.containsKey(b)) + importedPackages + .put(b, + new TreeSet( + exportedPackageComparator)); + Set impPackages = (Set) importedPackages + .get(b); + impPackages.add(pkg); + } + } + } + } + + TreeParent mPackageNode = new TreeParent("Multiple Packages"); + // TreeParent aPackageNode = new TreeParent("All Packages"); + for (String packageName : packages.keySet()) { + Set pkgs = packages.get(packageName); + if (pkgs.size() > 1) { + MultiplePackagesNode mpn = new MultiplePackagesNode( + packageName, pkgs); + mPackageNode.addChild(mpn); + // aPackageNode.addChild(mpn); + } else { + // aPackageNode.addChild(new ExportedPackageNode(pkgs + // .iterator().next())); + } + } + + return new Object[] { bundlesNode, mPackageNode };// , + // aPackageNode + // }; + } else if (parentElement instanceof TreeParent) { + return ((TreeParent) parentElement).getChildren(); + } else { + return null; + } + } + + public Object getParent(Object element) { + // TODO Auto-generated method stub + return null; + } + + public boolean hasChildren(Object element) { + if (element instanceof TreeParent) { + return ((TreeParent) element).hasChildren(); + } + return false; + } + + public void dispose() { + // TODO Auto-generated method stub + + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + // TODO Auto-generated method stub + + } + + } + + protected Map dependencySpace(Bundle bundle, + Map> importedPackages, + Map> traces) { + log.debug("Dependency space for " + bundle.getSymbolicName()); + Map space = new TreeMap(); + fillDependencySpace(space, bundle, importedPackages, + bundle.getSymbolicName(), traces); + return space; + } + + /** Recursive */ + protected void fillDependencySpace(Map space, + Bundle bundle, Map> importedPackages, + String currTrace, Map> traces) { + if (importedPackages.containsKey(bundle)) { + Set imports = importedPackages.get(bundle); + // log.debug("## Fill dependency space for " + bundle + " : "); + for (ExportedPackage pkg : imports) { + if (!traces.containsKey(pkg.getName())) + traces.put(pkg.getName(), new TreeSet()); + traces.get(pkg.getName()).add(currTrace); + if (!space.containsKey(pkg.getName())) { + space.put(pkg.getName(), pkg); + Bundle exportingBundle = pkg.getExportingBundle(); + // if (bundle.getBundleId() != + // exportingBundle.getBundleId()) + fillDependencySpace(space, exportingBundle, + importedPackages, currTrace + " > " + + exportingBundle.getSymbolicName(), traces); + } + } + } + } + + private class ModulesLabelProvider extends LabelProvider implements + ITableLabelProvider { + + public Image getColumnImage(Object element, int columnIndex) { + // TODO Auto-generated method stub + return null; + } + + public String getColumnText(Object element, int columnIndex) { + return getText(element); + } + + } + + class BundleNode extends TreeParent { + private final Bundle bundle; + + public BundleNode(Bundle bundle) { + super(bundle.getSymbolicName()); + this.bundle = bundle; + + // Registered services + ServiceReference[] registeredServices = bundle + .getRegisteredServices(); + if (registeredServices != null) { + TreeParent registeredServicesNode = new TreeParent( + "Registered Services"); + addChild(registeredServicesNode); + for (ServiceReference sr : registeredServices) { + if (sr != null) + registeredServicesNode + .addChild(new ServiceReferenceNode(sr)); + } + } + + // Used services + ServiceReference[] usedServices = bundle.getRegisteredServices(); + if (usedServices != null) { + TreeParent usedServicesNode = new TreeParent("Used Services"); + addChild(usedServicesNode); + for (ServiceReference sr : usedServices) { + if (sr != null) + usedServicesNode.addChild(new ServiceReferenceNode(sr)); + } + } + } + + public Bundle getBundle() { + return bundle; + } + + } + + class ServiceReferenceNode extends TreeParent { + private final ServiceReference serviceReference; + + public ServiceReferenceNode(ServiceReference serviceReference) { + super(serviceReference.toString()); + this.serviceReference = serviceReference; + + Bundle[] usedBundles = serviceReference.getUsingBundles(); + if (usedBundles != null) { + TreeParent usingBundles = new TreeParent("Using Bundles"); + addChild(usingBundles); + for (Bundle b : usedBundles) { + if (b != null) + usingBundles.addChild(new TreeParent(b + .getSymbolicName())); + } + } + + TreeParent properties = new TreeParent("Properties"); + addChild(properties); + for (String key : serviceReference.getPropertyKeys()) { + properties.addChild(new TreeParent(key + "=" + + serviceReference.getProperty(key))); + } + + } + + public ServiceReference getServiceReference() { + return serviceReference; + } + + } + + class MultiplePackagesNode extends TreeParent { + private String packageName; + private Set exportedPackages; + + public MultiplePackagesNode(String packageName, + Set exportedPackages) { + super(packageName); + this.packageName = packageName; + this.exportedPackages = exportedPackages; + for (ExportedPackage pkg : exportedPackages) { + addChild(new ExportedPackageNode(pkg)); + } + } + + } + + class ConflictingPackageNode extends TreeParent { + private ExportedPackage exportedPackage; + + public ConflictingPackageNode(ExportedPackage exportedPackage) { + super(exportedPackage.getName() + " - " + + exportedPackage.getVersion() + " (" + + exportedPackage.getExportingBundle() + ")"); + this.exportedPackage = exportedPackage; + + TreeParent bundlesNode = new TreeParent("Dependent Bundles"); + this.addChild(bundlesNode); + Map bundles = new TreeMap(); + for (Bundle b : exportedPackage.getImportingBundles()) { + bundles.put(b.getSymbolicName(), b); + } + for (String key : bundles.keySet()) { + addDependentBundles(bundlesNode, bundles.get(key)); + } + } + } + + protected void addDependentBundles(TreeParent parent, Bundle bundle) { + TreeParent bundleNode = new TreeParent(bundle.toString()); + parent.addChild(bundleNode); + Map bundles = new TreeMap(); + ExportedPackage[] pkgs = packageAdmin.getExportedPackages(bundle); + if (pkgs != null) + for (ExportedPackage pkg : pkgs) { + for (Bundle b : pkg.getImportingBundles()) { + if (!bundles.containsKey(b.getSymbolicName()) + && b.getBundleId() != bundle.getBundleId()) { + bundles.put(b.getSymbolicName(), b); + } + } + } + + for (String key : bundles.keySet()) { + addDependentBundles(bundleNode, bundles.get(key)); + } + } + + class ExportedPackageNode extends TreeParent { + private ExportedPackage exportedPackage; + + public ExportedPackageNode(ExportedPackage exportedPackage) { + super(exportedPackage.getName() + " - " + + exportedPackage.getVersion() + " (" + + exportedPackage.getExportingBundle() + ")"); + this.exportedPackage = exportedPackage; + for (Bundle bundle : exportedPackage.getImportingBundles()) { + addChild(new BundleNode(bundle)); + } + } + } +} diff --git a/org.argeo.security.equinox/.classpath b/org.argeo.security.equinox/.classpath index 848725036..d2953a684 100644 --- a/org.argeo.security.equinox/.classpath +++ b/org.argeo.security.equinox/.classpath @@ -1,7 +1,9 @@ - - - - + + + + diff --git a/org.argeo.security.equinox/.settings/org.eclipse.pde.core.prefs b/org.argeo.security.equinox/.settings/org.eclipse.pde.core.prefs deleted file mode 100644 index 87ab38102..000000000 --- a/org.argeo.security.equinox/.settings/org.eclipse.pde.core.prefs +++ /dev/null @@ -1,4 +0,0 @@ -#Sun Jan 16 11:19:07 CET 2011 -eclipse.preferences.version=1 -pluginProject.extensions=false -resolve.requirebundle=false diff --git a/org.argeo.security.equinox/build.properties b/org.argeo.security.equinox/build.properties index 3e2615fae..ae2abc5ff 100644 --- a/org.argeo.security.equinox/build.properties +++ b/org.argeo.security.equinox/build.properties @@ -1,4 +1 @@ -bin.includes = META-INF/,\ - plugin.xml -source.. = src/main/java/ -output.. = target/classes/ +source.. = src/ \ No newline at end of file diff --git a/org.argeo.security.equinox/src/main/java/org/argeo/security/equinox/OsSpringLoginModule.java b/org.argeo.security.equinox/src/main/java/org/argeo/security/equinox/OsSpringLoginModule.java deleted file mode 100644 index 1a7ebb4d7..000000000 --- a/org.argeo.security.equinox/src/main/java/org/argeo/security/equinox/OsSpringLoginModule.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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.security.equinox; - -import java.util.Map; - -import javax.security.auth.Subject; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.login.LoginException; - -import org.argeo.security.OsAuthenticationToken; -import org.springframework.security.Authentication; -import org.springframework.security.AuthenticationManager; -import org.springframework.security.context.SecurityContextHolder; -import org.springframework.security.providers.jaas.SecurityContextLoginModule; - -/** Login module which caches one subject per thread. */ -public class OsSpringLoginModule extends SecurityContextLoginModule { - // private final static Log log = - // LogFactory.getLog(OsSpringLoginModule.class); - - private AuthenticationManager authenticationManager; - - private Subject subject; - - public OsSpringLoginModule() { - - } - - @SuppressWarnings("rawtypes") - public void initialize(Subject subject, CallbackHandler callbackHandler, - Map sharedState, Map options) { - super.initialize(subject, callbackHandler, sharedState, options); - this.subject = subject; - } - - public boolean login() throws LoginException { - // thread already logged in - if (SecurityContextHolder.getContext().getAuthentication() != null) - return super.login(); - - OsAuthenticationToken oat = new OsAuthenticationToken(); - Authentication authentication = authenticationManager.authenticate(oat); - registerAuthentication(authentication); - return super.login(); - } - - @Override - public boolean logout() throws LoginException { - subject.getPrincipals().clear(); - return super.logout(); - } - - /** - * Register an {@link Authentication} in the security context. - * - * @param authentication - * has to implement {@link Authentication}. - */ - protected void registerAuthentication(Object authentication) { - SecurityContextHolder.getContext().setAuthentication( - (Authentication) authentication); - } - - public void setAuthenticationManager( - AuthenticationManager authenticationManager) { - this.authenticationManager = authenticationManager; - } -} diff --git a/org.argeo.security.equinox/src/main/java/org/argeo/security/equinox/SpringLoginModule.java b/org.argeo.security.equinox/src/main/java/org/argeo/security/equinox/SpringLoginModule.java deleted file mode 100644 index 6fd179ead..000000000 --- a/org.argeo.security.equinox/src/main/java/org/argeo/security/equinox/SpringLoginModule.java +++ /dev/null @@ -1,243 +0,0 @@ -/* - * 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.security.equinox; - -import java.util.Locale; -import java.util.Map; -import java.util.UUID; - -import javax.security.auth.Subject; -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.NameCallback; -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.login.LoginException; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.security.NodeAuthenticationToken; -import org.argeo.util.LocaleCallback; -import org.argeo.util.LocaleUtils; -import org.springframework.security.Authentication; -import org.springframework.security.AuthenticationManager; -import org.springframework.security.BadCredentialsException; -import org.springframework.security.GrantedAuthority; -import org.springframework.security.GrantedAuthorityImpl; -import org.springframework.security.context.SecurityContextHolder; -import org.springframework.security.providers.anonymous.AnonymousAuthenticationToken; -import org.springframework.security.providers.jaas.SecurityContextLoginModule; - -/** Login module which caches one subject per thread. */ -public class SpringLoginModule extends SecurityContextLoginModule { - final static String NODE_REPO_URI = "argeo.node.repo.uri"; - - private final static Log log = LogFactory.getLog(SpringLoginModule.class); - - private AuthenticationManager authenticationManager; - - private CallbackHandler callbackHandler; - - private Subject subject; - - private Long waitBetweenFailedLoginAttempts = 5 * 1000l; - - private Boolean remote = false; - private Boolean anonymous = false; - /** Comma separated list of locales */ - private String availableLocales = ""; - - private String key = null; - private String anonymousRole = "ROLE_ANONYMOUS"; - - public SpringLoginModule() { - - } - - @SuppressWarnings("rawtypes") - public void initialize(Subject subject, CallbackHandler callbackHandler, - Map sharedState, Map options) { - super.initialize(subject, callbackHandler, sharedState, options); - this.callbackHandler = callbackHandler; - this.subject = subject; - } - - public boolean login() throws LoginException { - try { - // thread already logged in - if (SecurityContextHolder.getContext().getAuthentication() != null) - return super.login(); - - if (remote && anonymous) - throw new LoginException( - "Cannot have a Spring login module which is remote and anonymous"); - - // reset all principals and credentials - if (log.isTraceEnabled()) - log.trace("Resetting all principals and credentials of " - + subject); - if (subject.getPrincipals() != null) - subject.getPrincipals().clear(); - if (subject.getPrivateCredentials() != null) - subject.getPrivateCredentials().clear(); - if (subject.getPublicCredentials() != null) - subject.getPublicCredentials().clear(); - - Locale selectedLocale = null; - // deals first with public access since it's simple - if (anonymous) { - // multi locale - if (callbackHandler != null && availableLocales != null - && !availableLocales.trim().equals("")) { - LocaleCallback localeCallback = new LocaleCallback( - availableLocales); - callbackHandler.handle(new Callback[] { localeCallback }); - selectedLocale = localeCallback.getSelectedLocale(); - } - - // TODO integrate with JCR? - Object principal = UUID.randomUUID().toString(); - GrantedAuthority[] authorities = { new GrantedAuthorityImpl( - anonymousRole) }; - AnonymousAuthenticationToken anonymousToken = new AnonymousAuthenticationToken( - key, principal, authorities); - Authentication auth = authenticationManager - .authenticate(anonymousToken); - registerAuthentication(auth); - } else { - if (callbackHandler == null) - throw new LoginException("No call back handler available"); - - // ask for username and password - NameCallback nameCallback = new NameCallback("User"); - PasswordCallback passwordCallback = new PasswordCallback( - "Password", false); - final String defaultNodeUrl = System - .getProperty(NODE_REPO_URI, - "http://localhost:7070/org.argeo.jcr.webapp/remoting/node"); - NameCallback urlCallback = new NameCallback("Site URL", - defaultNodeUrl); - LocaleCallback localeCallback = new LocaleCallback( - availableLocales); - - // handle callbacks - if (remote) - callbackHandler.handle(new Callback[] { nameCallback, - passwordCallback, urlCallback, localeCallback }); - else - callbackHandler.handle(new Callback[] { nameCallback, - passwordCallback, localeCallback }); - - selectedLocale = localeCallback.getSelectedLocale(); - - // create credentials - String username = nameCallback.getName(); - if (username == null || username.trim().equals("")) - return false; - - String password = ""; - if (passwordCallback.getPassword() != null) - password = String.valueOf(passwordCallback.getPassword()); - - NodeAuthenticationToken credentials; - if (remote) { - String url = urlCallback.getName(); - credentials = new NodeAuthenticationToken(username, - password, url); - } else { - credentials = new NodeAuthenticationToken(username, - password); - } - - Authentication authentication; - try { - authentication = authenticationManager - .authenticate(credentials); - } catch (BadCredentialsException e) { - // wait between failed login attempts - Thread.sleep(waitBetweenFailedLoginAttempts); - throw e; - } - registerAuthentication(authentication); - } - - if (selectedLocale != null) - LocaleUtils.threadLocale.set(selectedLocale); - - return super.login(); - } catch (LoginException e) { - throw e; - } catch (ThreadDeath e) { - LoginException le = new LoginException( - "Spring Security login thread died"); - le.initCause(e); - throw le; - } catch (Exception e) { - LoginException le = new LoginException( - "Spring Security login failed"); - le.initCause(e); - throw le; - } - } - - @Override - public boolean logout() throws LoginException { - subject.getPrincipals().clear(); - return super.logout(); - } - - /** - * Register an {@link Authentication} in the security context. - * - * @param authentication - * has to implement {@link Authentication}. - */ - protected void registerAuthentication(Object authentication) { - SecurityContextHolder.getContext().setAuthentication( - (Authentication) authentication); - } - - public void setAuthenticationManager( - AuthenticationManager authenticationManager) { - this.authenticationManager = authenticationManager; - } - - /** Authenticates on a remote node */ - public void setRemote(Boolean remote) { - this.remote = remote; - } - - /** - * Request anonymous authentication (incompatible with remote) - */ - public void setAnonymous(Boolean anonymous) { - this.anonymous = anonymous; - } - - /** Role identifying an anonymous user */ - public void setAnonymousRole(String anonymousRole) { - this.anonymousRole = anonymousRole; - } - - /** System key */ - public void setKey(String key) { - this.key = key; - } - - public void setAvailableLocales(String locales) { - this.availableLocales = locales; - } - -} diff --git a/org.argeo.security.equinox/src/org/argeo/security/equinox/OsSpringLoginModule.java b/org.argeo.security.equinox/src/org/argeo/security/equinox/OsSpringLoginModule.java new file mode 100644 index 000000000..1a7ebb4d7 --- /dev/null +++ b/org.argeo.security.equinox/src/org/argeo/security/equinox/OsSpringLoginModule.java @@ -0,0 +1,82 @@ +/* + * 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.security.equinox; + +import java.util.Map; + +import javax.security.auth.Subject; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.login.LoginException; + +import org.argeo.security.OsAuthenticationToken; +import org.springframework.security.Authentication; +import org.springframework.security.AuthenticationManager; +import org.springframework.security.context.SecurityContextHolder; +import org.springframework.security.providers.jaas.SecurityContextLoginModule; + +/** Login module which caches one subject per thread. */ +public class OsSpringLoginModule extends SecurityContextLoginModule { + // private final static Log log = + // LogFactory.getLog(OsSpringLoginModule.class); + + private AuthenticationManager authenticationManager; + + private Subject subject; + + public OsSpringLoginModule() { + + } + + @SuppressWarnings("rawtypes") + public void initialize(Subject subject, CallbackHandler callbackHandler, + Map sharedState, Map options) { + super.initialize(subject, callbackHandler, sharedState, options); + this.subject = subject; + } + + public boolean login() throws LoginException { + // thread already logged in + if (SecurityContextHolder.getContext().getAuthentication() != null) + return super.login(); + + OsAuthenticationToken oat = new OsAuthenticationToken(); + Authentication authentication = authenticationManager.authenticate(oat); + registerAuthentication(authentication); + return super.login(); + } + + @Override + public boolean logout() throws LoginException { + subject.getPrincipals().clear(); + return super.logout(); + } + + /** + * Register an {@link Authentication} in the security context. + * + * @param authentication + * has to implement {@link Authentication}. + */ + protected void registerAuthentication(Object authentication) { + SecurityContextHolder.getContext().setAuthentication( + (Authentication) authentication); + } + + public void setAuthenticationManager( + AuthenticationManager authenticationManager) { + this.authenticationManager = authenticationManager; + } +} diff --git a/org.argeo.security.equinox/src/org/argeo/security/equinox/SpringLoginModule.java b/org.argeo.security.equinox/src/org/argeo/security/equinox/SpringLoginModule.java new file mode 100644 index 000000000..6fd179ead --- /dev/null +++ b/org.argeo.security.equinox/src/org/argeo/security/equinox/SpringLoginModule.java @@ -0,0 +1,243 @@ +/* + * 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.security.equinox; + +import java.util.Locale; +import java.util.Map; +import java.util.UUID; + +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.login.LoginException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.security.NodeAuthenticationToken; +import org.argeo.util.LocaleCallback; +import org.argeo.util.LocaleUtils; +import org.springframework.security.Authentication; +import org.springframework.security.AuthenticationManager; +import org.springframework.security.BadCredentialsException; +import org.springframework.security.GrantedAuthority; +import org.springframework.security.GrantedAuthorityImpl; +import org.springframework.security.context.SecurityContextHolder; +import org.springframework.security.providers.anonymous.AnonymousAuthenticationToken; +import org.springframework.security.providers.jaas.SecurityContextLoginModule; + +/** Login module which caches one subject per thread. */ +public class SpringLoginModule extends SecurityContextLoginModule { + final static String NODE_REPO_URI = "argeo.node.repo.uri"; + + private final static Log log = LogFactory.getLog(SpringLoginModule.class); + + private AuthenticationManager authenticationManager; + + private CallbackHandler callbackHandler; + + private Subject subject; + + private Long waitBetweenFailedLoginAttempts = 5 * 1000l; + + private Boolean remote = false; + private Boolean anonymous = false; + /** Comma separated list of locales */ + private String availableLocales = ""; + + private String key = null; + private String anonymousRole = "ROLE_ANONYMOUS"; + + public SpringLoginModule() { + + } + + @SuppressWarnings("rawtypes") + public void initialize(Subject subject, CallbackHandler callbackHandler, + Map sharedState, Map options) { + super.initialize(subject, callbackHandler, sharedState, options); + this.callbackHandler = callbackHandler; + this.subject = subject; + } + + public boolean login() throws LoginException { + try { + // thread already logged in + if (SecurityContextHolder.getContext().getAuthentication() != null) + return super.login(); + + if (remote && anonymous) + throw new LoginException( + "Cannot have a Spring login module which is remote and anonymous"); + + // reset all principals and credentials + if (log.isTraceEnabled()) + log.trace("Resetting all principals and credentials of " + + subject); + if (subject.getPrincipals() != null) + subject.getPrincipals().clear(); + if (subject.getPrivateCredentials() != null) + subject.getPrivateCredentials().clear(); + if (subject.getPublicCredentials() != null) + subject.getPublicCredentials().clear(); + + Locale selectedLocale = null; + // deals first with public access since it's simple + if (anonymous) { + // multi locale + if (callbackHandler != null && availableLocales != null + && !availableLocales.trim().equals("")) { + LocaleCallback localeCallback = new LocaleCallback( + availableLocales); + callbackHandler.handle(new Callback[] { localeCallback }); + selectedLocale = localeCallback.getSelectedLocale(); + } + + // TODO integrate with JCR? + Object principal = UUID.randomUUID().toString(); + GrantedAuthority[] authorities = { new GrantedAuthorityImpl( + anonymousRole) }; + AnonymousAuthenticationToken anonymousToken = new AnonymousAuthenticationToken( + key, principal, authorities); + Authentication auth = authenticationManager + .authenticate(anonymousToken); + registerAuthentication(auth); + } else { + if (callbackHandler == null) + throw new LoginException("No call back handler available"); + + // ask for username and password + NameCallback nameCallback = new NameCallback("User"); + PasswordCallback passwordCallback = new PasswordCallback( + "Password", false); + final String defaultNodeUrl = System + .getProperty(NODE_REPO_URI, + "http://localhost:7070/org.argeo.jcr.webapp/remoting/node"); + NameCallback urlCallback = new NameCallback("Site URL", + defaultNodeUrl); + LocaleCallback localeCallback = new LocaleCallback( + availableLocales); + + // handle callbacks + if (remote) + callbackHandler.handle(new Callback[] { nameCallback, + passwordCallback, urlCallback, localeCallback }); + else + callbackHandler.handle(new Callback[] { nameCallback, + passwordCallback, localeCallback }); + + selectedLocale = localeCallback.getSelectedLocale(); + + // create credentials + String username = nameCallback.getName(); + if (username == null || username.trim().equals("")) + return false; + + String password = ""; + if (passwordCallback.getPassword() != null) + password = String.valueOf(passwordCallback.getPassword()); + + NodeAuthenticationToken credentials; + if (remote) { + String url = urlCallback.getName(); + credentials = new NodeAuthenticationToken(username, + password, url); + } else { + credentials = new NodeAuthenticationToken(username, + password); + } + + Authentication authentication; + try { + authentication = authenticationManager + .authenticate(credentials); + } catch (BadCredentialsException e) { + // wait between failed login attempts + Thread.sleep(waitBetweenFailedLoginAttempts); + throw e; + } + registerAuthentication(authentication); + } + + if (selectedLocale != null) + LocaleUtils.threadLocale.set(selectedLocale); + + return super.login(); + } catch (LoginException e) { + throw e; + } catch (ThreadDeath e) { + LoginException le = new LoginException( + "Spring Security login thread died"); + le.initCause(e); + throw le; + } catch (Exception e) { + LoginException le = new LoginException( + "Spring Security login failed"); + le.initCause(e); + throw le; + } + } + + @Override + public boolean logout() throws LoginException { + subject.getPrincipals().clear(); + return super.logout(); + } + + /** + * Register an {@link Authentication} in the security context. + * + * @param authentication + * has to implement {@link Authentication}. + */ + protected void registerAuthentication(Object authentication) { + SecurityContextHolder.getContext().setAuthentication( + (Authentication) authentication); + } + + public void setAuthenticationManager( + AuthenticationManager authenticationManager) { + this.authenticationManager = authenticationManager; + } + + /** Authenticates on a remote node */ + public void setRemote(Boolean remote) { + this.remote = remote; + } + + /** + * Request anonymous authentication (incompatible with remote) + */ + public void setAnonymous(Boolean anonymous) { + this.anonymous = anonymous; + } + + /** Role identifying an anonymous user */ + public void setAnonymousRole(String anonymousRole) { + this.anonymousRole = anonymousRole; + } + + /** System key */ + public void setKey(String key) { + this.key = key; + } + + public void setAvailableLocales(String locales) { + this.availableLocales = locales; + } + +} diff --git a/org.argeo.security.ui.admin/.classpath b/org.argeo.security.ui.admin/.classpath index 848725036..d2953a684 100644 --- a/org.argeo.security.ui.admin/.classpath +++ b/org.argeo.security.ui.admin/.classpath @@ -1,7 +1,9 @@ - - - - + + + + diff --git a/org.argeo.security.ui.admin/build.properties b/org.argeo.security.ui.admin/build.properties index c41623e1f..30f715358 100644 --- a/org.argeo.security.ui.admin/build.properties +++ b/org.argeo.security.ui.admin/build.properties @@ -1,5 +1 @@ -bin.includes = plugin.xml,\ - META-INF/,\ - security-admin.properties -source.. = src/main/java/ -output.. = target/classes/ +source.. = src/ diff --git a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/SecurityAdminImages.java b/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/SecurityAdminImages.java deleted file mode 100644 index f7ffa9c8d..000000000 --- a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/SecurityAdminImages.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Argeo Connect - Data management and communications - * Copyright (C) 2012 Argeo GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - * - * Additional permission under GNU GPL version 3 section 7 - * - * If you modify this Program, or any covered work, by linking or combining it - * with software covered by the terms of the Eclipse Public License, the - * licensors of this Program grant you additional permission to convey the - * resulting work. Corresponding Source for a non-source form of such a - * combination shall include the source code for the parts of such software - * which are used as well as that of the covered work. - */ -package org.argeo.security.ui.admin; - -/** Shared icons that must be declared programmatically . */ -public class SecurityAdminImages { - @SuppressWarnings("unused") - private final static String PREFIX = "icons/"; -} diff --git a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/SecurityAdminPerspective.java b/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/SecurityAdminPerspective.java deleted file mode 100644 index c743f56bd..000000000 --- a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/SecurityAdminPerspective.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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.security.ui.admin; - -import org.argeo.security.ui.admin.views.RolesView; -import org.argeo.security.ui.admin.views.UsersView; -import org.eclipse.ui.IFolderLayout; -import org.eclipse.ui.IPageLayout; -import org.eclipse.ui.IPerspectiveFactory; - -public class SecurityAdminPerspective implements IPerspectiveFactory { - public void createInitialLayout(IPageLayout layout) { - String editorArea = layout.getEditorArea(); - layout.setEditorAreaVisible(true); - layout.setFixed(false); - - IFolderLayout left = layout.createFolder("left", IPageLayout.LEFT, - 0.65f, editorArea); - left.addView(UsersView.ID); - left.addView(RolesView.ID); - } - -} diff --git a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/SecurityAdminPlugin.java b/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/SecurityAdminPlugin.java deleted file mode 100644 index 06e9bd5b9..000000000 --- a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/SecurityAdminPlugin.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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.security.ui.admin; - -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.ui.plugin.AbstractUIPlugin; -import org.osgi.framework.BundleContext; - -public class SecurityAdminPlugin extends AbstractUIPlugin { - public static final String PLUGIN_ID = "org.argeo.security.ui.admin"; //$NON-NLS-1$ - private static SecurityAdminPlugin plugin; - - public SecurityAdminPlugin() { - } - - public void start(BundleContext context) throws Exception { - super.start(context); - plugin = this; - } - - public void stop(BundleContext context) throws Exception { - plugin = null; - super.stop(context); - } - - public static SecurityAdminPlugin getDefault() { - return plugin; - } - - public static ImageDescriptor getImageDescriptor(String path) { - return imageDescriptorFromPlugin(PLUGIN_ID, path); - } - -} diff --git a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/UserTableComposite.java b/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/UserTableComposite.java deleted file mode 100644 index 720faded4..000000000 --- a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/UserTableComposite.java +++ /dev/null @@ -1,367 +0,0 @@ -package org.argeo.security.ui.admin; - -import java.util.ArrayList; -import java.util.List; - -import javax.jcr.Node; -import javax.jcr.NodeIterator; -import javax.jcr.Property; -import javax.jcr.PropertyType; -import javax.jcr.RepositoryException; -import javax.jcr.Session; -import javax.jcr.query.QueryManager; -import javax.jcr.query.QueryResult; -import javax.jcr.query.qom.Constraint; -import javax.jcr.query.qom.Ordering; -import javax.jcr.query.qom.QueryObjectModel; -import javax.jcr.query.qom.QueryObjectModelFactory; -import javax.jcr.query.qom.Selector; -import javax.jcr.query.qom.StaticOperand; - -import org.argeo.ArgeoException; -import org.argeo.eclipse.ui.EclipseUiUtils; -import org.argeo.eclipse.ui.jcr.JcrUiUtils; -import org.argeo.eclipse.ui.jcr.lists.ColumnDefinition; -import org.argeo.eclipse.ui.jcr.lists.NodeViewerComparator; -import org.argeo.eclipse.ui.jcr.lists.SimpleJcrNodeLabelProvider; -import org.argeo.eclipse.ui.specific.EclipseUiSpecificUtils; -import org.argeo.eclipse.ui.utils.ViewerUtils; -import org.argeo.jcr.ArgeoNames; -import org.argeo.jcr.ArgeoTypes; -import org.argeo.jcr.JcrUtils; -import org.eclipse.jface.viewers.CheckboxTableViewer; -import org.eclipse.jface.viewers.ColumnLabelProvider; -import org.eclipse.jface.viewers.IStructuredContentProvider; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.jface.viewers.TableViewerColumn; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Font; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.Text; - -public class UserTableComposite extends Composite implements ArgeoNames { - // private final static Log log = - // LogFactory.getLog(UserTableComposite.class); - - private static final long serialVersionUID = -7385959046279360420L; - - private TableViewer usersViewer; - private Text filterTxt; - private final static String FILTER_HELP_MSG = "Type filter criterion " - + "separated by a space"; - private Session session; - - private Font italic; - private Font bold; - - private boolean hasFilter; - private boolean hasSelectionColumn; - - // private List selectedItems = new ArrayList(); - - /** - * Overwrite to display other columns - */ - public List getColumnsDef() { - List columnDefs = new ArrayList(); - - // User ID - columnDefs.add(new ColumnDefinition(null, ARGEO_USER_ID, - PropertyType.STRING, "User ID", 100)); - // Displayed name - columnDefs.add(new ColumnDefinition(null, Property.JCR_TITLE, - PropertyType.STRING, "Name", 150)); - - // E-mail - columnDefs.add(new ColumnDefinition(null, ARGEO_PRIMARY_EMAIL, - PropertyType.STRING, "E-mail", 150)); - - // Description - columnDefs.add(new ColumnDefinition(null, Property.JCR_DESCRIPTION, - PropertyType.STRING, "Description", 200)); - - return columnDefs; - } - - public UserTableComposite(Composite parent, int style, Session session) { - super(parent, style); - this.session = session; - } - - /** - * - * @param addFilter - * choose to add a field to filter results or not - * @param addSelection - * choose to add a column to select some of the displayed results - * or not - */ - public void populate(boolean addFilter, boolean addSelection) { - // initialization - Composite parent = this; - italic = EclipseUiUtils.getItalicFont(parent); - bold = EclipseUiUtils.getBoldFont(parent); - hasFilter = addFilter; - hasSelectionColumn = addSelection; - - // Main Layout - this.setLayout(new GridLayout(1, false)); - if (hasFilter) - createFilterPart(parent); - usersViewer = createTableViewer(parent); - EclipseUiSpecificUtils.enableToolTipSupport(usersViewer); - usersViewer.setContentProvider(new UsersContentProvider()); - refreshFilteredList(); - } - - public List getSelectedUsers() { - if (hasSelectionColumn) { - Object[] elements = ((CheckboxTableViewer) usersViewer) - .getCheckedElements(); - - List result = new ArrayList(); - for (Object obj : elements) { - result.add((Node) obj); - } - return result; - } else - throw new ArgeoException("Unvalid request: no selection column " - + "has been created for the current table"); - } - - /** Returns the User table viewer, typically to add doubleclick listener */ - public TableViewer getTableViewer() { - return usersViewer; - } - - /** Returns filter String or null*/ - protected String getFilterString() { - return hasFilter ? filterTxt.getText() : null; - } - - - - private TableViewer createTableViewer(final Composite parent) { - int style = SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL; - if (hasSelectionColumn) - style = style | SWT.CHECK; - - Table table = new Table(parent, style); - table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - - TableViewer viewer; - if (hasSelectionColumn) - viewer = new CheckboxTableViewer(table); - else - viewer = new TableViewer(table); - table.setLinesVisible(true); - table.setHeaderVisible(true); - - // pass a mapping between col index and property name to the comparator. - // List propertiesList = new ArrayList(); - - TableViewerColumn column; - int offset = 0; - if (hasSelectionColumn) { - offset = 1; - column = ViewerUtils.createTableViewerColumn(viewer, "", SWT.NONE, - 25); - column.setLabelProvider(new ColumnLabelProvider() { - private static final long serialVersionUID = 1L; - - @Override - public String getText(Object element) { - return null; - } - }); - SelectionAdapter selectionAdapter = new SelectionAdapter() { - private static final long serialVersionUID = 1L; - - boolean allSelected = false; - - @Override - public void widgetSelected(SelectionEvent e) { - allSelected = !allSelected; - ((CheckboxTableViewer) usersViewer) - .setAllChecked(allSelected); - } - }; - column.getColumn().addSelectionListener(selectionAdapter); - } - - // Create other columns - List colDefs = getColumnsDef(); - - NodeViewerComparator comparator = new NodeViewerComparator(); - int i = offset; - for (ColumnDefinition colDef : colDefs) { - column = ViewerUtils.createTableViewerColumn(viewer, - colDef.getHeaderLabel(), SWT.NONE, colDef.getColumnSize()); - column.setLabelProvider(new CLProvider(colDef.getPropertyName())); - column.getColumn().addSelectionListener( - JcrUiUtils.getNodeSelectionAdapter(i, - colDef.getPropertyType(), colDef.getPropertyName(), - comparator, viewer)); - i++; - } - - // IMPORTANT: initialize comparator before setting it - ColumnDefinition firstCol = colDefs.get(0); - comparator.setColumn(firstCol.getPropertyType(), - firstCol.getPropertyName()); - viewer.setComparator(comparator); - - return viewer; - } - - private class CLProvider extends SimpleJcrNodeLabelProvider { - - private static final long serialVersionUID = 1L; - - public CLProvider(String propertyName) { - super(propertyName); - } - - public String getToolTipText(Object element) { - return getText(element); - } - - @Override - public Font getFont(Object elem) { - // self - String username = getProperty(elem, ARGEO_USER_ID); - if (username.equals(session.getUserID())) - return bold; - - // disabled - try { - Node userProfile = (Node) elem; - // Node userProfile = userHome.getNode(ARGEO_PROFILE); - if (!userProfile.getProperty(ARGEO_ENABLED).getBoolean()) - return italic; - else - return null; - } catch (RepositoryException e) { - throw new ArgeoException("Cannot get font for " + username, e); - } - } - } - - @Override - public boolean setFocus() { - usersViewer.getTable().setFocus(); - return true; - } - - @Override - public void dispose() { - super.dispose(); - } - - public void refresh() { - refreshFilteredList(); - } - - private String getProperty(Object element, String name) { - try { - Node userProfile = (Node) element; - return userProfile.hasProperty(name) ? userProfile - .getProperty(name).getString() : ""; - } catch (RepositoryException e) { - throw new ArgeoException("Cannot get property " + name, e); - } - } - - private class UsersContentProvider implements IStructuredContentProvider { - private static final long serialVersionUID = 1L; - - public Object[] getElements(Object inputElement) { - return (Object[]) inputElement; - } - - public void dispose() { - } - - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - } - } - - /* MANAGE FILTER */ - private void createFilterPart(Composite parent) { - // Text Area for the filter - filterTxt = new Text(parent, SWT.BORDER | SWT.SEARCH | SWT.ICON_SEARCH - | SWT.ICON_CANCEL); - filterTxt.setMessage(FILTER_HELP_MSG); - filterTxt.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL - | GridData.HORIZONTAL_ALIGN_FILL)); - filterTxt.addModifyListener(new ModifyListener() { - private static final long serialVersionUID = 1L; - - public void modifyText(ModifyEvent event) { - refreshFilteredList(); - } - }); - } - - /** - * Refresh the user list: caller might overwrite in order to display a - * subset of all users, typically to remove current user from the list - */ - protected void refreshFilteredList() { - List nodes; - try { - nodes = JcrUtils.nodeIteratorToList(listFilteredElements(session, - hasFilter ? filterTxt.getText() : null)); - usersViewer.setInput(nodes.toArray()); - } catch (RepositoryException e) { - throw new ArgeoException("Unable to list users", e); - } - } - - /** - * Build repository request : caller might overwrite in order to display a - * subset of all users - */ - protected NodeIterator listFilteredElements(Session session, String filter) - throws RepositoryException { - QueryManager queryManager = session.getWorkspace().getQueryManager(); - QueryObjectModelFactory factory = queryManager.getQOMFactory(); - - Selector source = factory.selector(ArgeoTypes.ARGEO_USER_PROFILE, - ArgeoTypes.ARGEO_USER_PROFILE); - - // Dynamically build constraint depending on the filter String - Constraint defaultC = null; - if (filter != null && !"".equals(filter.trim())) { - String[] strs = filter.trim().split(" "); - for (String token : strs) { - StaticOperand so = factory.literal(session.getValueFactory() - .createValue("*" + token + "*")); - Constraint currC = factory.fullTextSearch( - source.getSelectorName(), null, so); - if (defaultC == null) - defaultC = currC; - else - defaultC = factory.and(defaultC, currC); - } - } - - Ordering order = factory.ascending(factory.propertyValue( - source.getSelectorName(), ARGEO_USER_ID)); - Ordering[] orderings = { order }; - - QueryObjectModel query = factory.createQuery(source, defaultC, - orderings, null); - - QueryResult result = query.execute(); - return result.getNodes(); - } -} \ No newline at end of file diff --git a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/AddRole.java b/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/AddRole.java deleted file mode 100644 index a1008f699..000000000 --- a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/AddRole.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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.security.ui.admin.commands; - -import org.argeo.ArgeoException; -import org.argeo.security.UserAdminService; -import org.argeo.security.ui.admin.editors.ArgeoUserEditor; -import org.argeo.security.ui.admin.views.RolesView; -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import org.eclipse.ui.IEditorReference; -import org.eclipse.ui.IWorkbenchPage; -import org.eclipse.ui.handlers.HandlerUtil; - -/** Add a new role. */ -public class AddRole extends AbstractHandler { - public final static String COMMAND_ID = "org.argeo.security.ui.admin.addRole"; - private UserAdminService userAdminService; - private String rolePrefix = "ROLE_"; - - public Object execute(ExecutionEvent event) throws ExecutionException { - RolesView rolesView = (RolesView) HandlerUtil - .getActiveWorkbenchWindow(event).getActivePage() - .findView(RolesView.ID); - String role = rolesView.getNewRole(); - if (role.trim().equals("")) - return null; - if (role.equals(rolesView.getAddNewRoleText())) - return null; - role = role.trim().toUpperCase(); - if (!role.startsWith(rolePrefix)) - role = rolePrefix + role; - if (userAdminService.listEditableRoles().contains(role)) - throw new ArgeoException("Role " + role + " already exists"); - userAdminService.newRole(role); - rolesView.refresh(); - - // refresh editors - IEditorReference[] refs = HandlerUtil.getActiveWorkbenchWindow(event) - .getActivePage() - .findEditors(null, ArgeoUserEditor.ID, IWorkbenchPage.MATCH_ID); - for (IEditorReference ref : refs) { - ArgeoUserEditor userEditor = (ArgeoUserEditor) ref.getEditor(false); - if (userEditor != null) { - userEditor.refresh(); - } - } - return null; - } - - public void setUserAdminService(UserAdminService userAdminService) { - this.userAdminService = userAdminService; - } - -} diff --git a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/DeleteRole.java b/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/DeleteRole.java deleted file mode 100644 index 6cba11eb9..000000000 --- a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/DeleteRole.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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.security.ui.admin.commands; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import org.argeo.security.UserAdminService; -import org.argeo.security.ui.admin.views.RolesView; -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.ui.handlers.HandlerUtil; - -/** Deletes the selected roles */ -public class DeleteRole extends AbstractHandler { - private UserAdminService userAdminService; - - @SuppressWarnings("unchecked") - public Object execute(ExecutionEvent event) throws ExecutionException { - ISelection selection = HandlerUtil.getCurrentSelection(event); - if (selection.isEmpty()) - return null; - - List toDelete = new ArrayList(); - Iterator it = ((IStructuredSelection) selection).iterator(); - while (it.hasNext()) { - toDelete.add(it.next()); - } - - if (!MessageDialog - .openQuestion( - HandlerUtil.getActiveShell(event), - "Delete Role", - "Are you sure that you want to delete " - + toDelete - + "?\n" - + "This may lead to inconsistencies in the application.")) - return null; - - for (String role : toDelete) { - userAdminService.deleteRole(role); - } - - RolesView view = (RolesView) HandlerUtil - .getActiveWorkbenchWindow(event).getActivePage() - .findView(RolesView.ID); - view.refresh(); - return null; - } - - public void setUserAdminService(UserAdminService userAdminService) { - this.userAdminService = userAdminService; - } -} \ No newline at end of file diff --git a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/DeleteUser.java b/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/DeleteUser.java deleted file mode 100644 index ccf360fd0..000000000 --- a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/DeleteUser.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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.security.ui.admin.commands; - -import java.util.Iterator; -import java.util.Map; -import java.util.TreeMap; - -import javax.jcr.Node; -import javax.jcr.RepositoryException; -import javax.jcr.Session; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.ArgeoException; -import org.argeo.jcr.ArgeoNames; -import org.argeo.jcr.JcrUtils; -import org.argeo.security.UserAdminService; -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.ui.handlers.HandlerUtil; - -/** Deletes the selected user nodes */ -public class DeleteUser extends AbstractHandler { - private final static Log log = LogFactory.getLog(DeleteUser.class); - - private UserAdminService userAdminService; - - @SuppressWarnings("unchecked") - public Object execute(ExecutionEvent event) throws ExecutionException { - ISelection selection = HandlerUtil.getCurrentSelection(event); - if (selection.isEmpty()) - return null; - - Map toDelete = new TreeMap(); - Iterator it = ((IStructuredSelection) selection).iterator(); - nodes: while (it.hasNext()) { - Node profileNode = it.next(); - try { - String userName = profileNode.getProperty( - ArgeoNames.ARGEO_USER_ID).getString(); - if (userName.equals(profileNode.getSession().getUserID())) { - log.warn("Cannot delete its own user: " + userName); - continue nodes; - } - toDelete.put(userName, profileNode); - } catch (RepositoryException e) { - log.warn("Cannot interpred user " + profileNode); - } - } - - if (!MessageDialog - .openQuestion( - HandlerUtil.getActiveShell(event), - "Delete User", - "Are you sure that you want to delete users " - + toDelete.keySet() - + "?\n" - + "This may lead to inconsistencies in the application.")) - return null; - - for (String username : toDelete.keySet()) { - Session session = null; - try { - Node profileNode = toDelete.get(username); - userAdminService.deleteUser(username); - profileNode.getParent().remove(); - session = profileNode.getSession(); - session.save(); - } catch (RepositoryException e) { - JcrUtils.discardQuietly(session); - throw new ArgeoException("Cannot list users", e); - } - } - - userAdminService.synchronize(); - // UsersView view = (UsersView) HandlerUtil - // .getActiveWorkbenchWindow(event).getActivePage() - // .findView(UsersView.ID); - // view.refresh(); - return null; - } - - public void setUserAdminService(UserAdminService userAdminService) { - this.userAdminService = userAdminService; - } -} \ No newline at end of file diff --git a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/NewUser.java b/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/NewUser.java deleted file mode 100644 index 660896de8..000000000 --- a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/NewUser.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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.security.ui.admin.commands; - -import javax.jcr.Repository; -import javax.jcr.Session; - -import org.argeo.jcr.JcrUtils; -import org.argeo.security.UserAdminService; -import org.argeo.security.jcr.JcrSecurityModel; -import org.argeo.security.ui.admin.wizards.NewUserWizard; -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import org.eclipse.jface.wizard.WizardDialog; -import org.eclipse.ui.handlers.HandlerUtil; - -/** Launch a wizard that enables creation of a new user. */ -public class NewUser extends AbstractHandler { - private Repository repository; - private UserAdminService userAdminService; - private JcrSecurityModel jcrSecurityModel; - - public Object execute(ExecutionEvent event) throws ExecutionException { - Session session = null; - try { - session = repository.login(); - NewUserWizard newUserWizard = new NewUserWizard(session, - userAdminService, jcrSecurityModel); - WizardDialog dialog = new WizardDialog( - HandlerUtil.getActiveShell(event), newUserWizard); - dialog.open(); - } catch (Exception e) { - throw new ExecutionException("Cannot open wizard", e); - } finally { - JcrUtils.logoutQuietly(session); - } - return null; - } - - public void setRepository(Repository repository) { - this.repository = repository; - } - - public void setUserAdminService(UserAdminService userAdminService) { - this.userAdminService = userAdminService; - } - - public void setJcrSecurityModel(JcrSecurityModel jcrSecurityModel) { - this.jcrSecurityModel = jcrSecurityModel; - } - -} diff --git a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/OpenArgeoUserEditor.java b/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/OpenArgeoUserEditor.java deleted file mode 100644 index bae928c22..000000000 --- a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/OpenArgeoUserEditor.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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.security.ui.admin.commands; - -import org.argeo.security.ui.admin.editors.ArgeoUserEditor; -import org.argeo.security.ui.admin.editors.ArgeoUserEditorInput; -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import org.eclipse.ui.IWorkbenchPage; -import org.eclipse.ui.handlers.HandlerUtil; - -/** Command handler to set visible or open a Argeo user. */ -public class OpenArgeoUserEditor extends AbstractHandler { - public final static String COMMAND_ID = "org.argeo.security.ui.admin.openArgeoUserEditor"; - public final static String PARAM_USERNAME = "org.argeo.security.ui.admin.username"; - - public Object execute(ExecutionEvent event) throws ExecutionException { - try { - ArgeoUserEditorInput editorInput = new ArgeoUserEditorInput( - event.getParameter(PARAM_USERNAME)); - IWorkbenchPage activePage = HandlerUtil.getActiveWorkbenchWindow( - event).getActivePage(); - activePage.openEditor(editorInput, ArgeoUserEditor.ID); - } catch (Exception e) { - throw new ExecutionException("Cannot open editor", e); - } - return null; - } -} diff --git a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/RefreshRoles.java b/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/RefreshRoles.java deleted file mode 100644 index 41c78f077..000000000 --- a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/RefreshRoles.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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.security.ui.admin.commands; - -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; - -/** - * Refreshes the roles view. - */ -public class RefreshRoles extends AbstractHandler { - public Object execute(ExecutionEvent event) throws ExecutionException { - - return null; - } - -} \ No newline at end of file diff --git a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/RefreshUsersList.java b/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/RefreshUsersList.java deleted file mode 100644 index e4c14ab21..000000000 --- a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/RefreshUsersList.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * 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.security.ui.admin.commands; - -import java.util.Set; - -import javax.jcr.Node; -import javax.jcr.NodeIterator; -import javax.jcr.Repository; -import javax.jcr.RepositoryException; -import javax.jcr.Session; -import javax.jcr.query.Query; - -import org.argeo.ArgeoException; -import org.argeo.jcr.ArgeoNames; -import org.argeo.jcr.ArgeoTypes; -import org.argeo.jcr.JcrUtils; -import org.argeo.security.UserAdminService; -import org.argeo.security.ui.admin.views.UsersView; -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import org.eclipse.ui.IWorkbenchPart; -import org.eclipse.ui.handlers.HandlerUtil; - -/** - * Refreshes the main user list, removing nodes which are not referenced by user - * admin service. - */ -public class RefreshUsersList extends AbstractHandler { - private UserAdminService userAdminService; - private Repository repository; - - public Object execute(ExecutionEvent event) throws ExecutionException { - Set users = userAdminService.listUsers(); - Session session = null; - try { - session = repository.login(); - Query query = session - .getWorkspace() - .getQueryManager() - .createQuery( - "select * from [" + ArgeoTypes.ARGEO_USER_HOME - + "]", Query.JCR_SQL2); - NodeIterator nit = query.execute().getNodes(); - while (nit.hasNext()) { - Node node = nit.nextNode(); - String username = node.getProperty(ArgeoNames.ARGEO_USER_ID) - .getString(); - if (!users.contains(username)) - node.remove(); - } - session.save(); - } catch (RepositoryException e) { - JcrUtils.discardQuietly(session); - throw new ArgeoException("Cannot list users", e); - } finally { - JcrUtils.logoutQuietly(session); - } - userAdminService.synchronize(); - - // FIXME try to refresh views that extend the UsersView and have another - // ID - IWorkbenchPart part = HandlerUtil.getActiveWorkbenchWindow(event) - .getActivePage().getActivePart(); - if (part instanceof UsersView) - ((UsersView) part).refresh(); - - // Try to refresh UsersView if opened - UsersView view = (UsersView) HandlerUtil - .getActiveWorkbenchWindow(event).getActivePage() - .findView(UsersView.ID); - if (view != null) - view.refresh(); - - return null; - } - - public void setUserAdminService(UserAdminService userAdminService) { - this.userAdminService = userAdminService; - } - - public void setRepository(Repository repository) { - this.repository = repository; - } - -} \ No newline at end of file diff --git a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/SaveArgeoUser.java b/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/SaveArgeoUser.java deleted file mode 100644 index bd16f8bcf..000000000 --- a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/SaveArgeoUser.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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.security.ui.admin.commands; - -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.swt.widgets.Display; -import org.eclipse.ui.IEditorPart; -import org.eclipse.ui.IWorkbenchPart; -import org.eclipse.ui.handlers.HandlerUtil; - -/** Save the currently edited Argeo user. */ -public class SaveArgeoUser extends AbstractHandler { - public final static String COMMAND_ID = "org.argeo.security.ui.admin.saveArgeoUser"; - - public Object execute(ExecutionEvent event) throws ExecutionException { - try { - IWorkbenchPart iwp = HandlerUtil.getActiveWorkbenchWindow(event) - .getActivePage().getActivePart(); - - if (!(iwp instanceof IEditorPart)) - return null; - IEditorPart editor = (IEditorPart) iwp; - editor.doSave(null); - } catch (Exception e) { - MessageDialog.openError(Display.getDefault().getActiveShell(), - "Error", "Cannot save user: " + e.getMessage()); - } - return null; - } - -} diff --git a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/UserBatchUpdate.java b/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/UserBatchUpdate.java deleted file mode 100644 index 657dfc70a..000000000 --- a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/UserBatchUpdate.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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.security.ui.admin.commands; - -import javax.jcr.Repository; -import javax.jcr.Session; - -import org.argeo.jcr.JcrUtils; -import org.argeo.security.UserAdminService; -import org.argeo.security.jcr.JcrSecurityModel; -import org.argeo.security.ui.admin.wizards.UserBatchUpdateWizard; -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import org.eclipse.jface.wizard.WizardDialog; -import org.eclipse.ui.handlers.HandlerUtil; - -/** Launch a wizard to update various properties about users in JCR. */ -public class UserBatchUpdate extends AbstractHandler { - private Repository repository; - private UserAdminService userAdminService; - private JcrSecurityModel jcrSecurityModel; - - public Object execute(ExecutionEvent event) throws ExecutionException { - Session session = null; - try { - session = repository.login(); - UserBatchUpdateWizard userBatchUpdateWizard = new UserBatchUpdateWizard(session, - userAdminService, jcrSecurityModel); - WizardDialog dialog = new WizardDialog( - HandlerUtil.getActiveShell(event), userBatchUpdateWizard); - dialog.open(); - } catch (Exception e) { - throw new ExecutionException("Cannot open wizard", e); - } finally { - JcrUtils.logoutQuietly(session); - } - return null; - } - - public void setRepository(Repository repository) { - this.repository = repository; - } - - public void setUserAdminService(UserAdminService userAdminService) { - this.userAdminService = userAdminService; - } - - public void setJcrSecurityModel(JcrSecurityModel jcrSecurityModel) { - this.jcrSecurityModel = jcrSecurityModel; - } - -} diff --git a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/ArgeoUserEditor.java b/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/ArgeoUserEditor.java deleted file mode 100644 index ebc08319e..000000000 --- a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/ArgeoUserEditor.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * 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.security.ui.admin.editors; - -import javax.jcr.Node; -import javax.jcr.Repository; -import javax.jcr.RepositoryException; -import javax.jcr.Session; - -import org.argeo.ArgeoException; -import org.argeo.jcr.JcrUtils; -import org.argeo.jcr.UserJcrUtils; -import org.argeo.security.UserAdminService; -import org.argeo.security.jcr.JcrUserDetails; -import org.argeo.security.ui.admin.SecurityAdminPlugin; -import org.argeo.security.ui.admin.views.UsersView; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.ui.IEditorInput; -import org.eclipse.ui.IEditorSite; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.forms.editor.FormEditor; -import org.springframework.security.GrantedAuthority; - -/** Editor for an Argeo user. */ -public class ArgeoUserEditor extends FormEditor { - public final static String ID = SecurityAdminPlugin.PLUGIN_ID - + ".adminArgeoUserEditor"; - - /* DEPENDENCY INJECTION */ - private Session session; - private UserAdminService userAdminService; - - // private Node userHome; - private Node userProfile; - private JcrUserDetails userDetails; - - public void init(IEditorSite site, IEditorInput input) - throws PartInitException { - super.init(site, input); - String username = ((ArgeoUserEditorInput) getEditorInput()) - .getUsername(); - userProfile = UserJcrUtils.getUserProfile(session, username); - - if (userAdminService.userExists(username)) { - userDetails = (JcrUserDetails) userAdminService - .loadUserByUsername(username); - } else { - GrantedAuthority[] authorities = {}; - try { - userDetails = new JcrUserDetails(session, username, null, - authorities); - } catch (RepositoryException e) { - throw new ArgeoException("Cannot retrieve disabled JCR profile"); - } - } - - this.setPartProperty("name", username != null ? username : ""); - setPartName(username != null ? username : ""); - } - - protected void addPages() { - try { - addPage(new DefaultUserMainPage(this, userProfile)); - addPage(new UserRolesPage(this, userDetails, userAdminService)); - } catch (Exception e) { - throw new ArgeoException("Cannot add pages", e); - } - } - - @Override - public void doSave(IProgressMonitor monitor) { - // list pages - // TODO: make it more generic - DefaultUserMainPage defaultUserMainPage = (DefaultUserMainPage) findPage(DefaultUserMainPage.ID); - if (defaultUserMainPage.isDirty()) { - defaultUserMainPage.doSave(monitor); - String newPassword = defaultUserMainPage.getNewPassword(); - defaultUserMainPage.resetNewPassword(); - if (newPassword != null) - userDetails = userDetails.cloneWithNewPassword(newPassword); - } - - UserRolesPage userRolesPage = (UserRolesPage) findPage(UserRolesPage.ID); - if (userRolesPage.isDirty()) { - userRolesPage.doSave(monitor); - userDetails = userDetails.cloneWithNewRoles(userRolesPage - .getRoles()); - } - - userAdminService.updateUser(userDetails); - - // if (userAdminService.userExists(user.getUsername())) - // userAdminService.updateUser(user); - // else { - // userAdminService.newUser(user); - // setPartName(user.getUsername()); - // } - firePropertyChange(PROP_DIRTY); - - userRolesPage.setUserDetails(userDetails); - - // FIXME rather use a refresh command. Fails when called by another - // view. - // refresh users view - IWorkbench iw = SecurityAdminPlugin.getDefault().getWorkbench(); - UsersView usersView = (UsersView) iw.getActiveWorkbenchWindow() - .getActivePage().findView(UsersView.ID); - if (usersView != null) - usersView.refresh(); - } - - @Override - public void doSaveAs() { - } - - @Override - public boolean isSaveAsAllowed() { - return false; - } - - public void refresh() { - UserRolesPage userRolesPage = (UserRolesPage) findPage(UserRolesPage.ID); - userRolesPage.refresh(); - } - - @Override - public void dispose() { - JcrUtils.logoutQuietly(session); - super.dispose(); - } - - /* DEPENDENCY INJECTION */ - public void setUserAdminService(UserAdminService userAdminService) { - this.userAdminService = userAdminService; - } - - public void setRepository(Repository repository) { - try { - session = repository.login(); - } catch (RepositoryException re) { - throw new ArgeoException("Unable to initialise local session", re); - } - } -} diff --git a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/ArgeoUserEditorInput.java b/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/ArgeoUserEditorInput.java deleted file mode 100644 index 9d1d99573..000000000 --- a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/ArgeoUserEditorInput.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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.security.ui.admin.editors; - -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.ui.IEditorInput; -import org.eclipse.ui.IPersistableElement; - -/** Editor input for an Argeo user. */ -public class ArgeoUserEditorInput implements IEditorInput { - private final String username; - - public ArgeoUserEditorInput(String username) { - this.username = username; - } - - public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) { - return null; - } - - public boolean exists() { - return username != null; - } - - public ImageDescriptor getImageDescriptor() { - return null; - } - - public String getName() { - return username != null ? username : ""; - } - - public IPersistableElement getPersistable() { - return null; - } - - public String getToolTipText() { - return username != null ? username : ""; - } - - public boolean equals(Object obj) { - if (!(obj instanceof ArgeoUserEditorInput)) - return false; - if (((ArgeoUserEditorInput) obj).getUsername() == null) - return false; - return ((ArgeoUserEditorInput) obj).getUsername().equals(username); - } - - public String getUsername() { - return username; - } -} diff --git a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/DefaultUserMainPage.java b/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/DefaultUserMainPage.java deleted file mode 100644 index 5f99e195b..000000000 --- a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/DefaultUserMainPage.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * 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.security.ui.admin.editors; - -import java.util.Arrays; - -import javax.jcr.Node; -import javax.jcr.Property; -import javax.jcr.RepositoryException; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.ArgeoException; -import org.argeo.jcr.ArgeoNames; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.forms.AbstractFormPart; -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.SectionPart; -import org.eclipse.ui.forms.editor.FormEditor; -import org.eclipse.ui.forms.editor.FormPage; -import org.eclipse.ui.forms.widgets.FormToolkit; -import org.eclipse.ui.forms.widgets.ScrolledForm; -import org.eclipse.ui.forms.widgets.Section; - -/** - * Display/edit the properties common to all Argeo users - */ -public class DefaultUserMainPage extends FormPage implements ArgeoNames { - final static String ID = "argeoUserEditor.mainPage"; - - private final static Log log = LogFactory.getLog(DefaultUserMainPage.class); - private Node userProfile; - - private char[] newPassword; - - public DefaultUserMainPage(FormEditor editor, Node userProfile) { - super(editor, ID, "Main"); - this.userProfile = userProfile; - } - - protected void createFormContent(final IManagedForm mf) { - try { - ScrolledForm form = mf.getForm(); - refreshFormTitle(form); - GridLayout mainLayout = new GridLayout(1, true); - form.getBody().setLayout(mainLayout); - - createGeneralPart(form.getBody()); - createPassworPart(form.getBody()); - } catch (RepositoryException e) { - throw new ArgeoException("Cannot create form content", e); - } - } - - /** Creates the general section */ - protected void createGeneralPart(Composite parent) - throws RepositoryException { - FormToolkit tk = getManagedForm().getToolkit(); - Section section = tk.createSection(parent, Section.TITLE_BAR); - section.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); - section.setText("General"); - Composite body = tk.createComposite(section, SWT.WRAP); - section.setClient(body); - GridLayout layout = new GridLayout(2, false); - body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); - body.setLayout(layout); - - final Text commonName = createLT(body, "Displayed Name", - getProperty(Property.JCR_TITLE)); - final Text firstName = createLT(body, "First name", - getProperty(ARGEO_FIRST_NAME)); - final Text lastName = createLT(body, "Last name", - getProperty(ARGEO_LAST_NAME)); - final Text email = createLT(body, "Email", - getProperty(ARGEO_PRIMARY_EMAIL)); - final Text description = createLMT(body, "Description", - getProperty(Property.JCR_DESCRIPTION)); - - // create form part (controller) - AbstractFormPart part = new SectionPart(section) { - public void commit(boolean onSave) { - try { - userProfile.getSession().getWorkspace().getVersionManager() - .checkout(userProfile.getPath()); - userProfile.setProperty(Property.JCR_TITLE, - commonName.getText()); - userProfile.setProperty(ARGEO_FIRST_NAME, - firstName.getText()); - userProfile - .setProperty(ARGEO_LAST_NAME, lastName.getText()); - userProfile.setProperty(ARGEO_PRIMARY_EMAIL, - email.getText()); - userProfile.setProperty(Property.JCR_DESCRIPTION, - description.getText()); - userProfile.getSession().save(); - userProfile.getSession().getWorkspace().getVersionManager() - .checkin(userProfile.getPath()); - super.commit(onSave); - refreshFormTitle(getManagedForm().getForm()); - if (log.isTraceEnabled()) - log.trace("General part committed"); - } catch (RepositoryException e) { - throw new ArgeoException("Cannot commit", e); - } - } - }; - // if (username != null) - // username.addModifyListener(new FormPartML(part)); - commonName.addModifyListener(new FormPartML(part)); - firstName.addModifyListener(new FormPartML(part)); - lastName.addModifyListener(new FormPartML(part)); - email.addModifyListener(new FormPartML(part)); - description.addModifyListener(new FormPartML(part)); - getManagedForm().addPart(part); - } - - private void refreshFormTitle(ScrolledForm form) throws RepositoryException { - form.setText(getProperty(Property.JCR_TITLE) - + (userProfile.getProperty(ARGEO_ENABLED).getBoolean() ? "" - : " [DISABLED]")); - } - - /** @return the property, or the empty string if not set */ - protected String getProperty(String name) throws RepositoryException { - return userProfile.hasProperty(name) ? userProfile.getProperty(name) - .getString() : ""; - } - - /** Creates the password section */ - protected void createPassworPart(Composite parent) { - FormToolkit tk = getManagedForm().getToolkit(); - Section section = tk.createSection(parent, Section.TITLE_BAR); - section.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); - section.setText("Password"); - - Composite body = tk.createComposite(section, SWT.WRAP); - section.setClient(body); - GridLayout layout = new GridLayout(2, false); - body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); - body.setLayout(layout); - - // add widgets (view) - final Text password1 = createLP(body, "New password", ""); - final Text password2 = createLP(body, "Repeat password", ""); - // create form part (controller) - AbstractFormPart part = new SectionPart(section) { - - public void commit(boolean onSave) { - if (!password1.getText().equals("") - || !password2.getText().equals("")) { - if (password1.getText().equals(password2.getText())) { - newPassword = password1.getText().toCharArray(); - password1.setText(""); - password2.setText(""); - super.commit(onSave); - } else { - password1.setText(""); - password2.setText(""); - throw new ArgeoException("Passwords are not equals"); - } - } - } - - }; - password1.addModifyListener(new FormPartML(part)); - password2.addModifyListener(new FormPartML(part)); - getManagedForm().addPart(part); - } - - /** Creates label and text. */ - protected Text createLT(Composite body, String label, String value) { - FormToolkit toolkit = getManagedForm().getToolkit(); - Label lbl = toolkit.createLabel(body, label); - lbl.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false)); - Text text = toolkit.createText(body, value, SWT.BORDER); - text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); - return text; - } - - /** Creates label and multiline text. */ - protected Text createLMT(Composite body, String label, String value) { - FormToolkit toolkit = getManagedForm().getToolkit(); - Label lbl = toolkit.createLabel(body, label); - lbl.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false)); - Text text = toolkit.createText(body, value, SWT.BORDER | SWT.MULTI); - text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true)); - return text; - } - - /** Creates label and password. */ - protected Text createLP(Composite body, String label, String value) { - FormToolkit toolkit = getManagedForm().getToolkit(); - Label lbl = toolkit.createLabel(body, label); - lbl.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false)); - Text text = toolkit.createText(body, value, SWT.BORDER | SWT.PASSWORD); - text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); - return text; - } - - private class FormPartML implements ModifyListener { - private AbstractFormPart formPart; - - public FormPartML(AbstractFormPart generalPart) { - this.formPart = generalPart; - } - - public void modifyText(ModifyEvent e) { - formPart.markDirty(); - } - - } - - public String getNewPassword() { - if (newPassword != null) - return new String(newPassword); - else - return null; - } - - public void resetNewPassword() { - if (newPassword != null) - Arrays.fill(newPassword, 'x'); - newPassword = null; - } -} diff --git a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/UserRolesPage.java b/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/UserRolesPage.java deleted file mode 100644 index 08cd457ad..000000000 --- a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/UserRolesPage.java +++ /dev/null @@ -1,225 +0,0 @@ -/* - * 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.security.ui.admin.editors; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.jcr.ArgeoNames; -import org.argeo.security.UserAdminService; -import org.argeo.security.ui.admin.SecurityAdminPlugin; -import org.eclipse.jface.viewers.CellEditor; -import org.eclipse.jface.viewers.CheckboxCellEditor; -import org.eclipse.jface.viewers.ColumnLabelProvider; -import org.eclipse.jface.viewers.EditingSupport; -import org.eclipse.jface.viewers.IStructuredContentProvider; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.jface.viewers.TableViewerColumn; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.layout.FillLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableColumn; -import org.eclipse.ui.forms.AbstractFormPart; -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.editor.FormEditor; -import org.eclipse.ui.forms.editor.FormPage; -import org.eclipse.ui.forms.widgets.ScrolledForm; -import org.springframework.security.GrantedAuthority; -import org.springframework.security.userdetails.UserDetails; - -/** - * Display/edit the roles of a user. - */ -public class UserRolesPage extends FormPage implements ArgeoNames { - final static String ID = "argeoUserEditor.rolesPage"; - - private final static Log log = LogFactory.getLog(UserRolesPage.class); - private final static Image ROLE_CHECKED = SecurityAdminPlugin - .getImageDescriptor("icons/security.gif").createImage(); - - private TableViewer rolesViewer; - private UserAdminService userAdminService; - private List roles; - - public UserRolesPage(FormEditor editor, UserDetails userDetails, - UserAdminService userAdminService) { - super(editor, ID, "Roles"); - setUserDetails(userDetails); - this.userAdminService = userAdminService; - } - - public void setUserDetails(UserDetails userDetails) { - this.roles = new ArrayList(); - for (GrantedAuthority ga : userDetails.getAuthorities()) - roles.add(ga.getAuthority()); - if (rolesViewer != null) - rolesViewer.refresh(); - } - - protected void createFormContent(final IManagedForm mf) { - ScrolledForm form = mf.getForm(); - form.setText("Roles"); - FillLayout mainLayout = new FillLayout(); - // ColumnLayout mainLayout = new ColumnLayout(); - // mainLayout.minNumColumns = 1; - // mainLayout.maxNumColumns = 4; - // mainLayout.topMargin = 0; - // mainLayout.bottomMargin = 5; - // mainLayout.leftMargin = mainLayout.rightMargin = - // mainLayout.horizontalSpacing = mainLayout.verticalSpacing = 10; - form.getBody().setLayout(mainLayout); - createRolesPart(form.getBody()); - } - - /** Creates the role section */ - protected void createRolesPart(Composite parent) { - Table table = new Table(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); - - AbstractFormPart part = new AbstractFormPart() { - public void commit(boolean onSave) { - // roles have already been modified in editing - super.commit(onSave); - if (log.isTraceEnabled()) - log.trace("Role part committed"); - } - }; - getManagedForm().addPart(part); - - // GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true); - // gridData.verticalSpan = 20; - // table.setLayoutData(gridData); - table.setLinesVisible(true); - table.setHeaderVisible(false); - rolesViewer = new TableViewer(table); - - // check column - TableViewerColumn column = createTableViewerColumn(rolesViewer, - "checked", 20); - column.setLabelProvider(new ColumnLabelProvider() { - public String getText(Object element) { - return null; - } - - public Image getImage(Object element) { - String role = element.toString(); - if (roles.contains(role)) { - return ROLE_CHECKED; - } else { - return null; - } - } - }); - column.setEditingSupport(new RoleEditingSupport(rolesViewer, part)); - - // role column - column = createTableViewerColumn(rolesViewer, "Role", 200); - column.setLabelProvider(new ColumnLabelProvider() { - public String getText(Object element) { - return element.toString(); - } - - public Image getImage(Object element) { - return null; - } - }); - rolesViewer.setContentProvider(new RolesContentProvider()); - rolesViewer.setInput(getEditorSite()); - } - - protected TableViewerColumn createTableViewerColumn(TableViewer viewer, - String title, int bound) { - final TableViewerColumn viewerColumn = new TableViewerColumn(viewer, - SWT.NONE); - final TableColumn column = viewerColumn.getColumn(); - column.setText(title); - column.setWidth(bound); - column.setResizable(true); - column.setMoveable(true); - return viewerColumn; - - } - - public List getRoles() { - return roles; - } - - public void refresh() { - rolesViewer.refresh(); - } - - private class RolesContentProvider implements IStructuredContentProvider { - public Object[] getElements(Object inputElement) { - return userAdminService.listEditableRoles().toArray(); - } - - public void dispose() { - } - - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - } - } - - /** Select the columns by editing the checkbox in the first column */ - class RoleEditingSupport extends EditingSupport { - - private final TableViewer viewer; - private final AbstractFormPart formPart; - - public RoleEditingSupport(TableViewer viewer, AbstractFormPart formPart) { - super(viewer); - this.viewer = viewer; - this.formPart = formPart; - } - - @Override - protected CellEditor getCellEditor(Object element) { - return new CheckboxCellEditor(null, SWT.CHECK | SWT.READ_ONLY); - - } - - @Override - protected boolean canEdit(Object element) { - return true; - } - - @Override - protected Object getValue(Object element) { - String role = element.toString(); - return roles.contains(role); - - } - - @Override - protected void setValue(Object element, Object value) { - Boolean inRole = (Boolean) value; - String role = element.toString(); - if (inRole && !roles.contains(role)) { - roles.add(role); - formPart.markDirty(); - } else if (!inRole && roles.contains(role)) { - roles.remove(role); - formPart.markDirty(); - } - viewer.refresh(); - } - } - -} diff --git a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/views/RolesView.java b/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/views/RolesView.java deleted file mode 100644 index fbe7dd570..000000000 --- a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/views/RolesView.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * 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.security.ui.admin.views; - -import org.argeo.ArgeoException; -import org.argeo.security.UserAdminService; -import org.argeo.security.ui.admin.SecurityAdminPlugin; -import org.argeo.security.ui.admin.commands.AddRole; -import org.eclipse.jface.viewers.IStructuredContentProvider; -import org.eclipse.jface.viewers.ITableLabelProvider; -import org.eclipse.jface.viewers.LabelProvider; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.Listener; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.handlers.IHandlerService; -import org.eclipse.ui.part.ViewPart; - -/** List all roles. */ -public class RolesView extends ViewPart { - public final static String ID = SecurityAdminPlugin.PLUGIN_ID - + ".adminRolesView"; - - private Text newRole; - - private TableViewer viewer; - private UserAdminService userAdminService; - - private String addNewRoleText = ""; - - @Override - public void createPartControl(Composite parent) { - parent.setLayout(new GridLayout(1, false)); - - // new role text field - newRole = new Text(parent, SWT.BORDER); - newRole.setText(addNewRoleText); - newRole.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); - // default action is add role - newRole.addListener(SWT.DefaultSelection, new Listener() { - public void handleEvent(Event evt) { - IWorkbench iw = SecurityAdminPlugin.getDefault().getWorkbench(); - IHandlerService handlerService = (IHandlerService) iw - .getService(IHandlerService.class); - try { - handlerService.executeCommand(AddRole.COMMAND_ID, evt); - } catch (Exception e) { - throw new ArgeoException("Cannot execute add role command", - e); - } - } - }); - // select all on focus - newRole.addListener(SWT.FocusIn, new Listener() { - public void handleEvent(Event e) { - newRole.selectAll(); - } - }); - - // roles table - Table table = new Table(parent, SWT.V_SCROLL | SWT.BORDER); - table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - table.setLinesVisible(false); - table.setHeaderVisible(false); - viewer = new TableViewer(table); - viewer.setContentProvider(new RolesContentProvider()); - viewer.setLabelProvider(new UsersLabelProvider()); - getViewSite().setSelectionProvider(viewer); - viewer.setInput(getViewSite()); - } - - @Override - public void setFocus() { - viewer.getTable().setFocus(); - } - - public void setUserAdminService(UserAdminService userAdminService) { - this.userAdminService = userAdminService; - } - - public String getAddNewRoleText() { - return addNewRoleText; - } - - private class RolesContentProvider implements IStructuredContentProvider { - - public Object[] getElements(Object inputElement) { - return userAdminService.listEditableRoles().toArray(); - } - - public void dispose() { - } - - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - } - - } - - private class UsersLabelProvider extends LabelProvider implements - ITableLabelProvider { - public String getColumnText(Object element, int columnIndex) { - return element.toString(); - } - - public Image getColumnImage(Object element, int columnIndex) { - return null; - } - - } - - public String getNewRole() { - return newRole.getText(); - } - - public void refresh() { - viewer.refresh(); - newRole.setText(addNewRoleText); - } -} diff --git a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/views/UsersView.java b/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/views/UsersView.java deleted file mode 100644 index a7437156d..000000000 --- a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/views/UsersView.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * 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.security.ui.admin.views; - -import javax.jcr.Node; -import javax.jcr.Repository; -import javax.jcr.RepositoryException; -import javax.jcr.Session; -import javax.jcr.observation.Event; -import javax.jcr.observation.EventIterator; -import javax.jcr.observation.EventListener; - -import org.argeo.ArgeoException; -import org.argeo.eclipse.ui.utils.CommandUtils; -import org.argeo.jcr.ArgeoJcrConstants; -import org.argeo.jcr.ArgeoNames; -import org.argeo.jcr.ArgeoTypes; -import org.argeo.jcr.JcrUtils; -import org.argeo.security.ui.admin.SecurityAdminPlugin; -import org.argeo.security.ui.admin.UserTableComposite; -import org.argeo.security.ui.admin.commands.OpenArgeoUserEditor; -import org.eclipse.jface.viewers.DoubleClickEvent; -import org.eclipse.jface.viewers.IDoubleClickListener; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.swt.SWT; -import org.eclipse.swt.layout.FillLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Display; -import org.eclipse.ui.part.ViewPart; - -/** List all users with filter. */ -public class UsersView extends ViewPart implements ArgeoNames { - public final static String ID = SecurityAdminPlugin.PLUGIN_ID - + ".adminUsersView"; - - /* DEPENDENCY INJECTION */ - private Session session; - - private UserTableComposite userTableCmp; - private JcrUserListener userStructureListener; - private JcrUserListener userPropertiesListener; - - @Override - public void createPartControl(Composite parent) { - parent.setLayout(new FillLayout()); - - // Create the composite that displays the list and a filter - userTableCmp = new UserTableComposite(parent, SWT.NO_FOCUS, session); - userTableCmp.populate(true, false); - - // Configure - userTableCmp.getTableViewer().addDoubleClickListener( - new ViewDoubleClickListener()); - getViewSite().setSelectionProvider(userTableCmp.getTableViewer()); - - // Add listener to refresh the list when something changes - userStructureListener = new JcrUserListener(getSite().getShell() - .getDisplay()); - JcrUtils.addListener(session, userStructureListener, Event.NODE_ADDED - | Event.NODE_REMOVED, ArgeoJcrConstants.PEOPLE_BASE_PATH, null); - userPropertiesListener = new JcrUserListener(getSite().getShell() - .getDisplay()); - JcrUtils.addListener(session, userStructureListener, - Event.PROPERTY_CHANGED | Event.PROPERTY_ADDED - | Event.PROPERTY_REMOVED, - ArgeoJcrConstants.PEOPLE_BASE_PATH, - ArgeoTypes.ARGEO_USER_PROFILE); - } - - @Override - public void setFocus() { - userTableCmp.setFocus(); - } - - @Override - public void dispose() { - JcrUtils.removeListenerQuietly(session, userStructureListener); - JcrUtils.removeListenerQuietly(session, userPropertiesListener); - JcrUtils.logoutQuietly(session); - super.dispose(); - } - - // public void setSession(Session session) { - // this.session = session; - // } - - public void refresh() { - this.getSite().getShell().getDisplay().asyncExec(new Runnable() { - @Override - public void run() { - userTableCmp.refresh(); - } - }); - } - - private class JcrUserListener implements EventListener { - private final Display display; - - public JcrUserListener(Display display) { - super(); - this.display = display; - } - - @Override - public void onEvent(EventIterator events) { - display.asyncExec(new Runnable() { - @Override - public void run() { - userTableCmp.refresh(); - } - }); - } - } - - class ViewDoubleClickListener implements IDoubleClickListener { - public void doubleClick(DoubleClickEvent evt) { - if (evt.getSelection().isEmpty()) - return; - - Object obj = ((IStructuredSelection) evt.getSelection()) - .getFirstElement(); - if (obj instanceof Node) { - try { - String username = ((Node) obj).getProperty(ARGEO_USER_ID) - .getString(); - String commandId = OpenArgeoUserEditor.COMMAND_ID; - String paramName = OpenArgeoUserEditor.PARAM_USERNAME; - CommandUtils.callCommand(commandId, paramName, username); - } catch (RepositoryException e) { - throw new ArgeoException("Cannot open user editor", e); - } - } - } - } - - /* DEPENDENCY INJECTION */ - public void setRepository(Repository repository) { - try { - session = repository.login(); - } catch (RepositoryException re) { - throw new ArgeoException("Unable to initialise local session", re); - } - } - -} \ No newline at end of file diff --git a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/wizards/MainUserInfoWizardPage.java b/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/wizards/MainUserInfoWizardPage.java deleted file mode 100644 index ad3662b6f..000000000 --- a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/wizards/MainUserInfoWizardPage.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * 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.security.ui.admin.wizards; - -import javax.jcr.Node; -import javax.jcr.Property; -import javax.jcr.RepositoryException; - -import org.argeo.ArgeoException; -import org.argeo.eclipse.ui.EclipseUiUtils; -import org.argeo.jcr.ArgeoNames; -import org.argeo.security.UserAdminService; -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Text; -import org.springframework.security.userdetails.UserDetails; -import org.springframework.security.userdetails.UsernameNotFoundException; - -public class MainUserInfoWizardPage extends WizardPage implements - ModifyListener, ArgeoNames { - private Text username, firstName, lastName, primaryEmail, password1, - password2; - private UserAdminService userAdminService; - - public MainUserInfoWizardPage(UserAdminService userAdminService) { - super("Main"); - this.userAdminService = userAdminService; - setTitle("Required Information"); - } - - @Override - public void createControl(Composite parent) { - Composite composite = new Composite(parent, SWT.NONE); - composite.setLayout(new GridLayout(2, false)); - username = EclipseUiUtils.createGridLT(composite, "Username", this); - primaryEmail = EclipseUiUtils.createGridLT(composite, "Email", this); - firstName = EclipseUiUtils.createGridLT(composite, "First name", this); - lastName = EclipseUiUtils.createGridLT(composite, "Last name", this); - password1 = EclipseUiUtils.createGridLP(composite, "Password", this); - password2 = EclipseUiUtils.createGridLP(composite, "Repeat password", - this); - setControl(composite); - - // Initialize buttons - setPageComplete(false); - getContainer().updateButtons(); - } - - @Override - public void modifyText(ModifyEvent event) { - String message = checkComplete(); - if (message != null) { - setMessage(message, WizardPage.ERROR); - setPageComplete(false); - } else { - setMessage("Complete", WizardPage.INFORMATION); - setPageComplete(true); - } - getContainer().updateButtons(); - } - - /** @return error message or null if complete */ - protected String checkComplete() { - // if (!username.getText().matches(UserAdminService.USERNAME_PATTERN)) - // return - // "Wrong user name format, should be lower case, between 3 and 64 characters with only '_' an '@' as acceptable special character."; - - if (username.getText().trim().equals("")) - return "User name must not be empty"; - - try { - UserDetails userDetails = userAdminService - .loadUserByUsername(username.getText()); - return "User " + userDetails.getUsername() + " already exists"; - } catch (UsernameNotFoundException e) { - // silent - } - if (!primaryEmail.getText().matches(UserAdminService.EMAIL_PATTERN)) - return "Not a valid email address"; - if (firstName.getText().trim().equals("")) - return "Specify a first name"; - if (lastName.getText().trim().equals("")) - return "Specify a last name"; - if (password1.getText().trim().equals("")) - return "Specify a password"; - if (password2.getText().trim().equals("")) - return "Repeat the password"; - if (!password2.getText().equals(password1.getText())) - return "Passwords are different"; - return null; - } - - public String getUsername() { - return username.getText(); - } - - public String getPassword() { - return password1.getText(); - } - - public void mapToProfileNode(Node up) { - try { - up.setProperty(ARGEO_PRIMARY_EMAIL, primaryEmail.getText()); - up.setProperty(ARGEO_FIRST_NAME, firstName.getText()); - up.setProperty(ARGEO_LAST_NAME, lastName.getText()); - - // derived values - // TODO add wizard pages to do it - up.setProperty(Property.JCR_TITLE, firstName.getText() + " " - + lastName.getText()); - up.setProperty(Property.JCR_DESCRIPTION, ""); - } catch (RepositoryException e) { - throw new ArgeoException("Cannot map to " + up, e); - } - } -} diff --git a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/wizards/NewUserWizard.java b/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/wizards/NewUserWizard.java deleted file mode 100644 index c2d041f56..000000000 --- a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/wizards/NewUserWizard.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * 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.security.ui.admin.wizards; - -import javax.jcr.Node; -import javax.jcr.RepositoryException; -import javax.jcr.Session; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.eclipse.ui.ErrorFeedback; -import org.argeo.jcr.JcrUtils; -import org.argeo.jcr.UserJcrUtils; -import org.argeo.security.UserAdminService; -import org.argeo.security.jcr.JcrSecurityModel; -import org.argeo.security.jcr.JcrUserDetails; -import org.eclipse.jface.wizard.Wizard; -import org.springframework.security.GrantedAuthority; - -/** Wizard to create a new user */ -public class NewUserWizard extends Wizard { - private final static Log log = LogFactory.getLog(NewUserWizard.class); - private Session session; - private UserAdminService userAdminService; - private JcrSecurityModel jcrSecurityModel; - - // pages - private MainUserInfoWizardPage mainUserInfo; - - public NewUserWizard(Session session, UserAdminService userAdminService, - JcrSecurityModel jcrSecurityModel) { - this.session = session; - this.userAdminService = userAdminService; - this.jcrSecurityModel = jcrSecurityModel; - } - - @Override - public void addPages() { - mainUserInfo = new MainUserInfoWizardPage(userAdminService); - addPage(mainUserInfo); - } - - @Override - public boolean performFinish() { - if (!canFinish()) - return false; - - String username = mainUserInfo.getUsername(); - try { - // Node userProfile = SecurityJcrUtils.createUserProfile(session, - // username); - Node userProfile = jcrSecurityModel.sync(session, username, null); - session.getWorkspace().getVersionManager() - .checkout(userProfile.getPath()); - mainUserInfo.mapToProfileNode(userProfile); - String password = mainUserInfo.getPassword(); - // TODO add roles - JcrUserDetails jcrUserDetails = new JcrUserDetails(userProfile, - password, new GrantedAuthority[0]); - session.save(); - session.getWorkspace().getVersionManager() - .checkin(userProfile.getPath()); - userAdminService.createUser(jcrUserDetails); - return true; - } catch (Exception e) { - JcrUtils.discardQuietly(session); - Node userHome = UserJcrUtils.getUserHome(session, username); - if (userHome != null) { - try { - userHome.remove(); - session.save(); - } catch (RepositoryException e1) { - JcrUtils.discardQuietly(session); - log.warn("Error when trying to clean up failed new user " - + username, e1); - } - } - ErrorFeedback.show("Cannot create new user " + username, e); - return false; - } - } - - public void setSession(Session session) { - this.session = session; - } - -} diff --git a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/wizards/UserBatchUpdateWizard.java b/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/wizards/UserBatchUpdateWizard.java deleted file mode 100644 index 71e4a1b73..000000000 --- a/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/wizards/UserBatchUpdateWizard.java +++ /dev/null @@ -1,607 +0,0 @@ -/* - * 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.security.ui.admin.wizards; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.jcr.Node; -import javax.jcr.NodeIterator; -import javax.jcr.RepositoryException; -import javax.jcr.Session; -import javax.jcr.version.VersionManager; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.ArgeoException; -import org.argeo.ArgeoMonitor; -import org.argeo.eclipse.ui.EclipseArgeoMonitor; -import org.argeo.jcr.ArgeoNames; -import org.argeo.jcr.JcrUtils; -import org.argeo.security.UserAdminService; -import org.argeo.security.jcr.JcrSecurityModel; -import org.argeo.security.jcr.JcrUserDetails; -import org.argeo.security.ui.PrivilegedJob; -import org.argeo.security.ui.admin.SecurityAdminPlugin; -import org.argeo.security.ui.admin.UserTableComposite; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.jface.dialogs.IPageChangeProvider; -import org.eclipse.jface.dialogs.IPageChangedListener; -import org.eclipse.jface.dialogs.PageChangedEvent; -import org.eclipse.jface.wizard.IWizardContainer; -import org.eclipse.jface.wizard.Wizard; -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.layout.FillLayout; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Text; - -/** Wizard to update users */ -public class UserBatchUpdateWizard extends Wizard { - private final static Log log = LogFactory - .getLog(UserBatchUpdateWizard.class); - private Session session; - private UserAdminService userAdminService; - - // pages - private ChooseCommandWizardPage chooseCommandPage; - private ChooseUsersWizardPage userListPage; - private ValidateAndLaunchWizardPage validatePage; - - // ///////////////////////////////////////////////// - // / Definition of the various implemented commands - private final static String CMD_UPDATE_PASSWORD = "resetPassword"; - private final static String CMD_GROUP_MEMBERSHIP = "groupMembership"; - - private final Map commands = new HashMap() { - private static final long serialVersionUID = 1L; - { - put("Enable user(s)", ArgeoNames.ARGEO_ENABLED); - put("Expire credentials", ArgeoNames.ARGEO_CREDENTIALS_NON_EXPIRED); - put("Expire account(s)", ArgeoNames.ARGEO_ACCOUNT_NON_EXPIRED); - put("Lock account(s)", ArgeoNames.ARGEO_ACCOUNT_NON_LOCKED); - put("Reset password(s)", CMD_UPDATE_PASSWORD); - // TODO implement role / group management - // put("Add/Remove from group", CMD_GROUP_MEMBERSHIP); - } - }; - - public UserBatchUpdateWizard(Session session, - UserAdminService userAdminService, JcrSecurityModel jcrSecurityModel) { - this.session = session; - this.userAdminService = userAdminService; - // this.jcrSecurityModel = jcrSecurityModel; - } - - @Override - public void addPages() { - chooseCommandPage = new ChooseCommandWizardPage(); - addPage(chooseCommandPage); - userListPage = new ChooseUsersWizardPage(session); - addPage(userListPage); - validatePage = new ValidateAndLaunchWizardPage(session); - addPage(validatePage); - } - - @Override - public boolean performFinish() { - if (!canFinish()) - return false; - - UpdateJob job = null; - if (ArgeoNames.ARGEO_ENABLED.equals(chooseCommandPage.getCommand())) { - job = new UpdateBoolean(session, userListPage.getSelectedUsers(), - ArgeoNames.ARGEO_ENABLED, - chooseCommandPage.getBoleanValue()); - } else if (ArgeoNames.ARGEO_CREDENTIALS_NON_EXPIRED - .equals(chooseCommandPage.getCommand())) { - job = new UpdateBoolean(session, userListPage.getSelectedUsers(), - ArgeoNames.ARGEO_CREDENTIALS_NON_EXPIRED, - chooseCommandPage.getBoleanValue()); - } else if (ArgeoNames.ARGEO_ACCOUNT_NON_EXPIRED - .equals(chooseCommandPage.getCommand())) { - job = new UpdateBoolean(session, userListPage.getSelectedUsers(), - ArgeoNames.ARGEO_ACCOUNT_NON_EXPIRED, - chooseCommandPage.getBoleanValue()); - } else if (ArgeoNames.ARGEO_ACCOUNT_NON_LOCKED.equals(chooseCommandPage - .getCommand())) { - job = new UpdateBoolean(session, userListPage.getSelectedUsers(), - ArgeoNames.ARGEO_ACCOUNT_NON_LOCKED, - chooseCommandPage.getBoleanValue()); - } else if (CMD_UPDATE_PASSWORD.equals(chooseCommandPage.getCommand())) { - String newValue = chooseCommandPage.getPwdValue(); - if (newValue == null) - throw new ArgeoException( - "Password cannot be null or an empty string"); - job = new ResetPassword(session, userAdminService, - userListPage.getSelectedUsers(), newValue); - } - - if (job != null) - job.schedule(); - return true; - } - - public void setSession(Session session) { - this.session = session; - } - - public boolean canFinish() { - if (this.getContainer().getCurrentPage() == validatePage) - return true; - return false; - } - - // ///////////////////////// - // REEL UPDATE JOB - private class UpdateBoolean extends UpdateJob { - private String propertyName; - private boolean value; - - public UpdateBoolean(Session session, List nodesToUpdate, - String propertyName, boolean value) { - super(session, nodesToUpdate); - this.propertyName = propertyName; - this.value = value; - } - - protected void doUpdate(Node node) { - try { - node.setProperty(propertyName, value); - } catch (RepositoryException re) { - throw new ArgeoException( - "Unable to update boolean value for node " + node, re); - } - } - } - - private class ResetPassword extends UpdateJob { - private String newValue; - private UserAdminService userAdminService; - - public ResetPassword(Session session, - UserAdminService userAdminService, List nodesToUpdate, - String newValue) { - super(session, nodesToUpdate); - this.newValue = newValue; - this.userAdminService = userAdminService; - } - - protected void doUpdate(Node node) { - try { - String userId = node.getProperty(ArgeoNames.ARGEO_USER_ID) - .getString(); - if (userAdminService.userExists(userId)) { - JcrUserDetails userDetails = (JcrUserDetails) userAdminService - .loadUserByUsername(userId); - userAdminService.updateUser(userDetails - .cloneWithNewPassword(newValue)); - } - } catch (RepositoryException re) { - throw new ArgeoException( - "Unable to update boolean value for node " + node, re); - } - } - } - - @SuppressWarnings("unused") - private class AddToGroup extends UpdateJob { - private String groupID; - private Session session; - - public AddToGroup(Session session, List nodesToUpdate, - String groupID) { - super(session, nodesToUpdate); - this.session = session; - this.groupID = groupID; - } - - protected void doUpdate(Node node) { - log.info("Add/Remove to group actions are not yet implemented"); - // TODO implement this - // try { - // throw new ArgeoException("Not yet implemented"); - // } catch (RepositoryException re) { - // throw new ArgeoException( - // "Unable to update boolean value for node " + node, re); - // } - } - } - - /** - * Base privileged job that will be run asynchronously to perform the batch - * update - */ - private abstract class UpdateJob extends PrivilegedJob { - - private final Session currSession; - private final List nodesToUpdate; - - protected abstract void doUpdate(Node node); - - public UpdateJob(Session session, List nodesToUpdate) { - super("Perform update"); - try { - this.currSession = session.getRepository().login(); - // "move" nodes to update in the new session - // the "old" session will be closed by the calling command - // before the job has effectively ran - // TODO there must be a cleaner way to do. - List nodes = new ArrayList(); - for (Node node : nodesToUpdate) { - nodes.add(currSession.getNode(node.getPath())); - } - this.nodesToUpdate = nodes; - } catch (RepositoryException e) { - throw new ArgeoException("Error while dupplicating " - + "session for job", e); - } - } - - @Override - protected IStatus doRun(IProgressMonitor progressMonitor) { - try { - ArgeoMonitor monitor = new EclipseArgeoMonitor(progressMonitor); - VersionManager vm = currSession.getWorkspace() - .getVersionManager(); - int total = nodesToUpdate.size(); - monitor.beginTask("Performing change", total); - for (Node node : nodesToUpdate) { - String path = node.getPath(); - vm.checkout(path); - doUpdate(node); - currSession.save(); - vm.checkin(path); - monitor.worked(1); - } - } catch (Exception e) { - log.error("Cannot perform batch update on users", e); - // e.printStackTrace(); - - // Dig exception to find the root cause that will enable the - // user to understand the problem - Throwable cause = e; - Throwable originalCause = e; - while (cause != null) { - if (log.isTraceEnabled()) - log.trace("Parent Cause message : " - + cause.getMessage()); - originalCause = cause; - cause = cause.getCause(); - } - return new Status(IStatus.ERROR, SecurityAdminPlugin.PLUGIN_ID, - "Cannot perform updates.", originalCause); - } finally { - JcrUtils.logoutQuietly(currSession); - } - return Status.OK_STATUS; - } - } - - // ////////////////////// - // Pages definition - /** Displays a combo box that enables user to choose which action to perform */ - private class ChooseCommandWizardPage extends WizardPage { - private static final long serialVersionUID = 1L; - - private Combo chooseCommandCmb; - private Button trueChk; - private Text valueTxt; - private Text pwdTxt; - private Text pwd2Txt; - - public ChooseCommandWizardPage() { - super("Choose a command to run."); - setTitle("Choose a command to run."); - } - - @Override - public void createControl(Composite parent) { - GridLayout gl = new GridLayout(); - Composite container = new Composite(parent, SWT.NO_FOCUS); - container.setLayout(gl); - - chooseCommandCmb = new Combo(container, SWT.NO_FOCUS); - String[] values = commands.keySet().toArray( - new String[commands.size()]); - chooseCommandCmb.setItems(values); - chooseCommandCmb.setLayoutData(new GridData(SWT.FILL, SWT.TOP, - true, false)); - - final Composite bottomPart = new Composite(container, SWT.NO_FOCUS); - gl = new GridLayout(); - gl.horizontalSpacing = gl.marginWidth = gl.verticalSpacing = 0; - bottomPart.setLayout(gl); - bottomPart.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, - true)); - - chooseCommandCmb.addSelectionListener(new SelectionListener() { - private static final long serialVersionUID = 1L; - - @Override - public void widgetSelected(SelectionEvent e) { - if (getCommand().equals(CMD_UPDATE_PASSWORD)) - populatePasswordCmp(bottomPart); - else if (getCommand().equals(CMD_GROUP_MEMBERSHIP)) - populateGroupCmp(bottomPart); - else - populateBooleanFlagCmp(bottomPart); - bottomPart.pack(true); - bottomPart.layout(); - } - - @Override - public void widgetDefaultSelected(SelectionEvent e) { - } - }); - - setControl(container); - } - - private void cleanParent(Composite parent) { - if (parent.getChildren().length > 0) { - for (Control control : parent.getChildren()) - control.dispose(); - } - } - - private void populateBooleanFlagCmp(Composite parent) { - cleanParent(parent); - trueChk = new Button(parent, SWT.CHECK); - trueChk.setText("Do it. (It will to the contrary if unchecked)"); - trueChk.setSelection(true); - trueChk.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false)); - } - - private void populatePasswordCmp(Composite parent) { - cleanParent(parent); - Composite body = new Composite(parent, SWT.NO_FOCUS); - body.setLayout(new GridLayout(2, false)); - body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - pwdTxt = createLP(body, "New password", ""); - pwd2Txt = createLP(body, "Repeat password", ""); - } - - /** Creates label and password. */ - protected Text createLP(Composite body, String label, String value) { - Label lbl = new Label(body, SWT.NONE); - lbl.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false)); - lbl.setText(label); - Text text = new Text(body, SWT.BORDER | SWT.PASSWORD); - text.setText(value); - text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); - return text; - } - - private void populateGroupCmp(Composite parent) { - if (parent.getChildren().length > 0) { - for (Control control : parent.getChildren()) - control.dispose(); - } - trueChk = new Button(parent, SWT.CHECK); - trueChk.setText("Add to group. (It will remove user(s) from the " - + "corresponding group if unchecked)"); - trueChk.setSelection(true); - trueChk.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false)); - } - - protected String getCommand() { - return commands.get(chooseCommandCmb.getItem(chooseCommandCmb - .getSelectionIndex())); - } - - protected String getCommandLbl() { - return chooseCommandCmb.getItem(chooseCommandCmb - .getSelectionIndex()); - } - - protected boolean getBoleanValue() { - // FIXME this is not consistent and will lead to errors. - if (ArgeoNames.ARGEO_ENABLED.equals(getCommand())) - return trueChk.getSelection(); - else - return !trueChk.getSelection(); - } - - @SuppressWarnings("unused") - protected String getStringValue() { - String value = null; - if (valueTxt != null) { - value = valueTxt.getText(); - if ("".equals(value.trim())) - value = null; - } - return value; - } - - protected String getPwdValue() { - String newPwd = null; - if (pwdTxt == null || pwd2Txt == null) - return null; - if (!pwdTxt.getText().equals("") || !pwd2Txt.getText().equals("")) { - if (pwdTxt.getText().equals(pwd2Txt.getText())) { - newPwd = pwdTxt.getText(); - pwdTxt.setText(""); - pwd2Txt.setText(""); - } else { - pwdTxt.setText(""); - pwd2Txt.setText(""); - throw new ArgeoException("Passwords are not equals"); - } - } - return newPwd; - } - } - - /** - * Displays a list of users with a check box to be able to choose some of - * them - */ - private class ChooseUsersWizardPage extends WizardPage implements - IPageChangedListener { - private static final long serialVersionUID = 1L; - private UserTableComposite userTableCmp; - private Composite container; - private Session session; - - public ChooseUsersWizardPage(Session session) { - super("Choose Users"); - this.session = session; - setTitle("Select users who will be impacted"); - } - - @Override - public void createControl(Composite parent) { - container = new Composite(parent, SWT.NONE); - container.setLayout(new FillLayout()); - userTableCmp = new MyUserTableCmp(container, SWT.NO_FOCUS, session); - userTableCmp.populate(true, true); - setControl(container); - - // Add listener to update message when shown - final IWizardContainer container = this.getContainer(); - if (container instanceof IPageChangeProvider) { - ((IPageChangeProvider) container).addPageChangedListener(this); - } - - } - - @Override - public void pageChanged(PageChangedEvent event) { - if (event.getSelectedPage() == this) { - String msg = "Chosen batch action: " - + chooseCommandPage.getCommandLbl(); - ((WizardPage) event.getSelectedPage()).setMessage(msg); - } - } - - protected List getSelectedUsers() { - return userTableCmp.getSelectedUsers(); - } - - private class MyUserTableCmp extends UserTableComposite { - - private static final long serialVersionUID = 1L; - - public MyUserTableCmp(Composite parent, int style, Session session) { - super(parent, style, session); - } - - @Override - protected void refreshFilteredList() { - List nodes = new ArrayList(); - try { - NodeIterator ni = listFilteredElements(session, - getFilterString()); - - users: while (ni.hasNext()) { - Node currNode = ni.nextNode(); - String username = currNode.hasProperty(ARGEO_USER_ID) ? currNode - .getProperty(ARGEO_USER_ID).getString() : ""; - if (username.equals(session.getUserID())) - continue users; - else - nodes.add(currNode); - } - getTableViewer().setInput(nodes.toArray()); - } catch (RepositoryException e) { - throw new ArgeoException("Unable to list users", e); - } - } - } - } - - /** - * Recapitulation of input data before running real update - */ - private class ValidateAndLaunchWizardPage extends WizardPage implements - IPageChangedListener { - private static final long serialVersionUID = 1L; - private UserTableComposite userTableCmp; - private Session session; - - public ValidateAndLaunchWizardPage(Session session) { - super("Validate and launch"); - this.session = session; - setTitle("Validate and launch"); - } - - @Override - public void createControl(Composite parent) { - Composite mainCmp = new Composite(parent, SWT.NO_FOCUS); - mainCmp.setLayout(new FillLayout()); - - // Add listener to update user list when shown - final IWizardContainer container = this.getContainer(); - if (container instanceof IPageChangeProvider) { - ((IPageChangeProvider) container).addPageChangedListener(this); - } - - userTableCmp = new UserTableComposite(mainCmp, SWT.NO_FOCUS, - session); - userTableCmp.populate(false, false); - setControl(mainCmp); - } - - @Override - public void pageChanged(PageChangedEvent event) { - if (event.getSelectedPage() == this) { - @SuppressWarnings({ "unchecked", "rawtypes" }) - Object[] values = ((ArrayList) userListPage.getSelectedUsers()) - .toArray(new Object[userListPage.getSelectedUsers() - .size()]); - userTableCmp.getTableViewer().setInput(values); - String msg = "Following batch action: [" - + chooseCommandPage.getCommandLbl() - + "] will be perfomed on the users listed below.\n" - + "Are you sure you want to proceed?"; - ((WizardPage) event.getSelectedPage()).setMessage(msg); - } - } - - // private class MyUserTableCmp extends UserTableComposite { - // public MyUserTableCmp(Composite parent, int style, Session session) { - // super(parent, style, session); - // } - // - // @Override - // protected void refreshFilteredList() { - // @SuppressWarnings({ "unchecked", "rawtypes" }) - // - // setFilteredList(values); - // } - // - // @Override - // public void setVisible(boolean visible) { - // super.setVisible(visible); - // if (visible) - // refreshFilteredList(); - // } - // } - } -} \ No newline at end of file diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/SecurityAdminImages.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/SecurityAdminImages.java new file mode 100644 index 000000000..f7ffa9c8d --- /dev/null +++ b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/SecurityAdminImages.java @@ -0,0 +1,33 @@ +/* + * Argeo Connect - Data management and communications + * Copyright (C) 2012 Argeo GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + * + * Additional permission under GNU GPL version 3 section 7 + * + * If you modify this Program, or any covered work, by linking or combining it + * with software covered by the terms of the Eclipse Public License, the + * licensors of this Program grant you additional permission to convey the + * resulting work. Corresponding Source for a non-source form of such a + * combination shall include the source code for the parts of such software + * which are used as well as that of the covered work. + */ +package org.argeo.security.ui.admin; + +/** Shared icons that must be declared programmatically . */ +public class SecurityAdminImages { + @SuppressWarnings("unused") + private final static String PREFIX = "icons/"; +} diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/SecurityAdminPerspective.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/SecurityAdminPerspective.java new file mode 100644 index 000000000..c743f56bd --- /dev/null +++ b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/SecurityAdminPerspective.java @@ -0,0 +1,36 @@ +/* + * 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.security.ui.admin; + +import org.argeo.security.ui.admin.views.RolesView; +import org.argeo.security.ui.admin.views.UsersView; +import org.eclipse.ui.IFolderLayout; +import org.eclipse.ui.IPageLayout; +import org.eclipse.ui.IPerspectiveFactory; + +public class SecurityAdminPerspective implements IPerspectiveFactory { + public void createInitialLayout(IPageLayout layout) { + String editorArea = layout.getEditorArea(); + layout.setEditorAreaVisible(true); + layout.setFixed(false); + + IFolderLayout left = layout.createFolder("left", IPageLayout.LEFT, + 0.65f, editorArea); + left.addView(UsersView.ID); + left.addView(RolesView.ID); + } + +} diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/SecurityAdminPlugin.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/SecurityAdminPlugin.java new file mode 100644 index 000000000..06e9bd5b9 --- /dev/null +++ b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/SecurityAdminPlugin.java @@ -0,0 +1,47 @@ +/* + * 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.security.ui.admin; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +public class SecurityAdminPlugin extends AbstractUIPlugin { + public static final String PLUGIN_ID = "org.argeo.security.ui.admin"; //$NON-NLS-1$ + private static SecurityAdminPlugin plugin; + + public SecurityAdminPlugin() { + } + + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + } + + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + public static SecurityAdminPlugin getDefault() { + return plugin; + } + + public static ImageDescriptor getImageDescriptor(String path) { + return imageDescriptorFromPlugin(PLUGIN_ID, path); + } + +} diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/UserTableComposite.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/UserTableComposite.java new file mode 100644 index 000000000..720faded4 --- /dev/null +++ b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/UserTableComposite.java @@ -0,0 +1,367 @@ +package org.argeo.security.ui.admin; + +import java.util.ArrayList; +import java.util.List; + +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.Property; +import javax.jcr.PropertyType; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.query.QueryManager; +import javax.jcr.query.QueryResult; +import javax.jcr.query.qom.Constraint; +import javax.jcr.query.qom.Ordering; +import javax.jcr.query.qom.QueryObjectModel; +import javax.jcr.query.qom.QueryObjectModelFactory; +import javax.jcr.query.qom.Selector; +import javax.jcr.query.qom.StaticOperand; + +import org.argeo.ArgeoException; +import org.argeo.eclipse.ui.EclipseUiUtils; +import org.argeo.eclipse.ui.jcr.JcrUiUtils; +import org.argeo.eclipse.ui.jcr.lists.ColumnDefinition; +import org.argeo.eclipse.ui.jcr.lists.NodeViewerComparator; +import org.argeo.eclipse.ui.jcr.lists.SimpleJcrNodeLabelProvider; +import org.argeo.eclipse.ui.specific.EclipseUiSpecificUtils; +import org.argeo.eclipse.ui.utils.ViewerUtils; +import org.argeo.jcr.ArgeoNames; +import org.argeo.jcr.ArgeoTypes; +import org.argeo.jcr.JcrUtils; +import org.eclipse.jface.viewers.CheckboxTableViewer; +import org.eclipse.jface.viewers.ColumnLabelProvider; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.Text; + +public class UserTableComposite extends Composite implements ArgeoNames { + // private final static Log log = + // LogFactory.getLog(UserTableComposite.class); + + private static final long serialVersionUID = -7385959046279360420L; + + private TableViewer usersViewer; + private Text filterTxt; + private final static String FILTER_HELP_MSG = "Type filter criterion " + + "separated by a space"; + private Session session; + + private Font italic; + private Font bold; + + private boolean hasFilter; + private boolean hasSelectionColumn; + + // private List selectedItems = new ArrayList(); + + /** + * Overwrite to display other columns + */ + public List getColumnsDef() { + List columnDefs = new ArrayList(); + + // User ID + columnDefs.add(new ColumnDefinition(null, ARGEO_USER_ID, + PropertyType.STRING, "User ID", 100)); + // Displayed name + columnDefs.add(new ColumnDefinition(null, Property.JCR_TITLE, + PropertyType.STRING, "Name", 150)); + + // E-mail + columnDefs.add(new ColumnDefinition(null, ARGEO_PRIMARY_EMAIL, + PropertyType.STRING, "E-mail", 150)); + + // Description + columnDefs.add(new ColumnDefinition(null, Property.JCR_DESCRIPTION, + PropertyType.STRING, "Description", 200)); + + return columnDefs; + } + + public UserTableComposite(Composite parent, int style, Session session) { + super(parent, style); + this.session = session; + } + + /** + * + * @param addFilter + * choose to add a field to filter results or not + * @param addSelection + * choose to add a column to select some of the displayed results + * or not + */ + public void populate(boolean addFilter, boolean addSelection) { + // initialization + Composite parent = this; + italic = EclipseUiUtils.getItalicFont(parent); + bold = EclipseUiUtils.getBoldFont(parent); + hasFilter = addFilter; + hasSelectionColumn = addSelection; + + // Main Layout + this.setLayout(new GridLayout(1, false)); + if (hasFilter) + createFilterPart(parent); + usersViewer = createTableViewer(parent); + EclipseUiSpecificUtils.enableToolTipSupport(usersViewer); + usersViewer.setContentProvider(new UsersContentProvider()); + refreshFilteredList(); + } + + public List getSelectedUsers() { + if (hasSelectionColumn) { + Object[] elements = ((CheckboxTableViewer) usersViewer) + .getCheckedElements(); + + List result = new ArrayList(); + for (Object obj : elements) { + result.add((Node) obj); + } + return result; + } else + throw new ArgeoException("Unvalid request: no selection column " + + "has been created for the current table"); + } + + /** Returns the User table viewer, typically to add doubleclick listener */ + public TableViewer getTableViewer() { + return usersViewer; + } + + /** Returns filter String or null*/ + protected String getFilterString() { + return hasFilter ? filterTxt.getText() : null; + } + + + + private TableViewer createTableViewer(final Composite parent) { + int style = SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL; + if (hasSelectionColumn) + style = style | SWT.CHECK; + + Table table = new Table(parent, style); + table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + TableViewer viewer; + if (hasSelectionColumn) + viewer = new CheckboxTableViewer(table); + else + viewer = new TableViewer(table); + table.setLinesVisible(true); + table.setHeaderVisible(true); + + // pass a mapping between col index and property name to the comparator. + // List propertiesList = new ArrayList(); + + TableViewerColumn column; + int offset = 0; + if (hasSelectionColumn) { + offset = 1; + column = ViewerUtils.createTableViewerColumn(viewer, "", SWT.NONE, + 25); + column.setLabelProvider(new ColumnLabelProvider() { + private static final long serialVersionUID = 1L; + + @Override + public String getText(Object element) { + return null; + } + }); + SelectionAdapter selectionAdapter = new SelectionAdapter() { + private static final long serialVersionUID = 1L; + + boolean allSelected = false; + + @Override + public void widgetSelected(SelectionEvent e) { + allSelected = !allSelected; + ((CheckboxTableViewer) usersViewer) + .setAllChecked(allSelected); + } + }; + column.getColumn().addSelectionListener(selectionAdapter); + } + + // Create other columns + List colDefs = getColumnsDef(); + + NodeViewerComparator comparator = new NodeViewerComparator(); + int i = offset; + for (ColumnDefinition colDef : colDefs) { + column = ViewerUtils.createTableViewerColumn(viewer, + colDef.getHeaderLabel(), SWT.NONE, colDef.getColumnSize()); + column.setLabelProvider(new CLProvider(colDef.getPropertyName())); + column.getColumn().addSelectionListener( + JcrUiUtils.getNodeSelectionAdapter(i, + colDef.getPropertyType(), colDef.getPropertyName(), + comparator, viewer)); + i++; + } + + // IMPORTANT: initialize comparator before setting it + ColumnDefinition firstCol = colDefs.get(0); + comparator.setColumn(firstCol.getPropertyType(), + firstCol.getPropertyName()); + viewer.setComparator(comparator); + + return viewer; + } + + private class CLProvider extends SimpleJcrNodeLabelProvider { + + private static final long serialVersionUID = 1L; + + public CLProvider(String propertyName) { + super(propertyName); + } + + public String getToolTipText(Object element) { + return getText(element); + } + + @Override + public Font getFont(Object elem) { + // self + String username = getProperty(elem, ARGEO_USER_ID); + if (username.equals(session.getUserID())) + return bold; + + // disabled + try { + Node userProfile = (Node) elem; + // Node userProfile = userHome.getNode(ARGEO_PROFILE); + if (!userProfile.getProperty(ARGEO_ENABLED).getBoolean()) + return italic; + else + return null; + } catch (RepositoryException e) { + throw new ArgeoException("Cannot get font for " + username, e); + } + } + } + + @Override + public boolean setFocus() { + usersViewer.getTable().setFocus(); + return true; + } + + @Override + public void dispose() { + super.dispose(); + } + + public void refresh() { + refreshFilteredList(); + } + + private String getProperty(Object element, String name) { + try { + Node userProfile = (Node) element; + return userProfile.hasProperty(name) ? userProfile + .getProperty(name).getString() : ""; + } catch (RepositoryException e) { + throw new ArgeoException("Cannot get property " + name, e); + } + } + + private class UsersContentProvider implements IStructuredContentProvider { + private static final long serialVersionUID = 1L; + + public Object[] getElements(Object inputElement) { + return (Object[]) inputElement; + } + + public void dispose() { + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + } + } + + /* MANAGE FILTER */ + private void createFilterPart(Composite parent) { + // Text Area for the filter + filterTxt = new Text(parent, SWT.BORDER | SWT.SEARCH | SWT.ICON_SEARCH + | SWT.ICON_CANCEL); + filterTxt.setMessage(FILTER_HELP_MSG); + filterTxt.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL + | GridData.HORIZONTAL_ALIGN_FILL)); + filterTxt.addModifyListener(new ModifyListener() { + private static final long serialVersionUID = 1L; + + public void modifyText(ModifyEvent event) { + refreshFilteredList(); + } + }); + } + + /** + * Refresh the user list: caller might overwrite in order to display a + * subset of all users, typically to remove current user from the list + */ + protected void refreshFilteredList() { + List nodes; + try { + nodes = JcrUtils.nodeIteratorToList(listFilteredElements(session, + hasFilter ? filterTxt.getText() : null)); + usersViewer.setInput(nodes.toArray()); + } catch (RepositoryException e) { + throw new ArgeoException("Unable to list users", e); + } + } + + /** + * Build repository request : caller might overwrite in order to display a + * subset of all users + */ + protected NodeIterator listFilteredElements(Session session, String filter) + throws RepositoryException { + QueryManager queryManager = session.getWorkspace().getQueryManager(); + QueryObjectModelFactory factory = queryManager.getQOMFactory(); + + Selector source = factory.selector(ArgeoTypes.ARGEO_USER_PROFILE, + ArgeoTypes.ARGEO_USER_PROFILE); + + // Dynamically build constraint depending on the filter String + Constraint defaultC = null; + if (filter != null && !"".equals(filter.trim())) { + String[] strs = filter.trim().split(" "); + for (String token : strs) { + StaticOperand so = factory.literal(session.getValueFactory() + .createValue("*" + token + "*")); + Constraint currC = factory.fullTextSearch( + source.getSelectorName(), null, so); + if (defaultC == null) + defaultC = currC; + else + defaultC = factory.and(defaultC, currC); + } + } + + Ordering order = factory.ascending(factory.propertyValue( + source.getSelectorName(), ARGEO_USER_ID)); + Ordering[] orderings = { order }; + + QueryObjectModel query = factory.createQuery(source, defaultC, + orderings, null); + + QueryResult result = query.execute(); + return result.getNodes(); + } +} \ No newline at end of file diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/commands/AddRole.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/commands/AddRole.java new file mode 100644 index 000000000..a1008f699 --- /dev/null +++ b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/commands/AddRole.java @@ -0,0 +1,69 @@ +/* + * 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.security.ui.admin.commands; + +import org.argeo.ArgeoException; +import org.argeo.security.UserAdminService; +import org.argeo.security.ui.admin.editors.ArgeoUserEditor; +import org.argeo.security.ui.admin.views.RolesView; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.ui.IEditorReference; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.handlers.HandlerUtil; + +/** Add a new role. */ +public class AddRole extends AbstractHandler { + public final static String COMMAND_ID = "org.argeo.security.ui.admin.addRole"; + private UserAdminService userAdminService; + private String rolePrefix = "ROLE_"; + + public Object execute(ExecutionEvent event) throws ExecutionException { + RolesView rolesView = (RolesView) HandlerUtil + .getActiveWorkbenchWindow(event).getActivePage() + .findView(RolesView.ID); + String role = rolesView.getNewRole(); + if (role.trim().equals("")) + return null; + if (role.equals(rolesView.getAddNewRoleText())) + return null; + role = role.trim().toUpperCase(); + if (!role.startsWith(rolePrefix)) + role = rolePrefix + role; + if (userAdminService.listEditableRoles().contains(role)) + throw new ArgeoException("Role " + role + " already exists"); + userAdminService.newRole(role); + rolesView.refresh(); + + // refresh editors + IEditorReference[] refs = HandlerUtil.getActiveWorkbenchWindow(event) + .getActivePage() + .findEditors(null, ArgeoUserEditor.ID, IWorkbenchPage.MATCH_ID); + for (IEditorReference ref : refs) { + ArgeoUserEditor userEditor = (ArgeoUserEditor) ref.getEditor(false); + if (userEditor != null) { + userEditor.refresh(); + } + } + return null; + } + + public void setUserAdminService(UserAdminService userAdminService) { + this.userAdminService = userAdminService; + } + +} diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/commands/DeleteRole.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/commands/DeleteRole.java new file mode 100644 index 000000000..6cba11eb9 --- /dev/null +++ b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/commands/DeleteRole.java @@ -0,0 +1,72 @@ +/* + * 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.security.ui.admin.commands; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.argeo.security.UserAdminService; +import org.argeo.security.ui.admin.views.RolesView; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.handlers.HandlerUtil; + +/** Deletes the selected roles */ +public class DeleteRole extends AbstractHandler { + private UserAdminService userAdminService; + + @SuppressWarnings("unchecked") + public Object execute(ExecutionEvent event) throws ExecutionException { + ISelection selection = HandlerUtil.getCurrentSelection(event); + if (selection.isEmpty()) + return null; + + List toDelete = new ArrayList(); + Iterator it = ((IStructuredSelection) selection).iterator(); + while (it.hasNext()) { + toDelete.add(it.next()); + } + + if (!MessageDialog + .openQuestion( + HandlerUtil.getActiveShell(event), + "Delete Role", + "Are you sure that you want to delete " + + toDelete + + "?\n" + + "This may lead to inconsistencies in the application.")) + return null; + + for (String role : toDelete) { + userAdminService.deleteRole(role); + } + + RolesView view = (RolesView) HandlerUtil + .getActiveWorkbenchWindow(event).getActivePage() + .findView(RolesView.ID); + view.refresh(); + return null; + } + + public void setUserAdminService(UserAdminService userAdminService) { + this.userAdminService = userAdminService; + } +} \ No newline at end of file diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/commands/DeleteUser.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/commands/DeleteUser.java new file mode 100644 index 000000000..ccf360fd0 --- /dev/null +++ b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/commands/DeleteUser.java @@ -0,0 +1,104 @@ +/* + * 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.security.ui.admin.commands; + +import java.util.Iterator; +import java.util.Map; +import java.util.TreeMap; + +import javax.jcr.Node; +import javax.jcr.RepositoryException; +import javax.jcr.Session; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.ArgeoException; +import org.argeo.jcr.ArgeoNames; +import org.argeo.jcr.JcrUtils; +import org.argeo.security.UserAdminService; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.handlers.HandlerUtil; + +/** Deletes the selected user nodes */ +public class DeleteUser extends AbstractHandler { + private final static Log log = LogFactory.getLog(DeleteUser.class); + + private UserAdminService userAdminService; + + @SuppressWarnings("unchecked") + public Object execute(ExecutionEvent event) throws ExecutionException { + ISelection selection = HandlerUtil.getCurrentSelection(event); + if (selection.isEmpty()) + return null; + + Map toDelete = new TreeMap(); + Iterator it = ((IStructuredSelection) selection).iterator(); + nodes: while (it.hasNext()) { + Node profileNode = it.next(); + try { + String userName = profileNode.getProperty( + ArgeoNames.ARGEO_USER_ID).getString(); + if (userName.equals(profileNode.getSession().getUserID())) { + log.warn("Cannot delete its own user: " + userName); + continue nodes; + } + toDelete.put(userName, profileNode); + } catch (RepositoryException e) { + log.warn("Cannot interpred user " + profileNode); + } + } + + if (!MessageDialog + .openQuestion( + HandlerUtil.getActiveShell(event), + "Delete User", + "Are you sure that you want to delete users " + + toDelete.keySet() + + "?\n" + + "This may lead to inconsistencies in the application.")) + return null; + + for (String username : toDelete.keySet()) { + Session session = null; + try { + Node profileNode = toDelete.get(username); + userAdminService.deleteUser(username); + profileNode.getParent().remove(); + session = profileNode.getSession(); + session.save(); + } catch (RepositoryException e) { + JcrUtils.discardQuietly(session); + throw new ArgeoException("Cannot list users", e); + } + } + + userAdminService.synchronize(); + // UsersView view = (UsersView) HandlerUtil + // .getActiveWorkbenchWindow(event).getActivePage() + // .findView(UsersView.ID); + // view.refresh(); + return null; + } + + public void setUserAdminService(UserAdminService userAdminService) { + this.userAdminService = userAdminService; + } +} \ No newline at end of file diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/commands/NewUser.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/commands/NewUser.java new file mode 100644 index 000000000..660896de8 --- /dev/null +++ b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/commands/NewUser.java @@ -0,0 +1,66 @@ +/* + * 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.security.ui.admin.commands; + +import javax.jcr.Repository; +import javax.jcr.Session; + +import org.argeo.jcr.JcrUtils; +import org.argeo.security.UserAdminService; +import org.argeo.security.jcr.JcrSecurityModel; +import org.argeo.security.ui.admin.wizards.NewUserWizard; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.wizard.WizardDialog; +import org.eclipse.ui.handlers.HandlerUtil; + +/** Launch a wizard that enables creation of a new user. */ +public class NewUser extends AbstractHandler { + private Repository repository; + private UserAdminService userAdminService; + private JcrSecurityModel jcrSecurityModel; + + public Object execute(ExecutionEvent event) throws ExecutionException { + Session session = null; + try { + session = repository.login(); + NewUserWizard newUserWizard = new NewUserWizard(session, + userAdminService, jcrSecurityModel); + WizardDialog dialog = new WizardDialog( + HandlerUtil.getActiveShell(event), newUserWizard); + dialog.open(); + } catch (Exception e) { + throw new ExecutionException("Cannot open wizard", e); + } finally { + JcrUtils.logoutQuietly(session); + } + return null; + } + + public void setRepository(Repository repository) { + this.repository = repository; + } + + public void setUserAdminService(UserAdminService userAdminService) { + this.userAdminService = userAdminService; + } + + public void setJcrSecurityModel(JcrSecurityModel jcrSecurityModel) { + this.jcrSecurityModel = jcrSecurityModel; + } + +} diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/commands/OpenArgeoUserEditor.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/commands/OpenArgeoUserEditor.java new file mode 100644 index 000000000..bae928c22 --- /dev/null +++ b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/commands/OpenArgeoUserEditor.java @@ -0,0 +1,43 @@ +/* + * 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.security.ui.admin.commands; + +import org.argeo.security.ui.admin.editors.ArgeoUserEditor; +import org.argeo.security.ui.admin.editors.ArgeoUserEditorInput; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.handlers.HandlerUtil; + +/** Command handler to set visible or open a Argeo user. */ +public class OpenArgeoUserEditor extends AbstractHandler { + public final static String COMMAND_ID = "org.argeo.security.ui.admin.openArgeoUserEditor"; + public final static String PARAM_USERNAME = "org.argeo.security.ui.admin.username"; + + public Object execute(ExecutionEvent event) throws ExecutionException { + try { + ArgeoUserEditorInput editorInput = new ArgeoUserEditorInput( + event.getParameter(PARAM_USERNAME)); + IWorkbenchPage activePage = HandlerUtil.getActiveWorkbenchWindow( + event).getActivePage(); + activePage.openEditor(editorInput, ArgeoUserEditor.ID); + } catch (Exception e) { + throw new ExecutionException("Cannot open editor", e); + } + return null; + } +} diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/commands/RefreshRoles.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/commands/RefreshRoles.java new file mode 100644 index 000000000..41c78f077 --- /dev/null +++ b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/commands/RefreshRoles.java @@ -0,0 +1,31 @@ +/* + * 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.security.ui.admin.commands; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; + +/** + * Refreshes the roles view. + */ +public class RefreshRoles extends AbstractHandler { + public Object execute(ExecutionEvent event) throws ExecutionException { + + return null; + } + +} \ No newline at end of file diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/commands/RefreshUsersList.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/commands/RefreshUsersList.java new file mode 100644 index 000000000..e4c14ab21 --- /dev/null +++ b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/commands/RefreshUsersList.java @@ -0,0 +1,100 @@ +/* + * 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.security.ui.admin.commands; + +import java.util.Set; + +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.query.Query; + +import org.argeo.ArgeoException; +import org.argeo.jcr.ArgeoNames; +import org.argeo.jcr.ArgeoTypes; +import org.argeo.jcr.JcrUtils; +import org.argeo.security.UserAdminService; +import org.argeo.security.ui.admin.views.UsersView; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * Refreshes the main user list, removing nodes which are not referenced by user + * admin service. + */ +public class RefreshUsersList extends AbstractHandler { + private UserAdminService userAdminService; + private Repository repository; + + public Object execute(ExecutionEvent event) throws ExecutionException { + Set users = userAdminService.listUsers(); + Session session = null; + try { + session = repository.login(); + Query query = session + .getWorkspace() + .getQueryManager() + .createQuery( + "select * from [" + ArgeoTypes.ARGEO_USER_HOME + + "]", Query.JCR_SQL2); + NodeIterator nit = query.execute().getNodes(); + while (nit.hasNext()) { + Node node = nit.nextNode(); + String username = node.getProperty(ArgeoNames.ARGEO_USER_ID) + .getString(); + if (!users.contains(username)) + node.remove(); + } + session.save(); + } catch (RepositoryException e) { + JcrUtils.discardQuietly(session); + throw new ArgeoException("Cannot list users", e); + } finally { + JcrUtils.logoutQuietly(session); + } + userAdminService.synchronize(); + + // FIXME try to refresh views that extend the UsersView and have another + // ID + IWorkbenchPart part = HandlerUtil.getActiveWorkbenchWindow(event) + .getActivePage().getActivePart(); + if (part instanceof UsersView) + ((UsersView) part).refresh(); + + // Try to refresh UsersView if opened + UsersView view = (UsersView) HandlerUtil + .getActiveWorkbenchWindow(event).getActivePage() + .findView(UsersView.ID); + if (view != null) + view.refresh(); + + return null; + } + + public void setUserAdminService(UserAdminService userAdminService) { + this.userAdminService = userAdminService; + } + + public void setRepository(Repository repository) { + this.repository = repository; + } + +} \ No newline at end of file diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/commands/SaveArgeoUser.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/commands/SaveArgeoUser.java new file mode 100644 index 000000000..bd16f8bcf --- /dev/null +++ b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/commands/SaveArgeoUser.java @@ -0,0 +1,47 @@ +/* + * 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.security.ui.admin.commands; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.handlers.HandlerUtil; + +/** Save the currently edited Argeo user. */ +public class SaveArgeoUser extends AbstractHandler { + public final static String COMMAND_ID = "org.argeo.security.ui.admin.saveArgeoUser"; + + public Object execute(ExecutionEvent event) throws ExecutionException { + try { + IWorkbenchPart iwp = HandlerUtil.getActiveWorkbenchWindow(event) + .getActivePage().getActivePart(); + + if (!(iwp instanceof IEditorPart)) + return null; + IEditorPart editor = (IEditorPart) iwp; + editor.doSave(null); + } catch (Exception e) { + MessageDialog.openError(Display.getDefault().getActiveShell(), + "Error", "Cannot save user: " + e.getMessage()); + } + return null; + } + +} diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/commands/UserBatchUpdate.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/commands/UserBatchUpdate.java new file mode 100644 index 000000000..657dfc70a --- /dev/null +++ b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/commands/UserBatchUpdate.java @@ -0,0 +1,66 @@ +/* + * 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.security.ui.admin.commands; + +import javax.jcr.Repository; +import javax.jcr.Session; + +import org.argeo.jcr.JcrUtils; +import org.argeo.security.UserAdminService; +import org.argeo.security.jcr.JcrSecurityModel; +import org.argeo.security.ui.admin.wizards.UserBatchUpdateWizard; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.wizard.WizardDialog; +import org.eclipse.ui.handlers.HandlerUtil; + +/** Launch a wizard to update various properties about users in JCR. */ +public class UserBatchUpdate extends AbstractHandler { + private Repository repository; + private UserAdminService userAdminService; + private JcrSecurityModel jcrSecurityModel; + + public Object execute(ExecutionEvent event) throws ExecutionException { + Session session = null; + try { + session = repository.login(); + UserBatchUpdateWizard userBatchUpdateWizard = new UserBatchUpdateWizard(session, + userAdminService, jcrSecurityModel); + WizardDialog dialog = new WizardDialog( + HandlerUtil.getActiveShell(event), userBatchUpdateWizard); + dialog.open(); + } catch (Exception e) { + throw new ExecutionException("Cannot open wizard", e); + } finally { + JcrUtils.logoutQuietly(session); + } + return null; + } + + public void setRepository(Repository repository) { + this.repository = repository; + } + + public void setUserAdminService(UserAdminService userAdminService) { + this.userAdminService = userAdminService; + } + + public void setJcrSecurityModel(JcrSecurityModel jcrSecurityModel) { + this.jcrSecurityModel = jcrSecurityModel; + } + +} diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/editors/ArgeoUserEditor.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/editors/ArgeoUserEditor.java new file mode 100644 index 000000000..ebc08319e --- /dev/null +++ b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/editors/ArgeoUserEditor.java @@ -0,0 +1,158 @@ +/* + * 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.security.ui.admin.editors; + +import javax.jcr.Node; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.Session; + +import org.argeo.ArgeoException; +import org.argeo.jcr.JcrUtils; +import org.argeo.jcr.UserJcrUtils; +import org.argeo.security.UserAdminService; +import org.argeo.security.jcr.JcrUserDetails; +import org.argeo.security.ui.admin.SecurityAdminPlugin; +import org.argeo.security.ui.admin.views.UsersView; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorSite; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.forms.editor.FormEditor; +import org.springframework.security.GrantedAuthority; + +/** Editor for an Argeo user. */ +public class ArgeoUserEditor extends FormEditor { + public final static String ID = SecurityAdminPlugin.PLUGIN_ID + + ".adminArgeoUserEditor"; + + /* DEPENDENCY INJECTION */ + private Session session; + private UserAdminService userAdminService; + + // private Node userHome; + private Node userProfile; + private JcrUserDetails userDetails; + + public void init(IEditorSite site, IEditorInput input) + throws PartInitException { + super.init(site, input); + String username = ((ArgeoUserEditorInput) getEditorInput()) + .getUsername(); + userProfile = UserJcrUtils.getUserProfile(session, username); + + if (userAdminService.userExists(username)) { + userDetails = (JcrUserDetails) userAdminService + .loadUserByUsername(username); + } else { + GrantedAuthority[] authorities = {}; + try { + userDetails = new JcrUserDetails(session, username, null, + authorities); + } catch (RepositoryException e) { + throw new ArgeoException("Cannot retrieve disabled JCR profile"); + } + } + + this.setPartProperty("name", username != null ? username : ""); + setPartName(username != null ? username : ""); + } + + protected void addPages() { + try { + addPage(new DefaultUserMainPage(this, userProfile)); + addPage(new UserRolesPage(this, userDetails, userAdminService)); + } catch (Exception e) { + throw new ArgeoException("Cannot add pages", e); + } + } + + @Override + public void doSave(IProgressMonitor monitor) { + // list pages + // TODO: make it more generic + DefaultUserMainPage defaultUserMainPage = (DefaultUserMainPage) findPage(DefaultUserMainPage.ID); + if (defaultUserMainPage.isDirty()) { + defaultUserMainPage.doSave(monitor); + String newPassword = defaultUserMainPage.getNewPassword(); + defaultUserMainPage.resetNewPassword(); + if (newPassword != null) + userDetails = userDetails.cloneWithNewPassword(newPassword); + } + + UserRolesPage userRolesPage = (UserRolesPage) findPage(UserRolesPage.ID); + if (userRolesPage.isDirty()) { + userRolesPage.doSave(monitor); + userDetails = userDetails.cloneWithNewRoles(userRolesPage + .getRoles()); + } + + userAdminService.updateUser(userDetails); + + // if (userAdminService.userExists(user.getUsername())) + // userAdminService.updateUser(user); + // else { + // userAdminService.newUser(user); + // setPartName(user.getUsername()); + // } + firePropertyChange(PROP_DIRTY); + + userRolesPage.setUserDetails(userDetails); + + // FIXME rather use a refresh command. Fails when called by another + // view. + // refresh users view + IWorkbench iw = SecurityAdminPlugin.getDefault().getWorkbench(); + UsersView usersView = (UsersView) iw.getActiveWorkbenchWindow() + .getActivePage().findView(UsersView.ID); + if (usersView != null) + usersView.refresh(); + } + + @Override + public void doSaveAs() { + } + + @Override + public boolean isSaveAsAllowed() { + return false; + } + + public void refresh() { + UserRolesPage userRolesPage = (UserRolesPage) findPage(UserRolesPage.ID); + userRolesPage.refresh(); + } + + @Override + public void dispose() { + JcrUtils.logoutQuietly(session); + super.dispose(); + } + + /* DEPENDENCY INJECTION */ + public void setUserAdminService(UserAdminService userAdminService) { + this.userAdminService = userAdminService; + } + + public void setRepository(Repository repository) { + try { + session = repository.login(); + } catch (RepositoryException re) { + throw new ArgeoException("Unable to initialise local session", re); + } + } +} diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/editors/ArgeoUserEditorInput.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/editors/ArgeoUserEditorInput.java new file mode 100644 index 000000000..9d1d99573 --- /dev/null +++ b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/editors/ArgeoUserEditorInput.java @@ -0,0 +1,65 @@ +/* + * 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.security.ui.admin.editors; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IPersistableElement; + +/** Editor input for an Argeo user. */ +public class ArgeoUserEditorInput implements IEditorInput { + private final String username; + + public ArgeoUserEditorInput(String username) { + this.username = username; + } + + public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) { + return null; + } + + public boolean exists() { + return username != null; + } + + public ImageDescriptor getImageDescriptor() { + return null; + } + + public String getName() { + return username != null ? username : ""; + } + + public IPersistableElement getPersistable() { + return null; + } + + public String getToolTipText() { + return username != null ? username : ""; + } + + public boolean equals(Object obj) { + if (!(obj instanceof ArgeoUserEditorInput)) + return false; + if (((ArgeoUserEditorInput) obj).getUsername() == null) + return false; + return ((ArgeoUserEditorInput) obj).getUsername().equals(username); + } + + public String getUsername() { + return username; + } +} diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/editors/DefaultUserMainPage.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/editors/DefaultUserMainPage.java new file mode 100644 index 000000000..5f99e195b --- /dev/null +++ b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/editors/DefaultUserMainPage.java @@ -0,0 +1,245 @@ +/* + * 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.security.ui.admin.editors; + +import java.util.Arrays; + +import javax.jcr.Node; +import javax.jcr.Property; +import javax.jcr.RepositoryException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.ArgeoException; +import org.argeo.jcr.ArgeoNames; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.forms.AbstractFormPart; +import org.eclipse.ui.forms.IManagedForm; +import org.eclipse.ui.forms.SectionPart; +import org.eclipse.ui.forms.editor.FormEditor; +import org.eclipse.ui.forms.editor.FormPage; +import org.eclipse.ui.forms.widgets.FormToolkit; +import org.eclipse.ui.forms.widgets.ScrolledForm; +import org.eclipse.ui.forms.widgets.Section; + +/** + * Display/edit the properties common to all Argeo users + */ +public class DefaultUserMainPage extends FormPage implements ArgeoNames { + final static String ID = "argeoUserEditor.mainPage"; + + private final static Log log = LogFactory.getLog(DefaultUserMainPage.class); + private Node userProfile; + + private char[] newPassword; + + public DefaultUserMainPage(FormEditor editor, Node userProfile) { + super(editor, ID, "Main"); + this.userProfile = userProfile; + } + + protected void createFormContent(final IManagedForm mf) { + try { + ScrolledForm form = mf.getForm(); + refreshFormTitle(form); + GridLayout mainLayout = new GridLayout(1, true); + form.getBody().setLayout(mainLayout); + + createGeneralPart(form.getBody()); + createPassworPart(form.getBody()); + } catch (RepositoryException e) { + throw new ArgeoException("Cannot create form content", e); + } + } + + /** Creates the general section */ + protected void createGeneralPart(Composite parent) + throws RepositoryException { + FormToolkit tk = getManagedForm().getToolkit(); + Section section = tk.createSection(parent, Section.TITLE_BAR); + section.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + section.setText("General"); + Composite body = tk.createComposite(section, SWT.WRAP); + section.setClient(body); + GridLayout layout = new GridLayout(2, false); + body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + body.setLayout(layout); + + final Text commonName = createLT(body, "Displayed Name", + getProperty(Property.JCR_TITLE)); + final Text firstName = createLT(body, "First name", + getProperty(ARGEO_FIRST_NAME)); + final Text lastName = createLT(body, "Last name", + getProperty(ARGEO_LAST_NAME)); + final Text email = createLT(body, "Email", + getProperty(ARGEO_PRIMARY_EMAIL)); + final Text description = createLMT(body, "Description", + getProperty(Property.JCR_DESCRIPTION)); + + // create form part (controller) + AbstractFormPart part = new SectionPart(section) { + public void commit(boolean onSave) { + try { + userProfile.getSession().getWorkspace().getVersionManager() + .checkout(userProfile.getPath()); + userProfile.setProperty(Property.JCR_TITLE, + commonName.getText()); + userProfile.setProperty(ARGEO_FIRST_NAME, + firstName.getText()); + userProfile + .setProperty(ARGEO_LAST_NAME, lastName.getText()); + userProfile.setProperty(ARGEO_PRIMARY_EMAIL, + email.getText()); + userProfile.setProperty(Property.JCR_DESCRIPTION, + description.getText()); + userProfile.getSession().save(); + userProfile.getSession().getWorkspace().getVersionManager() + .checkin(userProfile.getPath()); + super.commit(onSave); + refreshFormTitle(getManagedForm().getForm()); + if (log.isTraceEnabled()) + log.trace("General part committed"); + } catch (RepositoryException e) { + throw new ArgeoException("Cannot commit", e); + } + } + }; + // if (username != null) + // username.addModifyListener(new FormPartML(part)); + commonName.addModifyListener(new FormPartML(part)); + firstName.addModifyListener(new FormPartML(part)); + lastName.addModifyListener(new FormPartML(part)); + email.addModifyListener(new FormPartML(part)); + description.addModifyListener(new FormPartML(part)); + getManagedForm().addPart(part); + } + + private void refreshFormTitle(ScrolledForm form) throws RepositoryException { + form.setText(getProperty(Property.JCR_TITLE) + + (userProfile.getProperty(ARGEO_ENABLED).getBoolean() ? "" + : " [DISABLED]")); + } + + /** @return the property, or the empty string if not set */ + protected String getProperty(String name) throws RepositoryException { + return userProfile.hasProperty(name) ? userProfile.getProperty(name) + .getString() : ""; + } + + /** Creates the password section */ + protected void createPassworPart(Composite parent) { + FormToolkit tk = getManagedForm().getToolkit(); + Section section = tk.createSection(parent, Section.TITLE_BAR); + section.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + section.setText("Password"); + + Composite body = tk.createComposite(section, SWT.WRAP); + section.setClient(body); + GridLayout layout = new GridLayout(2, false); + body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + body.setLayout(layout); + + // add widgets (view) + final Text password1 = createLP(body, "New password", ""); + final Text password2 = createLP(body, "Repeat password", ""); + // create form part (controller) + AbstractFormPart part = new SectionPart(section) { + + public void commit(boolean onSave) { + if (!password1.getText().equals("") + || !password2.getText().equals("")) { + if (password1.getText().equals(password2.getText())) { + newPassword = password1.getText().toCharArray(); + password1.setText(""); + password2.setText(""); + super.commit(onSave); + } else { + password1.setText(""); + password2.setText(""); + throw new ArgeoException("Passwords are not equals"); + } + } + } + + }; + password1.addModifyListener(new FormPartML(part)); + password2.addModifyListener(new FormPartML(part)); + getManagedForm().addPart(part); + } + + /** Creates label and text. */ + protected Text createLT(Composite body, String label, String value) { + FormToolkit toolkit = getManagedForm().getToolkit(); + Label lbl = toolkit.createLabel(body, label); + lbl.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false)); + Text text = toolkit.createText(body, value, SWT.BORDER); + text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + return text; + } + + /** Creates label and multiline text. */ + protected Text createLMT(Composite body, String label, String value) { + FormToolkit toolkit = getManagedForm().getToolkit(); + Label lbl = toolkit.createLabel(body, label); + lbl.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false)); + Text text = toolkit.createText(body, value, SWT.BORDER | SWT.MULTI); + text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true)); + return text; + } + + /** Creates label and password. */ + protected Text createLP(Composite body, String label, String value) { + FormToolkit toolkit = getManagedForm().getToolkit(); + Label lbl = toolkit.createLabel(body, label); + lbl.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false)); + Text text = toolkit.createText(body, value, SWT.BORDER | SWT.PASSWORD); + text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + return text; + } + + private class FormPartML implements ModifyListener { + private AbstractFormPart formPart; + + public FormPartML(AbstractFormPart generalPart) { + this.formPart = generalPart; + } + + public void modifyText(ModifyEvent e) { + formPart.markDirty(); + } + + } + + public String getNewPassword() { + if (newPassword != null) + return new String(newPassword); + else + return null; + } + + public void resetNewPassword() { + if (newPassword != null) + Arrays.fill(newPassword, 'x'); + newPassword = null; + } +} diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/editors/UserRolesPage.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/editors/UserRolesPage.java new file mode 100644 index 000000000..08cd457ad --- /dev/null +++ b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/editors/UserRolesPage.java @@ -0,0 +1,225 @@ +/* + * 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.security.ui.admin.editors; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.jcr.ArgeoNames; +import org.argeo.security.UserAdminService; +import org.argeo.security.ui.admin.SecurityAdminPlugin; +import org.eclipse.jface.viewers.CellEditor; +import org.eclipse.jface.viewers.CheckboxCellEditor; +import org.eclipse.jface.viewers.ColumnLabelProvider; +import org.eclipse.jface.viewers.EditingSupport; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.ui.forms.AbstractFormPart; +import org.eclipse.ui.forms.IManagedForm; +import org.eclipse.ui.forms.editor.FormEditor; +import org.eclipse.ui.forms.editor.FormPage; +import org.eclipse.ui.forms.widgets.ScrolledForm; +import org.springframework.security.GrantedAuthority; +import org.springframework.security.userdetails.UserDetails; + +/** + * Display/edit the roles of a user. + */ +public class UserRolesPage extends FormPage implements ArgeoNames { + final static String ID = "argeoUserEditor.rolesPage"; + + private final static Log log = LogFactory.getLog(UserRolesPage.class); + private final static Image ROLE_CHECKED = SecurityAdminPlugin + .getImageDescriptor("icons/security.gif").createImage(); + + private TableViewer rolesViewer; + private UserAdminService userAdminService; + private List roles; + + public UserRolesPage(FormEditor editor, UserDetails userDetails, + UserAdminService userAdminService) { + super(editor, ID, "Roles"); + setUserDetails(userDetails); + this.userAdminService = userAdminService; + } + + public void setUserDetails(UserDetails userDetails) { + this.roles = new ArrayList(); + for (GrantedAuthority ga : userDetails.getAuthorities()) + roles.add(ga.getAuthority()); + if (rolesViewer != null) + rolesViewer.refresh(); + } + + protected void createFormContent(final IManagedForm mf) { + ScrolledForm form = mf.getForm(); + form.setText("Roles"); + FillLayout mainLayout = new FillLayout(); + // ColumnLayout mainLayout = new ColumnLayout(); + // mainLayout.minNumColumns = 1; + // mainLayout.maxNumColumns = 4; + // mainLayout.topMargin = 0; + // mainLayout.bottomMargin = 5; + // mainLayout.leftMargin = mainLayout.rightMargin = + // mainLayout.horizontalSpacing = mainLayout.verticalSpacing = 10; + form.getBody().setLayout(mainLayout); + createRolesPart(form.getBody()); + } + + /** Creates the role section */ + protected void createRolesPart(Composite parent) { + Table table = new Table(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); + + AbstractFormPart part = new AbstractFormPart() { + public void commit(boolean onSave) { + // roles have already been modified in editing + super.commit(onSave); + if (log.isTraceEnabled()) + log.trace("Role part committed"); + } + }; + getManagedForm().addPart(part); + + // GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true); + // gridData.verticalSpan = 20; + // table.setLayoutData(gridData); + table.setLinesVisible(true); + table.setHeaderVisible(false); + rolesViewer = new TableViewer(table); + + // check column + TableViewerColumn column = createTableViewerColumn(rolesViewer, + "checked", 20); + column.setLabelProvider(new ColumnLabelProvider() { + public String getText(Object element) { + return null; + } + + public Image getImage(Object element) { + String role = element.toString(); + if (roles.contains(role)) { + return ROLE_CHECKED; + } else { + return null; + } + } + }); + column.setEditingSupport(new RoleEditingSupport(rolesViewer, part)); + + // role column + column = createTableViewerColumn(rolesViewer, "Role", 200); + column.setLabelProvider(new ColumnLabelProvider() { + public String getText(Object element) { + return element.toString(); + } + + public Image getImage(Object element) { + return null; + } + }); + rolesViewer.setContentProvider(new RolesContentProvider()); + rolesViewer.setInput(getEditorSite()); + } + + protected TableViewerColumn createTableViewerColumn(TableViewer viewer, + String title, int bound) { + final TableViewerColumn viewerColumn = new TableViewerColumn(viewer, + SWT.NONE); + final TableColumn column = viewerColumn.getColumn(); + column.setText(title); + column.setWidth(bound); + column.setResizable(true); + column.setMoveable(true); + return viewerColumn; + + } + + public List getRoles() { + return roles; + } + + public void refresh() { + rolesViewer.refresh(); + } + + private class RolesContentProvider implements IStructuredContentProvider { + public Object[] getElements(Object inputElement) { + return userAdminService.listEditableRoles().toArray(); + } + + public void dispose() { + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + } + } + + /** Select the columns by editing the checkbox in the first column */ + class RoleEditingSupport extends EditingSupport { + + private final TableViewer viewer; + private final AbstractFormPart formPart; + + public RoleEditingSupport(TableViewer viewer, AbstractFormPart formPart) { + super(viewer); + this.viewer = viewer; + this.formPart = formPart; + } + + @Override + protected CellEditor getCellEditor(Object element) { + return new CheckboxCellEditor(null, SWT.CHECK | SWT.READ_ONLY); + + } + + @Override + protected boolean canEdit(Object element) { + return true; + } + + @Override + protected Object getValue(Object element) { + String role = element.toString(); + return roles.contains(role); + + } + + @Override + protected void setValue(Object element, Object value) { + Boolean inRole = (Boolean) value; + String role = element.toString(); + if (inRole && !roles.contains(role)) { + roles.add(role); + formPart.markDirty(); + } else if (!inRole && roles.contains(role)) { + roles.remove(role); + formPart.markDirty(); + } + viewer.refresh(); + } + } + +} diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/views/RolesView.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/views/RolesView.java new file mode 100644 index 000000000..fbe7dd570 --- /dev/null +++ b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/views/RolesView.java @@ -0,0 +1,140 @@ +/* + * 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.security.ui.admin.views; + +import org.argeo.ArgeoException; +import org.argeo.security.UserAdminService; +import org.argeo.security.ui.admin.SecurityAdminPlugin; +import org.argeo.security.ui.admin.commands.AddRole; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.handlers.IHandlerService; +import org.eclipse.ui.part.ViewPart; + +/** List all roles. */ +public class RolesView extends ViewPart { + public final static String ID = SecurityAdminPlugin.PLUGIN_ID + + ".adminRolesView"; + + private Text newRole; + + private TableViewer viewer; + private UserAdminService userAdminService; + + private String addNewRoleText = ""; + + @Override + public void createPartControl(Composite parent) { + parent.setLayout(new GridLayout(1, false)); + + // new role text field + newRole = new Text(parent, SWT.BORDER); + newRole.setText(addNewRoleText); + newRole.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + // default action is add role + newRole.addListener(SWT.DefaultSelection, new Listener() { + public void handleEvent(Event evt) { + IWorkbench iw = SecurityAdminPlugin.getDefault().getWorkbench(); + IHandlerService handlerService = (IHandlerService) iw + .getService(IHandlerService.class); + try { + handlerService.executeCommand(AddRole.COMMAND_ID, evt); + } catch (Exception e) { + throw new ArgeoException("Cannot execute add role command", + e); + } + } + }); + // select all on focus + newRole.addListener(SWT.FocusIn, new Listener() { + public void handleEvent(Event e) { + newRole.selectAll(); + } + }); + + // roles table + Table table = new Table(parent, SWT.V_SCROLL | SWT.BORDER); + table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + table.setLinesVisible(false); + table.setHeaderVisible(false); + viewer = new TableViewer(table); + viewer.setContentProvider(new RolesContentProvider()); + viewer.setLabelProvider(new UsersLabelProvider()); + getViewSite().setSelectionProvider(viewer); + viewer.setInput(getViewSite()); + } + + @Override + public void setFocus() { + viewer.getTable().setFocus(); + } + + public void setUserAdminService(UserAdminService userAdminService) { + this.userAdminService = userAdminService; + } + + public String getAddNewRoleText() { + return addNewRoleText; + } + + private class RolesContentProvider implements IStructuredContentProvider { + + public Object[] getElements(Object inputElement) { + return userAdminService.listEditableRoles().toArray(); + } + + public void dispose() { + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + } + + } + + private class UsersLabelProvider extends LabelProvider implements + ITableLabelProvider { + public String getColumnText(Object element, int columnIndex) { + return element.toString(); + } + + public Image getColumnImage(Object element, int columnIndex) { + return null; + } + + } + + public String getNewRole() { + return newRole.getText(); + } + + public void refresh() { + viewer.refresh(); + newRole.setText(addNewRoleText); + } +} diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/views/UsersView.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/views/UsersView.java new file mode 100644 index 000000000..a7437156d --- /dev/null +++ b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/views/UsersView.java @@ -0,0 +1,158 @@ +/* + * 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.security.ui.admin.views; + +import javax.jcr.Node; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.observation.Event; +import javax.jcr.observation.EventIterator; +import javax.jcr.observation.EventListener; + +import org.argeo.ArgeoException; +import org.argeo.eclipse.ui.utils.CommandUtils; +import org.argeo.jcr.ArgeoJcrConstants; +import org.argeo.jcr.ArgeoNames; +import org.argeo.jcr.ArgeoTypes; +import org.argeo.jcr.JcrUtils; +import org.argeo.security.ui.admin.SecurityAdminPlugin; +import org.argeo.security.ui.admin.UserTableComposite; +import org.argeo.security.ui.admin.commands.OpenArgeoUserEditor; +import org.eclipse.jface.viewers.DoubleClickEvent; +import org.eclipse.jface.viewers.IDoubleClickListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.part.ViewPart; + +/** List all users with filter. */ +public class UsersView extends ViewPart implements ArgeoNames { + public final static String ID = SecurityAdminPlugin.PLUGIN_ID + + ".adminUsersView"; + + /* DEPENDENCY INJECTION */ + private Session session; + + private UserTableComposite userTableCmp; + private JcrUserListener userStructureListener; + private JcrUserListener userPropertiesListener; + + @Override + public void createPartControl(Composite parent) { + parent.setLayout(new FillLayout()); + + // Create the composite that displays the list and a filter + userTableCmp = new UserTableComposite(parent, SWT.NO_FOCUS, session); + userTableCmp.populate(true, false); + + // Configure + userTableCmp.getTableViewer().addDoubleClickListener( + new ViewDoubleClickListener()); + getViewSite().setSelectionProvider(userTableCmp.getTableViewer()); + + // Add listener to refresh the list when something changes + userStructureListener = new JcrUserListener(getSite().getShell() + .getDisplay()); + JcrUtils.addListener(session, userStructureListener, Event.NODE_ADDED + | Event.NODE_REMOVED, ArgeoJcrConstants.PEOPLE_BASE_PATH, null); + userPropertiesListener = new JcrUserListener(getSite().getShell() + .getDisplay()); + JcrUtils.addListener(session, userStructureListener, + Event.PROPERTY_CHANGED | Event.PROPERTY_ADDED + | Event.PROPERTY_REMOVED, + ArgeoJcrConstants.PEOPLE_BASE_PATH, + ArgeoTypes.ARGEO_USER_PROFILE); + } + + @Override + public void setFocus() { + userTableCmp.setFocus(); + } + + @Override + public void dispose() { + JcrUtils.removeListenerQuietly(session, userStructureListener); + JcrUtils.removeListenerQuietly(session, userPropertiesListener); + JcrUtils.logoutQuietly(session); + super.dispose(); + } + + // public void setSession(Session session) { + // this.session = session; + // } + + public void refresh() { + this.getSite().getShell().getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + userTableCmp.refresh(); + } + }); + } + + private class JcrUserListener implements EventListener { + private final Display display; + + public JcrUserListener(Display display) { + super(); + this.display = display; + } + + @Override + public void onEvent(EventIterator events) { + display.asyncExec(new Runnable() { + @Override + public void run() { + userTableCmp.refresh(); + } + }); + } + } + + class ViewDoubleClickListener implements IDoubleClickListener { + public void doubleClick(DoubleClickEvent evt) { + if (evt.getSelection().isEmpty()) + return; + + Object obj = ((IStructuredSelection) evt.getSelection()) + .getFirstElement(); + if (obj instanceof Node) { + try { + String username = ((Node) obj).getProperty(ARGEO_USER_ID) + .getString(); + String commandId = OpenArgeoUserEditor.COMMAND_ID; + String paramName = OpenArgeoUserEditor.PARAM_USERNAME; + CommandUtils.callCommand(commandId, paramName, username); + } catch (RepositoryException e) { + throw new ArgeoException("Cannot open user editor", e); + } + } + } + } + + /* DEPENDENCY INJECTION */ + public void setRepository(Repository repository) { + try { + session = repository.login(); + } catch (RepositoryException re) { + throw new ArgeoException("Unable to initialise local session", re); + } + } + +} \ No newline at end of file diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/wizards/MainUserInfoWizardPage.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/wizards/MainUserInfoWizardPage.java new file mode 100644 index 000000000..ad3662b6f --- /dev/null +++ b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/wizards/MainUserInfoWizardPage.java @@ -0,0 +1,133 @@ +/* + * 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.security.ui.admin.wizards; + +import javax.jcr.Node; +import javax.jcr.Property; +import javax.jcr.RepositoryException; + +import org.argeo.ArgeoException; +import org.argeo.eclipse.ui.EclipseUiUtils; +import org.argeo.jcr.ArgeoNames; +import org.argeo.security.UserAdminService; +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Text; +import org.springframework.security.userdetails.UserDetails; +import org.springframework.security.userdetails.UsernameNotFoundException; + +public class MainUserInfoWizardPage extends WizardPage implements + ModifyListener, ArgeoNames { + private Text username, firstName, lastName, primaryEmail, password1, + password2; + private UserAdminService userAdminService; + + public MainUserInfoWizardPage(UserAdminService userAdminService) { + super("Main"); + this.userAdminService = userAdminService; + setTitle("Required Information"); + } + + @Override + public void createControl(Composite parent) { + Composite composite = new Composite(parent, SWT.NONE); + composite.setLayout(new GridLayout(2, false)); + username = EclipseUiUtils.createGridLT(composite, "Username", this); + primaryEmail = EclipseUiUtils.createGridLT(composite, "Email", this); + firstName = EclipseUiUtils.createGridLT(composite, "First name", this); + lastName = EclipseUiUtils.createGridLT(composite, "Last name", this); + password1 = EclipseUiUtils.createGridLP(composite, "Password", this); + password2 = EclipseUiUtils.createGridLP(composite, "Repeat password", + this); + setControl(composite); + + // Initialize buttons + setPageComplete(false); + getContainer().updateButtons(); + } + + @Override + public void modifyText(ModifyEvent event) { + String message = checkComplete(); + if (message != null) { + setMessage(message, WizardPage.ERROR); + setPageComplete(false); + } else { + setMessage("Complete", WizardPage.INFORMATION); + setPageComplete(true); + } + getContainer().updateButtons(); + } + + /** @return error message or null if complete */ + protected String checkComplete() { + // if (!username.getText().matches(UserAdminService.USERNAME_PATTERN)) + // return + // "Wrong user name format, should be lower case, between 3 and 64 characters with only '_' an '@' as acceptable special character."; + + if (username.getText().trim().equals("")) + return "User name must not be empty"; + + try { + UserDetails userDetails = userAdminService + .loadUserByUsername(username.getText()); + return "User " + userDetails.getUsername() + " already exists"; + } catch (UsernameNotFoundException e) { + // silent + } + if (!primaryEmail.getText().matches(UserAdminService.EMAIL_PATTERN)) + return "Not a valid email address"; + if (firstName.getText().trim().equals("")) + return "Specify a first name"; + if (lastName.getText().trim().equals("")) + return "Specify a last name"; + if (password1.getText().trim().equals("")) + return "Specify a password"; + if (password2.getText().trim().equals("")) + return "Repeat the password"; + if (!password2.getText().equals(password1.getText())) + return "Passwords are different"; + return null; + } + + public String getUsername() { + return username.getText(); + } + + public String getPassword() { + return password1.getText(); + } + + public void mapToProfileNode(Node up) { + try { + up.setProperty(ARGEO_PRIMARY_EMAIL, primaryEmail.getText()); + up.setProperty(ARGEO_FIRST_NAME, firstName.getText()); + up.setProperty(ARGEO_LAST_NAME, lastName.getText()); + + // derived values + // TODO add wizard pages to do it + up.setProperty(Property.JCR_TITLE, firstName.getText() + " " + + lastName.getText()); + up.setProperty(Property.JCR_DESCRIPTION, ""); + } catch (RepositoryException e) { + throw new ArgeoException("Cannot map to " + up, e); + } + } +} diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/wizards/NewUserWizard.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/wizards/NewUserWizard.java new file mode 100644 index 000000000..c2d041f56 --- /dev/null +++ b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/wizards/NewUserWizard.java @@ -0,0 +1,100 @@ +/* + * 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.security.ui.admin.wizards; + +import javax.jcr.Node; +import javax.jcr.RepositoryException; +import javax.jcr.Session; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.eclipse.ui.ErrorFeedback; +import org.argeo.jcr.JcrUtils; +import org.argeo.jcr.UserJcrUtils; +import org.argeo.security.UserAdminService; +import org.argeo.security.jcr.JcrSecurityModel; +import org.argeo.security.jcr.JcrUserDetails; +import org.eclipse.jface.wizard.Wizard; +import org.springframework.security.GrantedAuthority; + +/** Wizard to create a new user */ +public class NewUserWizard extends Wizard { + private final static Log log = LogFactory.getLog(NewUserWizard.class); + private Session session; + private UserAdminService userAdminService; + private JcrSecurityModel jcrSecurityModel; + + // pages + private MainUserInfoWizardPage mainUserInfo; + + public NewUserWizard(Session session, UserAdminService userAdminService, + JcrSecurityModel jcrSecurityModel) { + this.session = session; + this.userAdminService = userAdminService; + this.jcrSecurityModel = jcrSecurityModel; + } + + @Override + public void addPages() { + mainUserInfo = new MainUserInfoWizardPage(userAdminService); + addPage(mainUserInfo); + } + + @Override + public boolean performFinish() { + if (!canFinish()) + return false; + + String username = mainUserInfo.getUsername(); + try { + // Node userProfile = SecurityJcrUtils.createUserProfile(session, + // username); + Node userProfile = jcrSecurityModel.sync(session, username, null); + session.getWorkspace().getVersionManager() + .checkout(userProfile.getPath()); + mainUserInfo.mapToProfileNode(userProfile); + String password = mainUserInfo.getPassword(); + // TODO add roles + JcrUserDetails jcrUserDetails = new JcrUserDetails(userProfile, + password, new GrantedAuthority[0]); + session.save(); + session.getWorkspace().getVersionManager() + .checkin(userProfile.getPath()); + userAdminService.createUser(jcrUserDetails); + return true; + } catch (Exception e) { + JcrUtils.discardQuietly(session); + Node userHome = UserJcrUtils.getUserHome(session, username); + if (userHome != null) { + try { + userHome.remove(); + session.save(); + } catch (RepositoryException e1) { + JcrUtils.discardQuietly(session); + log.warn("Error when trying to clean up failed new user " + + username, e1); + } + } + ErrorFeedback.show("Cannot create new user " + username, e); + return false; + } + } + + public void setSession(Session session) { + this.session = session; + } + +} diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/wizards/UserBatchUpdateWizard.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/wizards/UserBatchUpdateWizard.java new file mode 100644 index 000000000..71e4a1b73 --- /dev/null +++ b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/wizards/UserBatchUpdateWizard.java @@ -0,0 +1,607 @@ +/* + * 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.security.ui.admin.wizards; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.version.VersionManager; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.ArgeoException; +import org.argeo.ArgeoMonitor; +import org.argeo.eclipse.ui.EclipseArgeoMonitor; +import org.argeo.jcr.ArgeoNames; +import org.argeo.jcr.JcrUtils; +import org.argeo.security.UserAdminService; +import org.argeo.security.jcr.JcrSecurityModel; +import org.argeo.security.jcr.JcrUserDetails; +import org.argeo.security.ui.PrivilegedJob; +import org.argeo.security.ui.admin.SecurityAdminPlugin; +import org.argeo.security.ui.admin.UserTableComposite; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.dialogs.IPageChangeProvider; +import org.eclipse.jface.dialogs.IPageChangedListener; +import org.eclipse.jface.dialogs.PageChangedEvent; +import org.eclipse.jface.wizard.IWizardContainer; +import org.eclipse.jface.wizard.Wizard; +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; + +/** Wizard to update users */ +public class UserBatchUpdateWizard extends Wizard { + private final static Log log = LogFactory + .getLog(UserBatchUpdateWizard.class); + private Session session; + private UserAdminService userAdminService; + + // pages + private ChooseCommandWizardPage chooseCommandPage; + private ChooseUsersWizardPage userListPage; + private ValidateAndLaunchWizardPage validatePage; + + // ///////////////////////////////////////////////// + // / Definition of the various implemented commands + private final static String CMD_UPDATE_PASSWORD = "resetPassword"; + private final static String CMD_GROUP_MEMBERSHIP = "groupMembership"; + + private final Map commands = new HashMap() { + private static final long serialVersionUID = 1L; + { + put("Enable user(s)", ArgeoNames.ARGEO_ENABLED); + put("Expire credentials", ArgeoNames.ARGEO_CREDENTIALS_NON_EXPIRED); + put("Expire account(s)", ArgeoNames.ARGEO_ACCOUNT_NON_EXPIRED); + put("Lock account(s)", ArgeoNames.ARGEO_ACCOUNT_NON_LOCKED); + put("Reset password(s)", CMD_UPDATE_PASSWORD); + // TODO implement role / group management + // put("Add/Remove from group", CMD_GROUP_MEMBERSHIP); + } + }; + + public UserBatchUpdateWizard(Session session, + UserAdminService userAdminService, JcrSecurityModel jcrSecurityModel) { + this.session = session; + this.userAdminService = userAdminService; + // this.jcrSecurityModel = jcrSecurityModel; + } + + @Override + public void addPages() { + chooseCommandPage = new ChooseCommandWizardPage(); + addPage(chooseCommandPage); + userListPage = new ChooseUsersWizardPage(session); + addPage(userListPage); + validatePage = new ValidateAndLaunchWizardPage(session); + addPage(validatePage); + } + + @Override + public boolean performFinish() { + if (!canFinish()) + return false; + + UpdateJob job = null; + if (ArgeoNames.ARGEO_ENABLED.equals(chooseCommandPage.getCommand())) { + job = new UpdateBoolean(session, userListPage.getSelectedUsers(), + ArgeoNames.ARGEO_ENABLED, + chooseCommandPage.getBoleanValue()); + } else if (ArgeoNames.ARGEO_CREDENTIALS_NON_EXPIRED + .equals(chooseCommandPage.getCommand())) { + job = new UpdateBoolean(session, userListPage.getSelectedUsers(), + ArgeoNames.ARGEO_CREDENTIALS_NON_EXPIRED, + chooseCommandPage.getBoleanValue()); + } else if (ArgeoNames.ARGEO_ACCOUNT_NON_EXPIRED + .equals(chooseCommandPage.getCommand())) { + job = new UpdateBoolean(session, userListPage.getSelectedUsers(), + ArgeoNames.ARGEO_ACCOUNT_NON_EXPIRED, + chooseCommandPage.getBoleanValue()); + } else if (ArgeoNames.ARGEO_ACCOUNT_NON_LOCKED.equals(chooseCommandPage + .getCommand())) { + job = new UpdateBoolean(session, userListPage.getSelectedUsers(), + ArgeoNames.ARGEO_ACCOUNT_NON_LOCKED, + chooseCommandPage.getBoleanValue()); + } else if (CMD_UPDATE_PASSWORD.equals(chooseCommandPage.getCommand())) { + String newValue = chooseCommandPage.getPwdValue(); + if (newValue == null) + throw new ArgeoException( + "Password cannot be null or an empty string"); + job = new ResetPassword(session, userAdminService, + userListPage.getSelectedUsers(), newValue); + } + + if (job != null) + job.schedule(); + return true; + } + + public void setSession(Session session) { + this.session = session; + } + + public boolean canFinish() { + if (this.getContainer().getCurrentPage() == validatePage) + return true; + return false; + } + + // ///////////////////////// + // REEL UPDATE JOB + private class UpdateBoolean extends UpdateJob { + private String propertyName; + private boolean value; + + public UpdateBoolean(Session session, List nodesToUpdate, + String propertyName, boolean value) { + super(session, nodesToUpdate); + this.propertyName = propertyName; + this.value = value; + } + + protected void doUpdate(Node node) { + try { + node.setProperty(propertyName, value); + } catch (RepositoryException re) { + throw new ArgeoException( + "Unable to update boolean value for node " + node, re); + } + } + } + + private class ResetPassword extends UpdateJob { + private String newValue; + private UserAdminService userAdminService; + + public ResetPassword(Session session, + UserAdminService userAdminService, List nodesToUpdate, + String newValue) { + super(session, nodesToUpdate); + this.newValue = newValue; + this.userAdminService = userAdminService; + } + + protected void doUpdate(Node node) { + try { + String userId = node.getProperty(ArgeoNames.ARGEO_USER_ID) + .getString(); + if (userAdminService.userExists(userId)) { + JcrUserDetails userDetails = (JcrUserDetails) userAdminService + .loadUserByUsername(userId); + userAdminService.updateUser(userDetails + .cloneWithNewPassword(newValue)); + } + } catch (RepositoryException re) { + throw new ArgeoException( + "Unable to update boolean value for node " + node, re); + } + } + } + + @SuppressWarnings("unused") + private class AddToGroup extends UpdateJob { + private String groupID; + private Session session; + + public AddToGroup(Session session, List nodesToUpdate, + String groupID) { + super(session, nodesToUpdate); + this.session = session; + this.groupID = groupID; + } + + protected void doUpdate(Node node) { + log.info("Add/Remove to group actions are not yet implemented"); + // TODO implement this + // try { + // throw new ArgeoException("Not yet implemented"); + // } catch (RepositoryException re) { + // throw new ArgeoException( + // "Unable to update boolean value for node " + node, re); + // } + } + } + + /** + * Base privileged job that will be run asynchronously to perform the batch + * update + */ + private abstract class UpdateJob extends PrivilegedJob { + + private final Session currSession; + private final List nodesToUpdate; + + protected abstract void doUpdate(Node node); + + public UpdateJob(Session session, List nodesToUpdate) { + super("Perform update"); + try { + this.currSession = session.getRepository().login(); + // "move" nodes to update in the new session + // the "old" session will be closed by the calling command + // before the job has effectively ran + // TODO there must be a cleaner way to do. + List nodes = new ArrayList(); + for (Node node : nodesToUpdate) { + nodes.add(currSession.getNode(node.getPath())); + } + this.nodesToUpdate = nodes; + } catch (RepositoryException e) { + throw new ArgeoException("Error while dupplicating " + + "session for job", e); + } + } + + @Override + protected IStatus doRun(IProgressMonitor progressMonitor) { + try { + ArgeoMonitor monitor = new EclipseArgeoMonitor(progressMonitor); + VersionManager vm = currSession.getWorkspace() + .getVersionManager(); + int total = nodesToUpdate.size(); + monitor.beginTask("Performing change", total); + for (Node node : nodesToUpdate) { + String path = node.getPath(); + vm.checkout(path); + doUpdate(node); + currSession.save(); + vm.checkin(path); + monitor.worked(1); + } + } catch (Exception e) { + log.error("Cannot perform batch update on users", e); + // e.printStackTrace(); + + // Dig exception to find the root cause that will enable the + // user to understand the problem + Throwable cause = e; + Throwable originalCause = e; + while (cause != null) { + if (log.isTraceEnabled()) + log.trace("Parent Cause message : " + + cause.getMessage()); + originalCause = cause; + cause = cause.getCause(); + } + return new Status(IStatus.ERROR, SecurityAdminPlugin.PLUGIN_ID, + "Cannot perform updates.", originalCause); + } finally { + JcrUtils.logoutQuietly(currSession); + } + return Status.OK_STATUS; + } + } + + // ////////////////////// + // Pages definition + /** Displays a combo box that enables user to choose which action to perform */ + private class ChooseCommandWizardPage extends WizardPage { + private static final long serialVersionUID = 1L; + + private Combo chooseCommandCmb; + private Button trueChk; + private Text valueTxt; + private Text pwdTxt; + private Text pwd2Txt; + + public ChooseCommandWizardPage() { + super("Choose a command to run."); + setTitle("Choose a command to run."); + } + + @Override + public void createControl(Composite parent) { + GridLayout gl = new GridLayout(); + Composite container = new Composite(parent, SWT.NO_FOCUS); + container.setLayout(gl); + + chooseCommandCmb = new Combo(container, SWT.NO_FOCUS); + String[] values = commands.keySet().toArray( + new String[commands.size()]); + chooseCommandCmb.setItems(values); + chooseCommandCmb.setLayoutData(new GridData(SWT.FILL, SWT.TOP, + true, false)); + + final Composite bottomPart = new Composite(container, SWT.NO_FOCUS); + gl = new GridLayout(); + gl.horizontalSpacing = gl.marginWidth = gl.verticalSpacing = 0; + bottomPart.setLayout(gl); + bottomPart.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, + true)); + + chooseCommandCmb.addSelectionListener(new SelectionListener() { + private static final long serialVersionUID = 1L; + + @Override + public void widgetSelected(SelectionEvent e) { + if (getCommand().equals(CMD_UPDATE_PASSWORD)) + populatePasswordCmp(bottomPart); + else if (getCommand().equals(CMD_GROUP_MEMBERSHIP)) + populateGroupCmp(bottomPart); + else + populateBooleanFlagCmp(bottomPart); + bottomPart.pack(true); + bottomPart.layout(); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + } + }); + + setControl(container); + } + + private void cleanParent(Composite parent) { + if (parent.getChildren().length > 0) { + for (Control control : parent.getChildren()) + control.dispose(); + } + } + + private void populateBooleanFlagCmp(Composite parent) { + cleanParent(parent); + trueChk = new Button(parent, SWT.CHECK); + trueChk.setText("Do it. (It will to the contrary if unchecked)"); + trueChk.setSelection(true); + trueChk.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false)); + } + + private void populatePasswordCmp(Composite parent) { + cleanParent(parent); + Composite body = new Composite(parent, SWT.NO_FOCUS); + body.setLayout(new GridLayout(2, false)); + body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + pwdTxt = createLP(body, "New password", ""); + pwd2Txt = createLP(body, "Repeat password", ""); + } + + /** Creates label and password. */ + protected Text createLP(Composite body, String label, String value) { + Label lbl = new Label(body, SWT.NONE); + lbl.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false)); + lbl.setText(label); + Text text = new Text(body, SWT.BORDER | SWT.PASSWORD); + text.setText(value); + text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + return text; + } + + private void populateGroupCmp(Composite parent) { + if (parent.getChildren().length > 0) { + for (Control control : parent.getChildren()) + control.dispose(); + } + trueChk = new Button(parent, SWT.CHECK); + trueChk.setText("Add to group. (It will remove user(s) from the " + + "corresponding group if unchecked)"); + trueChk.setSelection(true); + trueChk.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false)); + } + + protected String getCommand() { + return commands.get(chooseCommandCmb.getItem(chooseCommandCmb + .getSelectionIndex())); + } + + protected String getCommandLbl() { + return chooseCommandCmb.getItem(chooseCommandCmb + .getSelectionIndex()); + } + + protected boolean getBoleanValue() { + // FIXME this is not consistent and will lead to errors. + if (ArgeoNames.ARGEO_ENABLED.equals(getCommand())) + return trueChk.getSelection(); + else + return !trueChk.getSelection(); + } + + @SuppressWarnings("unused") + protected String getStringValue() { + String value = null; + if (valueTxt != null) { + value = valueTxt.getText(); + if ("".equals(value.trim())) + value = null; + } + return value; + } + + protected String getPwdValue() { + String newPwd = null; + if (pwdTxt == null || pwd2Txt == null) + return null; + if (!pwdTxt.getText().equals("") || !pwd2Txt.getText().equals("")) { + if (pwdTxt.getText().equals(pwd2Txt.getText())) { + newPwd = pwdTxt.getText(); + pwdTxt.setText(""); + pwd2Txt.setText(""); + } else { + pwdTxt.setText(""); + pwd2Txt.setText(""); + throw new ArgeoException("Passwords are not equals"); + } + } + return newPwd; + } + } + + /** + * Displays a list of users with a check box to be able to choose some of + * them + */ + private class ChooseUsersWizardPage extends WizardPage implements + IPageChangedListener { + private static final long serialVersionUID = 1L; + private UserTableComposite userTableCmp; + private Composite container; + private Session session; + + public ChooseUsersWizardPage(Session session) { + super("Choose Users"); + this.session = session; + setTitle("Select users who will be impacted"); + } + + @Override + public void createControl(Composite parent) { + container = new Composite(parent, SWT.NONE); + container.setLayout(new FillLayout()); + userTableCmp = new MyUserTableCmp(container, SWT.NO_FOCUS, session); + userTableCmp.populate(true, true); + setControl(container); + + // Add listener to update message when shown + final IWizardContainer container = this.getContainer(); + if (container instanceof IPageChangeProvider) { + ((IPageChangeProvider) container).addPageChangedListener(this); + } + + } + + @Override + public void pageChanged(PageChangedEvent event) { + if (event.getSelectedPage() == this) { + String msg = "Chosen batch action: " + + chooseCommandPage.getCommandLbl(); + ((WizardPage) event.getSelectedPage()).setMessage(msg); + } + } + + protected List getSelectedUsers() { + return userTableCmp.getSelectedUsers(); + } + + private class MyUserTableCmp extends UserTableComposite { + + private static final long serialVersionUID = 1L; + + public MyUserTableCmp(Composite parent, int style, Session session) { + super(parent, style, session); + } + + @Override + protected void refreshFilteredList() { + List nodes = new ArrayList(); + try { + NodeIterator ni = listFilteredElements(session, + getFilterString()); + + users: while (ni.hasNext()) { + Node currNode = ni.nextNode(); + String username = currNode.hasProperty(ARGEO_USER_ID) ? currNode + .getProperty(ARGEO_USER_ID).getString() : ""; + if (username.equals(session.getUserID())) + continue users; + else + nodes.add(currNode); + } + getTableViewer().setInput(nodes.toArray()); + } catch (RepositoryException e) { + throw new ArgeoException("Unable to list users", e); + } + } + } + } + + /** + * Recapitulation of input data before running real update + */ + private class ValidateAndLaunchWizardPage extends WizardPage implements + IPageChangedListener { + private static final long serialVersionUID = 1L; + private UserTableComposite userTableCmp; + private Session session; + + public ValidateAndLaunchWizardPage(Session session) { + super("Validate and launch"); + this.session = session; + setTitle("Validate and launch"); + } + + @Override + public void createControl(Composite parent) { + Composite mainCmp = new Composite(parent, SWT.NO_FOCUS); + mainCmp.setLayout(new FillLayout()); + + // Add listener to update user list when shown + final IWizardContainer container = this.getContainer(); + if (container instanceof IPageChangeProvider) { + ((IPageChangeProvider) container).addPageChangedListener(this); + } + + userTableCmp = new UserTableComposite(mainCmp, SWT.NO_FOCUS, + session); + userTableCmp.populate(false, false); + setControl(mainCmp); + } + + @Override + public void pageChanged(PageChangedEvent event) { + if (event.getSelectedPage() == this) { + @SuppressWarnings({ "unchecked", "rawtypes" }) + Object[] values = ((ArrayList) userListPage.getSelectedUsers()) + .toArray(new Object[userListPage.getSelectedUsers() + .size()]); + userTableCmp.getTableViewer().setInput(values); + String msg = "Following batch action: [" + + chooseCommandPage.getCommandLbl() + + "] will be perfomed on the users listed below.\n" + + "Are you sure you want to proceed?"; + ((WizardPage) event.getSelectedPage()).setMessage(msg); + } + } + + // private class MyUserTableCmp extends UserTableComposite { + // public MyUserTableCmp(Composite parent, int style, Session session) { + // super(parent, style, session); + // } + // + // @Override + // protected void refreshFilteredList() { + // @SuppressWarnings({ "unchecked", "rawtypes" }) + // + // setFilteredList(values); + // } + // + // @Override + // public void setVisible(boolean visible) { + // super.setVisible(visible); + // if (visible) + // refreshFilteredList(); + // } + // } + } +} \ No newline at end of file diff --git a/org.argeo.security.ui.rap/.classpath b/org.argeo.security.ui.rap/.classpath index 5641c7ca3..d2953a684 100644 --- a/org.argeo.security.ui.rap/.classpath +++ b/org.argeo.security.ui.rap/.classpath @@ -1,7 +1,9 @@ - - >> - - + + + + diff --git a/org.argeo.security.ui.rap/build.properties b/org.argeo.security.ui.rap/build.properties index 5618fae36..30f715358 100644 --- a/org.argeo.security.ui.rap/build.properties +++ b/org.argeo.security.ui.rap/build.properties @@ -1,6 +1 @@ -bin.includes = plugin.xml,\ - META-INF/,\ - branding/,\ - icons/ -source.. = src/main/java/ -output.. = target/classes/ +source.. = src/ diff --git a/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/AnonymousEntryPoint.java b/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/AnonymousEntryPoint.java deleted file mode 100644 index 16d24897c..000000000 --- a/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/AnonymousEntryPoint.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * 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.security.ui.rap; - -import java.security.PrivilegedAction; - -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.eclipse.equinox.security.auth.ILoginContext; -import org.eclipse.rap.rwt.RWT; -import org.eclipse.rap.rwt.application.IEntryPoint; -import org.eclipse.swt.widgets.Display; -import org.eclipse.ui.PlatformUI; - -/** - * RAP entry point which authenticates the subject as anonymous, for public - * unauthenticated access. - */ -public class AnonymousEntryPoint implements IEntryPoint { - private final static Log log = LogFactory.getLog(AnonymousEntryPoint.class); - - /** - * How many seconds to wait before invalidating the session if the user has - * not yet logged in. - */ - private Integer loginTimeout = 1 * 60; - private Integer sessionTimeout = 15 * 60; - - @Override - public int createUI() { - // Short login timeout so that the modal dialog login doesn't hang - // around too long - RWT.getRequest().getSession().setMaxInactiveInterval(loginTimeout); - - if (log.isDebugEnabled()) - log.debug("Anonymous THREAD=" + Thread.currentThread().getId() - + ", sessionStore=" + RWT.getSessionStore().getId()); - - // create display - final Display display = PlatformUI.createDisplay(); - - // log in - final ILoginContext loginContext = SecureRapActivator - .createLoginContext(SecureRapActivator.CONTEXT_SPRING_ANONYMOUS); - Subject subject = null; - try { - loginContext.login(); - subject = loginContext.getSubject(); - } catch (LoginException e) { - throw new ArgeoException( - "Unexpected exception during authentication", e); - } - - // identify after successful login - if (log.isDebugEnabled()) - log.debug("Authenticated " + subject); - final String username = subject.getPrincipals().iterator().next() - .getName(); - - // Once the user is logged in, she can have a longer session timeout - RWT.getRequest().getSession().setMaxInactiveInterval(sessionTimeout); - - // Logout callback when the display is disposed - display.disposeExec(new Runnable() { - public void run() { - log.debug("Display disposed"); - logout(loginContext, username); - } - }); - - // - // RUN THE WORKBENCH - // - Integer returnCode = null; - try { - returnCode = Subject.doAs(subject, new PrivilegedAction() { - public Integer run() { - RapWorkbenchAdvisor workbenchAdvisor = new RapWorkbenchAdvisor( - null); - int result = PlatformUI.createAndRunWorkbench(display, - workbenchAdvisor); - return new Integer(result); - } - }); - logout(loginContext, username); - } finally { - display.dispose(); - } - return returnCode; - } - - private void logout(ILoginContext secureContext, String username) { - try { - secureContext.logout(); - log.info("Logged out " + (username != null ? username : "") - + " (THREAD=" + Thread.currentThread().getId() + ")"); - } catch (LoginException e) { - log.error("Erorr when logging out", e); - } - } -} diff --git a/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/LogoutEntryPoint.java b/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/LogoutEntryPoint.java deleted file mode 100644 index 733754901..000000000 --- a/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/LogoutEntryPoint.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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.security.ui.rap; - -import javax.security.auth.login.LoginException; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.eclipse.equinox.security.auth.ILoginContext; -import org.eclipse.rap.rwt.RWT; -import org.eclipse.rap.rwt.application.IEntryPoint; -import org.eclipse.ui.PlatformUI; -import org.springframework.security.context.SecurityContextHolder; - -/** - * RAP entry point which logs out the currently authenticated user - */ -public class LogoutEntryPoint implements IEntryPoint { - private final static Log log = LogFactory.getLog(LogoutEntryPoint.class); - - /** - * From org.springframework.security.context. - * HttpSessionContextIntegrationFilter - */ - protected static final String SPRING_SECURITY_CONTEXT_KEY = "SPRING_SECURITY_CONTEXT"; - - @Override - public int createUI() { - // create display - PlatformUI.createDisplay(); - - final ILoginContext loginContext = SecureRapActivator - .createLoginContext(SecureRapActivator.CONTEXT_SPRING); - try { - loginContext.logout(); - } catch (LoginException e) { - e.printStackTrace(); - } - - RWT.getRequest().getSession() - .removeAttribute(SPRING_SECURITY_CONTEXT_KEY); - SecurityContextHolder.clearContext(); - RWT.getRequest().getSession().setMaxInactiveInterval(1); - - if (log.isDebugEnabled()) - log.debug("Logged out session " + RWT.getSessionStore().getId()); - return 0; - } -} diff --git a/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/NullEntryPoint.java b/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/NullEntryPoint.java deleted file mode 100644 index 811cc2821..000000000 --- a/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/NullEntryPoint.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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.security.ui.rap; - -import org.eclipse.rap.rwt.application.IEntryPoint; -import org.eclipse.ui.PlatformUI; - -/** - * RAP entry point which does doesing except creating the display - */ -public class NullEntryPoint implements IEntryPoint { - @Override - public int createUI() { - // create display - PlatformUI.createDisplay(); - return 0; - } -} diff --git a/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/RapActionBarAdvisor.java b/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/RapActionBarAdvisor.java deleted file mode 100644 index 074b798c7..000000000 --- a/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/RapActionBarAdvisor.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * 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.security.ui.rap; - -import org.argeo.security.ui.commands.OpenHomePerspective; -import org.eclipse.core.commands.Category; -import org.eclipse.core.commands.Command; -import org.eclipse.jface.action.ICoolBarManager; -import org.eclipse.jface.action.IMenuManager; -import org.eclipse.jface.action.IToolBarManager; -import org.eclipse.jface.action.ToolBarManager; -import org.eclipse.swt.SWT; -import org.eclipse.ui.IWorkbenchWindow; -import org.eclipse.ui.actions.ActionFactory; -import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction; -import org.eclipse.ui.application.ActionBarAdvisor; -import org.eclipse.ui.application.IActionBarConfigurer; -import org.eclipse.ui.commands.ICommandService; - -/** Eclipse rap specific action bar advisor */ -public class RapActionBarAdvisor extends ActionBarAdvisor { - private final static String ID_BASE = "org.argeo.security.ui.rap"; - // private final static Log log = LogFactory - // .getLog(SecureActionBarAdvisor.class); - - /** Null means anonymous */ - private String username = null; - - // private IAction logoutAction; - // private IWorkbenchAction openPerspectiveDialogAction; - // private IWorkbenchAction showViewMenuAction; - // private IWorkbenchAction preferences; - private IWorkbenchAction saveAction; - private IWorkbenchAction saveAllAction; - - // private IWorkbenchAction closeAllAction; - - public RapActionBarAdvisor(IActionBarConfigurer configurer, String username) { - super(configurer); - this.username = username; - } - - protected void makeActions(IWorkbenchWindow window) { - // preferences = ActionFactory.PREFERENCES.create(window); - // register(preferences); - // openPerspectiveDialogAction = ActionFactory.OPEN_PERSPECTIVE_DIALOG - // .create(window); - // register(openPerspectiveDialogAction); - // showViewMenuAction = ActionFactory.SHOW_VIEW_MENU.create(window); - // register(showViewMenuAction); - // - // // logout - // logoutAction = ActionFactory.QUIT.create(window); - // // logoutAction = createLogoutAction(); - // register(logoutAction); - // - // Save semantics - saveAction = ActionFactory.SAVE.create(window); - register(saveAction); - saveAllAction = ActionFactory.SAVE_ALL.create(window); - register(saveAllAction); - // closeAllAction = ActionFactory.CLOSE_ALL.create(window); - // register(closeAllAction); - - } - - protected void fillMenuBar(IMenuManager menuBar) { - // MenuManager fileMenu = new MenuManager("&File", - // IWorkbenchActionConstants.M_FILE); - // MenuManager editMenu = new MenuManager("&Edit", - // IWorkbenchActionConstants.M_EDIT); - // MenuManager windowMenu = new MenuManager("&Window", - // IWorkbenchActionConstants.M_WINDOW); - // - // menuBar.add(fileMenu); - // menuBar.add(editMenu); - // menuBar.add(windowMenu); - // // Add a group marker indicating where action set menus will appear. - // menuBar.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); - // - // // File - // fileMenu.add(saveAction); - // fileMenu.add(saveAllAction); - // fileMenu.add(closeAllAction); - // fileMenu.add(new - // GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); - // fileMenu.add(new Separator()); - // fileMenu.add(logoutAction); - // - // // Edit - // editMenu.add(preferences); - // - // // Window - // windowMenu.add(openPerspectiveDialogAction); - // windowMenu.add(showViewMenuAction); - } - - @Override - protected void fillCoolBar(ICoolBarManager coolBar) { - if (username != null) { - ICommandService cmdService = (ICommandService) getActionBarConfigurer() - .getWindowConfigurer().getWorkbenchConfigurer() - .getWorkbench().getService(ICommandService.class); - Category userMenus = cmdService.getCategory(ID_BASE + ".userMenus"); - if (!userMenus.isDefined()) - userMenus.define("User Menus", "User related menus"); - - Command userMenu = cmdService.getCommand(ID_BASE - + ".userMenuCommand"); - if (userMenu.isDefined()) - userMenu.undefine(); - userMenu.define(username, "User menu actions", userMenus); - userMenu.setHandler(new OpenHomePerspective()); - - // userToolbar.add(new UserMenuAction()); - // coolBar.add(userToolbar); - } else {// anonymous - IToolBarManager userToolbar = new ToolBarManager(SWT.FLAT - | SWT.RIGHT); - // userToolbar.add(logoutAction); - coolBar.add(userToolbar); - } - // IToolBarManager saveToolbar = new ToolBarManager(SWT.FLAT | - // SWT.RIGHT); - // saveToolbar.add(saveAction); - // saveToolbar.add(saveAllAction); - // coolBar.add(saveToolbar); - } - - // class UserMenuAction extends Action implements IWorkbenchAction { - // - // public UserMenuAction() { - // super(username, IAction.AS_DROP_DOWN_MENU); - // // setMenuCreator(new UserMenu()); - // } - // - // @Override - // public String getId() { - // return "org.argeo.security.ui.rap.userMenu"; - // } - // - // @Override - // public void dispose() { - // } - // - // } - - // class UserMenu implements IMenuCreator { - // private Menu menu; - // - // public Menu getMenu(Control parent) { - // Menu menu = new Menu(parent); - // addActionToMenu(menu, logoutAction); - // return menu; - // } - // - // private void addActionToMenu(Menu menu, IAction action) { - // ActionContributionItem item = new ActionContributionItem(action); - // item.fill(menu, -1); - // } - // - // public void dispose() { - // if (menu != null) { - // menu.dispose(); - // } - // } - // - // public Menu getMenu(Menu parent) { - // // Not use - // return null; - // } - // - // } - - // protected IAction createLogoutAction() { - // Subject subject = Subject.getSubject(AccessController.getContext()); - // final String username = subject.getPrincipals().iterator().next() - // .getName(); - // - // IAction logoutAction = new Action() { - // public String getId() { - // return SecureRapActivator.ID + ".logoutAction"; - // } - // - // public String getText() { - // return "Logout " + username; - // } - // - // public void run() { - // // try { - // // Subject subject = SecureRapActivator.getLoginContext() - // // .getSubject(); - // // String subjectStr = subject.toString(); - // // subject.getPrincipals().clear(); - // // SecureRapActivator.getLoginContext().logout(); - // // log.info(subjectStr + " logged out"); - // // } catch (LoginException e) { - // // log.error("Error when logging out", e); - // // } - // // SecureEntryPoint.logout(username); - // // PlatformUI.getWorkbench().close(); - // // try { - // // RWT.getRequest().getSession().setMaxInactiveInterval(1); - // // } catch (Exception e) { - // // if (log.isTraceEnabled()) - // // log.trace("Error when invalidating session", e); - // // } - // } - // - // }; - // return logoutAction; - // } - -} diff --git a/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/RapWindowAdvisor.java b/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/RapWindowAdvisor.java deleted file mode 100644 index 480815279..000000000 --- a/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/RapWindowAdvisor.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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.security.ui.rap; - -import org.eclipse.swt.SWT; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.graphics.Rectangle; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.Listener; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.ui.IWorkbenchWindow; -import org.eclipse.ui.actions.ActionFactory; -import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction; -import org.eclipse.ui.application.ActionBarAdvisor; -import org.eclipse.ui.application.IActionBarConfigurer; -import org.eclipse.ui.application.IWorkbenchWindowConfigurer; -import org.eclipse.ui.application.WorkbenchWindowAdvisor; -import org.eclipse.ui.internal.UIPlugin; - -/** Eclipse RAP specific window advisor */ -public class RapWindowAdvisor extends WorkbenchWindowAdvisor { - - private String username; - - public RapWindowAdvisor(IWorkbenchWindowConfigurer configurer, - String username) { - super(configurer); - this.username = username; - } - - @Override - public ActionBarAdvisor createActionBarAdvisor( - IActionBarConfigurer configurer) { - return new RapActionBarAdvisor(configurer, username); - } - - public void preWindowOpen() { - IWorkbenchWindowConfigurer configurer = getWindowConfigurer(); - configurer.setShowCoolBar(true); - configurer.setShowMenuBar(false); - configurer.setShowStatusLine(false); - configurer.setShowPerspectiveBar(true); - configurer.setTitle("Argeo Web UI"); //$NON-NLS-1$ - // Full screen, see - // http://wiki.eclipse.org/RAP/FAQ#How_to_create_a_fullscreen_application - configurer.setShellStyle(SWT.NO_TRIM); - Rectangle bounds = Display.getCurrent().getBounds(); - configurer.setInitialSize(new Point(bounds.width, bounds.height)); - - // Handle window resize in Rap 2.1+ see https://bugs.eclipse.org/bugs/show_bug.cgi?id=417254 - Display.getCurrent().addListener(SWT.Resize, new Listener() { - @Override - public void handleEvent(Event event) { - Rectangle bounds = event.display.getBounds(); - IWorkbenchWindow iww = UIPlugin.getDefault().getWorkbench() - .getActiveWorkbenchWindow(); - iww.getShell().setBounds(bounds); - } - }); - } - - @Override - public void postWindowCreate() { - Shell shell = getWindowConfigurer().getWindow().getShell(); - shell.setMaximized(true); - } - - @Override - public void postWindowOpen() { - String defaultPerspective = getWindowConfigurer() - .getWorkbenchConfigurer().getWorkbench() - .getPerspectiveRegistry().getDefaultPerspective(); - if (defaultPerspective == null) { - IWorkbenchWindow window = getWindowConfigurer().getWindow(); - if (window == null) - return; - - IWorkbenchAction openPerspectiveDialogAction = ActionFactory.OPEN_PERSPECTIVE_DIALOG - .create(window); - openPerspectiveDialogAction.run(); - } - } - -} diff --git a/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/RapWorkbenchAdvisor.java b/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/RapWorkbenchAdvisor.java deleted file mode 100644 index edde41f14..000000000 --- a/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/RapWorkbenchAdvisor.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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.security.ui.rap; - -import org.eclipse.ui.IPerspectiveDescriptor; -import org.eclipse.ui.application.IWorkbenchConfigurer; -import org.eclipse.ui.application.IWorkbenchWindowConfigurer; -import org.eclipse.ui.application.WorkbenchAdvisor; -import org.eclipse.ui.application.WorkbenchWindowAdvisor; - -/** Eclipse RAP specific workbench advisor */ -public class RapWorkbenchAdvisor extends WorkbenchAdvisor { - public final static String INITIAL_PERSPECTIVE_PROPERTY = "org.argeo.security.ui.initialPerspective"; - public final static String SAVE_AND_RESTORE_PROPERTY = "org.argeo.security.ui.saveAndRestore"; - - private String initialPerspective = System.getProperty( - INITIAL_PERSPECTIVE_PROPERTY, null); - - private String username; - - public RapWorkbenchAdvisor(String username) { - this.username = username; - } - - @Override - public void initialize(IWorkbenchConfigurer configurer) { - super.initialize(configurer); - Boolean saveAndRestore = Boolean.parseBoolean(System.getProperty( - SAVE_AND_RESTORE_PROPERTY, "false")); - configurer.setSaveAndRestore(saveAndRestore); - } - - public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor( - IWorkbenchWindowConfigurer configurer) { - return new RapWindowAdvisor(configurer, username); - } - - public String getInitialWindowPerspectiveId() { - if (initialPerspective != null) { - // check whether this user can see the declared perspective - // (typically the perspective won't be listed if this user doesn't - // have the right to see it) - IPerspectiveDescriptor pd = getWorkbenchConfigurer().getWorkbench() - .getPerspectiveRegistry() - .findPerspectiveWithId(initialPerspective); - if (pd == null) - return null; - } - return initialPerspective; - } -} diff --git a/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/SecureEntryPoint.java b/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/SecureEntryPoint.java deleted file mode 100644 index 288ca623b..000000000 --- a/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/SecureEntryPoint.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * 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.security.ui.rap; - -import java.security.PrivilegedAction; - -import javax.security.auth.Subject; -import javax.security.auth.login.LoginException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.ArgeoException; -import org.argeo.eclipse.ui.ErrorFeedback; -import org.argeo.util.LocaleUtils; -import org.eclipse.equinox.security.auth.ILoginContext; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.rap.rwt.RWT; -import org.eclipse.rap.rwt.application.IEntryPoint; -import org.eclipse.swt.widgets.Display; -import org.eclipse.ui.PlatformUI; -import org.springframework.security.BadCredentialsException; -import org.springframework.security.context.SecurityContext; -import org.springframework.security.context.SecurityContextHolder; - -/** - * RAP entry point with login capabilities. Once the user has been - * authenticated, the workbench is run as a privileged action by the related - * subject. - */ -public class SecureEntryPoint implements IEntryPoint { - private final static Log log = LogFactory.getLog(SecureEntryPoint.class); - - /** - * From org.springframework.security.context. - * HttpSessionContextIntegrationFilter - */ - protected static final String SPRING_SECURITY_CONTEXT_KEY = "SPRING_SECURITY_CONTEXT"; - - /** - * How many seconds to wait before invalidating the session if the user has - * not yet logged in. - */ - private Integer loginTimeout = 1 * 60; - // TODO make it configurable - /** Default session timeout is 8 hours (European working day length) */ - private Integer sessionTimeout = 8 * 60 * 60; - - /** Override to provide an application specific workbench advisor */ - protected RapWorkbenchAdvisor createRapWorkbenchAdvisor(String username) { - return new RapWorkbenchAdvisor(username); - } - - @Override - public final int createUI() { - // Short login timeout so that the modal dialog login doesn't hang - // around too long - RWT.getRequest().getSession().setMaxInactiveInterval(loginTimeout); - - // Try to load security context thanks to the session processing filter - HttpServletRequest httpRequest = RWT.getRequest(); - HttpSession httpSession = httpRequest.getSession(); - Object contextFromSessionObject = httpSession - .getAttribute(SPRING_SECURITY_CONTEXT_KEY); - if (contextFromSessionObject != null) - SecurityContextHolder - .setContext((SecurityContext) contextFromSessionObject); - -// if (log.isDebugEnabled()) -// log.debug("THREAD=" + Thread.currentThread().getId() -// + ", sessionStore=" + RWT.getSessionStore().getId() -// + ", remote user=" + httpRequest.getRemoteUser()); - - // create display - final Display display = PlatformUI.createDisplay(); - - // log in - final ILoginContext loginContext = SecureRapActivator - .createLoginContext(SecureRapActivator.CONTEXT_SPRING); - Subject subject = null; - tryLogin: while (subject == null && !display.isDisposed()) { - try { - loginContext.login(); - subject = loginContext.getSubject(); - - // add security context to session - if (httpSession.getAttribute(SPRING_SECURITY_CONTEXT_KEY) == null) - httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY, - SecurityContextHolder.getContext()); - // add thread locale to RWT session - log.info("Locale "+LocaleUtils.threadLocale.get()); - RWT.setLocale(LocaleUtils.threadLocale.get()); - - // Once the user is logged in, she can have a longer session - // timeout - RWT.getRequest().getSession() - .setMaxInactiveInterval(sessionTimeout); - if (log.isDebugEnabled()) - log.debug("Authenticated " + subject); - } catch (LoginException e) { - BadCredentialsException bce = wasCausedByBadCredentials(e); - if (bce != null) { - MessageDialog.openInformation(display.getActiveShell(), - "Bad Credentials", bce.getMessage()); - // retry login - continue tryLogin; - } - return processLoginDeath(display, e); - } - } - - final String username = subject.getPrincipals().iterator().next() - .getName(); - // Logout callback when the display is disposed - display.disposeExec(new Runnable() { - public void run() { - log.debug("Display disposed"); - logout(loginContext, username); - } - }); - - // - // RUN THE WORKBENCH - // - Integer returnCode = null; - try { - returnCode = Subject.doAs(subject, new PrivilegedAction() { - public Integer run() { - RapWorkbenchAdvisor workbenchAdvisor = createRapWorkbenchAdvisor(username); - int result = PlatformUI.createAndRunWorkbench(display, - workbenchAdvisor); - return new Integer(result); - } - }); - // logout(loginContext, username); - } finally { - display.dispose(); - } - return returnCode; - } - - private Integer processLoginDeath(Display display, LoginException e) { - // check thread death - ThreadDeath td = wasCausedByThreadDeath(e); - if (td != null) { - display.dispose(); - throw td; - } - if (!display.isDisposed()) { - ErrorFeedback.show("Unexpected exception during authentication", e); - // this was not just bad credentials or death thread - RWT.getRequest().getSession().setMaxInactiveInterval(1); - display.dispose(); - return -1; - } else { - throw new ArgeoException( - "Unexpected exception during authentication", e); - } - - } - - /** Recursively look for {@link BadCredentialsException} in the root causes. */ - private BadCredentialsException wasCausedByBadCredentials(Throwable t) { - if (t instanceof BadCredentialsException) - return (BadCredentialsException) t; - - if (t.getCause() != null) - return wasCausedByBadCredentials(t.getCause()); - else - return null; - } - - /** - * If there is a {@link ThreadDeath} in the root causes, rethrow it - * (important for RAP cleaning mechanism) - */ - protected ThreadDeath wasCausedByThreadDeath(Throwable t) { - if (t instanceof ThreadDeath) - return (ThreadDeath) t; - - if (t.getCause() != null) - return wasCausedByThreadDeath(t.getCause()); - else - return null; - } - - protected void logout(ILoginContext secureContext, String username) { - try { - HttpServletRequest httpRequest = RWT.getRequest(); - HttpSession httpSession = httpRequest.getSession(); - httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY, null); - RWT.getRequest().getSession().setMaxInactiveInterval(1); - SecurityContextHolder.clearContext(); - secureContext.logout(); - log.info("Logged out " + (username != null ? username : "") - + " (THREAD=" + Thread.currentThread().getId() + ")"); - } catch (LoginException e) { - log.error("Erorr when logging out", e); - } - } -} diff --git a/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/SecureRapActivator.java b/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/SecureRapActivator.java deleted file mode 100644 index 4cbb441e7..000000000 --- a/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/SecureRapActivator.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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.security.ui.rap; - -import java.net.URL; - -import org.eclipse.equinox.security.auth.ILoginContext; -import org.eclipse.equinox.security.auth.LoginContextFactory; -import org.osgi.framework.BundleActivator; -import org.osgi.framework.BundleContext; - -/** Configure Equinox login context from the bundle context. */ -public class SecureRapActivator implements BundleActivator { - - public final static String ID = "org.argeo.security.ui.rap"; - public final static String CONTEXT_SPRING = "SPRING"; - public final static String CONTEXT_SPRING_ANONYMOUS = "SPRING_ANONYMOUS"; - private static final String JAAS_CONFIG_FILE = "/META-INF/jaas_default.txt"; - - private BundleContext bundleContext; - private static SecureRapActivator activator = null; - - public void start(BundleContext bundleContext) throws Exception { - activator = this; - this.bundleContext = bundleContext; - } - - public void stop(BundleContext context) throws Exception { - bundleContext = null; - activator = null; - } - - public BundleContext getBundleContext() { - return bundleContext; - } - - public static SecureRapActivator getActivator() { - return activator; - } - - static ILoginContext createLoginContext(String contextName) { - URL configUrl = getActivator().getBundleContext().getBundle() - .getEntry(JAAS_CONFIG_FILE); - return LoginContextFactory.createContext(contextName, configUrl); - } -} diff --git a/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/commands/UserMenu.java b/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/commands/UserMenu.java deleted file mode 100644 index 98674303b..000000000 --- a/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/commands/UserMenu.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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.security.ui.rap.commands; - -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; - -/** Default action of the user menu */ -public class UserMenu extends AbstractHandler { - - @Override - public Object execute(ExecutionEvent event) throws ExecutionException { - return null; - } - -} diff --git a/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/AnonymousEntryPoint.java b/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/AnonymousEntryPoint.java new file mode 100644 index 000000000..16d24897c --- /dev/null +++ b/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/AnonymousEntryPoint.java @@ -0,0 +1,118 @@ +/* + * 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.security.ui.rap; + +import java.security.PrivilegedAction; + +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.eclipse.equinox.security.auth.ILoginContext; +import org.eclipse.rap.rwt.RWT; +import org.eclipse.rap.rwt.application.IEntryPoint; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.PlatformUI; + +/** + * RAP entry point which authenticates the subject as anonymous, for public + * unauthenticated access. + */ +public class AnonymousEntryPoint implements IEntryPoint { + private final static Log log = LogFactory.getLog(AnonymousEntryPoint.class); + + /** + * How many seconds to wait before invalidating the session if the user has + * not yet logged in. + */ + private Integer loginTimeout = 1 * 60; + private Integer sessionTimeout = 15 * 60; + + @Override + public int createUI() { + // Short login timeout so that the modal dialog login doesn't hang + // around too long + RWT.getRequest().getSession().setMaxInactiveInterval(loginTimeout); + + if (log.isDebugEnabled()) + log.debug("Anonymous THREAD=" + Thread.currentThread().getId() + + ", sessionStore=" + RWT.getSessionStore().getId()); + + // create display + final Display display = PlatformUI.createDisplay(); + + // log in + final ILoginContext loginContext = SecureRapActivator + .createLoginContext(SecureRapActivator.CONTEXT_SPRING_ANONYMOUS); + Subject subject = null; + try { + loginContext.login(); + subject = loginContext.getSubject(); + } catch (LoginException e) { + throw new ArgeoException( + "Unexpected exception during authentication", e); + } + + // identify after successful login + if (log.isDebugEnabled()) + log.debug("Authenticated " + subject); + final String username = subject.getPrincipals().iterator().next() + .getName(); + + // Once the user is logged in, she can have a longer session timeout + RWT.getRequest().getSession().setMaxInactiveInterval(sessionTimeout); + + // Logout callback when the display is disposed + display.disposeExec(new Runnable() { + public void run() { + log.debug("Display disposed"); + logout(loginContext, username); + } + }); + + // + // RUN THE WORKBENCH + // + Integer returnCode = null; + try { + returnCode = Subject.doAs(subject, new PrivilegedAction() { + public Integer run() { + RapWorkbenchAdvisor workbenchAdvisor = new RapWorkbenchAdvisor( + null); + int result = PlatformUI.createAndRunWorkbench(display, + workbenchAdvisor); + return new Integer(result); + } + }); + logout(loginContext, username); + } finally { + display.dispose(); + } + return returnCode; + } + + private void logout(ILoginContext secureContext, String username) { + try { + secureContext.logout(); + log.info("Logged out " + (username != null ? username : "") + + " (THREAD=" + Thread.currentThread().getId() + ")"); + } catch (LoginException e) { + log.error("Erorr when logging out", e); + } + } +} diff --git a/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/LogoutEntryPoint.java b/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/LogoutEntryPoint.java new file mode 100644 index 000000000..733754901 --- /dev/null +++ b/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/LogoutEntryPoint.java @@ -0,0 +1,62 @@ +/* + * 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.security.ui.rap; + +import javax.security.auth.login.LoginException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.equinox.security.auth.ILoginContext; +import org.eclipse.rap.rwt.RWT; +import org.eclipse.rap.rwt.application.IEntryPoint; +import org.eclipse.ui.PlatformUI; +import org.springframework.security.context.SecurityContextHolder; + +/** + * RAP entry point which logs out the currently authenticated user + */ +public class LogoutEntryPoint implements IEntryPoint { + private final static Log log = LogFactory.getLog(LogoutEntryPoint.class); + + /** + * From org.springframework.security.context. + * HttpSessionContextIntegrationFilter + */ + protected static final String SPRING_SECURITY_CONTEXT_KEY = "SPRING_SECURITY_CONTEXT"; + + @Override + public int createUI() { + // create display + PlatformUI.createDisplay(); + + final ILoginContext loginContext = SecureRapActivator + .createLoginContext(SecureRapActivator.CONTEXT_SPRING); + try { + loginContext.logout(); + } catch (LoginException e) { + e.printStackTrace(); + } + + RWT.getRequest().getSession() + .removeAttribute(SPRING_SECURITY_CONTEXT_KEY); + SecurityContextHolder.clearContext(); + RWT.getRequest().getSession().setMaxInactiveInterval(1); + + if (log.isDebugEnabled()) + log.debug("Logged out session " + RWT.getSessionStore().getId()); + return 0; + } +} diff --git a/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/NullEntryPoint.java b/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/NullEntryPoint.java new file mode 100644 index 000000000..811cc2821 --- /dev/null +++ b/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/NullEntryPoint.java @@ -0,0 +1,31 @@ +/* + * 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.security.ui.rap; + +import org.eclipse.rap.rwt.application.IEntryPoint; +import org.eclipse.ui.PlatformUI; + +/** + * RAP entry point which does doesing except creating the display + */ +public class NullEntryPoint implements IEntryPoint { + @Override + public int createUI() { + // create display + PlatformUI.createDisplay(); + return 0; + } +} diff --git a/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/RapActionBarAdvisor.java b/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/RapActionBarAdvisor.java new file mode 100644 index 000000000..074b798c7 --- /dev/null +++ b/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/RapActionBarAdvisor.java @@ -0,0 +1,227 @@ +/* + * 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.security.ui.rap; + +import org.argeo.security.ui.commands.OpenHomePerspective; +import org.eclipse.core.commands.Category; +import org.eclipse.core.commands.Command; +import org.eclipse.jface.action.ICoolBarManager; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.action.ToolBarManager; +import org.eclipse.swt.SWT; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.actions.ActionFactory; +import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction; +import org.eclipse.ui.application.ActionBarAdvisor; +import org.eclipse.ui.application.IActionBarConfigurer; +import org.eclipse.ui.commands.ICommandService; + +/** Eclipse rap specific action bar advisor */ +public class RapActionBarAdvisor extends ActionBarAdvisor { + private final static String ID_BASE = "org.argeo.security.ui.rap"; + // private final static Log log = LogFactory + // .getLog(SecureActionBarAdvisor.class); + + /** Null means anonymous */ + private String username = null; + + // private IAction logoutAction; + // private IWorkbenchAction openPerspectiveDialogAction; + // private IWorkbenchAction showViewMenuAction; + // private IWorkbenchAction preferences; + private IWorkbenchAction saveAction; + private IWorkbenchAction saveAllAction; + + // private IWorkbenchAction closeAllAction; + + public RapActionBarAdvisor(IActionBarConfigurer configurer, String username) { + super(configurer); + this.username = username; + } + + protected void makeActions(IWorkbenchWindow window) { + // preferences = ActionFactory.PREFERENCES.create(window); + // register(preferences); + // openPerspectiveDialogAction = ActionFactory.OPEN_PERSPECTIVE_DIALOG + // .create(window); + // register(openPerspectiveDialogAction); + // showViewMenuAction = ActionFactory.SHOW_VIEW_MENU.create(window); + // register(showViewMenuAction); + // + // // logout + // logoutAction = ActionFactory.QUIT.create(window); + // // logoutAction = createLogoutAction(); + // register(logoutAction); + // + // Save semantics + saveAction = ActionFactory.SAVE.create(window); + register(saveAction); + saveAllAction = ActionFactory.SAVE_ALL.create(window); + register(saveAllAction); + // closeAllAction = ActionFactory.CLOSE_ALL.create(window); + // register(closeAllAction); + + } + + protected void fillMenuBar(IMenuManager menuBar) { + // MenuManager fileMenu = new MenuManager("&File", + // IWorkbenchActionConstants.M_FILE); + // MenuManager editMenu = new MenuManager("&Edit", + // IWorkbenchActionConstants.M_EDIT); + // MenuManager windowMenu = new MenuManager("&Window", + // IWorkbenchActionConstants.M_WINDOW); + // + // menuBar.add(fileMenu); + // menuBar.add(editMenu); + // menuBar.add(windowMenu); + // // Add a group marker indicating where action set menus will appear. + // menuBar.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); + // + // // File + // fileMenu.add(saveAction); + // fileMenu.add(saveAllAction); + // fileMenu.add(closeAllAction); + // fileMenu.add(new + // GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); + // fileMenu.add(new Separator()); + // fileMenu.add(logoutAction); + // + // // Edit + // editMenu.add(preferences); + // + // // Window + // windowMenu.add(openPerspectiveDialogAction); + // windowMenu.add(showViewMenuAction); + } + + @Override + protected void fillCoolBar(ICoolBarManager coolBar) { + if (username != null) { + ICommandService cmdService = (ICommandService) getActionBarConfigurer() + .getWindowConfigurer().getWorkbenchConfigurer() + .getWorkbench().getService(ICommandService.class); + Category userMenus = cmdService.getCategory(ID_BASE + ".userMenus"); + if (!userMenus.isDefined()) + userMenus.define("User Menus", "User related menus"); + + Command userMenu = cmdService.getCommand(ID_BASE + + ".userMenuCommand"); + if (userMenu.isDefined()) + userMenu.undefine(); + userMenu.define(username, "User menu actions", userMenus); + userMenu.setHandler(new OpenHomePerspective()); + + // userToolbar.add(new UserMenuAction()); + // coolBar.add(userToolbar); + } else {// anonymous + IToolBarManager userToolbar = new ToolBarManager(SWT.FLAT + | SWT.RIGHT); + // userToolbar.add(logoutAction); + coolBar.add(userToolbar); + } + // IToolBarManager saveToolbar = new ToolBarManager(SWT.FLAT | + // SWT.RIGHT); + // saveToolbar.add(saveAction); + // saveToolbar.add(saveAllAction); + // coolBar.add(saveToolbar); + } + + // class UserMenuAction extends Action implements IWorkbenchAction { + // + // public UserMenuAction() { + // super(username, IAction.AS_DROP_DOWN_MENU); + // // setMenuCreator(new UserMenu()); + // } + // + // @Override + // public String getId() { + // return "org.argeo.security.ui.rap.userMenu"; + // } + // + // @Override + // public void dispose() { + // } + // + // } + + // class UserMenu implements IMenuCreator { + // private Menu menu; + // + // public Menu getMenu(Control parent) { + // Menu menu = new Menu(parent); + // addActionToMenu(menu, logoutAction); + // return menu; + // } + // + // private void addActionToMenu(Menu menu, IAction action) { + // ActionContributionItem item = new ActionContributionItem(action); + // item.fill(menu, -1); + // } + // + // public void dispose() { + // if (menu != null) { + // menu.dispose(); + // } + // } + // + // public Menu getMenu(Menu parent) { + // // Not use + // return null; + // } + // + // } + + // protected IAction createLogoutAction() { + // Subject subject = Subject.getSubject(AccessController.getContext()); + // final String username = subject.getPrincipals().iterator().next() + // .getName(); + // + // IAction logoutAction = new Action() { + // public String getId() { + // return SecureRapActivator.ID + ".logoutAction"; + // } + // + // public String getText() { + // return "Logout " + username; + // } + // + // public void run() { + // // try { + // // Subject subject = SecureRapActivator.getLoginContext() + // // .getSubject(); + // // String subjectStr = subject.toString(); + // // subject.getPrincipals().clear(); + // // SecureRapActivator.getLoginContext().logout(); + // // log.info(subjectStr + " logged out"); + // // } catch (LoginException e) { + // // log.error("Error when logging out", e); + // // } + // // SecureEntryPoint.logout(username); + // // PlatformUI.getWorkbench().close(); + // // try { + // // RWT.getRequest().getSession().setMaxInactiveInterval(1); + // // } catch (Exception e) { + // // if (log.isTraceEnabled()) + // // log.trace("Error when invalidating session", e); + // // } + // } + // + // }; + // return logoutAction; + // } + +} diff --git a/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/RapWindowAdvisor.java b/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/RapWindowAdvisor.java new file mode 100644 index 000000000..480815279 --- /dev/null +++ b/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/RapWindowAdvisor.java @@ -0,0 +1,98 @@ +/* + * 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.security.ui.rap; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.actions.ActionFactory; +import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction; +import org.eclipse.ui.application.ActionBarAdvisor; +import org.eclipse.ui.application.IActionBarConfigurer; +import org.eclipse.ui.application.IWorkbenchWindowConfigurer; +import org.eclipse.ui.application.WorkbenchWindowAdvisor; +import org.eclipse.ui.internal.UIPlugin; + +/** Eclipse RAP specific window advisor */ +public class RapWindowAdvisor extends WorkbenchWindowAdvisor { + + private String username; + + public RapWindowAdvisor(IWorkbenchWindowConfigurer configurer, + String username) { + super(configurer); + this.username = username; + } + + @Override + public ActionBarAdvisor createActionBarAdvisor( + IActionBarConfigurer configurer) { + return new RapActionBarAdvisor(configurer, username); + } + + public void preWindowOpen() { + IWorkbenchWindowConfigurer configurer = getWindowConfigurer(); + configurer.setShowCoolBar(true); + configurer.setShowMenuBar(false); + configurer.setShowStatusLine(false); + configurer.setShowPerspectiveBar(true); + configurer.setTitle("Argeo Web UI"); //$NON-NLS-1$ + // Full screen, see + // http://wiki.eclipse.org/RAP/FAQ#How_to_create_a_fullscreen_application + configurer.setShellStyle(SWT.NO_TRIM); + Rectangle bounds = Display.getCurrent().getBounds(); + configurer.setInitialSize(new Point(bounds.width, bounds.height)); + + // Handle window resize in Rap 2.1+ see https://bugs.eclipse.org/bugs/show_bug.cgi?id=417254 + Display.getCurrent().addListener(SWT.Resize, new Listener() { + @Override + public void handleEvent(Event event) { + Rectangle bounds = event.display.getBounds(); + IWorkbenchWindow iww = UIPlugin.getDefault().getWorkbench() + .getActiveWorkbenchWindow(); + iww.getShell().setBounds(bounds); + } + }); + } + + @Override + public void postWindowCreate() { + Shell shell = getWindowConfigurer().getWindow().getShell(); + shell.setMaximized(true); + } + + @Override + public void postWindowOpen() { + String defaultPerspective = getWindowConfigurer() + .getWorkbenchConfigurer().getWorkbench() + .getPerspectiveRegistry().getDefaultPerspective(); + if (defaultPerspective == null) { + IWorkbenchWindow window = getWindowConfigurer().getWindow(); + if (window == null) + return; + + IWorkbenchAction openPerspectiveDialogAction = ActionFactory.OPEN_PERSPECTIVE_DIALOG + .create(window); + openPerspectiveDialogAction.run(); + } + } + +} diff --git a/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/RapWorkbenchAdvisor.java b/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/RapWorkbenchAdvisor.java new file mode 100644 index 000000000..edde41f14 --- /dev/null +++ b/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/RapWorkbenchAdvisor.java @@ -0,0 +1,64 @@ +/* + * 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.security.ui.rap; + +import org.eclipse.ui.IPerspectiveDescriptor; +import org.eclipse.ui.application.IWorkbenchConfigurer; +import org.eclipse.ui.application.IWorkbenchWindowConfigurer; +import org.eclipse.ui.application.WorkbenchAdvisor; +import org.eclipse.ui.application.WorkbenchWindowAdvisor; + +/** Eclipse RAP specific workbench advisor */ +public class RapWorkbenchAdvisor extends WorkbenchAdvisor { + public final static String INITIAL_PERSPECTIVE_PROPERTY = "org.argeo.security.ui.initialPerspective"; + public final static String SAVE_AND_RESTORE_PROPERTY = "org.argeo.security.ui.saveAndRestore"; + + private String initialPerspective = System.getProperty( + INITIAL_PERSPECTIVE_PROPERTY, null); + + private String username; + + public RapWorkbenchAdvisor(String username) { + this.username = username; + } + + @Override + public void initialize(IWorkbenchConfigurer configurer) { + super.initialize(configurer); + Boolean saveAndRestore = Boolean.parseBoolean(System.getProperty( + SAVE_AND_RESTORE_PROPERTY, "false")); + configurer.setSaveAndRestore(saveAndRestore); + } + + public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor( + IWorkbenchWindowConfigurer configurer) { + return new RapWindowAdvisor(configurer, username); + } + + public String getInitialWindowPerspectiveId() { + if (initialPerspective != null) { + // check whether this user can see the declared perspective + // (typically the perspective won't be listed if this user doesn't + // have the right to see it) + IPerspectiveDescriptor pd = getWorkbenchConfigurer().getWorkbench() + .getPerspectiveRegistry() + .findPerspectiveWithId(initialPerspective); + if (pd == null) + return null; + } + return initialPerspective; + } +} diff --git a/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/SecureEntryPoint.java b/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/SecureEntryPoint.java new file mode 100644 index 000000000..288ca623b --- /dev/null +++ b/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/SecureEntryPoint.java @@ -0,0 +1,215 @@ +/* + * 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.security.ui.rap; + +import java.security.PrivilegedAction; + +import javax.security.auth.Subject; +import javax.security.auth.login.LoginException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.ArgeoException; +import org.argeo.eclipse.ui.ErrorFeedback; +import org.argeo.util.LocaleUtils; +import org.eclipse.equinox.security.auth.ILoginContext; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.rap.rwt.RWT; +import org.eclipse.rap.rwt.application.IEntryPoint; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.PlatformUI; +import org.springframework.security.BadCredentialsException; +import org.springframework.security.context.SecurityContext; +import org.springframework.security.context.SecurityContextHolder; + +/** + * RAP entry point with login capabilities. Once the user has been + * authenticated, the workbench is run as a privileged action by the related + * subject. + */ +public class SecureEntryPoint implements IEntryPoint { + private final static Log log = LogFactory.getLog(SecureEntryPoint.class); + + /** + * From org.springframework.security.context. + * HttpSessionContextIntegrationFilter + */ + protected static final String SPRING_SECURITY_CONTEXT_KEY = "SPRING_SECURITY_CONTEXT"; + + /** + * How many seconds to wait before invalidating the session if the user has + * not yet logged in. + */ + private Integer loginTimeout = 1 * 60; + // TODO make it configurable + /** Default session timeout is 8 hours (European working day length) */ + private Integer sessionTimeout = 8 * 60 * 60; + + /** Override to provide an application specific workbench advisor */ + protected RapWorkbenchAdvisor createRapWorkbenchAdvisor(String username) { + return new RapWorkbenchAdvisor(username); + } + + @Override + public final int createUI() { + // Short login timeout so that the modal dialog login doesn't hang + // around too long + RWT.getRequest().getSession().setMaxInactiveInterval(loginTimeout); + + // Try to load security context thanks to the session processing filter + HttpServletRequest httpRequest = RWT.getRequest(); + HttpSession httpSession = httpRequest.getSession(); + Object contextFromSessionObject = httpSession + .getAttribute(SPRING_SECURITY_CONTEXT_KEY); + if (contextFromSessionObject != null) + SecurityContextHolder + .setContext((SecurityContext) contextFromSessionObject); + +// if (log.isDebugEnabled()) +// log.debug("THREAD=" + Thread.currentThread().getId() +// + ", sessionStore=" + RWT.getSessionStore().getId() +// + ", remote user=" + httpRequest.getRemoteUser()); + + // create display + final Display display = PlatformUI.createDisplay(); + + // log in + final ILoginContext loginContext = SecureRapActivator + .createLoginContext(SecureRapActivator.CONTEXT_SPRING); + Subject subject = null; + tryLogin: while (subject == null && !display.isDisposed()) { + try { + loginContext.login(); + subject = loginContext.getSubject(); + + // add security context to session + if (httpSession.getAttribute(SPRING_SECURITY_CONTEXT_KEY) == null) + httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY, + SecurityContextHolder.getContext()); + // add thread locale to RWT session + log.info("Locale "+LocaleUtils.threadLocale.get()); + RWT.setLocale(LocaleUtils.threadLocale.get()); + + // Once the user is logged in, she can have a longer session + // timeout + RWT.getRequest().getSession() + .setMaxInactiveInterval(sessionTimeout); + if (log.isDebugEnabled()) + log.debug("Authenticated " + subject); + } catch (LoginException e) { + BadCredentialsException bce = wasCausedByBadCredentials(e); + if (bce != null) { + MessageDialog.openInformation(display.getActiveShell(), + "Bad Credentials", bce.getMessage()); + // retry login + continue tryLogin; + } + return processLoginDeath(display, e); + } + } + + final String username = subject.getPrincipals().iterator().next() + .getName(); + // Logout callback when the display is disposed + display.disposeExec(new Runnable() { + public void run() { + log.debug("Display disposed"); + logout(loginContext, username); + } + }); + + // + // RUN THE WORKBENCH + // + Integer returnCode = null; + try { + returnCode = Subject.doAs(subject, new PrivilegedAction() { + public Integer run() { + RapWorkbenchAdvisor workbenchAdvisor = createRapWorkbenchAdvisor(username); + int result = PlatformUI.createAndRunWorkbench(display, + workbenchAdvisor); + return new Integer(result); + } + }); + // logout(loginContext, username); + } finally { + display.dispose(); + } + return returnCode; + } + + private Integer processLoginDeath(Display display, LoginException e) { + // check thread death + ThreadDeath td = wasCausedByThreadDeath(e); + if (td != null) { + display.dispose(); + throw td; + } + if (!display.isDisposed()) { + ErrorFeedback.show("Unexpected exception during authentication", e); + // this was not just bad credentials or death thread + RWT.getRequest().getSession().setMaxInactiveInterval(1); + display.dispose(); + return -1; + } else { + throw new ArgeoException( + "Unexpected exception during authentication", e); + } + + } + + /** Recursively look for {@link BadCredentialsException} in the root causes. */ + private BadCredentialsException wasCausedByBadCredentials(Throwable t) { + if (t instanceof BadCredentialsException) + return (BadCredentialsException) t; + + if (t.getCause() != null) + return wasCausedByBadCredentials(t.getCause()); + else + return null; + } + + /** + * If there is a {@link ThreadDeath} in the root causes, rethrow it + * (important for RAP cleaning mechanism) + */ + protected ThreadDeath wasCausedByThreadDeath(Throwable t) { + if (t instanceof ThreadDeath) + return (ThreadDeath) t; + + if (t.getCause() != null) + return wasCausedByThreadDeath(t.getCause()); + else + return null; + } + + protected void logout(ILoginContext secureContext, String username) { + try { + HttpServletRequest httpRequest = RWT.getRequest(); + HttpSession httpSession = httpRequest.getSession(); + httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY, null); + RWT.getRequest().getSession().setMaxInactiveInterval(1); + SecurityContextHolder.clearContext(); + secureContext.logout(); + log.info("Logged out " + (username != null ? username : "") + + " (THREAD=" + Thread.currentThread().getId() + ")"); + } catch (LoginException e) { + log.error("Erorr when logging out", e); + } + } +} diff --git a/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/SecureRapActivator.java b/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/SecureRapActivator.java new file mode 100644 index 000000000..4cbb441e7 --- /dev/null +++ b/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/SecureRapActivator.java @@ -0,0 +1,59 @@ +/* + * 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.security.ui.rap; + +import java.net.URL; + +import org.eclipse.equinox.security.auth.ILoginContext; +import org.eclipse.equinox.security.auth.LoginContextFactory; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +/** Configure Equinox login context from the bundle context. */ +public class SecureRapActivator implements BundleActivator { + + public final static String ID = "org.argeo.security.ui.rap"; + public final static String CONTEXT_SPRING = "SPRING"; + public final static String CONTEXT_SPRING_ANONYMOUS = "SPRING_ANONYMOUS"; + private static final String JAAS_CONFIG_FILE = "/META-INF/jaas_default.txt"; + + private BundleContext bundleContext; + private static SecureRapActivator activator = null; + + public void start(BundleContext bundleContext) throws Exception { + activator = this; + this.bundleContext = bundleContext; + } + + public void stop(BundleContext context) throws Exception { + bundleContext = null; + activator = null; + } + + public BundleContext getBundleContext() { + return bundleContext; + } + + public static SecureRapActivator getActivator() { + return activator; + } + + static ILoginContext createLoginContext(String contextName) { + URL configUrl = getActivator().getBundleContext().getBundle() + .getEntry(JAAS_CONFIG_FILE); + return LoginContextFactory.createContext(contextName, configUrl); + } +} diff --git a/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/commands/UserMenu.java b/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/commands/UserMenu.java new file mode 100644 index 000000000..98674303b --- /dev/null +++ b/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/commands/UserMenu.java @@ -0,0 +1,30 @@ +/* + * 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.security.ui.rap.commands; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; + +/** Default action of the user menu */ +public class UserMenu extends AbstractHandler { + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + return null; + } + +} diff --git a/org.argeo.security.ui.rcp/.classpath b/org.argeo.security.ui.rcp/.classpath index 8cf7f48a0..d2953a684 100644 --- a/org.argeo.security.ui.rcp/.classpath +++ b/org.argeo.security.ui.rcp/.classpath @@ -1,7 +1,9 @@ - - - - + + + + diff --git a/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/AbstractSecureApplication.java b/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/AbstractSecureApplication.java deleted file mode 100644 index 75184cbab..000000000 --- a/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/AbstractSecureApplication.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * 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.security.ui.rcp; - -import java.security.PrivilegedAction; - -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.OperatingSystem; -import org.eclipse.equinox.app.IApplication; -import org.eclipse.equinox.app.IApplicationContext; -import org.eclipse.equinox.security.auth.ILoginContext; -import org.eclipse.swt.widgets.Display; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.application.WorkbenchAdvisor; - -/** - * RCP workbench initialization - */ -public abstract class AbstractSecureApplication implements IApplication { - final static String NODE_REPO_URI = "argeo.node.repo.uri"; - - private static final Log log = LogFactory - .getLog(AbstractSecureApplication.class); - - protected WorkbenchAdvisor createWorkbenchAdvisor(String username) { - return new SecureWorkbenchAdvisor(username); - } - - public Object start(IApplicationContext context) throws Exception { - // wait for the system to be initialized - // try { - // Thread.sleep(3000); - // } catch (Exception e2) { - // // silent - // } - - boolean remote = System.getProperty(NODE_REPO_URI) != null; - - // choose login context - final ILoginContext loginContext; - if (remote) { - loginContext = SecureApplicationActivator - .createLoginContext(SecureApplicationActivator.CONTEXT_REMOTE); - } else { - if (OperatingSystem.os == OperatingSystem.WINDOWS) - loginContext = SecureApplicationActivator - .createLoginContext(SecureApplicationActivator.CONTEXT_WINDOWS); - else - loginContext = SecureApplicationActivator - .createLoginContext(SecureApplicationActivator.CONTEXT_NIX); - } - - final Display display = PlatformUI.createDisplay(); - - // login - Subject subject = null; - try { - loginContext.login(); - subject = loginContext.getSubject(); - } catch (LoginException e) { - log.error("Error when logging in.", e); - display.dispose(); - try { - Thread.sleep(2000); - } catch (InterruptedException e1) { - // silent - } - return null; - } - - // identify after successful login - if (log.isDebugEnabled()) - log.debug("subject=" + subject); - final String username = subject.getPrincipals().iterator().next() - .getName(); - if (log.isDebugEnabled()) - log.debug(username + " logged in"); -// display.disposeExec(new Runnable() { -// public void run() { -// log.debug("Display disposed"); -// logout(loginContext, username); -// } -// }); - - try { - PrivilegedAction privilegedAction = new PrivilegedAction() { - public Object run() { - int result = PlatformUI.createAndRunWorkbench(display, - createWorkbenchAdvisor(username)); - return new Integer(result); - } - }; - - Integer returnCode = (Integer) Subject.doAs(subject, - privilegedAction); - logout(loginContext, username); - return processReturnCode(returnCode); - } catch (Exception e) { - if (subject != null) - logout(loginContext, username); - log.error("Unexpected error", e); - } finally { - display.dispose(); - } - return null; - } - - protected Integer processReturnCode(Integer returnCode) { - if (returnCode == PlatformUI.RETURN_RESTART) - return IApplication.EXIT_RESTART; - else - return IApplication.EXIT_OK; - } - - static void logout(ILoginContext secureContext, String username) { - try { - secureContext.logout(); - log.info("Logged out " + (username != null ? username : "") - + " (THREAD=" + Thread.currentThread().getId() + ")"); - } catch (LoginException e) { - log.error("Erorr when logging out", e); - } - } - - public void stop() { - final IWorkbench workbench; - try { - workbench = PlatformUI.getWorkbench(); - } catch (Exception e) { - return; - } - if (workbench == null) - return; - final Display display = workbench.getDisplay(); - if (display != null && !display.isDisposed()) - display.syncExec(new Runnable() { - - public void run() { - if (!display.isDisposed()) - workbench.close(); - } - }); - - if (log.isDebugEnabled()) - log.debug("workbench stopped"); - } - -} diff --git a/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureActionBarAdvisor.java b/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureActionBarAdvisor.java deleted file mode 100644 index 481865bfa..000000000 --- a/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureActionBarAdvisor.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * 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.security.ui.rcp; - -import org.eclipse.jface.action.GroupMarker; -import org.eclipse.jface.action.ICoolBarManager; -import org.eclipse.jface.action.IMenuManager; -import org.eclipse.jface.action.IToolBarManager; -import org.eclipse.jface.action.MenuManager; -import org.eclipse.jface.action.Separator; -import org.eclipse.jface.action.ToolBarManager; -import org.eclipse.swt.SWT; -import org.eclipse.ui.IWorkbenchActionConstants; -import org.eclipse.ui.IWorkbenchWindow; -import org.eclipse.ui.actions.ActionFactory; -import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction; -import org.eclipse.ui.application.ActionBarAdvisor; -import org.eclipse.ui.application.IActionBarConfigurer; - -public class SecureActionBarAdvisor extends ActionBarAdvisor { - private IWorkbenchAction exitAction; - private IWorkbenchAction openPerspectiveDialogAction; - private IWorkbenchAction showViewMenuAction; - private IWorkbenchAction preferences; - private IWorkbenchAction saveAction; - private IWorkbenchAction saveAsAction; - private IWorkbenchAction saveAllAction; - private IWorkbenchAction closeAllAction; - - // private final Boolean isRcp; - - public SecureActionBarAdvisor(IActionBarConfigurer configurer, Boolean isRcp) { - super(configurer); - // this.isRcp = isRcp; - } - - protected void makeActions(IWorkbenchWindow window) { - preferences = ActionFactory.PREFERENCES.create(window); - register(preferences); - openPerspectiveDialogAction = ActionFactory.OPEN_PERSPECTIVE_DIALOG - .create(window); - register(openPerspectiveDialogAction); - showViewMenuAction = ActionFactory.SHOW_VIEW_MENU.create(window); - register(showViewMenuAction); - - exitAction = ActionFactory.QUIT.create(window); - register(exitAction); - - // Save semantiocs - saveAction = ActionFactory.SAVE.create(window); - register(saveAction); - saveAsAction = ActionFactory.SAVE_AS.create(window); - register(saveAsAction); - saveAllAction = ActionFactory.SAVE_ALL.create(window); - register(saveAllAction); - closeAllAction = ActionFactory.CLOSE_ALL.create(window); - register(closeAllAction); - - } - - protected void fillMenuBar(IMenuManager menuBar) { - MenuManager fileMenu = new MenuManager("&File", - IWorkbenchActionConstants.M_FILE); - MenuManager editMenu = new MenuManager("&Edit", - IWorkbenchActionConstants.M_EDIT); - MenuManager windowMenu = new MenuManager("&Window", - IWorkbenchActionConstants.M_WINDOW); - - menuBar.add(fileMenu); - menuBar.add(editMenu); - menuBar.add(windowMenu); - // Add a group marker indicating where action set menus will appear. - menuBar.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); - - // File - fileMenu.add(saveAction); - fileMenu.add(saveAsAction); - fileMenu.add(saveAllAction); - fileMenu.add(closeAllAction); - fileMenu.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); - fileMenu.add(new Separator()); - fileMenu.add(exitAction); - - // Edit - editMenu.add(preferences); - - // Window - windowMenu.add(openPerspectiveDialogAction); - windowMenu.add(showViewMenuAction); - } - - @Override - protected void fillCoolBar(ICoolBarManager coolBar) { - IToolBarManager saveToolbar = new ToolBarManager(SWT.FLAT | SWT.RIGHT); - saveToolbar.add(saveAction); - saveToolbar.add(saveAllAction); - coolBar.add(saveToolbar); - } - -} diff --git a/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureApplicationActivator.java b/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureApplicationActivator.java deleted file mode 100644 index 9c0425c5b..000000000 --- a/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureApplicationActivator.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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.security.ui.rcp; - -import java.net.URL; - -import org.eclipse.equinox.security.auth.ILoginContext; -import org.eclipse.equinox.security.auth.LoginContextFactory; -import org.osgi.framework.BundleActivator; -import org.osgi.framework.BundleContext; - -/** Activator able to create {@link ILoginContext} */ -public class SecureApplicationActivator implements BundleActivator { - - public final static String CONTEXT_REMOTE = "REMOTE"; - public final static String CONTEXT_NIX = "NIX"; - public final static String CONTEXT_WINDOWS = "WINDOWS"; - private static final String JAAS_CONFIG_FILE = "/META-INF/jaas_default.txt"; - - private static BundleContext bundleContext; - - public void start(BundleContext bundleContext) throws Exception { - SecureApplicationActivator.bundleContext = bundleContext; - } - - public void stop(BundleContext context) throws Exception { - } - - static ILoginContext createLoginContext(String context) { - URL configUrl = bundleContext.getBundle().getEntry(JAAS_CONFIG_FILE); - return LoginContextFactory.createContext(context, configUrl); - } -} diff --git a/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureRcp.java b/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureRcp.java deleted file mode 100644 index d8125cf6f..000000000 --- a/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureRcp.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * 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.security.ui.rcp; - - -public class SecureRcp extends AbstractSecureApplication { -} diff --git a/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureWorkbenchAdvisor.java b/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureWorkbenchAdvisor.java deleted file mode 100644 index 33b781ee5..000000000 --- a/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureWorkbenchAdvisor.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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.security.ui.rcp; - -import org.eclipse.ui.IPerspectiveDescriptor; -import org.eclipse.ui.application.IWorkbenchConfigurer; -import org.eclipse.ui.application.IWorkbenchWindowConfigurer; -import org.eclipse.ui.application.WorkbenchAdvisor; -import org.eclipse.ui.application.WorkbenchWindowAdvisor; - -/** - * Workbench configuration which is aware of the logged in user and can remember - * workbench state. - */ -public class SecureWorkbenchAdvisor extends WorkbenchAdvisor { - public final static String INITIAL_PERSPECTIVE_PROPERTY = "org.argeo.security.ui.initialPerspective"; - public final static String SAVE_AND_RESTORE_PROPERTY = "org.argeo.security.ui.saveAndRestore"; - - private String initialPerspective = System.getProperty( - INITIAL_PERSPECTIVE_PROPERTY, null); - - private final String username; - - public SecureWorkbenchAdvisor(String username) { - this.username = username; - } - - @Override - public void initialize(final IWorkbenchConfigurer configurer) { - super.initialize(configurer); - Boolean saveAndRestore = Boolean.parseBoolean(System.getProperty( - SAVE_AND_RESTORE_PROPERTY, "true")); - configurer.setSaveAndRestore(saveAndRestore); - } - - public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor( - IWorkbenchWindowConfigurer configurer) { - return new SecureWorkbenchWindowAdvisor(configurer, username); - } - - public String getInitialWindowPerspectiveId() { - if (initialPerspective != null) { - // check whether this user can see the declared perspective - // (typically the perspective won't be listed if this user doesn't - // have the right to see it) - IPerspectiveDescriptor pd = getWorkbenchConfigurer().getWorkbench() - .getPerspectiveRegistry() - .findPerspectiveWithId(initialPerspective); - if (pd == null) - return null; - } - return initialPerspective; - } - - protected String getUsername() { - return username; - } -} diff --git a/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureWorkbenchWindowAdvisor.java b/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureWorkbenchWindowAdvisor.java deleted file mode 100644 index d8aaec443..000000000 --- a/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureWorkbenchWindowAdvisor.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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.security.ui.rcp; - -import org.eclipse.swt.graphics.Point; -import org.eclipse.ui.application.ActionBarAdvisor; -import org.eclipse.ui.application.IActionBarConfigurer; -import org.eclipse.ui.application.IWorkbenchWindowConfigurer; -import org.eclipse.ui.application.WorkbenchWindowAdvisor; - -public class SecureWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor { - private final String username; - - public SecureWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer, - String username) { - super(configurer); - this.username = username; - } - - public ActionBarAdvisor createActionBarAdvisor( - IActionBarConfigurer configurer) { - return new SecureActionBarAdvisor(configurer, true); - } - - public void preWindowOpen() { - IWorkbenchWindowConfigurer configurer = getWindowConfigurer(); - configurer.setInitialSize(new Point(1200, 900)); - configurer.setShowCoolBar(true); - configurer.setShowMenuBar(true); - configurer.setShowStatusLine(true); - configurer.setShowProgressIndicator(true); - - configurer.setShowPerspectiveBar(true); - String remoteUri = System - .getProperty(AbstractSecureApplication.NODE_REPO_URI); - if (remoteUri != null) - configurer - .setTitle("Argeo UI - " + username + " (" + remoteUri + ")"); //$NON-NLS-1$ - else - configurer.setTitle("Argeo UI - " + username); //$NON-NLS-1$ - - } -} diff --git a/org.argeo.security.ui.rcp/src/org/argeo/security/ui/rcp/AbstractSecureApplication.java b/org.argeo.security.ui.rcp/src/org/argeo/security/ui/rcp/AbstractSecureApplication.java new file mode 100644 index 000000000..75184cbab --- /dev/null +++ b/org.argeo.security.ui.rcp/src/org/argeo/security/ui/rcp/AbstractSecureApplication.java @@ -0,0 +1,166 @@ +/* + * 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.security.ui.rcp; + +import java.security.PrivilegedAction; + +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.OperatingSystem; +import org.eclipse.equinox.app.IApplication; +import org.eclipse.equinox.app.IApplicationContext; +import org.eclipse.equinox.security.auth.ILoginContext; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.application.WorkbenchAdvisor; + +/** + * RCP workbench initialization + */ +public abstract class AbstractSecureApplication implements IApplication { + final static String NODE_REPO_URI = "argeo.node.repo.uri"; + + private static final Log log = LogFactory + .getLog(AbstractSecureApplication.class); + + protected WorkbenchAdvisor createWorkbenchAdvisor(String username) { + return new SecureWorkbenchAdvisor(username); + } + + public Object start(IApplicationContext context) throws Exception { + // wait for the system to be initialized + // try { + // Thread.sleep(3000); + // } catch (Exception e2) { + // // silent + // } + + boolean remote = System.getProperty(NODE_REPO_URI) != null; + + // choose login context + final ILoginContext loginContext; + if (remote) { + loginContext = SecureApplicationActivator + .createLoginContext(SecureApplicationActivator.CONTEXT_REMOTE); + } else { + if (OperatingSystem.os == OperatingSystem.WINDOWS) + loginContext = SecureApplicationActivator + .createLoginContext(SecureApplicationActivator.CONTEXT_WINDOWS); + else + loginContext = SecureApplicationActivator + .createLoginContext(SecureApplicationActivator.CONTEXT_NIX); + } + + final Display display = PlatformUI.createDisplay(); + + // login + Subject subject = null; + try { + loginContext.login(); + subject = loginContext.getSubject(); + } catch (LoginException e) { + log.error("Error when logging in.", e); + display.dispose(); + try { + Thread.sleep(2000); + } catch (InterruptedException e1) { + // silent + } + return null; + } + + // identify after successful login + if (log.isDebugEnabled()) + log.debug("subject=" + subject); + final String username = subject.getPrincipals().iterator().next() + .getName(); + if (log.isDebugEnabled()) + log.debug(username + " logged in"); +// display.disposeExec(new Runnable() { +// public void run() { +// log.debug("Display disposed"); +// logout(loginContext, username); +// } +// }); + + try { + PrivilegedAction privilegedAction = new PrivilegedAction() { + public Object run() { + int result = PlatformUI.createAndRunWorkbench(display, + createWorkbenchAdvisor(username)); + return new Integer(result); + } + }; + + Integer returnCode = (Integer) Subject.doAs(subject, + privilegedAction); + logout(loginContext, username); + return processReturnCode(returnCode); + } catch (Exception e) { + if (subject != null) + logout(loginContext, username); + log.error("Unexpected error", e); + } finally { + display.dispose(); + } + return null; + } + + protected Integer processReturnCode(Integer returnCode) { + if (returnCode == PlatformUI.RETURN_RESTART) + return IApplication.EXIT_RESTART; + else + return IApplication.EXIT_OK; + } + + static void logout(ILoginContext secureContext, String username) { + try { + secureContext.logout(); + log.info("Logged out " + (username != null ? username : "") + + " (THREAD=" + Thread.currentThread().getId() + ")"); + } catch (LoginException e) { + log.error("Erorr when logging out", e); + } + } + + public void stop() { + final IWorkbench workbench; + try { + workbench = PlatformUI.getWorkbench(); + } catch (Exception e) { + return; + } + if (workbench == null) + return; + final Display display = workbench.getDisplay(); + if (display != null && !display.isDisposed()) + display.syncExec(new Runnable() { + + public void run() { + if (!display.isDisposed()) + workbench.close(); + } + }); + + if (log.isDebugEnabled()) + log.debug("workbench stopped"); + } + +} diff --git a/org.argeo.security.ui.rcp/src/org/argeo/security/ui/rcp/SecureActionBarAdvisor.java b/org.argeo.security.ui.rcp/src/org/argeo/security/ui/rcp/SecureActionBarAdvisor.java new file mode 100644 index 000000000..481865bfa --- /dev/null +++ b/org.argeo.security.ui.rcp/src/org/argeo/security/ui/rcp/SecureActionBarAdvisor.java @@ -0,0 +1,113 @@ +/* + * 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.security.ui.rcp; + +import org.eclipse.jface.action.GroupMarker; +import org.eclipse.jface.action.ICoolBarManager; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.jface.action.ToolBarManager; +import org.eclipse.swt.SWT; +import org.eclipse.ui.IWorkbenchActionConstants; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.actions.ActionFactory; +import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction; +import org.eclipse.ui.application.ActionBarAdvisor; +import org.eclipse.ui.application.IActionBarConfigurer; + +public class SecureActionBarAdvisor extends ActionBarAdvisor { + private IWorkbenchAction exitAction; + private IWorkbenchAction openPerspectiveDialogAction; + private IWorkbenchAction showViewMenuAction; + private IWorkbenchAction preferences; + private IWorkbenchAction saveAction; + private IWorkbenchAction saveAsAction; + private IWorkbenchAction saveAllAction; + private IWorkbenchAction closeAllAction; + + // private final Boolean isRcp; + + public SecureActionBarAdvisor(IActionBarConfigurer configurer, Boolean isRcp) { + super(configurer); + // this.isRcp = isRcp; + } + + protected void makeActions(IWorkbenchWindow window) { + preferences = ActionFactory.PREFERENCES.create(window); + register(preferences); + openPerspectiveDialogAction = ActionFactory.OPEN_PERSPECTIVE_DIALOG + .create(window); + register(openPerspectiveDialogAction); + showViewMenuAction = ActionFactory.SHOW_VIEW_MENU.create(window); + register(showViewMenuAction); + + exitAction = ActionFactory.QUIT.create(window); + register(exitAction); + + // Save semantiocs + saveAction = ActionFactory.SAVE.create(window); + register(saveAction); + saveAsAction = ActionFactory.SAVE_AS.create(window); + register(saveAsAction); + saveAllAction = ActionFactory.SAVE_ALL.create(window); + register(saveAllAction); + closeAllAction = ActionFactory.CLOSE_ALL.create(window); + register(closeAllAction); + + } + + protected void fillMenuBar(IMenuManager menuBar) { + MenuManager fileMenu = new MenuManager("&File", + IWorkbenchActionConstants.M_FILE); + MenuManager editMenu = new MenuManager("&Edit", + IWorkbenchActionConstants.M_EDIT); + MenuManager windowMenu = new MenuManager("&Window", + IWorkbenchActionConstants.M_WINDOW); + + menuBar.add(fileMenu); + menuBar.add(editMenu); + menuBar.add(windowMenu); + // Add a group marker indicating where action set menus will appear. + menuBar.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); + + // File + fileMenu.add(saveAction); + fileMenu.add(saveAsAction); + fileMenu.add(saveAllAction); + fileMenu.add(closeAllAction); + fileMenu.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); + fileMenu.add(new Separator()); + fileMenu.add(exitAction); + + // Edit + editMenu.add(preferences); + + // Window + windowMenu.add(openPerspectiveDialogAction); + windowMenu.add(showViewMenuAction); + } + + @Override + protected void fillCoolBar(ICoolBarManager coolBar) { + IToolBarManager saveToolbar = new ToolBarManager(SWT.FLAT | SWT.RIGHT); + saveToolbar.add(saveAction); + saveToolbar.add(saveAllAction); + coolBar.add(saveToolbar); + } + +} diff --git a/org.argeo.security.ui.rcp/src/org/argeo/security/ui/rcp/SecureApplicationActivator.java b/org.argeo.security.ui.rcp/src/org/argeo/security/ui/rcp/SecureApplicationActivator.java new file mode 100644 index 000000000..9c0425c5b --- /dev/null +++ b/org.argeo.security.ui.rcp/src/org/argeo/security/ui/rcp/SecureApplicationActivator.java @@ -0,0 +1,46 @@ +/* + * 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.security.ui.rcp; + +import java.net.URL; + +import org.eclipse.equinox.security.auth.ILoginContext; +import org.eclipse.equinox.security.auth.LoginContextFactory; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +/** Activator able to create {@link ILoginContext} */ +public class SecureApplicationActivator implements BundleActivator { + + public final static String CONTEXT_REMOTE = "REMOTE"; + public final static String CONTEXT_NIX = "NIX"; + public final static String CONTEXT_WINDOWS = "WINDOWS"; + private static final String JAAS_CONFIG_FILE = "/META-INF/jaas_default.txt"; + + private static BundleContext bundleContext; + + public void start(BundleContext bundleContext) throws Exception { + SecureApplicationActivator.bundleContext = bundleContext; + } + + public void stop(BundleContext context) throws Exception { + } + + static ILoginContext createLoginContext(String context) { + URL configUrl = bundleContext.getBundle().getEntry(JAAS_CONFIG_FILE); + return LoginContextFactory.createContext(context, configUrl); + } +} diff --git a/org.argeo.security.ui.rcp/src/org/argeo/security/ui/rcp/SecureRcp.java b/org.argeo.security.ui.rcp/src/org/argeo/security/ui/rcp/SecureRcp.java new file mode 100644 index 000000000..d8125cf6f --- /dev/null +++ b/org.argeo.security.ui.rcp/src/org/argeo/security/ui/rcp/SecureRcp.java @@ -0,0 +1,20 @@ +/* + * 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.security.ui.rcp; + + +public class SecureRcp extends AbstractSecureApplication { +} diff --git a/org.argeo.security.ui.rcp/src/org/argeo/security/ui/rcp/SecureWorkbenchAdvisor.java b/org.argeo.security.ui.rcp/src/org/argeo/security/ui/rcp/SecureWorkbenchAdvisor.java new file mode 100644 index 000000000..33b781ee5 --- /dev/null +++ b/org.argeo.security.ui.rcp/src/org/argeo/security/ui/rcp/SecureWorkbenchAdvisor.java @@ -0,0 +1,71 @@ +/* + * 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.security.ui.rcp; + +import org.eclipse.ui.IPerspectiveDescriptor; +import org.eclipse.ui.application.IWorkbenchConfigurer; +import org.eclipse.ui.application.IWorkbenchWindowConfigurer; +import org.eclipse.ui.application.WorkbenchAdvisor; +import org.eclipse.ui.application.WorkbenchWindowAdvisor; + +/** + * Workbench configuration which is aware of the logged in user and can remember + * workbench state. + */ +public class SecureWorkbenchAdvisor extends WorkbenchAdvisor { + public final static String INITIAL_PERSPECTIVE_PROPERTY = "org.argeo.security.ui.initialPerspective"; + public final static String SAVE_AND_RESTORE_PROPERTY = "org.argeo.security.ui.saveAndRestore"; + + private String initialPerspective = System.getProperty( + INITIAL_PERSPECTIVE_PROPERTY, null); + + private final String username; + + public SecureWorkbenchAdvisor(String username) { + this.username = username; + } + + @Override + public void initialize(final IWorkbenchConfigurer configurer) { + super.initialize(configurer); + Boolean saveAndRestore = Boolean.parseBoolean(System.getProperty( + SAVE_AND_RESTORE_PROPERTY, "true")); + configurer.setSaveAndRestore(saveAndRestore); + } + + public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor( + IWorkbenchWindowConfigurer configurer) { + return new SecureWorkbenchWindowAdvisor(configurer, username); + } + + public String getInitialWindowPerspectiveId() { + if (initialPerspective != null) { + // check whether this user can see the declared perspective + // (typically the perspective won't be listed if this user doesn't + // have the right to see it) + IPerspectiveDescriptor pd = getWorkbenchConfigurer().getWorkbench() + .getPerspectiveRegistry() + .findPerspectiveWithId(initialPerspective); + if (pd == null) + return null; + } + return initialPerspective; + } + + protected String getUsername() { + return username; + } +} diff --git a/org.argeo.security.ui.rcp/src/org/argeo/security/ui/rcp/SecureWorkbenchWindowAdvisor.java b/org.argeo.security.ui.rcp/src/org/argeo/security/ui/rcp/SecureWorkbenchWindowAdvisor.java new file mode 100644 index 000000000..d8aaec443 --- /dev/null +++ b/org.argeo.security.ui.rcp/src/org/argeo/security/ui/rcp/SecureWorkbenchWindowAdvisor.java @@ -0,0 +1,56 @@ +/* + * 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.security.ui.rcp; + +import org.eclipse.swt.graphics.Point; +import org.eclipse.ui.application.ActionBarAdvisor; +import org.eclipse.ui.application.IActionBarConfigurer; +import org.eclipse.ui.application.IWorkbenchWindowConfigurer; +import org.eclipse.ui.application.WorkbenchWindowAdvisor; + +public class SecureWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor { + private final String username; + + public SecureWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer, + String username) { + super(configurer); + this.username = username; + } + + public ActionBarAdvisor createActionBarAdvisor( + IActionBarConfigurer configurer) { + return new SecureActionBarAdvisor(configurer, true); + } + + public void preWindowOpen() { + IWorkbenchWindowConfigurer configurer = getWindowConfigurer(); + configurer.setInitialSize(new Point(1200, 900)); + configurer.setShowCoolBar(true); + configurer.setShowMenuBar(true); + configurer.setShowStatusLine(true); + configurer.setShowProgressIndicator(true); + + configurer.setShowPerspectiveBar(true); + String remoteUri = System + .getProperty(AbstractSecureApplication.NODE_REPO_URI); + if (remoteUri != null) + configurer + .setTitle("Argeo UI - " + username + " (" + remoteUri + ")"); //$NON-NLS-1$ + else + configurer.setTitle("Argeo UI - " + username); //$NON-NLS-1$ + + } +} diff --git a/org.argeo.security.ui/.classpath b/org.argeo.security.ui/.classpath index 5641c7ca3..d2953a684 100644 --- a/org.argeo.security.ui/.classpath +++ b/org.argeo.security.ui/.classpath @@ -1,7 +1,9 @@ - - >> - - + + + + diff --git a/org.argeo.security.ui/build.properties b/org.argeo.security.ui/build.properties index 3868784bf..30f715358 100644 --- a/org.argeo.security.ui/build.properties +++ b/org.argeo.security.ui/build.properties @@ -1,6 +1 @@ -source.. = src/main/java/ -output.. = target/classes/ -bin.includes = META-INF/,\ - .,\ - plugin.xml,\ - icons/ +source.. = src/ diff --git a/org.argeo.security.ui/src/main/java/org/argeo/security/ui/MaintenancePerspective.java b/org.argeo.security.ui/src/main/java/org/argeo/security/ui/MaintenancePerspective.java deleted file mode 100644 index 86307abd2..000000000 --- a/org.argeo.security.ui/src/main/java/org/argeo/security/ui/MaintenancePerspective.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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.security.ui; - -import org.argeo.security.ui.views.AdminLogView; -import org.argeo.security.ui.views.UserProfile; -import org.eclipse.ui.IFolderLayout; -import org.eclipse.ui.IPageLayout; -import org.eclipse.ui.IPerspectiveFactory; - -/** Home perspective for the current user */ -public class MaintenancePerspective implements IPerspectiveFactory { - public final static String ID = SecurityUiPlugin.PLUGIN_ID - + ".adminMaintenancePerspective"; - - public void createInitialLayout(IPageLayout layout) { - String editorArea = layout.getEditorArea(); - layout.setEditorAreaVisible(true); - layout.setFixed(false); - - IFolderLayout bottom = layout.createFolder("bottom", - IPageLayout.BOTTOM, 0.50f, editorArea); - bottom.addView(AdminLogView.ID); - - IFolderLayout left = layout.createFolder("left", IPageLayout.LEFT, - 0.30f, editorArea); - left.addView(UserProfile.ID); - // left.addView(RolesView.ID); - - } - -} diff --git a/org.argeo.security.ui/src/main/java/org/argeo/security/ui/PrivilegedJob.java b/org.argeo.security.ui/src/main/java/org/argeo/security/ui/PrivilegedJob.java deleted file mode 100644 index 1ded50fdb..000000000 --- a/org.argeo.security.ui/src/main/java/org/argeo/security/ui/PrivilegedJob.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.argeo.security.ui; - -import java.security.AccessController; -import java.security.PrivilegedAction; - -import javax.security.auth.Subject; - -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.jobs.Job; -import org.springframework.security.Authentication; -import org.springframework.security.context.SecurityContextHolder; - -/** - * Propagate authentication to an eclipse job. Typically to execute a privileged - * action outside the UI thread - */ -public abstract class PrivilegedJob extends Job { - - private final Authentication authentication; - private Subject subject; - - public PrivilegedJob(String jobName) { - super(jobName); - authentication = SecurityContextHolder.getContext().getAuthentication(); - subject = Subject.getSubject(AccessController.getContext()); - } - - @Override - protected IStatus run(final IProgressMonitor progressMonitor) { - PrivilegedAction privilegedAction = new PrivilegedAction() { - public IStatus run() { - SecurityContextHolder.getContext().setAuthentication( - authentication); - return doRun(progressMonitor); - } - }; - return Subject.doAs(subject, privilegedAction); - } - - /** - * Implement here what should be executed with default context - * authentication - */ - protected abstract IStatus doRun(IProgressMonitor progressMonitor); -} \ No newline at end of file diff --git a/org.argeo.security.ui/src/main/java/org/argeo/security/ui/RolesSourceProvider.java b/org.argeo.security.ui/src/main/java/org/argeo/security/ui/RolesSourceProvider.java deleted file mode 100644 index a81dc200a..000000000 --- a/org.argeo.security.ui/src/main/java/org/argeo/security/ui/RolesSourceProvider.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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.security.ui; - -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import org.argeo.security.ui.internal.CurrentUser; -import org.eclipse.ui.AbstractSourceProvider; - -/** - * Provides the roles of the current user as a variable to be used for activity - * binding - */ -public class RolesSourceProvider extends AbstractSourceProvider { - public final static String ROLES_VARIABLE = "roles"; - private final static String[] PROVIDED_SOURCE_NAMES = new String[] { ROLES_VARIABLE }; - - public Map> getCurrentState() { - Map> stateMap = new HashMap>(); - stateMap.put(ROLES_VARIABLE, CurrentUser.roles()); - return stateMap; - } - - public String[] getProvidedSourceNames() { - return PROVIDED_SOURCE_NAMES; - } - - public void updateRoles() { - fireSourceChanged(0, getCurrentState()); - } - - public void dispose() { - } -} \ No newline at end of file diff --git a/org.argeo.security.ui/src/main/java/org/argeo/security/ui/SecurityUiPlugin.java b/org.argeo.security.ui/src/main/java/org/argeo/security/ui/SecurityUiPlugin.java deleted file mode 100644 index 03584185b..000000000 --- a/org.argeo.security.ui/src/main/java/org/argeo/security/ui/SecurityUiPlugin.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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.security.ui; - -import java.io.IOException; - -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.UnsupportedCallbackException; - -import org.argeo.ArgeoException; -import org.argeo.security.ui.dialogs.DefaultLoginDialog; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.swt.widgets.Display; -import org.eclipse.ui.plugin.AbstractUIPlugin; -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceRegistration; - -/** - * The activator class controls the plug-in life cycle - */ -public class SecurityUiPlugin extends AbstractUIPlugin { - - // The plug-in ID - public static final String PLUGIN_ID = "org.argeo.security.ui"; //$NON-NLS-1$ - - public final static String CONTEXT_KEYRING = "KEYRING"; - - private CallbackHandler defaultCallbackHandler; - private ServiceRegistration defaultCallbackHandlerReg; - - private static SecurityUiPlugin plugin; - - public static InheritableThreadLocal display = new InheritableThreadLocal() { - - @Override - protected Display initialValue() { - return Display.getCurrent(); - } - }; - - public void start(BundleContext context) throws Exception { - super.start(context); - plugin = this; - - defaultCallbackHandler = new DefaultCallbackHandler(); - defaultCallbackHandlerReg = context.registerService( - CallbackHandler.class.getName(), defaultCallbackHandler, null); - } - - public void stop(BundleContext context) throws Exception { - plugin = null; - defaultCallbackHandlerReg.unregister(); - super.stop(context); - } - - /** - * Returns the shared instance - * - * @return the shared instance - */ - public static SecurityUiPlugin getDefault() { - return plugin; - } - - public static ImageDescriptor getImageDescriptor(String path) { - return imageDescriptorFromPlugin(PLUGIN_ID, path); - } - - protected class DefaultCallbackHandler implements CallbackHandler { - public void handle(final Callback[] callbacks) throws IOException, - UnsupportedCallbackException { - - // if (display != null) // RCP - Display displayToUse = display.get(); - if (displayToUse == null)// RCP - displayToUse = Display.getDefault(); - displayToUse.syncExec(new Runnable() { - public void run() { - DefaultLoginDialog dialog = new DefaultLoginDialog(display - .get().getActiveShell()); - try { - dialog.handle(callbacks); - } catch (IOException e) { - throw new ArgeoException("Cannot open dialog", e); - } - } - }); - // else {// RAP - // DefaultLoginDialog dialog = new DefaultLoginDialog(); - // dialog.handle(callbacks); - // } - } - - } -} diff --git a/org.argeo.security.ui/src/main/java/org/argeo/security/ui/UserHomePerspective.java b/org.argeo.security.ui/src/main/java/org/argeo/security/ui/UserHomePerspective.java deleted file mode 100644 index 119549ffd..000000000 --- a/org.argeo.security.ui/src/main/java/org/argeo/security/ui/UserHomePerspective.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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.security.ui; - -import org.argeo.security.ui.views.LogView; -import org.argeo.security.ui.views.UserProfile; -import org.eclipse.ui.IFolderLayout; -import org.eclipse.ui.IPageLayout; -import org.eclipse.ui.IPerspectiveFactory; - -/** Home perspective for the current user */ -public class UserHomePerspective implements IPerspectiveFactory { - public final static String ID = SecurityUiPlugin.PLUGIN_ID - + ".userHomePerspective"; - - public void createInitialLayout(IPageLayout layout) { - String editorArea = layout.getEditorArea(); - layout.setEditorAreaVisible(true); - layout.setFixed(false); - - IFolderLayout left = layout.createFolder("left", IPageLayout.LEFT, - 0.30f, editorArea); - left.addView(UserProfile.ID); - left.addView(LogView.ID); - } - -} diff --git a/org.argeo.security.ui/src/main/java/org/argeo/security/ui/commands/OpenChangePasswordDialog.java b/org.argeo.security.ui/src/main/java/org/argeo/security/ui/commands/OpenChangePasswordDialog.java deleted file mode 100644 index 3044e2c6c..000000000 --- a/org.argeo.security.ui/src/main/java/org/argeo/security/ui/commands/OpenChangePasswordDialog.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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.security.ui.commands; - -import org.argeo.security.ui.dialogs.ChangePasswordDialog; -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import org.eclipse.jface.dialogs.Dialog; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.ui.handlers.HandlerUtil; -import org.springframework.security.userdetails.UserDetailsManager; - -/** Opens the change password dialog. */ -public class OpenChangePasswordDialog extends AbstractHandler { - private UserDetailsManager userDetailsManager; - - public Object execute(ExecutionEvent event) throws ExecutionException { - ChangePasswordDialog dialog = new ChangePasswordDialog( - HandlerUtil.getActiveShell(event), userDetailsManager); - if (dialog.open() == Dialog.OK) { - MessageDialog.openInformation(HandlerUtil.getActiveShell(event), - "Password changed", "Password changed."); - } - return null; - } - - public void setUserDetailsManager(UserDetailsManager userDetailsManager) { - this.userDetailsManager = userDetailsManager; - } - -} diff --git a/org.argeo.security.ui/src/main/java/org/argeo/security/ui/commands/OpenHomePerspective.java b/org.argeo.security.ui/src/main/java/org/argeo/security/ui/commands/OpenHomePerspective.java deleted file mode 100644 index d56498a15..000000000 --- a/org.argeo.security.ui/src/main/java/org/argeo/security/ui/commands/OpenHomePerspective.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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.security.ui.commands; - -import org.argeo.eclipse.ui.ErrorFeedback; -import org.argeo.security.ui.UserHomePerspective; -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import org.eclipse.ui.WorkbenchException; -import org.eclipse.ui.handlers.HandlerUtil; - -/** Default action of the user menu */ -public class OpenHomePerspective extends AbstractHandler { - - public Object execute(ExecutionEvent event) throws ExecutionException { - try { - HandlerUtil.getActiveSite(event).getWorkbenchWindow() - .openPage(UserHomePerspective.ID, null); - } catch (WorkbenchException e) { - ErrorFeedback.show("Cannot open home perspective", e); - } - return null; - } - -} diff --git a/org.argeo.security.ui/src/main/java/org/argeo/security/ui/dialogs/AbstractLoginDialog.java b/org.argeo.security.ui/src/main/java/org/argeo/security/ui/dialogs/AbstractLoginDialog.java deleted file mode 100644 index 7c7e0c6b6..000000000 --- a/org.argeo.security.ui/src/main/java/org/argeo/security/ui/dialogs/AbstractLoginDialog.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * 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.security.ui.dialogs; - -import java.io.IOException; - -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.NameCallback; -import javax.security.auth.callback.PasswordCallback; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.security.ui.SecurityUiPlugin; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.jface.dialogs.IDialogConstants; -import org.eclipse.jface.dialogs.TrayDialog; -import org.eclipse.jface.operation.IRunnableWithProgress; -import org.eclipse.jface.operation.ModalContext; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Shell; - -/** Base for login dialogs */ -public abstract class AbstractLoginDialog extends TrayDialog implements - CallbackHandler { - - private final static Log log = LogFactory.getLog(AbstractLoginDialog.class); - - private Thread modalContextThread = null; - boolean processCallbacks = false; - boolean isCancelled = false; - Callback[] callbackArray; - - protected final Callback[] getCallbacks() { - return this.callbackArray; - } - - public abstract void internalHandle(); - - public boolean isCancelled() { - return isCancelled; - } - - protected AbstractLoginDialog(Shell parentShell) { - super(parentShell); - } - - /* - * (non-Javadoc) - * - * @see - * javax.security.auth.callback.CallbackHandler#handle(javax.security.auth - * .callback.Callback[]) - */ - public void handle(final Callback[] callbacks) throws IOException { - // clean previous usage - if (processCallbacks) { - // this handler was already used - processCallbacks = false; - } - - if (modalContextThread != null) { - try { - modalContextThread.join(1000); - } catch (InterruptedException e) { - // silent - } - modalContextThread = null; - } - - // initialize - this.callbackArray = callbacks; - final Display display = Display.getDefault(); - display.syncExec(new Runnable() { - - public void run() { - isCancelled = false; - setBlockOnOpen(false); - open(); - - final Button okButton = getButton(IDialogConstants.OK_ID); - okButton.setText("Login"); - okButton.addSelectionListener(new SelectionListener() { - - public void widgetSelected(final SelectionEvent event) { - processCallbacks = true; - } - - public void widgetDefaultSelected(final SelectionEvent event) { - // nothing to do - } - }); - final Button cancel = getButton(IDialogConstants.CANCEL_ID); - cancel.addSelectionListener(new SelectionListener() { - - public void widgetSelected(final SelectionEvent event) { - isCancelled = true; - processCallbacks = true; - } - - public void widgetDefaultSelected(final SelectionEvent event) { - // nothing to do - } - }); - } - }); - try { - ModalContext.setAllowReadAndDispatch(true); // Works for now. - ModalContext.run(new IRunnableWithProgress() { - - public void run(final IProgressMonitor monitor) { - modalContextThread = Thread.currentThread(); - // Wait here until OK or cancel is pressed, then let it rip. - // The event - // listener - // is responsible for closing the dialog (in the - // loginSucceeded - // event). - while (!processCallbacks && (modalContextThread != null) - && (modalContextThread == Thread.currentThread()) - && SecurityUiPlugin.getDefault() != null) { - // Note: SecurityUiPlugin.getDefault() != null is false - // when the OSGi runtime is shut down - try { - Thread.sleep(100); - // if (display.isDisposed()) { - // log.warn("Display is disposed, killing login dialog thread"); - // throw new ThreadDeath(); - // } - } catch (final Exception e) { - // do nothing - } - } - processCallbacks = false; - // Call the adapter to handle the callbacks - if (!isCancelled()) - internalHandle(); - else - // clear callbacks are when cancelling - for (Callback callback : callbacks) - if (callback instanceof PasswordCallback) - ((PasswordCallback) callback).setPassword(null); - else if (callback instanceof NameCallback) - ((NameCallback) callback).setName(null); - } - }, true, new NullProgressMonitor(), Display.getDefault()); - } catch (ThreadDeath e) { - isCancelled = true; - log.debug("Thread " + Thread.currentThread().getId() + " died"); - throw e; - } catch (Exception e) { - isCancelled = true; - IOException ioe = new IOException( - "Unexpected issue in login dialog, see root cause for more details"); - ioe.initCause(e); - throw ioe; - } finally { - // so that the modal thread dies - processCallbacks = true; - // try { - // // wait for the modal context thread to gracefully exit - // modalContextThread.join(); - // } catch (InterruptedException ie) { - // // silent - // } - modalContextThread = null; - } - } - - protected void configureShell(Shell shell) { - super.configureShell(shell); - shell.setText("Authentication"); - } -} diff --git a/org.argeo.security.ui/src/main/java/org/argeo/security/ui/dialogs/ChangePasswordDialog.java b/org.argeo.security.ui/src/main/java/org/argeo/security/ui/dialogs/ChangePasswordDialog.java deleted file mode 100644 index fe9b6ae9d..000000000 --- a/org.argeo.security.ui/src/main/java/org/argeo/security/ui/dialogs/ChangePasswordDialog.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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.security.ui.dialogs; - -import org.argeo.ArgeoException; -import org.argeo.eclipse.ui.ErrorFeedback; -import org.eclipse.jface.dialogs.IMessageProvider; -import org.eclipse.jface.dialogs.TitleAreaDialog; -import org.eclipse.swt.SWT; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Text; -import org.springframework.security.userdetails.UserDetailsManager; - -/** Dialog to change the current user password */ -public class ChangePasswordDialog extends TitleAreaDialog { - private Text currentPassword, newPassword1, newPassword2; - private UserDetailsManager userDetailsManager; - - public ChangePasswordDialog(Shell parentShell, - UserDetailsManager securityService) { - super(parentShell); - this.userDetailsManager = securityService; - } - - protected Point getInitialSize() { - return new Point(300, 250); - } - - protected Control createDialogArea(Composite parent) { - Composite dialogarea = (Composite) super.createDialogArea(parent); - dialogarea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - Composite composite = new Composite(dialogarea, SWT.NONE); - composite.setLayout(new GridLayout(2, false)); - composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); - currentPassword = createLP(composite, "Current password"); - newPassword1 = createLP(composite, "New password"); - newPassword2 = createLP(composite, "Repeat new password"); - - setMessage("Change password", IMessageProvider.INFORMATION); - parent.pack(); - return composite; - } - - @Override - protected void okPressed() { - if (!newPassword1.getText().equals(newPassword2.getText())) - throw new ArgeoException("Passwords are different"); - try { - userDetailsManager.changePassword(currentPassword.getText(), - newPassword1.getText()); - close(); - } catch (Exception e) { - ErrorFeedback.show("Cannot change password", e); - } - } - - /** Creates label and password. */ - protected Text createLP(Composite parent, String label) { - new Label(parent, SWT.NONE).setText(label); - Text text = new Text(parent, SWT.SINGLE | SWT.LEAD | SWT.PASSWORD - | SWT.BORDER); - text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); - return text; - } - - protected void configureShell(Shell shell) { - super.configureShell(shell); - shell.setText("Change password"); - } - -} diff --git a/org.argeo.security.ui/src/main/java/org/argeo/security/ui/dialogs/DefaultLoginDialog.java b/org.argeo.security.ui/src/main/java/org/argeo/security/ui/dialogs/DefaultLoginDialog.java deleted file mode 100644 index 57ba01b5b..000000000 --- a/org.argeo.security.ui/src/main/java/org/argeo/security/ui/dialogs/DefaultLoginDialog.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * 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.security.ui.dialogs; - -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.NameCallback; -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.callback.TextOutputCallback; - -import org.argeo.security.ui.SecurityUiPlugin; -import org.argeo.util.LocaleCallback; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -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.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Text; - -/** Default authentication dialog, to be used as {@link CallbackHandler}. */ -public class DefaultLoginDialog extends AbstractLoginDialog { - public DefaultLoginDialog() { - this(SecurityUiPlugin.display.get().getActiveShell()); - } - - public DefaultLoginDialog(Shell parentShell) { - super(parentShell); - } - - protected Point getInitialSize() { - return new Point(350, 180); - } - - @Override - protected Control createContents(Composite parent) { - Control control = super.createContents(parent); - parent.pack(); - - // Move the dialog to the center of the top level shell. - Rectangle shellBounds; - if (Display.getCurrent().getActiveShell() != null) // RCP - shellBounds = Display.getCurrent().getActiveShell().getBounds(); - else - shellBounds = Display.getCurrent().getBounds();// RAP - Point dialogSize = parent.getSize(); - int x = shellBounds.x + (shellBounds.width - dialogSize.x) / 2; - int y = shellBounds.y + (shellBounds.height - dialogSize.y) / 2; - parent.setLocation(x, y); - return control; - } - - protected Control createDialogArea(Composite parent) { - Composite dialogarea = (Composite) super.createDialogArea(parent); - Composite composite = new Composite(dialogarea, SWT.NONE); - composite.setLayout(new GridLayout(2, false)); - composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); - createCallbackHandlers(composite); - // parent.pack(); - return composite; - } - - private void createCallbackHandlers(Composite composite) { - Callback[] callbacks = getCallbacks(); - for (int i = 0; i < callbacks.length; i++) { - Callback callback = callbacks[i]; - if (callback instanceof TextOutputCallback) { - createLabelTextoutputHandler(composite, - (TextOutputCallback) callback); - } else if (callback instanceof NameCallback) { - createNameHandler(composite, (NameCallback) callback); - } else if (callback instanceof PasswordCallback) { - createPasswordHandler(composite, (PasswordCallback) callback); - } else if (callback instanceof LocaleCallback) { - createLocaleHandler(composite, (LocaleCallback) callback); - } - } - } - - private void createPasswordHandler(Composite composite, - final PasswordCallback callback) { - Label label = new Label(composite, SWT.NONE); - label.setText(callback.getPrompt()); - final Text passwordText = new Text(composite, SWT.SINGLE | SWT.LEAD - | SWT.PASSWORD | SWT.BORDER); - passwordText - .setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - passwordText.addModifyListener(new ModifyListener() { - - public void modifyText(ModifyEvent event) { - // FIXME use getTextChars() in Eclipse 3.7 - callback.setPassword(passwordText.getText().toCharArray()); - } - }); - } - - private void createLocaleHandler(Composite composite, - final LocaleCallback callback) { - String[] labels = callback.getSupportedLocalesLabels(); - if (labels.length == 0) - return; - Label label = new Label(composite, SWT.NONE); - label.setText(callback.getPrompt()); - - final Combo combo = new Combo(composite, SWT.READ_ONLY); - combo.setItems(labels); - combo.select(callback.getDefaultIndex()); - combo.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - combo.addSelectionListener(new SelectionListener() { - @Override - public void widgetSelected(SelectionEvent e) { - callback.setSelectedIndex(combo.getSelectionIndex()); - } - - @Override - public void widgetDefaultSelected(SelectionEvent e) { - } - }); - } - - private void createNameHandler(Composite composite, - final NameCallback callback) { - Label label = new Label(composite, SWT.NONE); - label.setText(callback.getPrompt()); - final Text text = new Text(composite, SWT.SINGLE | SWT.LEAD - | SWT.BORDER); - if (callback.getDefaultName() != null) { - // set default value, if provided - text.setText(callback.getDefaultName()); - callback.setName(callback.getDefaultName()); - } - text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - text.addModifyListener(new ModifyListener() { - - public void modifyText(ModifyEvent event) { - callback.setName(text.getText()); - } - }); - } - - private void createLabelTextoutputHandler(Composite composite, - final TextOutputCallback callback) { - Label label = new Label(composite, SWT.NONE); - label.setText(callback.getMessage()); - GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); - data.horizontalSpan = 2; - label.setLayoutData(data); - // TODO: find a way to pass this information - // int messageType = callback.getMessageType(); - // int dialogMessageType = IMessageProvider.NONE; - // switch (messageType) { - // case TextOutputCallback.INFORMATION: - // dialogMessageType = IMessageProvider.INFORMATION; - // break; - // case TextOutputCallback.WARNING: - // dialogMessageType = IMessageProvider.WARNING; - // break; - // case TextOutputCallback.ERROR: - // dialogMessageType = IMessageProvider.ERROR; - // break; - // } - // setMessage(callback.getMessage(), dialogMessageType); - } - - public void internalHandle() { - } -} diff --git a/org.argeo.security.ui/src/main/java/org/argeo/security/ui/internal/CurrentUser.java b/org.argeo.security.ui/src/main/java/org/argeo/security/ui/internal/CurrentUser.java deleted file mode 100644 index 43ca5884e..000000000 --- a/org.argeo.security.ui/src/main/java/org/argeo/security/ui/internal/CurrentUser.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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.security.ui.internal; - -import java.security.AccessController; -import java.security.Principal; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -import javax.security.auth.Subject; - -import org.argeo.ArgeoException; -import org.springframework.security.Authentication; -import org.springframework.security.GrantedAuthority; - -/** - * Retrieves information about the current user. Not an API, can change without - * notice. - */ -public class CurrentUser { - public final static String getUsername() { - Subject subject = getSubject(); - if (subject == null) - return null; - Principal principal = subject.getPrincipals().iterator().next(); - return principal.getName(); - - } - - public final static Set roles() { - Set roles = Collections.synchronizedSet(new HashSet()); - Authentication authentication = getAuthentication(); - for (GrantedAuthority ga : authentication.getAuthorities()) { - roles.add(ga.getAuthority()); - } - return Collections.unmodifiableSet(roles); - } - - public final static Authentication getAuthentication() { - Set authens = getSubject().getPrincipals( - Authentication.class); - if (authens != null && !authens.isEmpty()) { - Principal principal = authens.iterator().next(); - Authentication authentication = (Authentication) principal; - return authentication; - } - throw new ArgeoException("No authentication found"); - } - - public final static Subject getSubject() { - Subject subject = Subject.getSubject(AccessController.getContext()); - if (subject == null) - throw new ArgeoException("Not authenticated."); - return subject; - } -} diff --git a/org.argeo.security.ui/src/main/java/org/argeo/security/ui/views/AdminLogView.java b/org.argeo.security.ui/src/main/java/org/argeo/security/ui/views/AdminLogView.java deleted file mode 100644 index d59edf883..000000000 --- a/org.argeo.security.ui/src/main/java/org/argeo/security/ui/views/AdminLogView.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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.security.ui.views; - -import java.util.ArrayList; - -import org.argeo.ArgeoLogger; -import org.argeo.security.ui.SecurityUiPlugin; -import org.eclipse.jface.resource.JFaceResources; -import org.eclipse.jface.viewers.LabelProvider; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.graphics.Font; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Table; -import org.eclipse.ui.part.ViewPart; - -/** - * Display log lines for all users with a virtual table. - */ -public class AdminLogView extends ViewPart { - public static String ID = SecurityUiPlugin.PLUGIN_ID + ".adminLogView"; - - private TableViewer viewer; - - private LogContentProvider logContentProvider; - private ArgeoLogger argeoLogger; - - @Override - public void createPartControl(Composite parent) { - // FIXME doesn't return a monospace font in RAP - Font font = JFaceResources.getTextFont(); - Table table = new Table(parent, SWT.VIRTUAL | SWT.MULTI | SWT.H_SCROLL - | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER); - table.setFont(font); - - viewer = new TableViewer(table); - viewer.setLabelProvider(new LabelProvider()); - logContentProvider = new LogContentProvider(viewer) { - - @Override - protected StringBuffer prefix(String username, Long timestamp, - String level, String category, String thread) { - return super - .prefix(username, timestamp, level, category, thread) - .append(norm(level, 5)) - .append(' ') - .append(norm(username != null ? username - : "", 16)).append(' '); - } - }; - viewer.setContentProvider(logContentProvider); - // viewer.setUseHashlookup(true); - viewer.setInput(new ArrayList()); - - if (argeoLogger != null) - argeoLogger.registerForAll(logContentProvider, 1000, true); - } - - @Override - public void setFocus() { - viewer.getTable().setFocus(); - } - - @Override - public void dispose() { - if (argeoLogger != null) - argeoLogger.unregisterForAll(logContentProvider); - } - - public void setArgeoLogger(ArgeoLogger argeoLogger) { - this.argeoLogger = argeoLogger; - } - -} diff --git a/org.argeo.security.ui/src/main/java/org/argeo/security/ui/views/LogContentProvider.java b/org.argeo.security.ui/src/main/java/org/argeo/security/ui/views/LogContentProvider.java deleted file mode 100644 index 72f205932..000000000 --- a/org.argeo.security.ui/src/main/java/org/argeo/security/ui/views/LogContentProvider.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * 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.security.ui.views; - -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Arrays; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; - -import org.argeo.ArgeoLogListener; -import org.eclipse.jface.viewers.ILazyContentProvider; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableItem; - -/** A content provider maintaining an array of lines */ -class LogContentProvider implements ILazyContentProvider, ArgeoLogListener { - private DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss"); - - private final Long start; - /** current - start = line number. first line is number '1' */ - private Long current; - - // TODO make it configurable - private final Integer maxLineBufferSize = 10 * 1000; - - private final TableViewer viewer; - private LinkedList lines; - - public LogContentProvider(TableViewer viewer) { - this.viewer = viewer; - start = System.currentTimeMillis(); - lines = new LinkedList(); - current = start; - } - - public synchronized void dispose() { - lines.clear(); - lines = null; - } - - @SuppressWarnings("unchecked") - public synchronized void inputChanged(Viewer viewer, Object oldInput, - Object newInput) { - List lin = (List) newInput; - if (lin == null) - return; - for (String line : lin) { - addLine(line); - } - this.viewer.setItemCount(lines.size()); - } - - public void updateElement(int index) { - viewer.replace(lines.get(index), index); - } - - public synchronized void appendLog(String username, Long timestamp, - String level, String category, String thread, Object msg, - String[] exception) { - // check if valid - if (lines == null) - return; - - String message = msg.toString(); - int count = 0; - String prefix = prefix(username, timestamp, level, category, thread) - .toString(); - // String suffix = suffix(username, timestamp, level, category, thread); - for (String line : message.split("\n")) { - addLine(count == 0 ? prefix + line : line); - count++; - } - - if (exception != null) { - for (String ste : exception) { - addLine(ste); - } - } - - viewer.getTable().getDisplay().asyncExec(new Runnable() { - public void run() { - if (lines == null) - return; - viewer.setItemCount(lines.size()); - // doesn't work with syncExec - scrollToLastLine(); - } - }); - } - - protected StringBuffer prefix(String username, Long timestamp, - String level, String category, String thread) { - StringBuffer buf = new StringBuffer(""); - buf.append(dateFormat.format(new Date(timestamp))).append(" "); - // buf.append(level).append(" "); - return buf; - } - - /** Normalize string to the given size */ - protected String norm(String str, Integer size) { - int length = str.length(); - if (length == size) - return str; - else if (length > size) - return str.substring(0, size); - else { - char[] arr = new char[size - length]; - Arrays.fill(arr, ' '); - return str + new String(arr); - } - } - - // protected String suffix(String username, Long timestamp, String level, - // String category, String thread) { - // return ""; - // } - - /** Scroll to the last line */ - protected synchronized void scrollToLastLine() { - // we try to show last line with two methods - // viewer.reveal(lines.peekLast()); - - Table table = viewer.getTable(); - TableItem ti = table.getItem(table.getItemCount() - 1); - table.showItem(ti); - } - - protected synchronized LogLine addLine(String line) { - // check for maximal size and purge if necessary - while (lines.size() >= maxLineBufferSize) { - for (int i = 0; i < maxLineBufferSize / 10; i++) { - lines.poll(); - } - } - - current++; - LogLine logLine = new LogLine(current, line); - lines.add(logLine); - return logLine; - } - - private class LogLine { - private Long linenumber; - private String message; - - public LogLine(Long linenumber, String message) { - this.linenumber = linenumber; - this.message = message; - } - - @Override - public int hashCode() { - return linenumber.intValue(); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof LogLine) - return ((LogLine) obj).linenumber.equals(linenumber); - else - return false; - } - - @Override - public String toString() { - return message; - } - - } -} \ No newline at end of file diff --git a/org.argeo.security.ui/src/main/java/org/argeo/security/ui/views/LogView.java b/org.argeo.security.ui/src/main/java/org/argeo/security/ui/views/LogView.java deleted file mode 100644 index c7c47b352..000000000 --- a/org.argeo.security.ui/src/main/java/org/argeo/security/ui/views/LogView.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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.security.ui.views; - -import java.util.ArrayList; - -import org.argeo.ArgeoLogListener; -import org.argeo.ArgeoLogger; -import org.argeo.security.ui.SecurityUiPlugin; -import org.eclipse.jface.resource.JFaceResources; -import org.eclipse.jface.viewers.LabelProvider; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.graphics.Font; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Table; -import org.eclipse.ui.part.ViewPart; - -/** - * Display log lines with a virtual table. Register and unregisters a - * {@link ArgeoLogListener} via OSGi services. - */ -public class LogView extends ViewPart { - public static String ID = SecurityUiPlugin.PLUGIN_ID + ".logView"; - - private TableViewer viewer; - - private LogContentProvider logContentProvider; - private ArgeoLogger argeoLogger; - - @Override - public void createPartControl(Composite parent) { - Font font = JFaceResources.getTextFont(); - Table table = new Table(parent, SWT.VIRTUAL | SWT.MULTI | SWT.H_SCROLL - | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER); - table.setFont(font); - - viewer = new TableViewer(table); - viewer.setLabelProvider(new LabelProvider()); - logContentProvider = new LogContentProvider(viewer); - viewer.setContentProvider(logContentProvider); - // viewer.setUseHashlookup(true); - viewer.setInput(new ArrayList()); - - if (argeoLogger != null) - argeoLogger.register(logContentProvider, 1000); - } - - @Override - public void setFocus() { - viewer.getTable().setFocus(); - } - - @Override - public void dispose() { - if (argeoLogger != null) - argeoLogger.unregister(logContentProvider); - } - - public void setArgeoLogger(ArgeoLogger argeoLogger) { - this.argeoLogger = argeoLogger; - } - -} diff --git a/org.argeo.security.ui/src/main/java/org/argeo/security/ui/views/UserProfile.java b/org.argeo.security.ui/src/main/java/org/argeo/security/ui/views/UserProfile.java deleted file mode 100644 index 3f1f000bf..000000000 --- a/org.argeo.security.ui/src/main/java/org/argeo/security/ui/views/UserProfile.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 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.security.ui.views; - -import java.util.TreeSet; - -import org.argeo.eclipse.ui.EclipseUiUtils; -import org.argeo.security.ui.SecurityUiPlugin; -import org.argeo.security.ui.internal.CurrentUser; -import org.eclipse.jface.viewers.IStructuredContentProvider; -import org.eclipse.jface.viewers.LabelProvider; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Table; -import org.eclipse.ui.part.ViewPart; -import org.springframework.security.Authentication; - -/** Information about the currently logged in user */ -public class UserProfile extends ViewPart { - public static String ID = SecurityUiPlugin.PLUGIN_ID + ".userProfile"; - - private TableViewer viewer; - - @Override - public void createPartControl(Composite parent) { - parent.setLayout(new GridLayout(2, false)); - - Authentication authentication = CurrentUser.getAuthentication(); - EclipseUiUtils.createGridLL(parent, "Name", authentication - .getPrincipal().toString()); - EclipseUiUtils.createGridLL(parent, "User ID", - CurrentUser.getUsername()); - - // roles table - Table table = new Table(parent, SWT.V_SCROLL | SWT.BORDER); - table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1)); - table.setLinesVisible(false); - table.setHeaderVisible(false); - viewer = new TableViewer(table); - viewer.setContentProvider(new RolesContentProvider()); - viewer.setLabelProvider(new LabelProvider()); - getViewSite().setSelectionProvider(viewer); - viewer.setInput(getViewSite()); - } - - @Override - public void setFocus() { - viewer.getTable(); - } - - private class RolesContentProvider implements IStructuredContentProvider { - public Object[] getElements(Object inputElement) { - return new TreeSet(CurrentUser.roles()).toArray(); - } - - public void dispose() { - } - - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - } - - } - -} diff --git a/org.argeo.security.ui/src/org/argeo/security/ui/MaintenancePerspective.java b/org.argeo.security.ui/src/org/argeo/security/ui/MaintenancePerspective.java new file mode 100644 index 000000000..86307abd2 --- /dev/null +++ b/org.argeo.security.ui/src/org/argeo/security/ui/MaintenancePerspective.java @@ -0,0 +1,45 @@ +/* + * 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.security.ui; + +import org.argeo.security.ui.views.AdminLogView; +import org.argeo.security.ui.views.UserProfile; +import org.eclipse.ui.IFolderLayout; +import org.eclipse.ui.IPageLayout; +import org.eclipse.ui.IPerspectiveFactory; + +/** Home perspective for the current user */ +public class MaintenancePerspective implements IPerspectiveFactory { + public final static String ID = SecurityUiPlugin.PLUGIN_ID + + ".adminMaintenancePerspective"; + + public void createInitialLayout(IPageLayout layout) { + String editorArea = layout.getEditorArea(); + layout.setEditorAreaVisible(true); + layout.setFixed(false); + + IFolderLayout bottom = layout.createFolder("bottom", + IPageLayout.BOTTOM, 0.50f, editorArea); + bottom.addView(AdminLogView.ID); + + IFolderLayout left = layout.createFolder("left", IPageLayout.LEFT, + 0.30f, editorArea); + left.addView(UserProfile.ID); + // left.addView(RolesView.ID); + + } + +} diff --git a/org.argeo.security.ui/src/org/argeo/security/ui/PrivilegedJob.java b/org.argeo.security.ui/src/org/argeo/security/ui/PrivilegedJob.java new file mode 100644 index 000000000..1ded50fdb --- /dev/null +++ b/org.argeo.security.ui/src/org/argeo/security/ui/PrivilegedJob.java @@ -0,0 +1,46 @@ +package org.argeo.security.ui; + +import java.security.AccessController; +import java.security.PrivilegedAction; + +import javax.security.auth.Subject; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.jobs.Job; +import org.springframework.security.Authentication; +import org.springframework.security.context.SecurityContextHolder; + +/** + * Propagate authentication to an eclipse job. Typically to execute a privileged + * action outside the UI thread + */ +public abstract class PrivilegedJob extends Job { + + private final Authentication authentication; + private Subject subject; + + public PrivilegedJob(String jobName) { + super(jobName); + authentication = SecurityContextHolder.getContext().getAuthentication(); + subject = Subject.getSubject(AccessController.getContext()); + } + + @Override + protected IStatus run(final IProgressMonitor progressMonitor) { + PrivilegedAction privilegedAction = new PrivilegedAction() { + public IStatus run() { + SecurityContextHolder.getContext().setAuthentication( + authentication); + return doRun(progressMonitor); + } + }; + return Subject.doAs(subject, privilegedAction); + } + + /** + * Implement here what should be executed with default context + * authentication + */ + protected abstract IStatus doRun(IProgressMonitor progressMonitor); +} \ No newline at end of file diff --git a/org.argeo.security.ui/src/org/argeo/security/ui/RolesSourceProvider.java b/org.argeo.security.ui/src/org/argeo/security/ui/RolesSourceProvider.java new file mode 100644 index 000000000..a81dc200a --- /dev/null +++ b/org.argeo.security.ui/src/org/argeo/security/ui/RolesSourceProvider.java @@ -0,0 +1,49 @@ +/* + * 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.security.ui; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.argeo.security.ui.internal.CurrentUser; +import org.eclipse.ui.AbstractSourceProvider; + +/** + * Provides the roles of the current user as a variable to be used for activity + * binding + */ +public class RolesSourceProvider extends AbstractSourceProvider { + public final static String ROLES_VARIABLE = "roles"; + private final static String[] PROVIDED_SOURCE_NAMES = new String[] { ROLES_VARIABLE }; + + public Map> getCurrentState() { + Map> stateMap = new HashMap>(); + stateMap.put(ROLES_VARIABLE, CurrentUser.roles()); + return stateMap; + } + + public String[] getProvidedSourceNames() { + return PROVIDED_SOURCE_NAMES; + } + + public void updateRoles() { + fireSourceChanged(0, getCurrentState()); + } + + public void dispose() { + } +} \ No newline at end of file diff --git a/org.argeo.security.ui/src/org/argeo/security/ui/SecurityUiPlugin.java b/org.argeo.security.ui/src/org/argeo/security/ui/SecurityUiPlugin.java new file mode 100644 index 000000000..03584185b --- /dev/null +++ b/org.argeo.security.ui/src/org/argeo/security/ui/SecurityUiPlugin.java @@ -0,0 +1,109 @@ +/* + * 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.security.ui; + +import java.io.IOException; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.UnsupportedCallbackException; + +import org.argeo.ArgeoException; +import org.argeo.security.ui.dialogs.DefaultLoginDialog; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceRegistration; + +/** + * The activator class controls the plug-in life cycle + */ +public class SecurityUiPlugin extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "org.argeo.security.ui"; //$NON-NLS-1$ + + public final static String CONTEXT_KEYRING = "KEYRING"; + + private CallbackHandler defaultCallbackHandler; + private ServiceRegistration defaultCallbackHandlerReg; + + private static SecurityUiPlugin plugin; + + public static InheritableThreadLocal display = new InheritableThreadLocal() { + + @Override + protected Display initialValue() { + return Display.getCurrent(); + } + }; + + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + + defaultCallbackHandler = new DefaultCallbackHandler(); + defaultCallbackHandlerReg = context.registerService( + CallbackHandler.class.getName(), defaultCallbackHandler, null); + } + + public void stop(BundleContext context) throws Exception { + plugin = null; + defaultCallbackHandlerReg.unregister(); + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static SecurityUiPlugin getDefault() { + return plugin; + } + + public static ImageDescriptor getImageDescriptor(String path) { + return imageDescriptorFromPlugin(PLUGIN_ID, path); + } + + protected class DefaultCallbackHandler implements CallbackHandler { + public void handle(final Callback[] callbacks) throws IOException, + UnsupportedCallbackException { + + // if (display != null) // RCP + Display displayToUse = display.get(); + if (displayToUse == null)// RCP + displayToUse = Display.getDefault(); + displayToUse.syncExec(new Runnable() { + public void run() { + DefaultLoginDialog dialog = new DefaultLoginDialog(display + .get().getActiveShell()); + try { + dialog.handle(callbacks); + } catch (IOException e) { + throw new ArgeoException("Cannot open dialog", e); + } + } + }); + // else {// RAP + // DefaultLoginDialog dialog = new DefaultLoginDialog(); + // dialog.handle(callbacks); + // } + } + + } +} diff --git a/org.argeo.security.ui/src/org/argeo/security/ui/UserHomePerspective.java b/org.argeo.security.ui/src/org/argeo/security/ui/UserHomePerspective.java new file mode 100644 index 000000000..119549ffd --- /dev/null +++ b/org.argeo.security.ui/src/org/argeo/security/ui/UserHomePerspective.java @@ -0,0 +1,40 @@ +/* + * 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.security.ui; + +import org.argeo.security.ui.views.LogView; +import org.argeo.security.ui.views.UserProfile; +import org.eclipse.ui.IFolderLayout; +import org.eclipse.ui.IPageLayout; +import org.eclipse.ui.IPerspectiveFactory; + +/** Home perspective for the current user */ +public class UserHomePerspective implements IPerspectiveFactory { + public final static String ID = SecurityUiPlugin.PLUGIN_ID + + ".userHomePerspective"; + + public void createInitialLayout(IPageLayout layout) { + String editorArea = layout.getEditorArea(); + layout.setEditorAreaVisible(true); + layout.setFixed(false); + + IFolderLayout left = layout.createFolder("left", IPageLayout.LEFT, + 0.30f, editorArea); + left.addView(UserProfile.ID); + left.addView(LogView.ID); + } + +} diff --git a/org.argeo.security.ui/src/org/argeo/security/ui/commands/OpenChangePasswordDialog.java b/org.argeo.security.ui/src/org/argeo/security/ui/commands/OpenChangePasswordDialog.java new file mode 100644 index 000000000..3044e2c6c --- /dev/null +++ b/org.argeo.security.ui/src/org/argeo/security/ui/commands/OpenChangePasswordDialog.java @@ -0,0 +1,45 @@ +/* + * 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.security.ui.commands; + +import org.argeo.security.ui.dialogs.ChangePasswordDialog; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.ui.handlers.HandlerUtil; +import org.springframework.security.userdetails.UserDetailsManager; + +/** Opens the change password dialog. */ +public class OpenChangePasswordDialog extends AbstractHandler { + private UserDetailsManager userDetailsManager; + + public Object execute(ExecutionEvent event) throws ExecutionException { + ChangePasswordDialog dialog = new ChangePasswordDialog( + HandlerUtil.getActiveShell(event), userDetailsManager); + if (dialog.open() == Dialog.OK) { + MessageDialog.openInformation(HandlerUtil.getActiveShell(event), + "Password changed", "Password changed."); + } + return null; + } + + public void setUserDetailsManager(UserDetailsManager userDetailsManager) { + this.userDetailsManager = userDetailsManager; + } + +} diff --git a/org.argeo.security.ui/src/org/argeo/security/ui/commands/OpenHomePerspective.java b/org.argeo.security.ui/src/org/argeo/security/ui/commands/OpenHomePerspective.java new file mode 100644 index 000000000..d56498a15 --- /dev/null +++ b/org.argeo.security.ui/src/org/argeo/security/ui/commands/OpenHomePerspective.java @@ -0,0 +1,39 @@ +/* + * 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.security.ui.commands; + +import org.argeo.eclipse.ui.ErrorFeedback; +import org.argeo.security.ui.UserHomePerspective; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.ui.WorkbenchException; +import org.eclipse.ui.handlers.HandlerUtil; + +/** Default action of the user menu */ +public class OpenHomePerspective extends AbstractHandler { + + public Object execute(ExecutionEvent event) throws ExecutionException { + try { + HandlerUtil.getActiveSite(event).getWorkbenchWindow() + .openPage(UserHomePerspective.ID, null); + } catch (WorkbenchException e) { + ErrorFeedback.show("Cannot open home perspective", e); + } + return null; + } + +} diff --git a/org.argeo.security.ui/src/org/argeo/security/ui/dialogs/AbstractLoginDialog.java b/org.argeo.security.ui/src/org/argeo/security/ui/dialogs/AbstractLoginDialog.java new file mode 100644 index 000000000..7c7e0c6b6 --- /dev/null +++ b/org.argeo.security.ui/src/org/argeo/security/ui/dialogs/AbstractLoginDialog.java @@ -0,0 +1,191 @@ +/* + * 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.security.ui.dialogs; + +import java.io.IOException; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.security.ui.SecurityUiPlugin; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.TrayDialog; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.operation.ModalContext; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; + +/** Base for login dialogs */ +public abstract class AbstractLoginDialog extends TrayDialog implements + CallbackHandler { + + private final static Log log = LogFactory.getLog(AbstractLoginDialog.class); + + private Thread modalContextThread = null; + boolean processCallbacks = false; + boolean isCancelled = false; + Callback[] callbackArray; + + protected final Callback[] getCallbacks() { + return this.callbackArray; + } + + public abstract void internalHandle(); + + public boolean isCancelled() { + return isCancelled; + } + + protected AbstractLoginDialog(Shell parentShell) { + super(parentShell); + } + + /* + * (non-Javadoc) + * + * @see + * javax.security.auth.callback.CallbackHandler#handle(javax.security.auth + * .callback.Callback[]) + */ + public void handle(final Callback[] callbacks) throws IOException { + // clean previous usage + if (processCallbacks) { + // this handler was already used + processCallbacks = false; + } + + if (modalContextThread != null) { + try { + modalContextThread.join(1000); + } catch (InterruptedException e) { + // silent + } + modalContextThread = null; + } + + // initialize + this.callbackArray = callbacks; + final Display display = Display.getDefault(); + display.syncExec(new Runnable() { + + public void run() { + isCancelled = false; + setBlockOnOpen(false); + open(); + + final Button okButton = getButton(IDialogConstants.OK_ID); + okButton.setText("Login"); + okButton.addSelectionListener(new SelectionListener() { + + public void widgetSelected(final SelectionEvent event) { + processCallbacks = true; + } + + public void widgetDefaultSelected(final SelectionEvent event) { + // nothing to do + } + }); + final Button cancel = getButton(IDialogConstants.CANCEL_ID); + cancel.addSelectionListener(new SelectionListener() { + + public void widgetSelected(final SelectionEvent event) { + isCancelled = true; + processCallbacks = true; + } + + public void widgetDefaultSelected(final SelectionEvent event) { + // nothing to do + } + }); + } + }); + try { + ModalContext.setAllowReadAndDispatch(true); // Works for now. + ModalContext.run(new IRunnableWithProgress() { + + public void run(final IProgressMonitor monitor) { + modalContextThread = Thread.currentThread(); + // Wait here until OK or cancel is pressed, then let it rip. + // The event + // listener + // is responsible for closing the dialog (in the + // loginSucceeded + // event). + while (!processCallbacks && (modalContextThread != null) + && (modalContextThread == Thread.currentThread()) + && SecurityUiPlugin.getDefault() != null) { + // Note: SecurityUiPlugin.getDefault() != null is false + // when the OSGi runtime is shut down + try { + Thread.sleep(100); + // if (display.isDisposed()) { + // log.warn("Display is disposed, killing login dialog thread"); + // throw new ThreadDeath(); + // } + } catch (final Exception e) { + // do nothing + } + } + processCallbacks = false; + // Call the adapter to handle the callbacks + if (!isCancelled()) + internalHandle(); + else + // clear callbacks are when cancelling + for (Callback callback : callbacks) + if (callback instanceof PasswordCallback) + ((PasswordCallback) callback).setPassword(null); + else if (callback instanceof NameCallback) + ((NameCallback) callback).setName(null); + } + }, true, new NullProgressMonitor(), Display.getDefault()); + } catch (ThreadDeath e) { + isCancelled = true; + log.debug("Thread " + Thread.currentThread().getId() + " died"); + throw e; + } catch (Exception e) { + isCancelled = true; + IOException ioe = new IOException( + "Unexpected issue in login dialog, see root cause for more details"); + ioe.initCause(e); + throw ioe; + } finally { + // so that the modal thread dies + processCallbacks = true; + // try { + // // wait for the modal context thread to gracefully exit + // modalContextThread.join(); + // } catch (InterruptedException ie) { + // // silent + // } + modalContextThread = null; + } + } + + protected void configureShell(Shell shell) { + super.configureShell(shell); + shell.setText("Authentication"); + } +} diff --git a/org.argeo.security.ui/src/org/argeo/security/ui/dialogs/ChangePasswordDialog.java b/org.argeo.security.ui/src/org/argeo/security/ui/dialogs/ChangePasswordDialog.java new file mode 100644 index 000000000..fe9b6ae9d --- /dev/null +++ b/org.argeo.security.ui/src/org/argeo/security/ui/dialogs/ChangePasswordDialog.java @@ -0,0 +1,90 @@ +/* + * 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.security.ui.dialogs; + +import org.argeo.ArgeoException; +import org.argeo.eclipse.ui.ErrorFeedback; +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.dialogs.TitleAreaDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.springframework.security.userdetails.UserDetailsManager; + +/** Dialog to change the current user password */ +public class ChangePasswordDialog extends TitleAreaDialog { + private Text currentPassword, newPassword1, newPassword2; + private UserDetailsManager userDetailsManager; + + public ChangePasswordDialog(Shell parentShell, + UserDetailsManager securityService) { + super(parentShell); + this.userDetailsManager = securityService; + } + + protected Point getInitialSize() { + return new Point(300, 250); + } + + protected Control createDialogArea(Composite parent) { + Composite dialogarea = (Composite) super.createDialogArea(parent); + dialogarea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + Composite composite = new Composite(dialogarea, SWT.NONE); + composite.setLayout(new GridLayout(2, false)); + composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + currentPassword = createLP(composite, "Current password"); + newPassword1 = createLP(composite, "New password"); + newPassword2 = createLP(composite, "Repeat new password"); + + setMessage("Change password", IMessageProvider.INFORMATION); + parent.pack(); + return composite; + } + + @Override + protected void okPressed() { + if (!newPassword1.getText().equals(newPassword2.getText())) + throw new ArgeoException("Passwords are different"); + try { + userDetailsManager.changePassword(currentPassword.getText(), + newPassword1.getText()); + close(); + } catch (Exception e) { + ErrorFeedback.show("Cannot change password", e); + } + } + + /** Creates label and password. */ + protected Text createLP(Composite parent, String label) { + new Label(parent, SWT.NONE).setText(label); + Text text = new Text(parent, SWT.SINGLE | SWT.LEAD | SWT.PASSWORD + | SWT.BORDER); + text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + return text; + } + + protected void configureShell(Shell shell) { + super.configureShell(shell); + shell.setText("Change password"); + } + +} diff --git a/org.argeo.security.ui/src/org/argeo/security/ui/dialogs/DefaultLoginDialog.java b/org.argeo.security.ui/src/org/argeo/security/ui/dialogs/DefaultLoginDialog.java new file mode 100644 index 000000000..57ba01b5b --- /dev/null +++ b/org.argeo.security.ui/src/org/argeo/security/ui/dialogs/DefaultLoginDialog.java @@ -0,0 +1,189 @@ +/* + * 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.security.ui.dialogs; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.TextOutputCallback; + +import org.argeo.security.ui.SecurityUiPlugin; +import org.argeo.util.LocaleCallback; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +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.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +/** Default authentication dialog, to be used as {@link CallbackHandler}. */ +public class DefaultLoginDialog extends AbstractLoginDialog { + public DefaultLoginDialog() { + this(SecurityUiPlugin.display.get().getActiveShell()); + } + + public DefaultLoginDialog(Shell parentShell) { + super(parentShell); + } + + protected Point getInitialSize() { + return new Point(350, 180); + } + + @Override + protected Control createContents(Composite parent) { + Control control = super.createContents(parent); + parent.pack(); + + // Move the dialog to the center of the top level shell. + Rectangle shellBounds; + if (Display.getCurrent().getActiveShell() != null) // RCP + shellBounds = Display.getCurrent().getActiveShell().getBounds(); + else + shellBounds = Display.getCurrent().getBounds();// RAP + Point dialogSize = parent.getSize(); + int x = shellBounds.x + (shellBounds.width - dialogSize.x) / 2; + int y = shellBounds.y + (shellBounds.height - dialogSize.y) / 2; + parent.setLocation(x, y); + return control; + } + + protected Control createDialogArea(Composite parent) { + Composite dialogarea = (Composite) super.createDialogArea(parent); + Composite composite = new Composite(dialogarea, SWT.NONE); + composite.setLayout(new GridLayout(2, false)); + composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + createCallbackHandlers(composite); + // parent.pack(); + return composite; + } + + private void createCallbackHandlers(Composite composite) { + Callback[] callbacks = getCallbacks(); + for (int i = 0; i < callbacks.length; i++) { + Callback callback = callbacks[i]; + if (callback instanceof TextOutputCallback) { + createLabelTextoutputHandler(composite, + (TextOutputCallback) callback); + } else if (callback instanceof NameCallback) { + createNameHandler(composite, (NameCallback) callback); + } else if (callback instanceof PasswordCallback) { + createPasswordHandler(composite, (PasswordCallback) callback); + } else if (callback instanceof LocaleCallback) { + createLocaleHandler(composite, (LocaleCallback) callback); + } + } + } + + private void createPasswordHandler(Composite composite, + final PasswordCallback callback) { + Label label = new Label(composite, SWT.NONE); + label.setText(callback.getPrompt()); + final Text passwordText = new Text(composite, SWT.SINGLE | SWT.LEAD + | SWT.PASSWORD | SWT.BORDER); + passwordText + .setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + passwordText.addModifyListener(new ModifyListener() { + + public void modifyText(ModifyEvent event) { + // FIXME use getTextChars() in Eclipse 3.7 + callback.setPassword(passwordText.getText().toCharArray()); + } + }); + } + + private void createLocaleHandler(Composite composite, + final LocaleCallback callback) { + String[] labels = callback.getSupportedLocalesLabels(); + if (labels.length == 0) + return; + Label label = new Label(composite, SWT.NONE); + label.setText(callback.getPrompt()); + + final Combo combo = new Combo(composite, SWT.READ_ONLY); + combo.setItems(labels); + combo.select(callback.getDefaultIndex()); + combo.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + combo.addSelectionListener(new SelectionListener() { + @Override + public void widgetSelected(SelectionEvent e) { + callback.setSelectedIndex(combo.getSelectionIndex()); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + } + }); + } + + private void createNameHandler(Composite composite, + final NameCallback callback) { + Label label = new Label(composite, SWT.NONE); + label.setText(callback.getPrompt()); + final Text text = new Text(composite, SWT.SINGLE | SWT.LEAD + | SWT.BORDER); + if (callback.getDefaultName() != null) { + // set default value, if provided + text.setText(callback.getDefaultName()); + callback.setName(callback.getDefaultName()); + } + text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + text.addModifyListener(new ModifyListener() { + + public void modifyText(ModifyEvent event) { + callback.setName(text.getText()); + } + }); + } + + private void createLabelTextoutputHandler(Composite composite, + final TextOutputCallback callback) { + Label label = new Label(composite, SWT.NONE); + label.setText(callback.getMessage()); + GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); + data.horizontalSpan = 2; + label.setLayoutData(data); + // TODO: find a way to pass this information + // int messageType = callback.getMessageType(); + // int dialogMessageType = IMessageProvider.NONE; + // switch (messageType) { + // case TextOutputCallback.INFORMATION: + // dialogMessageType = IMessageProvider.INFORMATION; + // break; + // case TextOutputCallback.WARNING: + // dialogMessageType = IMessageProvider.WARNING; + // break; + // case TextOutputCallback.ERROR: + // dialogMessageType = IMessageProvider.ERROR; + // break; + // } + // setMessage(callback.getMessage(), dialogMessageType); + } + + public void internalHandle() { + } +} diff --git a/org.argeo.security.ui/src/org/argeo/security/ui/internal/CurrentUser.java b/org.argeo.security.ui/src/org/argeo/security/ui/internal/CurrentUser.java new file mode 100644 index 000000000..43ca5884e --- /dev/null +++ b/org.argeo.security.ui/src/org/argeo/security/ui/internal/CurrentUser.java @@ -0,0 +1,70 @@ +/* + * 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.security.ui.internal; + +import java.security.AccessController; +import java.security.Principal; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import javax.security.auth.Subject; + +import org.argeo.ArgeoException; +import org.springframework.security.Authentication; +import org.springframework.security.GrantedAuthority; + +/** + * Retrieves information about the current user. Not an API, can change without + * notice. + */ +public class CurrentUser { + public final static String getUsername() { + Subject subject = getSubject(); + if (subject == null) + return null; + Principal principal = subject.getPrincipals().iterator().next(); + return principal.getName(); + + } + + public final static Set roles() { + Set roles = Collections.synchronizedSet(new HashSet()); + Authentication authentication = getAuthentication(); + for (GrantedAuthority ga : authentication.getAuthorities()) { + roles.add(ga.getAuthority()); + } + return Collections.unmodifiableSet(roles); + } + + public final static Authentication getAuthentication() { + Set authens = getSubject().getPrincipals( + Authentication.class); + if (authens != null && !authens.isEmpty()) { + Principal principal = authens.iterator().next(); + Authentication authentication = (Authentication) principal; + return authentication; + } + throw new ArgeoException("No authentication found"); + } + + public final static Subject getSubject() { + Subject subject = Subject.getSubject(AccessController.getContext()); + if (subject == null) + throw new ArgeoException("Not authenticated."); + return subject; + } +} diff --git a/org.argeo.security.ui/src/org/argeo/security/ui/views/AdminLogView.java b/org.argeo.security.ui/src/org/argeo/security/ui/views/AdminLogView.java new file mode 100644 index 000000000..d59edf883 --- /dev/null +++ b/org.argeo.security.ui/src/org/argeo/security/ui/views/AdminLogView.java @@ -0,0 +1,88 @@ +/* + * 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.security.ui.views; + +import java.util.ArrayList; + +import org.argeo.ArgeoLogger; +import org.argeo.security.ui.SecurityUiPlugin; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Table; +import org.eclipse.ui.part.ViewPart; + +/** + * Display log lines for all users with a virtual table. + */ +public class AdminLogView extends ViewPart { + public static String ID = SecurityUiPlugin.PLUGIN_ID + ".adminLogView"; + + private TableViewer viewer; + + private LogContentProvider logContentProvider; + private ArgeoLogger argeoLogger; + + @Override + public void createPartControl(Composite parent) { + // FIXME doesn't return a monospace font in RAP + Font font = JFaceResources.getTextFont(); + Table table = new Table(parent, SWT.VIRTUAL | SWT.MULTI | SWT.H_SCROLL + | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER); + table.setFont(font); + + viewer = new TableViewer(table); + viewer.setLabelProvider(new LabelProvider()); + logContentProvider = new LogContentProvider(viewer) { + + @Override + protected StringBuffer prefix(String username, Long timestamp, + String level, String category, String thread) { + return super + .prefix(username, timestamp, level, category, thread) + .append(norm(level, 5)) + .append(' ') + .append(norm(username != null ? username + : "", 16)).append(' '); + } + }; + viewer.setContentProvider(logContentProvider); + // viewer.setUseHashlookup(true); + viewer.setInput(new ArrayList()); + + if (argeoLogger != null) + argeoLogger.registerForAll(logContentProvider, 1000, true); + } + + @Override + public void setFocus() { + viewer.getTable().setFocus(); + } + + @Override + public void dispose() { + if (argeoLogger != null) + argeoLogger.unregisterForAll(logContentProvider); + } + + public void setArgeoLogger(ArgeoLogger argeoLogger) { + this.argeoLogger = argeoLogger; + } + +} diff --git a/org.argeo.security.ui/src/org/argeo/security/ui/views/LogContentProvider.java b/org.argeo.security.ui/src/org/argeo/security/ui/views/LogContentProvider.java new file mode 100644 index 000000000..72f205932 --- /dev/null +++ b/org.argeo.security.ui/src/org/argeo/security/ui/views/LogContentProvider.java @@ -0,0 +1,187 @@ +/* + * 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.security.ui.views; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +import org.argeo.ArgeoLogListener; +import org.eclipse.jface.viewers.ILazyContentProvider; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableItem; + +/** A content provider maintaining an array of lines */ +class LogContentProvider implements ILazyContentProvider, ArgeoLogListener { + private DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss"); + + private final Long start; + /** current - start = line number. first line is number '1' */ + private Long current; + + // TODO make it configurable + private final Integer maxLineBufferSize = 10 * 1000; + + private final TableViewer viewer; + private LinkedList lines; + + public LogContentProvider(TableViewer viewer) { + this.viewer = viewer; + start = System.currentTimeMillis(); + lines = new LinkedList(); + current = start; + } + + public synchronized void dispose() { + lines.clear(); + lines = null; + } + + @SuppressWarnings("unchecked") + public synchronized void inputChanged(Viewer viewer, Object oldInput, + Object newInput) { + List lin = (List) newInput; + if (lin == null) + return; + for (String line : lin) { + addLine(line); + } + this.viewer.setItemCount(lines.size()); + } + + public void updateElement(int index) { + viewer.replace(lines.get(index), index); + } + + public synchronized void appendLog(String username, Long timestamp, + String level, String category, String thread, Object msg, + String[] exception) { + // check if valid + if (lines == null) + return; + + String message = msg.toString(); + int count = 0; + String prefix = prefix(username, timestamp, level, category, thread) + .toString(); + // String suffix = suffix(username, timestamp, level, category, thread); + for (String line : message.split("\n")) { + addLine(count == 0 ? prefix + line : line); + count++; + } + + if (exception != null) { + for (String ste : exception) { + addLine(ste); + } + } + + viewer.getTable().getDisplay().asyncExec(new Runnable() { + public void run() { + if (lines == null) + return; + viewer.setItemCount(lines.size()); + // doesn't work with syncExec + scrollToLastLine(); + } + }); + } + + protected StringBuffer prefix(String username, Long timestamp, + String level, String category, String thread) { + StringBuffer buf = new StringBuffer(""); + buf.append(dateFormat.format(new Date(timestamp))).append(" "); + // buf.append(level).append(" "); + return buf; + } + + /** Normalize string to the given size */ + protected String norm(String str, Integer size) { + int length = str.length(); + if (length == size) + return str; + else if (length > size) + return str.substring(0, size); + else { + char[] arr = new char[size - length]; + Arrays.fill(arr, ' '); + return str + new String(arr); + } + } + + // protected String suffix(String username, Long timestamp, String level, + // String category, String thread) { + // return ""; + // } + + /** Scroll to the last line */ + protected synchronized void scrollToLastLine() { + // we try to show last line with two methods + // viewer.reveal(lines.peekLast()); + + Table table = viewer.getTable(); + TableItem ti = table.getItem(table.getItemCount() - 1); + table.showItem(ti); + } + + protected synchronized LogLine addLine(String line) { + // check for maximal size and purge if necessary + while (lines.size() >= maxLineBufferSize) { + for (int i = 0; i < maxLineBufferSize / 10; i++) { + lines.poll(); + } + } + + current++; + LogLine logLine = new LogLine(current, line); + lines.add(logLine); + return logLine; + } + + private class LogLine { + private Long linenumber; + private String message; + + public LogLine(Long linenumber, String message) { + this.linenumber = linenumber; + this.message = message; + } + + @Override + public int hashCode() { + return linenumber.intValue(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof LogLine) + return ((LogLine) obj).linenumber.equals(linenumber); + else + return false; + } + + @Override + public String toString() { + return message; + } + + } +} \ No newline at end of file diff --git a/org.argeo.security.ui/src/org/argeo/security/ui/views/LogView.java b/org.argeo.security.ui/src/org/argeo/security/ui/views/LogView.java new file mode 100644 index 000000000..c7c47b352 --- /dev/null +++ b/org.argeo.security.ui/src/org/argeo/security/ui/views/LogView.java @@ -0,0 +1,77 @@ +/* + * 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.security.ui.views; + +import java.util.ArrayList; + +import org.argeo.ArgeoLogListener; +import org.argeo.ArgeoLogger; +import org.argeo.security.ui.SecurityUiPlugin; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Table; +import org.eclipse.ui.part.ViewPart; + +/** + * Display log lines with a virtual table. Register and unregisters a + * {@link ArgeoLogListener} via OSGi services. + */ +public class LogView extends ViewPart { + public static String ID = SecurityUiPlugin.PLUGIN_ID + ".logView"; + + private TableViewer viewer; + + private LogContentProvider logContentProvider; + private ArgeoLogger argeoLogger; + + @Override + public void createPartControl(Composite parent) { + Font font = JFaceResources.getTextFont(); + Table table = new Table(parent, SWT.VIRTUAL | SWT.MULTI | SWT.H_SCROLL + | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER); + table.setFont(font); + + viewer = new TableViewer(table); + viewer.setLabelProvider(new LabelProvider()); + logContentProvider = new LogContentProvider(viewer); + viewer.setContentProvider(logContentProvider); + // viewer.setUseHashlookup(true); + viewer.setInput(new ArrayList()); + + if (argeoLogger != null) + argeoLogger.register(logContentProvider, 1000); + } + + @Override + public void setFocus() { + viewer.getTable().setFocus(); + } + + @Override + public void dispose() { + if (argeoLogger != null) + argeoLogger.unregister(logContentProvider); + } + + public void setArgeoLogger(ArgeoLogger argeoLogger) { + this.argeoLogger = argeoLogger; + } + +} diff --git a/org.argeo.security.ui/src/org/argeo/security/ui/views/UserProfile.java b/org.argeo.security.ui/src/org/argeo/security/ui/views/UserProfile.java new file mode 100644 index 000000000..3f1f000bf --- /dev/null +++ b/org.argeo.security.ui/src/org/argeo/security/ui/views/UserProfile.java @@ -0,0 +1,81 @@ +/* + * 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.security.ui.views; + +import java.util.TreeSet; + +import org.argeo.eclipse.ui.EclipseUiUtils; +import org.argeo.security.ui.SecurityUiPlugin; +import org.argeo.security.ui.internal.CurrentUser; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Table; +import org.eclipse.ui.part.ViewPart; +import org.springframework.security.Authentication; + +/** Information about the currently logged in user */ +public class UserProfile extends ViewPart { + public static String ID = SecurityUiPlugin.PLUGIN_ID + ".userProfile"; + + private TableViewer viewer; + + @Override + public void createPartControl(Composite parent) { + parent.setLayout(new GridLayout(2, false)); + + Authentication authentication = CurrentUser.getAuthentication(); + EclipseUiUtils.createGridLL(parent, "Name", authentication + .getPrincipal().toString()); + EclipseUiUtils.createGridLL(parent, "User ID", + CurrentUser.getUsername()); + + // roles table + Table table = new Table(parent, SWT.V_SCROLL | SWT.BORDER); + table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1)); + table.setLinesVisible(false); + table.setHeaderVisible(false); + viewer = new TableViewer(table); + viewer.setContentProvider(new RolesContentProvider()); + viewer.setLabelProvider(new LabelProvider()); + getViewSite().setSelectionProvider(viewer); + viewer.setInput(getViewSite()); + } + + @Override + public void setFocus() { + viewer.getTable(); + } + + private class RolesContentProvider implements IStructuredContentProvider { + public Object[] getElements(Object inputElement) { + return new TreeSet(CurrentUser.roles()).toArray(); + } + + public void dispose() { + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + } + + } + +} diff --git a/org.argeo.server.ads.server/bnd.bnd b/org.argeo.server.ads.server/bnd.bnd new file mode 100644 index 000000000..71b51a334 --- /dev/null +++ b/org.argeo.server.ads.server/bnd.bnd @@ -0,0 +1,23 @@ +Spring-Context: META-INF/spring/*.xml;create-asynchronously:=false +Import-Package: javax.naming.directory,\ +jdbm,\ +org.apache.directory.server.configuration,\ +org.apache.directory.server.core.authn,\ +org.apache.directory.server.core.authz,\ +org.apache.directory.server.core.collective,\ +org.apache.directory.server.core.configuration,\ +org.apache.directory.server.core.event,\ +org.apache.directory.server.core.exception,\ +org.apache.directory.server.core.normalization,\ +org.apache.directory.server.core.operational,\ +org.apache.directory.server.core.partition.impl.btree,\ +org.apache.directory.server.core.referral,\ +org.apache.directory.server.core.schema,\ +org.apache.directory.server.core.schema.bootstrap,\ +org.apache.directory.server.core.subtree,\ +org.apache.directory.server.jndi,\ +org.apache.directory.server.ldap.support.extended,\ +org.apache.directory.shared.asn1.codec,\ +org.argeo.server.ads,\ +org.springframework.beans.factory.config,\ +* \ No newline at end of file diff --git a/org.argeo.server.ads.server/pom.xml b/org.argeo.server.ads.server/pom.xml index 4e6c53721..3f491595a 100644 --- a/org.argeo.server.ads.server/pom.xml +++ b/org.argeo.server.ads.server/pom.xml @@ -8,43 +8,4 @@ org.argeo.server.ads.server Commons Server Default ADS LDAP Server - - - - org.apache.felix - maven-bundle-plugin - - - - META-INF/spring/*.xml;create-asynchronously:=false - - *, - javax.naming.directory, - jdbm, - org.apache.directory.server.configuration, - org.apache.directory.server.core.authn, - org.apache.directory.server.core.authz, - org.apache.directory.server.core.collective, - org.apache.directory.server.core.configuration, - org.apache.directory.server.core.event, - org.apache.directory.server.core.exception, - org.apache.directory.server.core.normalization, - org.apache.directory.server.core.operational, - org.apache.directory.server.core.partition.impl.btree, - org.apache.directory.server.core.referral, - org.apache.directory.server.core.schema, - org.apache.directory.server.core.schema.bootstrap, - org.apache.directory.server.core.subtree, - org.apache.directory.server.jndi, - org.apache.directory.server.ldap.support.extended, - org.apache.directory.shared.asn1.codec, - org.argeo.server.ads, - org.springframework.beans.factory.config - - - - - - \ No newline at end of file diff --git a/org.argeo.server.ads/.classpath b/org.argeo.server.ads/.classpath index ff41fbb4d..d2953a684 100644 --- a/org.argeo.server.ads/.classpath +++ b/org.argeo.server.ads/.classpath @@ -1,7 +1,9 @@ - - - - + + + + diff --git a/org.argeo.server.ads/.settings/org.eclipse.jdt.core.prefs b/org.argeo.server.ads/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 34d3d6088..000000000 --- a/org.argeo.server.ads/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,67 +0,0 @@ -#Sun Feb 21 11:17:20 CET 2010 -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 -org.eclipse.jdt.core.compiler.compliance=1.5 -org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning -org.eclipse.jdt.core.compiler.problem.autoboxing=ignore -org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning -org.eclipse.jdt.core.compiler.problem.deadCode=warning -org.eclipse.jdt.core.compiler.problem.deprecation=warning -org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled -org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled -org.eclipse.jdt.core.compiler.problem.discouragedReference=warning -org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore -org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore -org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled -org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore -org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning -org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning -org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning -org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning -org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning -org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore -org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore -org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore -org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning -org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore -org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore -org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore -org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning -org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore -org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning -org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning -org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore -org.eclipse.jdt.core.compiler.problem.nullReference=warning -org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning -org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore -org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore -org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore -org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning -org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore -org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore -org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled -org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning -org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled -org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore -org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning -org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning -org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore -org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning -org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore -org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore -org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore -org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore -org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled -org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled -org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled -org.eclipse.jdt.core.compiler.problem.unusedImport=warning -org.eclipse.jdt.core.compiler.problem.unusedLabel=warning -org.eclipse.jdt.core.compiler.problem.unusedLocal=warning -org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore -org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled -org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled -org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled -org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning -org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning -org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning -org.eclipse.jdt.core.compiler.source=1.5 diff --git a/org.argeo.server.ads/.settings/org.maven.ide.eclipse.prefs b/org.argeo.server.ads/.settings/org.maven.ide.eclipse.prefs deleted file mode 100644 index 8a80a771a..000000000 --- a/org.argeo.server.ads/.settings/org.maven.ide.eclipse.prefs +++ /dev/null @@ -1,9 +0,0 @@ -#Mon Nov 23 13:34:22 CET 2009 -activeProfiles= -eclipse.preferences.version=1 -fullBuildGoals=process-test-resources -includeModules=false -resolveWorkspaceProjects=true -resourceFilterGoals=process-resources resources\:testResources -skipCompilerPlugin=true -version=1 diff --git a/org.argeo.server.ads/build.properties b/org.argeo.server.ads/build.properties index f883dc49f..6e3ef5450 100644 --- a/org.argeo.server.ads/build.properties +++ b/org.argeo.server.ads/build.properties @@ -1,2 +1,2 @@ additional.bundles = org.apache.directory.server.core -source.. = src/main/java/ +source.. = src/ diff --git a/org.argeo.server.ads/pom.xml b/org.argeo.server.ads/pom.xml index 51e2a3d83..d2a3e7391 100644 --- a/org.argeo.server.ads/pom.xml +++ b/org.argeo.server.ads/pom.xml @@ -8,34 +8,6 @@ org.argeo.server.ads Commons Server Apache Directory Server - - - - org.apache.maven.plugins - maven-compiler-plugin - - - org.apache.maven.plugins - maven-source-plugin - - - org.apache.maven.plugins - maven-jar-plugin - - - org.apache.felix - maven-bundle-plugin - - - - - org.argeo.server.ads.* - - - - - - org.argeo.commons diff --git a/org.argeo.server.ads/src/main/java/org/argeo/server/ads/AdsContainer.java b/org.argeo.server.ads/src/main/java/org/argeo/server/ads/AdsContainer.java deleted file mode 100644 index e95cd8f5a..000000000 --- a/org.argeo.server.ads/src/main/java/org/argeo/server/ads/AdsContainer.java +++ /dev/null @@ -1,243 +0,0 @@ -/* - * 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.server.ads; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Writer; -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; - -import javax.naming.Context; -import javax.naming.InitialContext; -import javax.naming.NamingException; -import javax.naming.directory.InitialDirContext; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.directory.server.configuration.MutableServerStartupConfiguration; -import org.apache.directory.server.core.configuration.ShutdownConfiguration; -import org.apache.directory.server.jndi.ServerContextFactory; -import org.argeo.ArgeoException; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.core.io.Resource; -import org.springframework.util.Assert; - -/** Wraps an Apache Directory Server instance. */ -@SuppressWarnings("restriction") -public class AdsContainer implements InitializingBean, DisposableBean { - private final static Log log = LogFactory.getLog(AdsContainer.class); - - private MutableServerStartupConfiguration configuration; - private Properties environment = null; - private File workingDirectory = new File( - System.getProperty("java.io.tmpdir") + File.separator - + "argeo-apacheDirectoryServer"); - private Boolean deleteWorkingDirOnExit = false; - - // LDIF - private List ldifs = new ArrayList(); - private List ignoredLdifAttributes = new ArrayList(); - /** default is 'demo' */ - private String ldifPassword = "e1NIQX1pZVNWNTVRYytlUU9hWURSU2hhL0Fqek5USkU9"; - private String ldifPasswordAttribute = "userPassword"; - private File ldifDirectory; - - @SuppressWarnings("unchecked") - public void afterPropertiesSet() throws Exception { - - log.info("Starting directory server with id '" - + configuration.getInstanceId() + "' in directory " - + workingDirectory.getAbsolutePath()); - - if (deleteWorkingDirOnExit && workingDirectory.exists()) { - log.warn("Found existing directory " + workingDirectory - + " deleting it..."); - FileUtils.deleteDirectory(workingDirectory); - } - configuration.setWorkingDirectory(workingDirectory); - workingDirectory.mkdirs(); - - if (ldifDirectory != null) - configuration.setLdifDirectory(ldifDirectory); - else - configuration.setLdifDirectory(new File(workingDirectory - .getAbsolutePath() + File.separator + "ldif")); - - if (ignoredLdifAttributes.size() == 0) { - ignoredLdifAttributes.add("entryUUID"); - ignoredLdifAttributes.add("structuralObjectClass"); - ignoredLdifAttributes.add("creatorsName"); - ignoredLdifAttributes.add("createTimestamp"); - ignoredLdifAttributes.add("entryCSN"); - ignoredLdifAttributes.add("modifiersName"); - ignoredLdifAttributes.add("modifyTimestamp"); - } - - // Process provided LDIF files - if (ldifs.size() > 0) - configuration.getLdifDirectory().mkdirs(); - for (Resource ldif : ldifs) { - File targetFile = new File(configuration.getLdifDirectory() - .getAbsolutePath() - + File.separator - + ldif.getFilename().replace(':', '_')); - processLdif(ldif, targetFile); - } - - Properties env = new Properties(); - env.setProperty(Context.INITIAL_CONTEXT_FACTORY, - ServerContextFactory.class.getName()); - Assert.notNull(environment); - env.putAll(environment); - env.putAll(configuration.toJndiEnvironment()); - - try { - new InitialDirContext(env); - } catch (NamingException e) { - throw new ArgeoException("Failed to start Apache Directory server", - e); - } - } - - /** - * Processes an LDIF resource, filtering out attributes that cannot be - * imported in ADS and forcing a password. - */ - protected void processLdif(Resource ldif, File targetFile) { - BufferedReader reader = null; - Writer writer = null; - try { - reader = new BufferedReader(new InputStreamReader( - ldif.getInputStream())); - writer = new FileWriter(targetFile); - String line = null; - lines: while ((line = reader.readLine()) != null) { - // comment and empty lines - if (line.trim().equals("") || line.startsWith("#")) { - writer.write(line); - writer.write('\n'); - continue lines; - } - - String[] tokens = line.split(":"); - String attribute = null; - if (tokens != null && tokens.length > 1) { - attribute = tokens[0].trim(); - if (ignoredLdifAttributes.contains(attribute)) - continue lines;// ignore - - if (attribute.equals("bdb_db_open")) { - log.warn("Ignored OpenLDAP output\n" + line); - continue lines; - } - - if (ldifPassword != null - && attribute.equals(ldifPasswordAttribute)) { - line = ldifPasswordAttribute + ":: " + ldifPassword; - } - - writer.write(line); - writer.write('\n'); - } else { - log.warn("Ignored LDIF line\n" + line); - } - } - if (log.isDebugEnabled()) - log.debug("Processed " + ldif + " to LDIF directory " - + configuration.getLdifDirectory()); - } catch (IOException e) { - throw new ArgeoException("Cannot process LDIF " + ldif, e); - } finally { - IOUtils.closeQuietly(reader); - IOUtils.closeQuietly(writer); - } - } - - @SuppressWarnings("unchecked") - public void destroy() throws Exception { - ShutdownConfiguration shutdown = new ShutdownConfiguration( - configuration.getInstanceId()); - - Properties env = new Properties(); - env.setProperty(Context.INITIAL_CONTEXT_FACTORY, - ServerContextFactory.class.getName()); - Assert.notNull(environment); - env.putAll(environment); - env.putAll(shutdown.toJndiEnvironment()); - - log.info("Shutting down directory server with id '" - + configuration.getInstanceId() + "'"); - - try { - new InitialContext(env); - } catch (NamingException e) { - throw new ArgeoException("Failed to stop Apache Directory server", - e); - } - - if (workingDirectory.exists() && deleteWorkingDirOnExit) { - if (log.isDebugEnabled()) - log.debug("Delete Apache DS working dir " + workingDirectory); - FileUtils.deleteDirectory(workingDirectory); - } - - } - - public void setConfiguration(MutableServerStartupConfiguration configuration) { - this.configuration = configuration; - } - - public void setWorkingDirectory(File workingDirectory) { - this.workingDirectory = workingDirectory; - } - - public void setEnvironment(Properties environment) { - this.environment = environment; - } - - public void setLdifs(List ldifs) { - this.ldifs = ldifs; - } - - public void setLdifDirectory(File ldifDirectory) { - this.ldifDirectory = ldifDirectory; - } - - public void setDeleteWorkingDirOnExit(Boolean deleteWorkingDirOnExit) { - this.deleteWorkingDirOnExit = deleteWorkingDirOnExit; - } - - public void setIgnoredLdifAttributes(List ignoredLdifAttributes) { - this.ignoredLdifAttributes = ignoredLdifAttributes; - } - - public void setLdifPassword(String ldifPassword) { - this.ldifPassword = ldifPassword; - } - - public void setLdifPasswordAttribute(String ldifPasswordAttribute) { - this.ldifPasswordAttribute = ldifPasswordAttribute; - } - -} diff --git a/org.argeo.server.ads/src/org/argeo/server/ads/AdsContainer.java b/org.argeo.server.ads/src/org/argeo/server/ads/AdsContainer.java new file mode 100644 index 000000000..e95cd8f5a --- /dev/null +++ b/org.argeo.server.ads/src/org/argeo/server/ads/AdsContainer.java @@ -0,0 +1,243 @@ +/* + * 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.server.ads; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Writer; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.naming.directory.InitialDirContext; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.directory.server.configuration.MutableServerStartupConfiguration; +import org.apache.directory.server.core.configuration.ShutdownConfiguration; +import org.apache.directory.server.jndi.ServerContextFactory; +import org.argeo.ArgeoException; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.core.io.Resource; +import org.springframework.util.Assert; + +/** Wraps an Apache Directory Server instance. */ +@SuppressWarnings("restriction") +public class AdsContainer implements InitializingBean, DisposableBean { + private final static Log log = LogFactory.getLog(AdsContainer.class); + + private MutableServerStartupConfiguration configuration; + private Properties environment = null; + private File workingDirectory = new File( + System.getProperty("java.io.tmpdir") + File.separator + + "argeo-apacheDirectoryServer"); + private Boolean deleteWorkingDirOnExit = false; + + // LDIF + private List ldifs = new ArrayList(); + private List ignoredLdifAttributes = new ArrayList(); + /** default is 'demo' */ + private String ldifPassword = "e1NIQX1pZVNWNTVRYytlUU9hWURSU2hhL0Fqek5USkU9"; + private String ldifPasswordAttribute = "userPassword"; + private File ldifDirectory; + + @SuppressWarnings("unchecked") + public void afterPropertiesSet() throws Exception { + + log.info("Starting directory server with id '" + + configuration.getInstanceId() + "' in directory " + + workingDirectory.getAbsolutePath()); + + if (deleteWorkingDirOnExit && workingDirectory.exists()) { + log.warn("Found existing directory " + workingDirectory + + " deleting it..."); + FileUtils.deleteDirectory(workingDirectory); + } + configuration.setWorkingDirectory(workingDirectory); + workingDirectory.mkdirs(); + + if (ldifDirectory != null) + configuration.setLdifDirectory(ldifDirectory); + else + configuration.setLdifDirectory(new File(workingDirectory + .getAbsolutePath() + File.separator + "ldif")); + + if (ignoredLdifAttributes.size() == 0) { + ignoredLdifAttributes.add("entryUUID"); + ignoredLdifAttributes.add("structuralObjectClass"); + ignoredLdifAttributes.add("creatorsName"); + ignoredLdifAttributes.add("createTimestamp"); + ignoredLdifAttributes.add("entryCSN"); + ignoredLdifAttributes.add("modifiersName"); + ignoredLdifAttributes.add("modifyTimestamp"); + } + + // Process provided LDIF files + if (ldifs.size() > 0) + configuration.getLdifDirectory().mkdirs(); + for (Resource ldif : ldifs) { + File targetFile = new File(configuration.getLdifDirectory() + .getAbsolutePath() + + File.separator + + ldif.getFilename().replace(':', '_')); + processLdif(ldif, targetFile); + } + + Properties env = new Properties(); + env.setProperty(Context.INITIAL_CONTEXT_FACTORY, + ServerContextFactory.class.getName()); + Assert.notNull(environment); + env.putAll(environment); + env.putAll(configuration.toJndiEnvironment()); + + try { + new InitialDirContext(env); + } catch (NamingException e) { + throw new ArgeoException("Failed to start Apache Directory server", + e); + } + } + + /** + * Processes an LDIF resource, filtering out attributes that cannot be + * imported in ADS and forcing a password. + */ + protected void processLdif(Resource ldif, File targetFile) { + BufferedReader reader = null; + Writer writer = null; + try { + reader = new BufferedReader(new InputStreamReader( + ldif.getInputStream())); + writer = new FileWriter(targetFile); + String line = null; + lines: while ((line = reader.readLine()) != null) { + // comment and empty lines + if (line.trim().equals("") || line.startsWith("#")) { + writer.write(line); + writer.write('\n'); + continue lines; + } + + String[] tokens = line.split(":"); + String attribute = null; + if (tokens != null && tokens.length > 1) { + attribute = tokens[0].trim(); + if (ignoredLdifAttributes.contains(attribute)) + continue lines;// ignore + + if (attribute.equals("bdb_db_open")) { + log.warn("Ignored OpenLDAP output\n" + line); + continue lines; + } + + if (ldifPassword != null + && attribute.equals(ldifPasswordAttribute)) { + line = ldifPasswordAttribute + ":: " + ldifPassword; + } + + writer.write(line); + writer.write('\n'); + } else { + log.warn("Ignored LDIF line\n" + line); + } + } + if (log.isDebugEnabled()) + log.debug("Processed " + ldif + " to LDIF directory " + + configuration.getLdifDirectory()); + } catch (IOException e) { + throw new ArgeoException("Cannot process LDIF " + ldif, e); + } finally { + IOUtils.closeQuietly(reader); + IOUtils.closeQuietly(writer); + } + } + + @SuppressWarnings("unchecked") + public void destroy() throws Exception { + ShutdownConfiguration shutdown = new ShutdownConfiguration( + configuration.getInstanceId()); + + Properties env = new Properties(); + env.setProperty(Context.INITIAL_CONTEXT_FACTORY, + ServerContextFactory.class.getName()); + Assert.notNull(environment); + env.putAll(environment); + env.putAll(shutdown.toJndiEnvironment()); + + log.info("Shutting down directory server with id '" + + configuration.getInstanceId() + "'"); + + try { + new InitialContext(env); + } catch (NamingException e) { + throw new ArgeoException("Failed to stop Apache Directory server", + e); + } + + if (workingDirectory.exists() && deleteWorkingDirOnExit) { + if (log.isDebugEnabled()) + log.debug("Delete Apache DS working dir " + workingDirectory); + FileUtils.deleteDirectory(workingDirectory); + } + + } + + public void setConfiguration(MutableServerStartupConfiguration configuration) { + this.configuration = configuration; + } + + public void setWorkingDirectory(File workingDirectory) { + this.workingDirectory = workingDirectory; + } + + public void setEnvironment(Properties environment) { + this.environment = environment; + } + + public void setLdifs(List ldifs) { + this.ldifs = ldifs; + } + + public void setLdifDirectory(File ldifDirectory) { + this.ldifDirectory = ldifDirectory; + } + + public void setDeleteWorkingDirOnExit(Boolean deleteWorkingDirOnExit) { + this.deleteWorkingDirOnExit = deleteWorkingDirOnExit; + } + + public void setIgnoredLdifAttributes(List ignoredLdifAttributes) { + this.ignoredLdifAttributes = ignoredLdifAttributes; + } + + public void setLdifPassword(String ldifPassword) { + this.ldifPassword = ldifPassword; + } + + public void setLdifPasswordAttribute(String ldifPasswordAttribute) { + this.ldifPasswordAttribute = ldifPasswordAttribute; + } + +} diff --git a/org.argeo.server.jackrabbit/.classpath b/org.argeo.server.jackrabbit/.classpath index e9c521af6..d2953a684 100644 --- a/org.argeo.server.jackrabbit/.classpath +++ b/org.argeo.server.jackrabbit/.classpath @@ -1,8 +1,9 @@ - - - >> - - + + + + diff --git a/org.argeo.server.jackrabbit/bnd.bnd b/org.argeo.server.jackrabbit/bnd.bnd new file mode 100644 index 000000000..df9b79b1b --- /dev/null +++ b/org.argeo.server.jackrabbit/bnd.bnd @@ -0,0 +1,8 @@ +Import-Package: javax.servlet,\ +org.apache.jackrabbit.webdav.server,\ +org.springframework.web.context,\ +org.osgi.framework;version="0.0.0",\ +org.xml.sax;version="0.0.0",\ +org.apache.jackrabbit.webdav.jcr,\ +org.springframework.beans,\ +* diff --git a/org.argeo.server.jackrabbit/build.properties b/org.argeo.server.jackrabbit/build.properties index 722c27c73..d32561da6 100644 --- a/org.argeo.server.jackrabbit/build.properties +++ b/org.argeo.server.jackrabbit/build.properties @@ -6,5 +6,4 @@ additional.bundles = slf4j.api,\ org.h2,\ org.apache.lucene,\ org.springframework.context -source.. = src/main/java/,\ - src/main/resources/ +source.. = src/ diff --git a/org.argeo.server.jackrabbit/pom.xml b/org.argeo.server.jackrabbit/pom.xml index 3de65ea2f..e2edf43b9 100644 --- a/org.argeo.server.jackrabbit/pom.xml +++ b/org.argeo.server.jackrabbit/pom.xml @@ -10,43 +10,6 @@ org.argeo.server.jackrabbit Commons Server Jackrabbit - - - - org.apache.maven.plugins - maven-compiler-plugin - - - org.apache.maven.plugins - maven-source-plugin - - - org.apache.maven.plugins - maven-jar-plugin - - - org.apache.felix - maven-bundle-plugin - - - - org.argeo.jackrabbit.*, - - - javax.servlet, - org.apache.jackrabbit.webdav.server, - org.springframework.web.context, - org.osgi.framework;version="0.0.0", - org.xml.sax;version="0.0.0", - org.apache.jackrabbit.webdav.jcr, - org.springframework.beans, - * - - - - - - org.argeo.commons diff --git a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitAuthorizations.java b/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitAuthorizations.java deleted file mode 100644 index e880b6700..000000000 --- a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitAuthorizations.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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.jackrabbit; - -import java.security.Principal; -import java.util.Arrays; -import java.util.List; - -import javax.jcr.RepositoryException; -import javax.jcr.Session; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.jackrabbit.api.JackrabbitSession; -import org.apache.jackrabbit.api.security.user.Authorizable; -import org.apache.jackrabbit.api.security.user.UserManager; -import org.argeo.ArgeoException; -import org.argeo.jcr.security.JcrAuthorizations; - -/** Apply authorizations to a Jackrabbit repository. */ -public class JackrabbitAuthorizations extends JcrAuthorizations { - private final static Log log = LogFactory - .getLog(JackrabbitAuthorizations.class); - - private List groupPrefixes = Arrays - .asList(new String[] { "ROLE_" });// new ArrayList(); - - @Override - protected Principal getOrCreatePrincipal(Session session, - String principalName) throws RepositoryException { - UserManager um = ((JackrabbitSession) session).getUserManager(); - synchronized (um) { - Authorizable authorizable = um.getAuthorizable(principalName); - if (authorizable == null) { - groupPrefixes: for (String groupPrefix : groupPrefixes) { - if (principalName.startsWith(groupPrefix)) { - authorizable = um.createGroup(principalName); - log.info("Created group " + principalName); - break groupPrefixes; - } - } - if (authorizable == null) - throw new ArgeoException("Authorizable " + principalName - + " not found"); - } - return authorizable.getPrincipal(); - } - } - - public void setGroupPrefixes(List groupsToCreate) { - this.groupPrefixes = groupsToCreate; - } -} diff --git a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitContainer.java b/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitContainer.java deleted file mode 100644 index 9060b585a..000000000 --- a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitContainer.java +++ /dev/null @@ -1,352 +0,0 @@ -/* - * 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.jackrabbit; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.HashSet; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.TreeSet; -import java.util.UUID; - -import javax.jcr.Node; -import javax.jcr.Repository; -import javax.jcr.RepositoryException; -import javax.jcr.Session; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.jackrabbit.api.JackrabbitRepository; -import org.apache.jackrabbit.core.RepositoryImpl; -import org.apache.jackrabbit.core.config.RepositoryConfig; -import org.apache.jackrabbit.core.config.RepositoryConfigurationParser; -import org.argeo.ArgeoException; -import org.argeo.jcr.ArgeoNames; -import org.argeo.jcr.JcrUtils; -import org.argeo.jcr.MaintainedRepository; -import org.springframework.core.io.Resource; -import org.springframework.util.SystemPropertyUtils; -import org.xml.sax.InputSource; - -/** - * Wrapper around a Jackrabbit repository which allows to configure it in Spring - * and expose it as a {@link Repository}. - */ -public class JackrabbitContainer extends JackrabbitWrapper implements - MaintainedRepository { - private final static Log log = LogFactory.getLog(JackrabbitContainer.class); - - // local - private Resource configuration; - private Resource variables; - private RepositoryConfig repositoryConfig; - private File homeDirectory; - private Boolean inMemory = false; - - /** Migrations to execute (if not already done) */ - private Set dataModelMigrations = new HashSet(); - - /** - * Empty constructor, {@link #init()} should be called after properties have - * been set - */ - public JackrabbitContainer() { - } - - public void init() { - long begin = System.currentTimeMillis(); - - if (getRepository() != null) - throw new ArgeoException( - "Cannot be used to wrap another repository"); - Repository repository = createJackrabbitRepository(); - super.setRepository(repository); - - // migrate if needed - migrate(); - - // apply new CND files after migration - prepareDataModel(); - - double duration = ((double) (System.currentTimeMillis() - begin)) / 1000; - if (log.isDebugEnabled()) - log.debug("Initialized JCR repository wrapper in " + duration - + " s"); - } - - /** Actually creates the new repository. */ - protected Repository createJackrabbitRepository() { - long begin = System.currentTimeMillis(); - InputStream configurationIn = null; - Repository repository; - try { - // temporary - if (inMemory && getHomeDirectory().exists()) { - FileUtils.deleteDirectory(getHomeDirectory()); - log.warn("Deleted Jackrabbit home directory " - + getHomeDirectory()); - } - - // process configuration file - Properties vars = getConfigurationProperties(); - configurationIn = readConfiguration(); - vars.put(RepositoryConfigurationParser.REPOSITORY_HOME_VARIABLE, - getHomeDirectory().getCanonicalPath()); - repositoryConfig = RepositoryConfig.create(new InputSource( - configurationIn), vars); - - // - // Actual repository creation - // - repository = RepositoryImpl.create(repositoryConfig); - - double duration = ((double) (System.currentTimeMillis() - begin)) / 1000; - if (log.isTraceEnabled()) - log.trace("Created Jackrabbit repository in " + duration - + " s, home: " + getHomeDirectory()); - - return repository; - } catch (Exception e) { - throw new ArgeoException("Cannot create Jackrabbit repository " - + getHomeDirectory(), e); - } finally { - IOUtils.closeQuietly(configurationIn); - } - } - - /** Lazy init. */ - protected File getHomeDirectory() { - try { - if (homeDirectory == null) { - if (inMemory) { - homeDirectory = new File( - System.getProperty("java.io.tmpdir") - + File.separator - + System.getProperty("user.name") - + File.separator + "jackrabbit-" - + UUID.randomUUID()); - homeDirectory.mkdirs(); - // will it work if directory is not empty?? - homeDirectory.deleteOnExit(); - } - } - - return homeDirectory.getCanonicalFile(); - } catch (IOException e) { - throw new ArgeoException("Cannot get canonical file for " - + homeDirectory, e); - } - } - - /** Executes migrations, if needed. */ - protected void migrate() { - // No migration to perform - if (dataModelMigrations.size() == 0) - return; - - Boolean restartAndClearCaches = false; - - // migrate data - Session session = null; - try { - session = login(); - for (JackrabbitDataModelMigration dataModelMigration : new TreeSet( - dataModelMigrations)) { - if (dataModelMigration.migrate(session)) { - restartAndClearCaches = true; - } - } - } catch (ArgeoException e) { - throw e; - } catch (Exception e) { - throw new ArgeoException("Cannot migrate", e); - } finally { - JcrUtils.logoutQuietly(session); - } - - // restart repository - if (restartAndClearCaches) { - Repository repository = getRepository(); - if (repository instanceof RepositoryImpl) { - JackrabbitDataModelMigration - .clearRepositoryCaches(((RepositoryImpl) repository) - .getConfig()); - } - ((JackrabbitRepository) repository).shutdown(); - createJackrabbitRepository(); - } - - // set data model version - try { - session = login(); - } catch (RepositoryException e) { - throw new ArgeoException("Cannot login to migrated repository", e); - } - - for (JackrabbitDataModelMigration dataModelMigration : new TreeSet( - dataModelMigrations)) { - try { - if (session.itemExists(dataModelMigration - .getDataModelNodePath())) { - Node dataModelNode = session.getNode(dataModelMigration - .getDataModelNodePath()); - dataModelNode.setProperty( - ArgeoNames.ARGEO_DATA_MODEL_VERSION, - dataModelMigration.getTargetVersion()); - session.save(); - } - } catch (Exception e) { - log.error("Cannot set model version", e); - } - } - JcrUtils.logoutQuietly(session); - - } - - /** Shutdown the repository */ - public void destroy() throws Exception { - Repository repository = getRepository(); - if (repository != null && repository instanceof RepositoryImpl) { - long begin = System.currentTimeMillis(); - ((RepositoryImpl) repository).shutdown(); - if (inMemory) - if (getHomeDirectory().exists()) { - FileUtils.deleteDirectory(getHomeDirectory()); - if (log.isDebugEnabled()) - log.debug("Deleted Jackrabbit home directory " - + getHomeDirectory()); - } - double duration = ((double) (System.currentTimeMillis() - begin)) / 1000; - log.info("Destroyed Jackrabbit repository in " + duration - + " s, home: " + getHomeDirectory()); - } - repository = null; - } - - public void dispose() { - throw new IllegalArgumentException( - "Call destroy() method instead of dispose()"); - } - - /* - * UTILITIES - */ - /** - * Reads the configuration which will initialize a {@link RepositoryConfig}. - */ - protected InputStream readConfiguration() { - try { - return configuration != null ? configuration.getInputStream() - : null; - } catch (IOException e) { - throw new ArgeoException("Cannot read Jackrabbit configuration " - + configuration, e); - } - } - - /** - * Reads the variables which will initialize a {@link Properties}. Returns - * null by default, to be overridden. - * - * @return a new stream or null if no variables available - */ - protected InputStream readVariables() { - try { - return variables != null ? variables.getInputStream() : null; - } catch (IOException e) { - throw new ArgeoException("Cannot read Jackrabbit variables " - + variables, e); - } - } - - /** - * Resolves ${} placeholders in the provided string. Based on system - * properties if no map is provided. - */ - protected String resolvePlaceholders(String string, - Map variables) { - return SystemPropertyUtils.resolvePlaceholders(string); - } - - /** Generates the properties to use in the configuration. */ - protected Properties getConfigurationProperties() { - InputStream propsIn = null; - Properties vars; - try { - vars = new Properties(); - propsIn = readVariables(); - if (propsIn != null) { - vars.load(propsIn); - } - // resolve system properties - for (Object key : vars.keySet()) { - // TODO: implement a smarter mechanism to resolve nested ${} - String newValue = resolvePlaceholders( - vars.getProperty(key.toString()), null); - vars.put(key, newValue); - } - // override with system properties - vars.putAll(System.getProperties()); - - if (log.isTraceEnabled()) { - log.trace("Jackrabbit config variables:"); - for (Object key : new TreeSet(vars.keySet())) - log.trace(key + "=" + vars.getProperty(key.toString())); - } - - } catch (IOException e) { - throw new ArgeoException("Cannot read configuration properties", e); - } finally { - IOUtils.closeQuietly(propsIn); - } - return vars; - } - - /* - * FIELDS ACCESS - */ - - public void setHomeDirectory(File homeDirectory) { - this.homeDirectory = homeDirectory; - } - - public void setInMemory(Boolean inMemory) { - this.inMemory = inMemory; - } - - public void setRepository(Repository repository) { - throw new ArgeoException("Cannot be used to wrap another repository"); - } - - public void setDataModelMigrations( - Set dataModelMigrations) { - this.dataModelMigrations = dataModelMigrations; - } - - public void setVariables(Resource variables) { - this.variables = variables; - } - - public void setConfiguration(Resource configuration) { - this.configuration = configuration; - } - -} diff --git a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitDataModelMigration.java b/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitDataModelMigration.java deleted file mode 100644 index 401b34df6..000000000 --- a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitDataModelMigration.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * 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.jackrabbit; - -import java.io.InputStreamReader; -import java.io.Reader; - -import javax.jcr.Node; -import javax.jcr.Session; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.jackrabbit.commons.cnd.CndImporter; -import org.apache.jackrabbit.core.config.RepositoryConfig; -import org.argeo.ArgeoException; -import org.argeo.jcr.ArgeoNames; -import org.argeo.jcr.JcrCallback; -import org.argeo.jcr.JcrUtils; -import org.springframework.core.io.Resource; - -/** Migrate the data in a Jackrabbit repository. */ -public class JackrabbitDataModelMigration implements - Comparable { - private final static Log log = LogFactory - .getLog(JackrabbitDataModelMigration.class); - - private String dataModelNodePath; - private String targetVersion; - private Resource migrationCnd; - private JcrCallback dataModification; - - /** - * Expects an already started repository with the old data model to migrate. - * Expects to be run with admin rights (Repository.login() will be used). - * - * @return true if a migration was performed and the repository needs to be - * restarted and its caches cleared. - */ - public Boolean migrate(Session session) { - long begin = System.currentTimeMillis(); - Reader reader = null; - try { - // check if already migrated - if (!session.itemExists(dataModelNodePath)) { - log.warn("Node " + dataModelNodePath - + " does not exist: nothing to migrate."); - return false; - } - Node dataModelNode = session.getNode(dataModelNodePath); - if (dataModelNode.hasProperty(ArgeoNames.ARGEO_DATA_MODEL_VERSION)) { - String currentVersion = dataModelNode.getProperty( - ArgeoNames.ARGEO_DATA_MODEL_VERSION).getString(); - if (compareVersions(currentVersion, targetVersion) >= 0) { - log.info("Data model at version " + currentVersion - + ", no need to migrate."); - return false; - } - } - - // apply transitional CND - if (migrationCnd != null) { - reader = new InputStreamReader(migrationCnd.getInputStream()); - CndImporter.registerNodeTypes(reader, session, true); - session.save(); - log.info("Registered migration node types from " + migrationCnd); - } - - // modify data - dataModification.execute(session); - - // apply changes - session.save(); - - long duration = System.currentTimeMillis() - begin; - log.info("Migration of data model " + dataModelNodePath + " to " - + targetVersion + " performed in " + duration + "ms"); - return true; - } catch (Exception e) { - JcrUtils.discardQuietly(session); - throw new ArgeoException("Migration of data model " - + dataModelNodePath + " to " + targetVersion + " failed.", - e); - } finally { - JcrUtils.logoutQuietly(session); - IOUtils.closeQuietly(reader); - } - } - - protected static int compareVersions(String version1, String version2) { - // TODO do a proper version analysis and comparison - return version1.compareTo(version2); - } - - /** To be called on a stopped repository. */ - public static void clearRepositoryCaches(RepositoryConfig repositoryConfig) { - try { - String customeNodeTypesPath = "/nodetypes/custom_nodetypes.xml"; - repositoryConfig.getFileSystem().deleteFile(customeNodeTypesPath); - if (log.isDebugEnabled()) - log.debug("Cleared " + customeNodeTypesPath); - } catch (Exception e) { - throw new ArgeoException("Cannot clear caches", e); - } - - // File customNodeTypes = new File(home.getPath() - // + "/repository/nodetypes/custom_nodetypes.xml"); - // if (customNodeTypes.exists()) { - // customNodeTypes.delete(); - // if (log.isDebugEnabled()) - // log.debug("Cleared " + customNodeTypes); - // } else { - // log.warn("File " + customNodeTypes + " not found."); - // } - } - - /* - * FOR USE IN (SORTED) SETS - */ - - public int compareTo(JackrabbitDataModelMigration dataModelMigration) { - // TODO make ordering smarter - if (dataModelNodePath.equals(dataModelMigration.dataModelNodePath)) - return compareVersions(targetVersion, - dataModelMigration.targetVersion); - else - return dataModelNodePath - .compareTo(dataModelMigration.dataModelNodePath); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof JackrabbitDataModelMigration)) - return false; - JackrabbitDataModelMigration dataModelMigration = (JackrabbitDataModelMigration) obj; - return dataModelNodePath.equals(dataModelMigration.dataModelNodePath) - && targetVersion.equals(dataModelMigration.targetVersion); - } - - @Override - public int hashCode() { - return targetVersion.hashCode(); - } - - public void setDataModelNodePath(String dataModelNodePath) { - this.dataModelNodePath = dataModelNodePath; - } - - public void setTargetVersion(String targetVersion) { - this.targetVersion = targetVersion; - } - - public void setMigrationCnd(Resource migrationCnd) { - this.migrationCnd = migrationCnd; - } - - public void setDataModification(JcrCallback dataModification) { - this.dataModification = dataModification; - } - - public String getDataModelNodePath() { - return dataModelNodePath; - } - - public String getTargetVersion() { - return targetVersion; - } - -} diff --git a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitRepositoryFactory.java b/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitRepositoryFactory.java deleted file mode 100644 index d64bb5e68..000000000 --- a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitRepositoryFactory.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * 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.jackrabbit; - -import java.io.File; -import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; - -import javax.jcr.Repository; -import javax.jcr.RepositoryException; -import javax.jcr.RepositoryFactory; -import javax.jcr.Session; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.jackrabbit.commons.JcrUtils; -import org.apache.jackrabbit.core.RepositoryImpl; -import org.apache.jackrabbit.core.config.RepositoryConfig; -import org.apache.jackrabbit.core.config.RepositoryConfigurationParser; -import org.apache.jackrabbit.jcr2dav.Jcr2davRepositoryFactory; -import org.argeo.ArgeoException; -import org.argeo.jcr.ArgeoJcrConstants; -import org.argeo.jcr.DefaultRepositoryFactory; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; -import org.xml.sax.InputSource; - -/** - * Repository factory which can create new repositories and access remote - * Jackrabbit repositories - */ -public class JackrabbitRepositoryFactory extends DefaultRepositoryFactory - implements RepositoryFactory, ArgeoJcrConstants { - - private final static Log log = LogFactory - .getLog(JackrabbitRepositoryFactory.class); - - private Resource fileRepositoryConfiguration = new ClassPathResource( - "/org/argeo/jackrabbit/repository-h2.xml"); - - @SuppressWarnings({ "rawtypes", "unchecked" }) - public Repository getRepository(Map parameters) throws RepositoryException { - // check if can be found by alias - Repository repository = super.getRepository(parameters); - if (repository != null) - return repository; - - // check if remote - String uri = null; - if (parameters.containsKey(JCR_REPOSITORY_URI)) - uri = parameters.get(JCR_REPOSITORY_URI).toString(); - else if (parameters.containsKey(JcrUtils.REPOSITORY_URI)) - uri = parameters.get(JcrUtils.REPOSITORY_URI).toString(); - - if (uri != null) { - if (uri.startsWith("http"))// http, https - repository = createRemoteRepository(uri); - else if (uri.startsWith("file"))// http, https - repository = createFileRepository(uri, parameters); - else if (uri.startsWith("vm")) { - log.warn("URI " - + uri - + " should have been managed by generic JCR repository factory"); - repository = getRepositoryByAlias(getAliasFromURI(uri)); - } - } - - // publish under alias - if (parameters.containsKey(JCR_REPOSITORY_ALIAS)) { - Properties properties = new Properties(); - properties.putAll(parameters); - String alias = parameters.get(JCR_REPOSITORY_ALIAS).toString(); - publish(alias, repository, properties); - log.info("Registered JCR repository under alias '" + alias - + "' with properties " + properties); - } - - return repository; - } - - protected Repository createRemoteRepository(String uri) - throws RepositoryException { - Map params = new HashMap(); - params.put(JcrUtils.REPOSITORY_URI, uri); - Repository repository = new Jcr2davRepositoryFactory() - .getRepository(params); - if (repository == null) - throw new ArgeoException("Remote Davex repository " + uri - + " not found"); - log.info("Initialized remote Jackrabbit repository from uri " + uri); - return repository; - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - protected Repository createFileRepository(final String uri, Map parameters) - throws RepositoryException { - InputStream configurationIn = null; - try { - Properties vars = new Properties(); - vars.putAll(parameters); - String dirPath = uri.substring("file:".length()); - File homeDir = new File(dirPath); - if (homeDir.exists() && !homeDir.isDirectory()) - throw new ArgeoException("Repository home " + dirPath - + " is not a directory"); - if (!homeDir.exists()) - homeDir.mkdirs(); - configurationIn = fileRepositoryConfiguration.getInputStream(); - vars.put(RepositoryConfigurationParser.REPOSITORY_HOME_VARIABLE, - homeDir.getCanonicalPath()); - RepositoryConfig repositoryConfig = RepositoryConfig.create( - new InputSource(configurationIn), vars); - - // TransientRepository repository = new - // TransientRepository(repositoryConfig); - final RepositoryImpl repository = RepositoryImpl - .create(repositoryConfig); - Session session = repository.login(); - // FIXME make it generic - org.argeo.jcr.JcrUtils.addPrivilege(session, "/", "ROLE_ADMIN", - "jcr:all"); - org.argeo.jcr.JcrUtils.logoutQuietly(session); - Runtime.getRuntime().addShutdownHook( - new Thread("Clean JCR repository " + uri) { - public void run() { - repository.shutdown(); - log.info("Destroyed repository " + uri); - } - }); - log.info("Initialized file Jackrabbit repository from uri " + uri); - return repository; - } catch (Exception e) { - throw new ArgeoException("Cannot create repository " + uri, e); - } finally { - IOUtils.closeQuietly(configurationIn); - } - } - - /** - * Called after the repository has been initialised. Does nothing by - * default. - */ - @SuppressWarnings("rawtypes") - protected void postInitialization(Repository repository, Map parameters) { - - } - - public void setFileRepositoryConfiguration( - Resource fileRepositoryConfiguration) { - this.fileRepositoryConfiguration = fileRepositoryConfiguration; - } - -} diff --git a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitWrapper.java b/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitWrapper.java deleted file mode 100644 index f9f04c4cb..000000000 --- a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitWrapper.java +++ /dev/null @@ -1,375 +0,0 @@ -/* - * 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.jackrabbit; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.net.URL; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.jcr.Credentials; -import javax.jcr.Node; -import javax.jcr.NodeIterator; -import javax.jcr.Repository; -import javax.jcr.Session; -import javax.jcr.nodetype.NodeType; - -import org.apache.commons.io.FilenameUtils; -import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.jackrabbit.commons.NamespaceHelper; -import org.apache.jackrabbit.commons.cnd.CndImporter; -import org.argeo.ArgeoException; -import org.argeo.jcr.ArgeoJcrConstants; -import org.argeo.jcr.ArgeoNames; -import org.argeo.jcr.ArgeoTypes; -import org.argeo.jcr.JcrRepositoryWrapper; -import org.argeo.jcr.JcrUtils; -import org.argeo.util.security.DigestUtils; -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; -import org.osgi.service.packageadmin.ExportedPackage; -import org.osgi.service.packageadmin.PackageAdmin; -import org.springframework.context.ResourceLoaderAware; -import org.springframework.core.io.Resource; -import org.springframework.core.io.ResourceLoader; - -/** - * Wrapper around a Jackrabbit repository which allows to simplify configuration - * and intercept some actions. It exposes itself as a {@link Repository}. - */ -public class JackrabbitWrapper extends JcrRepositoryWrapper implements - ResourceLoaderAware { - private final static Log log = LogFactory.getLog(JackrabbitWrapper.class); - private final static String DIGEST_ALGORITHM = "MD5"; - - // local - private ResourceLoader resourceLoader; - - // data model - /** Node type definitions in CND format */ - private List cndFiles = new ArrayList(); - /** - * Always import CNDs. Useful during development of new data models. In - * production, explicit migration processes should be used. - */ - private Boolean forceCndImport = true; - - /** Namespaces to register: key is prefix, value namespace */ - private Map namespaces = new HashMap(); - - private BundleContext bundleContext; - - /** - * Explicitly set admin credentials used in initialization. Useful for - * testing, in real applications authentication is rather dealt with - * externally - */ - private Credentials adminCredentials = null; - - /** - * Empty constructor, {@link #init()} should be called after properties have - * been set - */ - public JackrabbitWrapper() { - } - - @Override - public void init() { - prepareDataModel(); - } - - /* - * DATA MODEL - */ - - /** - * Import declared node type definitions and register namespaces. Tries to - * update the node definitions if they have changed. In case of failures an - * error will be logged but no exception will be thrown. - */ - protected void prepareDataModel() { - if ((cndFiles == null || cndFiles.size() == 0) - && (namespaces == null || namespaces.size() == 0)) - return; - - Session session = null; - try { - session = login(adminCredentials); - // register namespaces - if (namespaces.size() > 0) { - NamespaceHelper namespaceHelper = new NamespaceHelper(session); - namespaceHelper.registerNamespaces(namespaces); - } - - // load CND files from classpath or as URL - for (String resUrl : cndFiles) { - processCndFile(session, resUrl); - } - } catch (Exception e) { - JcrUtils.discardQuietly(session); - throw new ArgeoException("Cannot import node type definitions " - + cndFiles, e); - } finally { - JcrUtils.logoutQuietly(session); - } - - } - - protected void processCndFile(Session session, String resUrl) { - Reader reader = null; - try { - // check existing data model nodes - new NamespaceHelper(session).registerNamespace(ArgeoNames.ARGEO, - ArgeoNames.ARGEO_NAMESPACE); - if (!session.itemExists(ArgeoJcrConstants.DATA_MODELS_BASE_PATH)) - JcrUtils.mkdirs(session, - ArgeoJcrConstants.DATA_MODELS_BASE_PATH); - Node dataModels = session - .getNode(ArgeoJcrConstants.DATA_MODELS_BASE_PATH); - NodeIterator it = dataModels.getNodes(); - Node dataModel = null; - while (it.hasNext()) { - Node node = it.nextNode(); - if (node.getProperty(ArgeoNames.ARGEO_URI).getString() - .equals(resUrl)) { - dataModel = node; - break; - } - } - - byte[] cndContent = readCndContent(resUrl); - String newDigest = DigestUtils.digest(DIGEST_ALGORITHM, cndContent); - Bundle bundle = findDataModelBundle(resUrl); - - String currentVersion = null; - if (dataModel != null) { - currentVersion = dataModel.getProperty( - ArgeoNames.ARGEO_DATA_MODEL_VERSION).getString(); - if (dataModel.hasNode(Node.JCR_CONTENT)) { - String oldDigest = JcrUtils.checksumFile(dataModel, - DIGEST_ALGORITHM); - if (oldDigest.equals(newDigest)) { - if (log.isDebugEnabled()) - log.debug("Data model " + resUrl - + " hasn't changed, keeping version " - + currentVersion); - return; - } - } - } - - if (dataModel != null && !forceCndImport) { - log.info("Data model " - + resUrl - + " has changed since version " - + currentVersion - + (bundle != null ? ": version " + bundle.getVersion() - + ", bundle " + bundle.getSymbolicName() : "")); - return; - } - - reader = new InputStreamReader(new ByteArrayInputStream(cndContent)); - // actually imports the CND - try { - CndImporter.registerNodeTypes(reader, session, true); - } catch (Exception e) { - log.error("Cannot import data model " + resUrl, e); - return; - } - - if (dataModel != null && !dataModel.isNodeType(NodeType.NT_FILE)) { - dataModel.remove(); - dataModel = null; - } - - // FIXME: what if argeo.cnd would not be the first called on - // a new repo? argeo:dataModel would not be found - String fileName = FilenameUtils.getName(resUrl); - if (dataModel == null) { - dataModel = dataModels.addNode(fileName, NodeType.NT_FILE); - dataModel.addNode(Node.JCR_CONTENT, NodeType.NT_RESOURCE); - dataModel.addMixin(ArgeoTypes.ARGEO_DATA_MODEL); - dataModel.setProperty(ArgeoNames.ARGEO_URI, resUrl); - } else { - session.getWorkspace().getVersionManager() - .checkout(dataModel.getPath()); - } - if (bundle != null) - dataModel.setProperty(ArgeoNames.ARGEO_DATA_MODEL_VERSION, - bundle.getVersion().toString()); - else - dataModel.setProperty(ArgeoNames.ARGEO_DATA_MODEL_VERSION, - "0.0.0"); - JcrUtils.copyBytesAsFile(dataModel.getParent(), fileName, - cndContent); - JcrUtils.updateLastModified(dataModel); - session.save(); - session.getWorkspace().getVersionManager() - .checkin(dataModel.getPath()); - - if (currentVersion == null) - log.info("Data model " - + resUrl - + (bundle != null ? ", version " + bundle.getVersion() - + ", bundle " + bundle.getSymbolicName() : "")); - else - log.info("Data model " - + resUrl - + " updated from version " - + currentVersion - + (bundle != null ? ", version " + bundle.getVersion() - + ", bundle " + bundle.getSymbolicName() : "")); - } catch (Exception e) { - throw new ArgeoException("Cannot process data model " + resUrl, e); - } finally { - IOUtils.closeQuietly(reader); - } - } - - protected byte[] readCndContent(String resUrl) { - InputStream in = null; - try { - boolean classpath; - // normalize URL - if (bundleContext != null && resUrl.startsWith("classpath:")) { - resUrl = resUrl.substring("classpath:".length()); - classpath = true; - } else if (resUrl.indexOf(':') < 0) { - if (!resUrl.startsWith("/")) { - resUrl = "/" + resUrl; - log.warn("Classpath should start with '/'"); - } - classpath = true; - } else { - classpath = false; - } - - URL url = null; - if (classpath) { - if (bundleContext != null) { - Bundle currentBundle = bundleContext.getBundle(); - url = currentBundle.getResource(resUrl); - } else { - resUrl = "classpath:" + resUrl; - url = null; - } - } else if (!resUrl.startsWith("classpath:")) { - url = new URL(resUrl); - } - - if (url != null) { - in = url.openStream(); - } else if (resourceLoader != null) { - Resource res = resourceLoader.getResource(resUrl); - in = res.getInputStream(); - url = res.getURL(); - } else { - throw new ArgeoException("No " + resUrl + " in the classpath," - + " make sure the containing" + " package is visible."); - } - - return IOUtils.toByteArray(in); - } catch (Exception e) { - throw new ArgeoException("Cannot read CND from " + resUrl, e); - } finally { - IOUtils.closeQuietly(in); - } - } - - /* - * REPOSITORY INTERCEPTOR - */ - - /* - * UTILITIES - */ - /** Find which OSGi bundle provided the data model resource */ - protected Bundle findDataModelBundle(String resUrl) { - if (bundleContext == null) - return null; - - if (resUrl.startsWith("/")) - resUrl = resUrl.substring(1); - String pkg = resUrl.substring(0, resUrl.lastIndexOf('/')).replace('/', - '.'); - ServiceReference paSr = bundleContext - .getServiceReference(PackageAdmin.class.getName()); - PackageAdmin packageAdmin = (PackageAdmin) bundleContext - .getService(paSr); - - // find exported package - ExportedPackage exportedPackage = null; - ExportedPackage[] exportedPackages = packageAdmin - .getExportedPackages(pkg); - if (exportedPackages == null) - throw new ArgeoException("No exported package found for " + pkg); - for (ExportedPackage ep : exportedPackages) { - for (Bundle b : ep.getImportingBundles()) { - if (b.getBundleId() == bundleContext.getBundle().getBundleId()) { - exportedPackage = ep; - break; - } - } - } - - Bundle exportingBundle = null; - if (exportedPackage != null) { - exportingBundle = exportedPackage.getExportingBundle(); - } else { - // assume this is in the same bundle - exportingBundle = bundleContext.getBundle(); -// throw new ArgeoException("No OSGi exporting package found for " -// + resUrl); - } - return exportingBundle; - } - - /* - * FIELDS ACCESS - */ - public void setNamespaces(Map namespaces) { - this.namespaces = namespaces; - } - - public void setCndFiles(List cndFiles) { - this.cndFiles = cndFiles; - } - - public void setBundleContext(BundleContext bundleContext) { - this.bundleContext = bundleContext; - } - - public void setForceCndImport(Boolean forceCndUpdate) { - this.forceCndImport = forceCndUpdate; - } - - public void setResourceLoader(ResourceLoader resourceLoader) { - this.resourceLoader = resourceLoader; - } - - public void setAdminCredentials(Credentials adminCredentials) { - this.adminCredentials = adminCredentials; - } - -} diff --git a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/OsgiJackrabbitRepositoryFactory.java b/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/OsgiJackrabbitRepositoryFactory.java deleted file mode 100644 index b28699e60..000000000 --- a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/OsgiJackrabbitRepositoryFactory.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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.jackrabbit; - -import java.util.Hashtable; -import java.util.Properties; - -import javax.jcr.Repository; - -import org.osgi.framework.BundleContext; - -/** - * OSGi-aware Jackrabbit repository factory which can retrieve/publish - * {@link Repository} as OSGi services. - */ -public class OsgiJackrabbitRepositoryFactory extends - JackrabbitRepositoryFactory { - private BundleContext bundleContext; - - protected void publish(String alias, Repository repository, - Properties properties) { - if (bundleContext != null) { - // do not modify reference - Hashtable props = new Hashtable(); - props.putAll(props); - props.put(JCR_REPOSITORY_ALIAS, alias); - bundleContext.registerService(Repository.class.getName(), - repository, props); - } - } - - public void setBundleContext(BundleContext bundleContext) { - this.bundleContext = bundleContext; - } - -} diff --git a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/AbstractJackrabbitHandlerMapping.java b/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/AbstractJackrabbitHandlerMapping.java deleted file mode 100644 index 99bfab4e8..000000000 --- a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/AbstractJackrabbitHandlerMapping.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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.jackrabbit.remote; - -import org.apache.jackrabbit.server.SessionProvider; -import org.argeo.jcr.mvc.MultipleRepositoryHandlerMapping; - -/** Base class for Jackrabbit handler mappings. */ -public abstract class AbstractJackrabbitHandlerMapping extends - MultipleRepositoryHandlerMapping { - private SessionProvider sessionProvider; - - protected SessionProvider getSessionProvider() { - return sessionProvider; - } - - public void setSessionProvider(SessionProvider sessionProvider) { - this.sessionProvider = sessionProvider; - } - -} diff --git a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/ExtendedDispatcherServlet.java b/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/ExtendedDispatcherServlet.java deleted file mode 100644 index 14b6e9989..000000000 --- a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/ExtendedDispatcherServlet.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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.jackrabbit.remote; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.ArgeoException; -import org.springframework.web.servlet.DispatcherServlet; - -/** - * Overrides Spring {@link DispatcherServlet}, see - * http://forum.springsource.org/showthread.php?t=53472. - */ -public class ExtendedDispatcherServlet extends DispatcherServlet { - private static final long serialVersionUID = -5584673209855752009L; - - private final static Log log = LogFactory - .getLog(ExtendedDispatcherServlet.class); - - protected void service(HttpServletRequest request, - HttpServletResponse response) throws ServletException, - java.io.IOException { - try { - if (log.isTraceEnabled()) { - log.trace("SessionID = " + request.getSession().getId()); - log.trace(" ContextPath = " + request.getContextPath()); - log.trace(" ServletPath = " + request.getServletPath()); - log.trace(" PathInfo = " + request.getPathInfo()); - log.trace(" Method = " + request.getMethod()); - log.trace(" User-Agent = " + request.getHeader("User-Agent")); - } - doService(request, response); - } catch (Exception e) { - throw new ArgeoException("Cannot process request", e); - } - } - -} diff --git a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/IOHandlerWrapper.java b/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/IOHandlerWrapper.java deleted file mode 100644 index daf2ecb2b..000000000 --- a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/IOHandlerWrapper.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * 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.jackrabbit.remote; - -import java.io.IOException; - -import org.apache.jackrabbit.server.io.ExportContext; -import org.apache.jackrabbit.server.io.IOHandler; -import org.apache.jackrabbit.server.io.IOManager; -import org.apache.jackrabbit.server.io.ImportContext; -import org.apache.jackrabbit.webdav.DavResource; -import org.argeo.ArgeoException; - -/** Wraps an IOHandler so that it can be injected a posteriori */ -public class IOHandlerWrapper implements IOHandler { - private IOManager ioManager = null; - private IOHandler ioHandler = null; - - public void setIOHandler(IOHandler ioHandler) { - if ((this.ioHandler != null) && (ioHandler != null)) - throw new ArgeoException( - "There is already an IO Handler registered"); - this.ioHandler = ioHandler; - if (ioManager != null && this.ioHandler != null) - ioHandler.setIOManager(ioManager); - } - - public IOHandler getIOHandler() { - return ioHandler; - } - - public IOManager getIOManager() { - return ioManager; - } - - public void setIOManager(IOManager ioManager) { - this.ioManager = ioManager; - if (ioHandler != null) - ioHandler.setIOManager(ioManager); - } - - public String getName() { - if (ioHandler != null) - return ioHandler.getName(); - else - return "Empty IOHandler Wrapper"; - } - - public boolean canImport(ImportContext context, boolean isCollection) { - if (ioHandler != null) - return ioHandler.canImport(context, isCollection); - return false; - } - - public boolean canImport(ImportContext context, DavResource resource) { - if (ioHandler != null) - return ioHandler.canImport(context, resource); - return false; - } - - public boolean importContent(ImportContext context, boolean isCollection) - throws IOException { - if (ioHandler != null) - ioHandler.importContent(context, isCollection); - return false; - } - - public boolean importContent(ImportContext context, DavResource resource) - throws IOException { - if (ioHandler != null) - ioHandler.importContent(context, resource); - return false; - } - - public boolean canExport(ExportContext context, boolean isCollection) { - if (ioHandler != null) - ioHandler.canExport(context, isCollection); - return false; - } - - public boolean canExport(ExportContext context, DavResource resource) { - if (ioHandler != null) - ioHandler.canExport(context, resource); - return false; - } - - public boolean exportContent(ExportContext context, boolean isCollection) - throws IOException { - if (ioHandler != null) - ioHandler.exportContent(context, isCollection); - return false; - } - - public boolean exportContent(ExportContext context, DavResource resource) - throws IOException { - if (ioHandler != null) - ioHandler.exportContent(context, resource); - return false; - } - -} diff --git a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/IOManagerBean.java b/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/IOManagerBean.java deleted file mode 100644 index 82a76738b..000000000 --- a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/IOManagerBean.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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.jackrabbit.remote; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import org.apache.jackrabbit.server.io.ExportContext; -import org.apache.jackrabbit.server.io.IOHandler; -import org.apache.jackrabbit.server.io.IOManager; -import org.apache.jackrabbit.server.io.ImportContext; -import org.apache.jackrabbit.webdav.DavResource; -import org.apache.tika.detect.Detector; - -/** {@link IOManager} that can easily be configured as a bean. */ -public class IOManagerBean implements IOManager { - private Detector detector = null; - private List ioHandlers = new ArrayList(); - - public boolean importContent(ImportContext context, boolean isCollection) - throws IOException { - // TODO Auto-generated method stub - return false; - } - - public boolean importContent(ImportContext context, DavResource resource) - throws IOException { - // TODO Auto-generated method stub - return false; - } - - public boolean exportContent(ExportContext context, boolean isCollection) - throws IOException { - // TODO Auto-generated method stub - return false; - } - - public boolean exportContent(ExportContext context, DavResource resource) - throws IOException { - // TODO Auto-generated method stub - return false; - } - - public synchronized void addIOHandler(IOHandler ioHandler) { - ioHandlers.add(ioHandler); - } - - public synchronized IOHandler[] getIOHandlers() { - return ioHandlers.toArray(new IOHandler[ioHandlers.size()]); - } - - public Detector getDetector() { - return detector; - } - - public void setDetector(Detector detector) { - this.detector = detector; - } - - public synchronized List getIoHandlers() { - return ioHandlers; - } - - public synchronized void setIoHandlers(List ioHandlers) { - this.ioHandlers = ioHandlers; - } - -} diff --git a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/JcrRemotingHandlerMapping.java b/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/JcrRemotingHandlerMapping.java deleted file mode 100644 index caea5fc8b..000000000 --- a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/JcrRemotingHandlerMapping.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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.jackrabbit.remote; - -import java.util.Properties; - -import javax.jcr.Repository; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; - -public class JcrRemotingHandlerMapping extends AbstractJackrabbitHandlerMapping { - - protected HttpServlet createServlet(Repository repository, String pathPrefix) - throws ServletException { - JcrRemotingServlet servlet = new JcrRemotingServlet(repository, - getSessionProvider()); - Properties initParameters = new Properties(); - initParameters.setProperty( - JcrRemotingServlet.INIT_PARAM_RESOURCE_PATH_PREFIX, pathPrefix); - servlet.init(new DelegatingServletConfig(pathPrefix.replace('/', '_'), - initParameters)); - return servlet; - } -} diff --git a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/JcrRemotingServlet.java b/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/JcrRemotingServlet.java deleted file mode 100644 index b3f079745..000000000 --- a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/JcrRemotingServlet.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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.jackrabbit.remote; - -import javax.jcr.Repository; - -import org.apache.jackrabbit.server.SessionProvider; - -public class JcrRemotingServlet extends - org.apache.jackrabbit.server.remoting.davex.JcrRemotingServlet { - - private static final long serialVersionUID = 3131835511468341309L; - - private final Repository repository; - private final SessionProvider sessionProvider; - - public JcrRemotingServlet(Repository repository, - SessionProvider sessionProvider) { - this.repository = repository; - this.sessionProvider = sessionProvider; - } - - @Override - protected Repository getRepository() { - return repository; - } - - @Override - protected SessionProvider getSessionProvider() { - return sessionProvider; - } - -} diff --git a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/OpenInViewSessionProvider.java b/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/OpenInViewSessionProvider.java deleted file mode 100644 index b4d1d6021..000000000 --- a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/OpenInViewSessionProvider.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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.jackrabbit.remote; - -import java.io.Serializable; - -import javax.jcr.LoginException; -import javax.jcr.Repository; -import javax.jcr.RepositoryException; -import javax.jcr.Session; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.jackrabbit.server.SessionProvider; -import org.argeo.jcr.JcrUtils; - -/** - * Implements an open session in view patter: a new JCR session is created for - * each request - */ -public class OpenInViewSessionProvider implements SessionProvider, Serializable { - private static final long serialVersionUID = 2270957712453841368L; - - private final static Log log = LogFactory - .getLog(OpenInViewSessionProvider.class); - - public Session getSession(HttpServletRequest request, Repository rep, - String workspace) throws LoginException, ServletException, - RepositoryException { - return login(request, rep, workspace); - } - - protected Session login(HttpServletRequest request, Repository repository, - String workspace) throws RepositoryException { - if (log.isTraceEnabled()) - log.trace("Login to workspace " - + (workspace == null ? "" : workspace) - + " in web session " + request.getSession().getId()); - return repository.login(workspace); - } - - public void releaseSession(Session session) { - JcrUtils.logoutQuietly(session); - if (log.isTraceEnabled()) - log.trace("Logged out remote JCR session " + session); - } - - public void init() { - } - - public void destroy() { - } - -} diff --git a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/ScopedSessionProvider.java b/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/ScopedSessionProvider.java deleted file mode 100644 index ffe6df9b1..000000000 --- a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/ScopedSessionProvider.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * 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.jackrabbit.remote; - -import java.io.Serializable; - -import javax.jcr.LoginException; -import javax.jcr.Repository; -import javax.jcr.RepositoryException; -import javax.jcr.Session; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.jackrabbit.server.SessionProvider; -import org.argeo.ArgeoException; -import org.argeo.jcr.ArgeoJcrConstants; -import org.argeo.jcr.JcrUtils; -import org.springframework.security.Authentication; -import org.springframework.security.context.SecurityContextHolder; - -/** - * Session provider assuming a single workspace and a short life cycle, - * typically a Spring bean of scope (web) 'session'. - */ -public class ScopedSessionProvider implements SessionProvider, Serializable { - private static final long serialVersionUID = 6589775984177317058L; - private static final Log log = LogFactory - .getLog(ScopedSessionProvider.class); - private transient HttpSession httpSession = null; - private transient Session jcrSession = null; - - private transient String currentRepositoryName = null; - private transient String currentWorkspaceName = null; - private transient String currentJcrUser = null; - - // private transient String anonymousUserId = "anonymous"; - - public Session getSession(HttpServletRequest request, Repository rep, - String workspace) throws LoginException, ServletException, - RepositoryException { - - Authentication authentication = SecurityContextHolder.getContext() - .getAuthentication(); - if (authentication == null) - throw new ArgeoException( - "Request not authenticated by Spring Security"); - String springUser = authentication.getName(); - - // HTTP - String requestJcrRepository = (String) request - .getAttribute(ArgeoJcrConstants.JCR_REPOSITORY_ALIAS); - - // HTTP session - if (httpSession != null - && !httpSession.getId().equals(request.getSession().getId())) - throw new ArgeoException( - "Only session scope is supported in this mode"); - if (httpSession == null) - httpSession = request.getSession(); - - // Initializes current values - if (currentRepositoryName == null) - currentRepositoryName = requestJcrRepository; - if (currentWorkspaceName == null) - currentWorkspaceName = workspace; - if (currentJcrUser == null) - currentJcrUser = springUser; - - // logout if there was a change in session coordinates - if (jcrSession != null) - if (!currentRepositoryName.equals(requestJcrRepository)) { - if (log.isDebugEnabled()) - log.debug(getHttpSessionId() + " Changed from repository '" - + currentRepositoryName + "' to '" - + requestJcrRepository - + "', logging out cached JCR session."); - logout(); - } else if (!currentWorkspaceName.equals(workspace)) { - if (log.isDebugEnabled()) - log.debug(getHttpSessionId() + " Changed from workspace '" - + currentWorkspaceName + "' to '" + workspace - + "', logging out cached JCR session."); - logout(); - } else if (!currentJcrUser.equals(springUser)) { - if (log.isDebugEnabled()) - log.debug(getHttpSessionId() + " Changed from user '" - + currentJcrUser + "' to '" + springUser - + "', logging out cached JCR session."); - logout(); - } - - // login if needed - if (jcrSession == null) - try { - Session session = login(rep, workspace); - if (!session.getUserID().equals(springUser)) { - JcrUtils.logoutQuietly(session); - throw new ArgeoException("Spring Security user '" - + springUser + "' not in line with JCR user '" - + session.getUserID() + "'"); - } - currentRepositoryName = requestJcrRepository; - // do not use workspace variable which may be null - currentWorkspaceName = session.getWorkspace().getName(); - currentJcrUser = session.getUserID(); - - jcrSession = session; - return jcrSession; - } catch (RepositoryException e) { - throw new ArgeoException("Cannot open session to workspace " - + workspace, e); - } - - // returns cached session - return jcrSession; - } - - protected Session login(Repository repository, String workspace) - throws RepositoryException { - Session session = repository.login(workspace); - if (log.isDebugEnabled()) - log.debug(getHttpSessionId() + " User '" + session.getUserID() - + "' logged in workspace '" - + session.getWorkspace().getName() + "' of repository '" - + currentRepositoryName + "'"); - return session; - } - - public void releaseSession(Session session) { - if (log.isTraceEnabled()) - log.trace(getHttpSessionId() + " Releasing JCR session " + session); - } - - protected void logout() { - JcrUtils.logoutQuietly(jcrSession); - jcrSession = null; - } - - protected final String getHttpSessionId() { - return httpSession != null ? httpSession.getId() : ""; - } - - public void init() { - } - - public void destroy() { - logout(); - if (getHttpSessionId() != null) - if (log.isDebugEnabled()) - log.debug(getHttpSessionId() - + " Cleaned up provider for web session "); - httpSession = null; - } - -} diff --git a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/SimpleSessionProvider.java b/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/SimpleSessionProvider.java deleted file mode 100644 index 1d438d504..000000000 --- a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/SimpleSessionProvider.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * 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.jackrabbit.remote; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import javax.jcr.LoginException; -import javax.jcr.Node; -import javax.jcr.Repository; -import javax.jcr.RepositoryException; -import javax.jcr.Session; -import javax.jcr.Value; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.jackrabbit.api.JackrabbitSession; -import org.apache.jackrabbit.api.security.user.Group; -import org.apache.jackrabbit.api.security.user.User; -import org.apache.jackrabbit.api.security.user.UserManager; -import org.apache.jackrabbit.server.SessionProvider; -import org.argeo.ArgeoException; -import org.argeo.jcr.ArgeoNames; -import org.argeo.jcr.JcrUtils; -import org.argeo.jcr.UserJcrUtils; - -/** - * Implements an open session in view patter: a new JCR session is created for - * each request - * - * @deprecated use {@link ScopedSessionProvider} or - * {@link OpenInViewSessionProvider} - */ -@Deprecated -public class SimpleSessionProvider implements SessionProvider, Serializable { - private static final long serialVersionUID = 2270957712453841368L; - - private final static Log log = LogFactory - .getLog(SimpleSessionProvider.class); - - private transient Map sessions; - - private Boolean openSessionInView = true; - - private String defaultWorkspace = "default"; - - private String webSessionId = null; - - public Session getSession(HttpServletRequest request, Repository rep, - String workspace) throws LoginException, ServletException, - RepositoryException { - - if (openSessionInView) { - JackrabbitSession session = (JackrabbitSession) login(request, rep, - workspace); - if (session.getWorkspace().getName().equals(defaultWorkspace)) - writeRemoteRoles(session); - return session; - } else { - if (webSessionId != null - && !webSessionId.equals(request.getSession().getId())) - throw new ArgeoException( - "Only session scope is supported in this mode"); - webSessionId = request.getSession().getId(); - - // since sessions is transient it can't be restored from the session - if (sessions == null) - sessions = Collections - .synchronizedMap(new HashMap()); - - if (!sessions.containsKey(workspace)) { - try { - // JackrabbitSession session = (JackrabbitSession) - // rep.login( - // null, workspace); - JackrabbitSession session = (JackrabbitSession) login( - request, rep, workspace); - if (session.getWorkspace().getName() - .equals(defaultWorkspace)) - writeRemoteRoles(session); - if (log.isTraceEnabled()) - log.trace("User " + session.getUserID() - + " logged into " + request.getServletPath()); - sessions.put(workspace, session); - return session; - } catch (Exception e) { - throw new ArgeoException("Cannot open session", e); - } - } else { - Session session = sessions.get(workspace); - if (!session.isLive()) { - sessions.remove(workspace); - session = login(request, rep, workspace); - sessions.put(workspace, session); - } - return session; - } - } - } - - protected Session login(HttpServletRequest request, Repository repository, - String workspace) throws RepositoryException { - if (log.isDebugEnabled()) - log.debug("Login to workspace " - + (workspace == null ? "" : workspace) - + " in web session " + request.getSession().getId()); - return repository.login(workspace); - } - - protected void writeRemoteRoles(JackrabbitSession session) - throws RepositoryException { - // FIXME better deal w/ non node repo - - // retrieve roles - String userId = session.getUserID(); - UserManager userManager = session.getUserManager(); - User user = (User) userManager.getAuthorizable(userId); - if (user == null) { - // anonymous - return; - } - List userGroupIds = new ArrayList(); - if (user != null) - for (Iterator it = user.memberOf(); it.hasNext();) - userGroupIds.add(it.next().getID()); - - // write roles if needed - Node userHome = UserJcrUtils.getUserHome(session); - boolean writeRoles = false; - if (userHome.hasProperty(ArgeoNames.ARGEO_REMOTE_ROLES)) { - Value[] roles = userHome.getProperty(ArgeoNames.ARGEO_REMOTE_ROLES) - .getValues(); - if (roles.length != userGroupIds.size()) - writeRoles = true; - else - for (int i = 0; i < roles.length; i++) - if (!roles[i].getString().equals(userGroupIds.get(i))) - writeRoles = true; - } else - writeRoles = true; - - if (writeRoles) { - session.getWorkspace().getVersionManager() - .checkout(userHome.getPath()); - String[] roleIds = userGroupIds.toArray(new String[userGroupIds - .size()]); - userHome.setProperty(ArgeoNames.ARGEO_REMOTE_ROLES, roleIds); - JcrUtils.updateLastModified(userHome); - session.save(); - session.getWorkspace().getVersionManager() - .checkin(userHome.getPath()); - } - - } - - public void releaseSession(Session session) { - if (log.isTraceEnabled()) - log.trace("Releasing JCR session " + session); - if (openSessionInView) { - JcrUtils.logoutQuietly(session); - if (log.isDebugEnabled()) - log.debug("Logged out remote JCR session " + session); - } - } - - public void init() { - if (log.isDebugEnabled()) - log.debug("Init session provider for web session " + webSessionId); - } - - public void destroy() { - if (log.isDebugEnabled()) - log.debug("Destroy session provider for web session " - + webSessionId); - - if (sessions != null) - for (String workspace : sessions.keySet()) { - Session session = sessions.get(workspace); - JcrUtils.logoutQuietly(session); - } - } - - /** - * If set to true a new session will be created each time (the default), - * otherwise a single session is cached by workspace and the object should - * be of scope session (not supported) - */ - public void setOpenSessionInView(Boolean openSessionInView) { - this.openSessionInView = openSessionInView; - } - - public void setSecurityWorkspace(String securityWorkspace) { - this.defaultWorkspace = securityWorkspace; - } - -} diff --git a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/SimpleWebdavHandlerMapping.java b/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/SimpleWebdavHandlerMapping.java deleted file mode 100644 index bd8d8041a..000000000 --- a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/SimpleWebdavHandlerMapping.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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.jackrabbit.remote; - -import java.util.Properties; - -import javax.jcr.Repository; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; - -/** Handler mapping for WebDav */ -public class SimpleWebdavHandlerMapping extends - AbstractJackrabbitHandlerMapping { - private String configuration; - - protected HttpServlet createServlet(Repository repository, String pathPrefix) - throws ServletException { - - SimpleWebdavServlet servlet = new SimpleWebdavServlet(repository, - getSessionProvider()); - Properties initParameters = new Properties(); - initParameters.setProperty( - SimpleWebdavServlet.INIT_PARAM_RESOURCE_CONFIG, configuration); - initParameters - .setProperty( - SimpleWebdavServlet.INIT_PARAM_RESOURCE_PATH_PREFIX, - pathPrefix); - servlet.init(new DelegatingServletConfig(pathPrefix.replace('/', '_'), - initParameters)); - return servlet; - } - - public void setConfiguration(String configuration) { - this.configuration = configuration; - } -} diff --git a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/SimpleWebdavServlet.java b/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/SimpleWebdavServlet.java deleted file mode 100644 index f1ca0a9f2..000000000 --- a/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/SimpleWebdavServlet.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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.jackrabbit.remote; - -import java.io.IOException; - -import javax.jcr.Repository; -import javax.servlet.ServletException; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.jackrabbit.server.SessionProvider; -import org.apache.jackrabbit.webdav.DavException; -import org.apache.jackrabbit.webdav.DavResource; -import org.apache.jackrabbit.webdav.WebdavRequest; -import org.apache.jackrabbit.webdav.WebdavResponse; - -/** WebDav servlet whose repository is injected */ -public class SimpleWebdavServlet extends - org.apache.jackrabbit.webdav.simple.SimpleWebdavServlet { - private static final long serialVersionUID = -369787931175177080L; - - private final static Log log = LogFactory.getLog(SimpleWebdavServlet.class); - - private final Repository repository; - - public SimpleWebdavServlet(Repository repository, - SessionProvider sessionProvider) { - this.repository = repository; - setSessionProvider(sessionProvider); - } - - public Repository getRepository() { - return repository; - } - - @Override - protected boolean execute(WebdavRequest request, WebdavResponse response, - int method, DavResource resource) throws ServletException, - IOException, DavException { - if (log.isTraceEnabled()) - log.trace(request.getMethod() + "\t" + request.getPathInfo()); - boolean res = super.execute(request, response, method, resource); - return res; - } - -} diff --git a/org.argeo.server.jackrabbit/src/main/resources/org/argeo/jackrabbit/repository-fs.xml b/org.argeo.server.jackrabbit/src/main/resources/org/argeo/jackrabbit/repository-fs.xml deleted file mode 100644 index 609fc8b33..000000000 --- a/org.argeo.server.jackrabbit/src/main/resources/org/argeo/jackrabbit/repository-fs.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.server.jackrabbit/src/main/resources/org/argeo/jackrabbit/repository-h2.xml b/org.argeo.server.jackrabbit/src/main/resources/org/argeo/jackrabbit/repository-h2.xml deleted file mode 100644 index b6a92528a..000000000 --- a/org.argeo.server.jackrabbit/src/main/resources/org/argeo/jackrabbit/repository-h2.xml +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.server.jackrabbit/src/main/resources/org/argeo/jackrabbit/repository-memory.xml b/org.argeo.server.jackrabbit/src/main/resources/org/argeo/jackrabbit/repository-memory.xml deleted file mode 100644 index e552c33a7..000000000 --- a/org.argeo.server.jackrabbit/src/main/resources/org/argeo/jackrabbit/repository-memory.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.server.jackrabbit/src/main/wikitext/design.mediawiki b/org.argeo.server.jackrabbit/src/main/wikitext/design.mediawiki deleted file mode 100644 index 1a273832c..000000000 --- a/org.argeo.server.jackrabbit/src/main/wikitext/design.mediawiki +++ /dev/null @@ -1,9 +0,0 @@ -= Titre = - - == Sous Titre == - -* point1 -* point2 - - Code (il suffit de mettre un espace en début de ligne - \ No newline at end of file diff --git a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/JackrabbitAuthorizations.java b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/JackrabbitAuthorizations.java new file mode 100644 index 000000000..e880b6700 --- /dev/null +++ b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/JackrabbitAuthorizations.java @@ -0,0 +1,66 @@ +/* + * 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.jackrabbit; + +import java.security.Principal; +import java.util.Arrays; +import java.util.List; + +import javax.jcr.RepositoryException; +import javax.jcr.Session; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jackrabbit.api.JackrabbitSession; +import org.apache.jackrabbit.api.security.user.Authorizable; +import org.apache.jackrabbit.api.security.user.UserManager; +import org.argeo.ArgeoException; +import org.argeo.jcr.security.JcrAuthorizations; + +/** Apply authorizations to a Jackrabbit repository. */ +public class JackrabbitAuthorizations extends JcrAuthorizations { + private final static Log log = LogFactory + .getLog(JackrabbitAuthorizations.class); + + private List groupPrefixes = Arrays + .asList(new String[] { "ROLE_" });// new ArrayList(); + + @Override + protected Principal getOrCreatePrincipal(Session session, + String principalName) throws RepositoryException { + UserManager um = ((JackrabbitSession) session).getUserManager(); + synchronized (um) { + Authorizable authorizable = um.getAuthorizable(principalName); + if (authorizable == null) { + groupPrefixes: for (String groupPrefix : groupPrefixes) { + if (principalName.startsWith(groupPrefix)) { + authorizable = um.createGroup(principalName); + log.info("Created group " + principalName); + break groupPrefixes; + } + } + if (authorizable == null) + throw new ArgeoException("Authorizable " + principalName + + " not found"); + } + return authorizable.getPrincipal(); + } + } + + public void setGroupPrefixes(List groupsToCreate) { + this.groupPrefixes = groupsToCreate; + } +} diff --git a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/JackrabbitContainer.java b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/JackrabbitContainer.java new file mode 100644 index 000000000..9060b585a --- /dev/null +++ b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/JackrabbitContainer.java @@ -0,0 +1,352 @@ +/* + * 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.jackrabbit; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashSet; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.TreeSet; +import java.util.UUID; + +import javax.jcr.Node; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.Session; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jackrabbit.api.JackrabbitRepository; +import org.apache.jackrabbit.core.RepositoryImpl; +import org.apache.jackrabbit.core.config.RepositoryConfig; +import org.apache.jackrabbit.core.config.RepositoryConfigurationParser; +import org.argeo.ArgeoException; +import org.argeo.jcr.ArgeoNames; +import org.argeo.jcr.JcrUtils; +import org.argeo.jcr.MaintainedRepository; +import org.springframework.core.io.Resource; +import org.springframework.util.SystemPropertyUtils; +import org.xml.sax.InputSource; + +/** + * Wrapper around a Jackrabbit repository which allows to configure it in Spring + * and expose it as a {@link Repository}. + */ +public class JackrabbitContainer extends JackrabbitWrapper implements + MaintainedRepository { + private final static Log log = LogFactory.getLog(JackrabbitContainer.class); + + // local + private Resource configuration; + private Resource variables; + private RepositoryConfig repositoryConfig; + private File homeDirectory; + private Boolean inMemory = false; + + /** Migrations to execute (if not already done) */ + private Set dataModelMigrations = new HashSet(); + + /** + * Empty constructor, {@link #init()} should be called after properties have + * been set + */ + public JackrabbitContainer() { + } + + public void init() { + long begin = System.currentTimeMillis(); + + if (getRepository() != null) + throw new ArgeoException( + "Cannot be used to wrap another repository"); + Repository repository = createJackrabbitRepository(); + super.setRepository(repository); + + // migrate if needed + migrate(); + + // apply new CND files after migration + prepareDataModel(); + + double duration = ((double) (System.currentTimeMillis() - begin)) / 1000; + if (log.isDebugEnabled()) + log.debug("Initialized JCR repository wrapper in " + duration + + " s"); + } + + /** Actually creates the new repository. */ + protected Repository createJackrabbitRepository() { + long begin = System.currentTimeMillis(); + InputStream configurationIn = null; + Repository repository; + try { + // temporary + if (inMemory && getHomeDirectory().exists()) { + FileUtils.deleteDirectory(getHomeDirectory()); + log.warn("Deleted Jackrabbit home directory " + + getHomeDirectory()); + } + + // process configuration file + Properties vars = getConfigurationProperties(); + configurationIn = readConfiguration(); + vars.put(RepositoryConfigurationParser.REPOSITORY_HOME_VARIABLE, + getHomeDirectory().getCanonicalPath()); + repositoryConfig = RepositoryConfig.create(new InputSource( + configurationIn), vars); + + // + // Actual repository creation + // + repository = RepositoryImpl.create(repositoryConfig); + + double duration = ((double) (System.currentTimeMillis() - begin)) / 1000; + if (log.isTraceEnabled()) + log.trace("Created Jackrabbit repository in " + duration + + " s, home: " + getHomeDirectory()); + + return repository; + } catch (Exception e) { + throw new ArgeoException("Cannot create Jackrabbit repository " + + getHomeDirectory(), e); + } finally { + IOUtils.closeQuietly(configurationIn); + } + } + + /** Lazy init. */ + protected File getHomeDirectory() { + try { + if (homeDirectory == null) { + if (inMemory) { + homeDirectory = new File( + System.getProperty("java.io.tmpdir") + + File.separator + + System.getProperty("user.name") + + File.separator + "jackrabbit-" + + UUID.randomUUID()); + homeDirectory.mkdirs(); + // will it work if directory is not empty?? + homeDirectory.deleteOnExit(); + } + } + + return homeDirectory.getCanonicalFile(); + } catch (IOException e) { + throw new ArgeoException("Cannot get canonical file for " + + homeDirectory, e); + } + } + + /** Executes migrations, if needed. */ + protected void migrate() { + // No migration to perform + if (dataModelMigrations.size() == 0) + return; + + Boolean restartAndClearCaches = false; + + // migrate data + Session session = null; + try { + session = login(); + for (JackrabbitDataModelMigration dataModelMigration : new TreeSet( + dataModelMigrations)) { + if (dataModelMigration.migrate(session)) { + restartAndClearCaches = true; + } + } + } catch (ArgeoException e) { + throw e; + } catch (Exception e) { + throw new ArgeoException("Cannot migrate", e); + } finally { + JcrUtils.logoutQuietly(session); + } + + // restart repository + if (restartAndClearCaches) { + Repository repository = getRepository(); + if (repository instanceof RepositoryImpl) { + JackrabbitDataModelMigration + .clearRepositoryCaches(((RepositoryImpl) repository) + .getConfig()); + } + ((JackrabbitRepository) repository).shutdown(); + createJackrabbitRepository(); + } + + // set data model version + try { + session = login(); + } catch (RepositoryException e) { + throw new ArgeoException("Cannot login to migrated repository", e); + } + + for (JackrabbitDataModelMigration dataModelMigration : new TreeSet( + dataModelMigrations)) { + try { + if (session.itemExists(dataModelMigration + .getDataModelNodePath())) { + Node dataModelNode = session.getNode(dataModelMigration + .getDataModelNodePath()); + dataModelNode.setProperty( + ArgeoNames.ARGEO_DATA_MODEL_VERSION, + dataModelMigration.getTargetVersion()); + session.save(); + } + } catch (Exception e) { + log.error("Cannot set model version", e); + } + } + JcrUtils.logoutQuietly(session); + + } + + /** Shutdown the repository */ + public void destroy() throws Exception { + Repository repository = getRepository(); + if (repository != null && repository instanceof RepositoryImpl) { + long begin = System.currentTimeMillis(); + ((RepositoryImpl) repository).shutdown(); + if (inMemory) + if (getHomeDirectory().exists()) { + FileUtils.deleteDirectory(getHomeDirectory()); + if (log.isDebugEnabled()) + log.debug("Deleted Jackrabbit home directory " + + getHomeDirectory()); + } + double duration = ((double) (System.currentTimeMillis() - begin)) / 1000; + log.info("Destroyed Jackrabbit repository in " + duration + + " s, home: " + getHomeDirectory()); + } + repository = null; + } + + public void dispose() { + throw new IllegalArgumentException( + "Call destroy() method instead of dispose()"); + } + + /* + * UTILITIES + */ + /** + * Reads the configuration which will initialize a {@link RepositoryConfig}. + */ + protected InputStream readConfiguration() { + try { + return configuration != null ? configuration.getInputStream() + : null; + } catch (IOException e) { + throw new ArgeoException("Cannot read Jackrabbit configuration " + + configuration, e); + } + } + + /** + * Reads the variables which will initialize a {@link Properties}. Returns + * null by default, to be overridden. + * + * @return a new stream or null if no variables available + */ + protected InputStream readVariables() { + try { + return variables != null ? variables.getInputStream() : null; + } catch (IOException e) { + throw new ArgeoException("Cannot read Jackrabbit variables " + + variables, e); + } + } + + /** + * Resolves ${} placeholders in the provided string. Based on system + * properties if no map is provided. + */ + protected String resolvePlaceholders(String string, + Map variables) { + return SystemPropertyUtils.resolvePlaceholders(string); + } + + /** Generates the properties to use in the configuration. */ + protected Properties getConfigurationProperties() { + InputStream propsIn = null; + Properties vars; + try { + vars = new Properties(); + propsIn = readVariables(); + if (propsIn != null) { + vars.load(propsIn); + } + // resolve system properties + for (Object key : vars.keySet()) { + // TODO: implement a smarter mechanism to resolve nested ${} + String newValue = resolvePlaceholders( + vars.getProperty(key.toString()), null); + vars.put(key, newValue); + } + // override with system properties + vars.putAll(System.getProperties()); + + if (log.isTraceEnabled()) { + log.trace("Jackrabbit config variables:"); + for (Object key : new TreeSet(vars.keySet())) + log.trace(key + "=" + vars.getProperty(key.toString())); + } + + } catch (IOException e) { + throw new ArgeoException("Cannot read configuration properties", e); + } finally { + IOUtils.closeQuietly(propsIn); + } + return vars; + } + + /* + * FIELDS ACCESS + */ + + public void setHomeDirectory(File homeDirectory) { + this.homeDirectory = homeDirectory; + } + + public void setInMemory(Boolean inMemory) { + this.inMemory = inMemory; + } + + public void setRepository(Repository repository) { + throw new ArgeoException("Cannot be used to wrap another repository"); + } + + public void setDataModelMigrations( + Set dataModelMigrations) { + this.dataModelMigrations = dataModelMigrations; + } + + public void setVariables(Resource variables) { + this.variables = variables; + } + + public void setConfiguration(Resource configuration) { + this.configuration = configuration; + } + +} diff --git a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/JackrabbitDataModelMigration.java b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/JackrabbitDataModelMigration.java new file mode 100644 index 000000000..401b34df6 --- /dev/null +++ b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/JackrabbitDataModelMigration.java @@ -0,0 +1,182 @@ +/* + * 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.jackrabbit; + +import java.io.InputStreamReader; +import java.io.Reader; + +import javax.jcr.Node; +import javax.jcr.Session; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jackrabbit.commons.cnd.CndImporter; +import org.apache.jackrabbit.core.config.RepositoryConfig; +import org.argeo.ArgeoException; +import org.argeo.jcr.ArgeoNames; +import org.argeo.jcr.JcrCallback; +import org.argeo.jcr.JcrUtils; +import org.springframework.core.io.Resource; + +/** Migrate the data in a Jackrabbit repository. */ +public class JackrabbitDataModelMigration implements + Comparable { + private final static Log log = LogFactory + .getLog(JackrabbitDataModelMigration.class); + + private String dataModelNodePath; + private String targetVersion; + private Resource migrationCnd; + private JcrCallback dataModification; + + /** + * Expects an already started repository with the old data model to migrate. + * Expects to be run with admin rights (Repository.login() will be used). + * + * @return true if a migration was performed and the repository needs to be + * restarted and its caches cleared. + */ + public Boolean migrate(Session session) { + long begin = System.currentTimeMillis(); + Reader reader = null; + try { + // check if already migrated + if (!session.itemExists(dataModelNodePath)) { + log.warn("Node " + dataModelNodePath + + " does not exist: nothing to migrate."); + return false; + } + Node dataModelNode = session.getNode(dataModelNodePath); + if (dataModelNode.hasProperty(ArgeoNames.ARGEO_DATA_MODEL_VERSION)) { + String currentVersion = dataModelNode.getProperty( + ArgeoNames.ARGEO_DATA_MODEL_VERSION).getString(); + if (compareVersions(currentVersion, targetVersion) >= 0) { + log.info("Data model at version " + currentVersion + + ", no need to migrate."); + return false; + } + } + + // apply transitional CND + if (migrationCnd != null) { + reader = new InputStreamReader(migrationCnd.getInputStream()); + CndImporter.registerNodeTypes(reader, session, true); + session.save(); + log.info("Registered migration node types from " + migrationCnd); + } + + // modify data + dataModification.execute(session); + + // apply changes + session.save(); + + long duration = System.currentTimeMillis() - begin; + log.info("Migration of data model " + dataModelNodePath + " to " + + targetVersion + " performed in " + duration + "ms"); + return true; + } catch (Exception e) { + JcrUtils.discardQuietly(session); + throw new ArgeoException("Migration of data model " + + dataModelNodePath + " to " + targetVersion + " failed.", + e); + } finally { + JcrUtils.logoutQuietly(session); + IOUtils.closeQuietly(reader); + } + } + + protected static int compareVersions(String version1, String version2) { + // TODO do a proper version analysis and comparison + return version1.compareTo(version2); + } + + /** To be called on a stopped repository. */ + public static void clearRepositoryCaches(RepositoryConfig repositoryConfig) { + try { + String customeNodeTypesPath = "/nodetypes/custom_nodetypes.xml"; + repositoryConfig.getFileSystem().deleteFile(customeNodeTypesPath); + if (log.isDebugEnabled()) + log.debug("Cleared " + customeNodeTypesPath); + } catch (Exception e) { + throw new ArgeoException("Cannot clear caches", e); + } + + // File customNodeTypes = new File(home.getPath() + // + "/repository/nodetypes/custom_nodetypes.xml"); + // if (customNodeTypes.exists()) { + // customNodeTypes.delete(); + // if (log.isDebugEnabled()) + // log.debug("Cleared " + customNodeTypes); + // } else { + // log.warn("File " + customNodeTypes + " not found."); + // } + } + + /* + * FOR USE IN (SORTED) SETS + */ + + public int compareTo(JackrabbitDataModelMigration dataModelMigration) { + // TODO make ordering smarter + if (dataModelNodePath.equals(dataModelMigration.dataModelNodePath)) + return compareVersions(targetVersion, + dataModelMigration.targetVersion); + else + return dataModelNodePath + .compareTo(dataModelMigration.dataModelNodePath); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof JackrabbitDataModelMigration)) + return false; + JackrabbitDataModelMigration dataModelMigration = (JackrabbitDataModelMigration) obj; + return dataModelNodePath.equals(dataModelMigration.dataModelNodePath) + && targetVersion.equals(dataModelMigration.targetVersion); + } + + @Override + public int hashCode() { + return targetVersion.hashCode(); + } + + public void setDataModelNodePath(String dataModelNodePath) { + this.dataModelNodePath = dataModelNodePath; + } + + public void setTargetVersion(String targetVersion) { + this.targetVersion = targetVersion; + } + + public void setMigrationCnd(Resource migrationCnd) { + this.migrationCnd = migrationCnd; + } + + public void setDataModification(JcrCallback dataModification) { + this.dataModification = dataModification; + } + + public String getDataModelNodePath() { + return dataModelNodePath; + } + + public String getTargetVersion() { + return targetVersion; + } + +} diff --git a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/JackrabbitRepositoryFactory.java b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/JackrabbitRepositoryFactory.java new file mode 100644 index 000000000..d64bb5e68 --- /dev/null +++ b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/JackrabbitRepositoryFactory.java @@ -0,0 +1,169 @@ +/* + * 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.jackrabbit; + +import java.io.File; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.RepositoryFactory; +import javax.jcr.Session; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jackrabbit.commons.JcrUtils; +import org.apache.jackrabbit.core.RepositoryImpl; +import org.apache.jackrabbit.core.config.RepositoryConfig; +import org.apache.jackrabbit.core.config.RepositoryConfigurationParser; +import org.apache.jackrabbit.jcr2dav.Jcr2davRepositoryFactory; +import org.argeo.ArgeoException; +import org.argeo.jcr.ArgeoJcrConstants; +import org.argeo.jcr.DefaultRepositoryFactory; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.xml.sax.InputSource; + +/** + * Repository factory which can create new repositories and access remote + * Jackrabbit repositories + */ +public class JackrabbitRepositoryFactory extends DefaultRepositoryFactory + implements RepositoryFactory, ArgeoJcrConstants { + + private final static Log log = LogFactory + .getLog(JackrabbitRepositoryFactory.class); + + private Resource fileRepositoryConfiguration = new ClassPathResource( + "/org/argeo/jackrabbit/repository-h2.xml"); + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public Repository getRepository(Map parameters) throws RepositoryException { + // check if can be found by alias + Repository repository = super.getRepository(parameters); + if (repository != null) + return repository; + + // check if remote + String uri = null; + if (parameters.containsKey(JCR_REPOSITORY_URI)) + uri = parameters.get(JCR_REPOSITORY_URI).toString(); + else if (parameters.containsKey(JcrUtils.REPOSITORY_URI)) + uri = parameters.get(JcrUtils.REPOSITORY_URI).toString(); + + if (uri != null) { + if (uri.startsWith("http"))// http, https + repository = createRemoteRepository(uri); + else if (uri.startsWith("file"))// http, https + repository = createFileRepository(uri, parameters); + else if (uri.startsWith("vm")) { + log.warn("URI " + + uri + + " should have been managed by generic JCR repository factory"); + repository = getRepositoryByAlias(getAliasFromURI(uri)); + } + } + + // publish under alias + if (parameters.containsKey(JCR_REPOSITORY_ALIAS)) { + Properties properties = new Properties(); + properties.putAll(parameters); + String alias = parameters.get(JCR_REPOSITORY_ALIAS).toString(); + publish(alias, repository, properties); + log.info("Registered JCR repository under alias '" + alias + + "' with properties " + properties); + } + + return repository; + } + + protected Repository createRemoteRepository(String uri) + throws RepositoryException { + Map params = new HashMap(); + params.put(JcrUtils.REPOSITORY_URI, uri); + Repository repository = new Jcr2davRepositoryFactory() + .getRepository(params); + if (repository == null) + throw new ArgeoException("Remote Davex repository " + uri + + " not found"); + log.info("Initialized remote Jackrabbit repository from uri " + uri); + return repository; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + protected Repository createFileRepository(final String uri, Map parameters) + throws RepositoryException { + InputStream configurationIn = null; + try { + Properties vars = new Properties(); + vars.putAll(parameters); + String dirPath = uri.substring("file:".length()); + File homeDir = new File(dirPath); + if (homeDir.exists() && !homeDir.isDirectory()) + throw new ArgeoException("Repository home " + dirPath + + " is not a directory"); + if (!homeDir.exists()) + homeDir.mkdirs(); + configurationIn = fileRepositoryConfiguration.getInputStream(); + vars.put(RepositoryConfigurationParser.REPOSITORY_HOME_VARIABLE, + homeDir.getCanonicalPath()); + RepositoryConfig repositoryConfig = RepositoryConfig.create( + new InputSource(configurationIn), vars); + + // TransientRepository repository = new + // TransientRepository(repositoryConfig); + final RepositoryImpl repository = RepositoryImpl + .create(repositoryConfig); + Session session = repository.login(); + // FIXME make it generic + org.argeo.jcr.JcrUtils.addPrivilege(session, "/", "ROLE_ADMIN", + "jcr:all"); + org.argeo.jcr.JcrUtils.logoutQuietly(session); + Runtime.getRuntime().addShutdownHook( + new Thread("Clean JCR repository " + uri) { + public void run() { + repository.shutdown(); + log.info("Destroyed repository " + uri); + } + }); + log.info("Initialized file Jackrabbit repository from uri " + uri); + return repository; + } catch (Exception e) { + throw new ArgeoException("Cannot create repository " + uri, e); + } finally { + IOUtils.closeQuietly(configurationIn); + } + } + + /** + * Called after the repository has been initialised. Does nothing by + * default. + */ + @SuppressWarnings("rawtypes") + protected void postInitialization(Repository repository, Map parameters) { + + } + + public void setFileRepositoryConfiguration( + Resource fileRepositoryConfiguration) { + this.fileRepositoryConfiguration = fileRepositoryConfiguration; + } + +} diff --git a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/JackrabbitWrapper.java b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/JackrabbitWrapper.java new file mode 100644 index 000000000..f9f04c4cb --- /dev/null +++ b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/JackrabbitWrapper.java @@ -0,0 +1,375 @@ +/* + * 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.jackrabbit; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.jcr.Credentials; +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.Repository; +import javax.jcr.Session; +import javax.jcr.nodetype.NodeType; + +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jackrabbit.commons.NamespaceHelper; +import org.apache.jackrabbit.commons.cnd.CndImporter; +import org.argeo.ArgeoException; +import org.argeo.jcr.ArgeoJcrConstants; +import org.argeo.jcr.ArgeoNames; +import org.argeo.jcr.ArgeoTypes; +import org.argeo.jcr.JcrRepositoryWrapper; +import org.argeo.jcr.JcrUtils; +import org.argeo.util.security.DigestUtils; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.service.packageadmin.ExportedPackage; +import org.osgi.service.packageadmin.PackageAdmin; +import org.springframework.context.ResourceLoaderAware; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; + +/** + * Wrapper around a Jackrabbit repository which allows to simplify configuration + * and intercept some actions. It exposes itself as a {@link Repository}. + */ +public class JackrabbitWrapper extends JcrRepositoryWrapper implements + ResourceLoaderAware { + private final static Log log = LogFactory.getLog(JackrabbitWrapper.class); + private final static String DIGEST_ALGORITHM = "MD5"; + + // local + private ResourceLoader resourceLoader; + + // data model + /** Node type definitions in CND format */ + private List cndFiles = new ArrayList(); + /** + * Always import CNDs. Useful during development of new data models. In + * production, explicit migration processes should be used. + */ + private Boolean forceCndImport = true; + + /** Namespaces to register: key is prefix, value namespace */ + private Map namespaces = new HashMap(); + + private BundleContext bundleContext; + + /** + * Explicitly set admin credentials used in initialization. Useful for + * testing, in real applications authentication is rather dealt with + * externally + */ + private Credentials adminCredentials = null; + + /** + * Empty constructor, {@link #init()} should be called after properties have + * been set + */ + public JackrabbitWrapper() { + } + + @Override + public void init() { + prepareDataModel(); + } + + /* + * DATA MODEL + */ + + /** + * Import declared node type definitions and register namespaces. Tries to + * update the node definitions if they have changed. In case of failures an + * error will be logged but no exception will be thrown. + */ + protected void prepareDataModel() { + if ((cndFiles == null || cndFiles.size() == 0) + && (namespaces == null || namespaces.size() == 0)) + return; + + Session session = null; + try { + session = login(adminCredentials); + // register namespaces + if (namespaces.size() > 0) { + NamespaceHelper namespaceHelper = new NamespaceHelper(session); + namespaceHelper.registerNamespaces(namespaces); + } + + // load CND files from classpath or as URL + for (String resUrl : cndFiles) { + processCndFile(session, resUrl); + } + } catch (Exception e) { + JcrUtils.discardQuietly(session); + throw new ArgeoException("Cannot import node type definitions " + + cndFiles, e); + } finally { + JcrUtils.logoutQuietly(session); + } + + } + + protected void processCndFile(Session session, String resUrl) { + Reader reader = null; + try { + // check existing data model nodes + new NamespaceHelper(session).registerNamespace(ArgeoNames.ARGEO, + ArgeoNames.ARGEO_NAMESPACE); + if (!session.itemExists(ArgeoJcrConstants.DATA_MODELS_BASE_PATH)) + JcrUtils.mkdirs(session, + ArgeoJcrConstants.DATA_MODELS_BASE_PATH); + Node dataModels = session + .getNode(ArgeoJcrConstants.DATA_MODELS_BASE_PATH); + NodeIterator it = dataModels.getNodes(); + Node dataModel = null; + while (it.hasNext()) { + Node node = it.nextNode(); + if (node.getProperty(ArgeoNames.ARGEO_URI).getString() + .equals(resUrl)) { + dataModel = node; + break; + } + } + + byte[] cndContent = readCndContent(resUrl); + String newDigest = DigestUtils.digest(DIGEST_ALGORITHM, cndContent); + Bundle bundle = findDataModelBundle(resUrl); + + String currentVersion = null; + if (dataModel != null) { + currentVersion = dataModel.getProperty( + ArgeoNames.ARGEO_DATA_MODEL_VERSION).getString(); + if (dataModel.hasNode(Node.JCR_CONTENT)) { + String oldDigest = JcrUtils.checksumFile(dataModel, + DIGEST_ALGORITHM); + if (oldDigest.equals(newDigest)) { + if (log.isDebugEnabled()) + log.debug("Data model " + resUrl + + " hasn't changed, keeping version " + + currentVersion); + return; + } + } + } + + if (dataModel != null && !forceCndImport) { + log.info("Data model " + + resUrl + + " has changed since version " + + currentVersion + + (bundle != null ? ": version " + bundle.getVersion() + + ", bundle " + bundle.getSymbolicName() : "")); + return; + } + + reader = new InputStreamReader(new ByteArrayInputStream(cndContent)); + // actually imports the CND + try { + CndImporter.registerNodeTypes(reader, session, true); + } catch (Exception e) { + log.error("Cannot import data model " + resUrl, e); + return; + } + + if (dataModel != null && !dataModel.isNodeType(NodeType.NT_FILE)) { + dataModel.remove(); + dataModel = null; + } + + // FIXME: what if argeo.cnd would not be the first called on + // a new repo? argeo:dataModel would not be found + String fileName = FilenameUtils.getName(resUrl); + if (dataModel == null) { + dataModel = dataModels.addNode(fileName, NodeType.NT_FILE); + dataModel.addNode(Node.JCR_CONTENT, NodeType.NT_RESOURCE); + dataModel.addMixin(ArgeoTypes.ARGEO_DATA_MODEL); + dataModel.setProperty(ArgeoNames.ARGEO_URI, resUrl); + } else { + session.getWorkspace().getVersionManager() + .checkout(dataModel.getPath()); + } + if (bundle != null) + dataModel.setProperty(ArgeoNames.ARGEO_DATA_MODEL_VERSION, + bundle.getVersion().toString()); + else + dataModel.setProperty(ArgeoNames.ARGEO_DATA_MODEL_VERSION, + "0.0.0"); + JcrUtils.copyBytesAsFile(dataModel.getParent(), fileName, + cndContent); + JcrUtils.updateLastModified(dataModel); + session.save(); + session.getWorkspace().getVersionManager() + .checkin(dataModel.getPath()); + + if (currentVersion == null) + log.info("Data model " + + resUrl + + (bundle != null ? ", version " + bundle.getVersion() + + ", bundle " + bundle.getSymbolicName() : "")); + else + log.info("Data model " + + resUrl + + " updated from version " + + currentVersion + + (bundle != null ? ", version " + bundle.getVersion() + + ", bundle " + bundle.getSymbolicName() : "")); + } catch (Exception e) { + throw new ArgeoException("Cannot process data model " + resUrl, e); + } finally { + IOUtils.closeQuietly(reader); + } + } + + protected byte[] readCndContent(String resUrl) { + InputStream in = null; + try { + boolean classpath; + // normalize URL + if (bundleContext != null && resUrl.startsWith("classpath:")) { + resUrl = resUrl.substring("classpath:".length()); + classpath = true; + } else if (resUrl.indexOf(':') < 0) { + if (!resUrl.startsWith("/")) { + resUrl = "/" + resUrl; + log.warn("Classpath should start with '/'"); + } + classpath = true; + } else { + classpath = false; + } + + URL url = null; + if (classpath) { + if (bundleContext != null) { + Bundle currentBundle = bundleContext.getBundle(); + url = currentBundle.getResource(resUrl); + } else { + resUrl = "classpath:" + resUrl; + url = null; + } + } else if (!resUrl.startsWith("classpath:")) { + url = new URL(resUrl); + } + + if (url != null) { + in = url.openStream(); + } else if (resourceLoader != null) { + Resource res = resourceLoader.getResource(resUrl); + in = res.getInputStream(); + url = res.getURL(); + } else { + throw new ArgeoException("No " + resUrl + " in the classpath," + + " make sure the containing" + " package is visible."); + } + + return IOUtils.toByteArray(in); + } catch (Exception e) { + throw new ArgeoException("Cannot read CND from " + resUrl, e); + } finally { + IOUtils.closeQuietly(in); + } + } + + /* + * REPOSITORY INTERCEPTOR + */ + + /* + * UTILITIES + */ + /** Find which OSGi bundle provided the data model resource */ + protected Bundle findDataModelBundle(String resUrl) { + if (bundleContext == null) + return null; + + if (resUrl.startsWith("/")) + resUrl = resUrl.substring(1); + String pkg = resUrl.substring(0, resUrl.lastIndexOf('/')).replace('/', + '.'); + ServiceReference paSr = bundleContext + .getServiceReference(PackageAdmin.class.getName()); + PackageAdmin packageAdmin = (PackageAdmin) bundleContext + .getService(paSr); + + // find exported package + ExportedPackage exportedPackage = null; + ExportedPackage[] exportedPackages = packageAdmin + .getExportedPackages(pkg); + if (exportedPackages == null) + throw new ArgeoException("No exported package found for " + pkg); + for (ExportedPackage ep : exportedPackages) { + for (Bundle b : ep.getImportingBundles()) { + if (b.getBundleId() == bundleContext.getBundle().getBundleId()) { + exportedPackage = ep; + break; + } + } + } + + Bundle exportingBundle = null; + if (exportedPackage != null) { + exportingBundle = exportedPackage.getExportingBundle(); + } else { + // assume this is in the same bundle + exportingBundle = bundleContext.getBundle(); +// throw new ArgeoException("No OSGi exporting package found for " +// + resUrl); + } + return exportingBundle; + } + + /* + * FIELDS ACCESS + */ + public void setNamespaces(Map namespaces) { + this.namespaces = namespaces; + } + + public void setCndFiles(List cndFiles) { + this.cndFiles = cndFiles; + } + + public void setBundleContext(BundleContext bundleContext) { + this.bundleContext = bundleContext; + } + + public void setForceCndImport(Boolean forceCndUpdate) { + this.forceCndImport = forceCndUpdate; + } + + public void setResourceLoader(ResourceLoader resourceLoader) { + this.resourceLoader = resourceLoader; + } + + public void setAdminCredentials(Credentials adminCredentials) { + this.adminCredentials = adminCredentials; + } + +} diff --git a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/OsgiJackrabbitRepositoryFactory.java b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/OsgiJackrabbitRepositoryFactory.java new file mode 100644 index 000000000..b28699e60 --- /dev/null +++ b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/OsgiJackrabbitRepositoryFactory.java @@ -0,0 +1,49 @@ +/* + * 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.jackrabbit; + +import java.util.Hashtable; +import java.util.Properties; + +import javax.jcr.Repository; + +import org.osgi.framework.BundleContext; + +/** + * OSGi-aware Jackrabbit repository factory which can retrieve/publish + * {@link Repository} as OSGi services. + */ +public class OsgiJackrabbitRepositoryFactory extends + JackrabbitRepositoryFactory { + private BundleContext bundleContext; + + protected void publish(String alias, Repository repository, + Properties properties) { + if (bundleContext != null) { + // do not modify reference + Hashtable props = new Hashtable(); + props.putAll(props); + props.put(JCR_REPOSITORY_ALIAS, alias); + bundleContext.registerService(Repository.class.getName(), + repository, props); + } + } + + public void setBundleContext(BundleContext bundleContext) { + this.bundleContext = bundleContext; + } + +} diff --git a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/AbstractJackrabbitHandlerMapping.java b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/AbstractJackrabbitHandlerMapping.java new file mode 100644 index 000000000..99bfab4e8 --- /dev/null +++ b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/AbstractJackrabbitHandlerMapping.java @@ -0,0 +1,34 @@ +/* + * 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.jackrabbit.remote; + +import org.apache.jackrabbit.server.SessionProvider; +import org.argeo.jcr.mvc.MultipleRepositoryHandlerMapping; + +/** Base class for Jackrabbit handler mappings. */ +public abstract class AbstractJackrabbitHandlerMapping extends + MultipleRepositoryHandlerMapping { + private SessionProvider sessionProvider; + + protected SessionProvider getSessionProvider() { + return sessionProvider; + } + + public void setSessionProvider(SessionProvider sessionProvider) { + this.sessionProvider = sessionProvider; + } + +} diff --git a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/ExtendedDispatcherServlet.java b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/ExtendedDispatcherServlet.java new file mode 100644 index 000000000..14b6e9989 --- /dev/null +++ b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/ExtendedDispatcherServlet.java @@ -0,0 +1,55 @@ +/* + * 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.jackrabbit.remote; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.ArgeoException; +import org.springframework.web.servlet.DispatcherServlet; + +/** + * Overrides Spring {@link DispatcherServlet}, see + * http://forum.springsource.org/showthread.php?t=53472. + */ +public class ExtendedDispatcherServlet extends DispatcherServlet { + private static final long serialVersionUID = -5584673209855752009L; + + private final static Log log = LogFactory + .getLog(ExtendedDispatcherServlet.class); + + protected void service(HttpServletRequest request, + HttpServletResponse response) throws ServletException, + java.io.IOException { + try { + if (log.isTraceEnabled()) { + log.trace("SessionID = " + request.getSession().getId()); + log.trace(" ContextPath = " + request.getContextPath()); + log.trace(" ServletPath = " + request.getServletPath()); + log.trace(" PathInfo = " + request.getPathInfo()); + log.trace(" Method = " + request.getMethod()); + log.trace(" User-Agent = " + request.getHeader("User-Agent")); + } + doService(request, response); + } catch (Exception e) { + throw new ArgeoException("Cannot process request", e); + } + } + +} diff --git a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/IOHandlerWrapper.java b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/IOHandlerWrapper.java new file mode 100644 index 000000000..daf2ecb2b --- /dev/null +++ b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/IOHandlerWrapper.java @@ -0,0 +1,114 @@ +/* + * 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.jackrabbit.remote; + +import java.io.IOException; + +import org.apache.jackrabbit.server.io.ExportContext; +import org.apache.jackrabbit.server.io.IOHandler; +import org.apache.jackrabbit.server.io.IOManager; +import org.apache.jackrabbit.server.io.ImportContext; +import org.apache.jackrabbit.webdav.DavResource; +import org.argeo.ArgeoException; + +/** Wraps an IOHandler so that it can be injected a posteriori */ +public class IOHandlerWrapper implements IOHandler { + private IOManager ioManager = null; + private IOHandler ioHandler = null; + + public void setIOHandler(IOHandler ioHandler) { + if ((this.ioHandler != null) && (ioHandler != null)) + throw new ArgeoException( + "There is already an IO Handler registered"); + this.ioHandler = ioHandler; + if (ioManager != null && this.ioHandler != null) + ioHandler.setIOManager(ioManager); + } + + public IOHandler getIOHandler() { + return ioHandler; + } + + public IOManager getIOManager() { + return ioManager; + } + + public void setIOManager(IOManager ioManager) { + this.ioManager = ioManager; + if (ioHandler != null) + ioHandler.setIOManager(ioManager); + } + + public String getName() { + if (ioHandler != null) + return ioHandler.getName(); + else + return "Empty IOHandler Wrapper"; + } + + public boolean canImport(ImportContext context, boolean isCollection) { + if (ioHandler != null) + return ioHandler.canImport(context, isCollection); + return false; + } + + public boolean canImport(ImportContext context, DavResource resource) { + if (ioHandler != null) + return ioHandler.canImport(context, resource); + return false; + } + + public boolean importContent(ImportContext context, boolean isCollection) + throws IOException { + if (ioHandler != null) + ioHandler.importContent(context, isCollection); + return false; + } + + public boolean importContent(ImportContext context, DavResource resource) + throws IOException { + if (ioHandler != null) + ioHandler.importContent(context, resource); + return false; + } + + public boolean canExport(ExportContext context, boolean isCollection) { + if (ioHandler != null) + ioHandler.canExport(context, isCollection); + return false; + } + + public boolean canExport(ExportContext context, DavResource resource) { + if (ioHandler != null) + ioHandler.canExport(context, resource); + return false; + } + + public boolean exportContent(ExportContext context, boolean isCollection) + throws IOException { + if (ioHandler != null) + ioHandler.exportContent(context, isCollection); + return false; + } + + public boolean exportContent(ExportContext context, DavResource resource) + throws IOException { + if (ioHandler != null) + ioHandler.exportContent(context, resource); + return false; + } + +} diff --git a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/IOManagerBean.java b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/IOManagerBean.java new file mode 100644 index 000000000..82a76738b --- /dev/null +++ b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/IOManagerBean.java @@ -0,0 +1,82 @@ +/* + * 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.jackrabbit.remote; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.jackrabbit.server.io.ExportContext; +import org.apache.jackrabbit.server.io.IOHandler; +import org.apache.jackrabbit.server.io.IOManager; +import org.apache.jackrabbit.server.io.ImportContext; +import org.apache.jackrabbit.webdav.DavResource; +import org.apache.tika.detect.Detector; + +/** {@link IOManager} that can easily be configured as a bean. */ +public class IOManagerBean implements IOManager { + private Detector detector = null; + private List ioHandlers = new ArrayList(); + + public boolean importContent(ImportContext context, boolean isCollection) + throws IOException { + // TODO Auto-generated method stub + return false; + } + + public boolean importContent(ImportContext context, DavResource resource) + throws IOException { + // TODO Auto-generated method stub + return false; + } + + public boolean exportContent(ExportContext context, boolean isCollection) + throws IOException { + // TODO Auto-generated method stub + return false; + } + + public boolean exportContent(ExportContext context, DavResource resource) + throws IOException { + // TODO Auto-generated method stub + return false; + } + + public synchronized void addIOHandler(IOHandler ioHandler) { + ioHandlers.add(ioHandler); + } + + public synchronized IOHandler[] getIOHandlers() { + return ioHandlers.toArray(new IOHandler[ioHandlers.size()]); + } + + public Detector getDetector() { + return detector; + } + + public void setDetector(Detector detector) { + this.detector = detector; + } + + public synchronized List getIoHandlers() { + return ioHandlers; + } + + public synchronized void setIoHandlers(List ioHandlers) { + this.ioHandlers = ioHandlers; + } + +} diff --git a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/JcrRemotingHandlerMapping.java b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/JcrRemotingHandlerMapping.java new file mode 100644 index 000000000..caea5fc8b --- /dev/null +++ b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/JcrRemotingHandlerMapping.java @@ -0,0 +1,37 @@ +/* + * 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.jackrabbit.remote; + +import java.util.Properties; + +import javax.jcr.Repository; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; + +public class JcrRemotingHandlerMapping extends AbstractJackrabbitHandlerMapping { + + protected HttpServlet createServlet(Repository repository, String pathPrefix) + throws ServletException { + JcrRemotingServlet servlet = new JcrRemotingServlet(repository, + getSessionProvider()); + Properties initParameters = new Properties(); + initParameters.setProperty( + JcrRemotingServlet.INIT_PARAM_RESOURCE_PATH_PREFIX, pathPrefix); + servlet.init(new DelegatingServletConfig(pathPrefix.replace('/', '_'), + initParameters)); + return servlet; + } +} diff --git a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/JcrRemotingServlet.java b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/JcrRemotingServlet.java new file mode 100644 index 000000000..b3f079745 --- /dev/null +++ b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/JcrRemotingServlet.java @@ -0,0 +1,46 @@ +/* + * 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.jackrabbit.remote; + +import javax.jcr.Repository; + +import org.apache.jackrabbit.server.SessionProvider; + +public class JcrRemotingServlet extends + org.apache.jackrabbit.server.remoting.davex.JcrRemotingServlet { + + private static final long serialVersionUID = 3131835511468341309L; + + private final Repository repository; + private final SessionProvider sessionProvider; + + public JcrRemotingServlet(Repository repository, + SessionProvider sessionProvider) { + this.repository = repository; + this.sessionProvider = sessionProvider; + } + + @Override + protected Repository getRepository() { + return repository; + } + + @Override + protected SessionProvider getSessionProvider() { + return sessionProvider; + } + +} diff --git a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/OpenInViewSessionProvider.java b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/OpenInViewSessionProvider.java new file mode 100644 index 000000000..b4d1d6021 --- /dev/null +++ b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/OpenInViewSessionProvider.java @@ -0,0 +1,69 @@ +/* + * 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.jackrabbit.remote; + +import java.io.Serializable; + +import javax.jcr.LoginException; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jackrabbit.server.SessionProvider; +import org.argeo.jcr.JcrUtils; + +/** + * Implements an open session in view patter: a new JCR session is created for + * each request + */ +public class OpenInViewSessionProvider implements SessionProvider, Serializable { + private static final long serialVersionUID = 2270957712453841368L; + + private final static Log log = LogFactory + .getLog(OpenInViewSessionProvider.class); + + public Session getSession(HttpServletRequest request, Repository rep, + String workspace) throws LoginException, ServletException, + RepositoryException { + return login(request, rep, workspace); + } + + protected Session login(HttpServletRequest request, Repository repository, + String workspace) throws RepositoryException { + if (log.isTraceEnabled()) + log.trace("Login to workspace " + + (workspace == null ? "" : workspace) + + " in web session " + request.getSession().getId()); + return repository.login(workspace); + } + + public void releaseSession(Session session) { + JcrUtils.logoutQuietly(session); + if (log.isTraceEnabled()) + log.trace("Logged out remote JCR session " + session); + } + + public void init() { + } + + public void destroy() { + } + +} diff --git a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/ScopedSessionProvider.java b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/ScopedSessionProvider.java new file mode 100644 index 000000000..ffe6df9b1 --- /dev/null +++ b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/ScopedSessionProvider.java @@ -0,0 +1,171 @@ +/* + * 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.jackrabbit.remote; + +import java.io.Serializable; + +import javax.jcr.LoginException; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jackrabbit.server.SessionProvider; +import org.argeo.ArgeoException; +import org.argeo.jcr.ArgeoJcrConstants; +import org.argeo.jcr.JcrUtils; +import org.springframework.security.Authentication; +import org.springframework.security.context.SecurityContextHolder; + +/** + * Session provider assuming a single workspace and a short life cycle, + * typically a Spring bean of scope (web) 'session'. + */ +public class ScopedSessionProvider implements SessionProvider, Serializable { + private static final long serialVersionUID = 6589775984177317058L; + private static final Log log = LogFactory + .getLog(ScopedSessionProvider.class); + private transient HttpSession httpSession = null; + private transient Session jcrSession = null; + + private transient String currentRepositoryName = null; + private transient String currentWorkspaceName = null; + private transient String currentJcrUser = null; + + // private transient String anonymousUserId = "anonymous"; + + public Session getSession(HttpServletRequest request, Repository rep, + String workspace) throws LoginException, ServletException, + RepositoryException { + + Authentication authentication = SecurityContextHolder.getContext() + .getAuthentication(); + if (authentication == null) + throw new ArgeoException( + "Request not authenticated by Spring Security"); + String springUser = authentication.getName(); + + // HTTP + String requestJcrRepository = (String) request + .getAttribute(ArgeoJcrConstants.JCR_REPOSITORY_ALIAS); + + // HTTP session + if (httpSession != null + && !httpSession.getId().equals(request.getSession().getId())) + throw new ArgeoException( + "Only session scope is supported in this mode"); + if (httpSession == null) + httpSession = request.getSession(); + + // Initializes current values + if (currentRepositoryName == null) + currentRepositoryName = requestJcrRepository; + if (currentWorkspaceName == null) + currentWorkspaceName = workspace; + if (currentJcrUser == null) + currentJcrUser = springUser; + + // logout if there was a change in session coordinates + if (jcrSession != null) + if (!currentRepositoryName.equals(requestJcrRepository)) { + if (log.isDebugEnabled()) + log.debug(getHttpSessionId() + " Changed from repository '" + + currentRepositoryName + "' to '" + + requestJcrRepository + + "', logging out cached JCR session."); + logout(); + } else if (!currentWorkspaceName.equals(workspace)) { + if (log.isDebugEnabled()) + log.debug(getHttpSessionId() + " Changed from workspace '" + + currentWorkspaceName + "' to '" + workspace + + "', logging out cached JCR session."); + logout(); + } else if (!currentJcrUser.equals(springUser)) { + if (log.isDebugEnabled()) + log.debug(getHttpSessionId() + " Changed from user '" + + currentJcrUser + "' to '" + springUser + + "', logging out cached JCR session."); + logout(); + } + + // login if needed + if (jcrSession == null) + try { + Session session = login(rep, workspace); + if (!session.getUserID().equals(springUser)) { + JcrUtils.logoutQuietly(session); + throw new ArgeoException("Spring Security user '" + + springUser + "' not in line with JCR user '" + + session.getUserID() + "'"); + } + currentRepositoryName = requestJcrRepository; + // do not use workspace variable which may be null + currentWorkspaceName = session.getWorkspace().getName(); + currentJcrUser = session.getUserID(); + + jcrSession = session; + return jcrSession; + } catch (RepositoryException e) { + throw new ArgeoException("Cannot open session to workspace " + + workspace, e); + } + + // returns cached session + return jcrSession; + } + + protected Session login(Repository repository, String workspace) + throws RepositoryException { + Session session = repository.login(workspace); + if (log.isDebugEnabled()) + log.debug(getHttpSessionId() + " User '" + session.getUserID() + + "' logged in workspace '" + + session.getWorkspace().getName() + "' of repository '" + + currentRepositoryName + "'"); + return session; + } + + public void releaseSession(Session session) { + if (log.isTraceEnabled()) + log.trace(getHttpSessionId() + " Releasing JCR session " + session); + } + + protected void logout() { + JcrUtils.logoutQuietly(jcrSession); + jcrSession = null; + } + + protected final String getHttpSessionId() { + return httpSession != null ? httpSession.getId() : ""; + } + + public void init() { + } + + public void destroy() { + logout(); + if (getHttpSessionId() != null) + if (log.isDebugEnabled()) + log.debug(getHttpSessionId() + + " Cleaned up provider for web session "); + httpSession = null; + } + +} diff --git a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/SimpleSessionProvider.java b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/SimpleSessionProvider.java new file mode 100644 index 000000000..1d438d504 --- /dev/null +++ b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/SimpleSessionProvider.java @@ -0,0 +1,216 @@ +/* + * 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.jackrabbit.remote; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.jcr.LoginException; +import javax.jcr.Node; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.Value; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jackrabbit.api.JackrabbitSession; +import org.apache.jackrabbit.api.security.user.Group; +import org.apache.jackrabbit.api.security.user.User; +import org.apache.jackrabbit.api.security.user.UserManager; +import org.apache.jackrabbit.server.SessionProvider; +import org.argeo.ArgeoException; +import org.argeo.jcr.ArgeoNames; +import org.argeo.jcr.JcrUtils; +import org.argeo.jcr.UserJcrUtils; + +/** + * Implements an open session in view patter: a new JCR session is created for + * each request + * + * @deprecated use {@link ScopedSessionProvider} or + * {@link OpenInViewSessionProvider} + */ +@Deprecated +public class SimpleSessionProvider implements SessionProvider, Serializable { + private static final long serialVersionUID = 2270957712453841368L; + + private final static Log log = LogFactory + .getLog(SimpleSessionProvider.class); + + private transient Map sessions; + + private Boolean openSessionInView = true; + + private String defaultWorkspace = "default"; + + private String webSessionId = null; + + public Session getSession(HttpServletRequest request, Repository rep, + String workspace) throws LoginException, ServletException, + RepositoryException { + + if (openSessionInView) { + JackrabbitSession session = (JackrabbitSession) login(request, rep, + workspace); + if (session.getWorkspace().getName().equals(defaultWorkspace)) + writeRemoteRoles(session); + return session; + } else { + if (webSessionId != null + && !webSessionId.equals(request.getSession().getId())) + throw new ArgeoException( + "Only session scope is supported in this mode"); + webSessionId = request.getSession().getId(); + + // since sessions is transient it can't be restored from the session + if (sessions == null) + sessions = Collections + .synchronizedMap(new HashMap()); + + if (!sessions.containsKey(workspace)) { + try { + // JackrabbitSession session = (JackrabbitSession) + // rep.login( + // null, workspace); + JackrabbitSession session = (JackrabbitSession) login( + request, rep, workspace); + if (session.getWorkspace().getName() + .equals(defaultWorkspace)) + writeRemoteRoles(session); + if (log.isTraceEnabled()) + log.trace("User " + session.getUserID() + + " logged into " + request.getServletPath()); + sessions.put(workspace, session); + return session; + } catch (Exception e) { + throw new ArgeoException("Cannot open session", e); + } + } else { + Session session = sessions.get(workspace); + if (!session.isLive()) { + sessions.remove(workspace); + session = login(request, rep, workspace); + sessions.put(workspace, session); + } + return session; + } + } + } + + protected Session login(HttpServletRequest request, Repository repository, + String workspace) throws RepositoryException { + if (log.isDebugEnabled()) + log.debug("Login to workspace " + + (workspace == null ? "" : workspace) + + " in web session " + request.getSession().getId()); + return repository.login(workspace); + } + + protected void writeRemoteRoles(JackrabbitSession session) + throws RepositoryException { + // FIXME better deal w/ non node repo + + // retrieve roles + String userId = session.getUserID(); + UserManager userManager = session.getUserManager(); + User user = (User) userManager.getAuthorizable(userId); + if (user == null) { + // anonymous + return; + } + List userGroupIds = new ArrayList(); + if (user != null) + for (Iterator it = user.memberOf(); it.hasNext();) + userGroupIds.add(it.next().getID()); + + // write roles if needed + Node userHome = UserJcrUtils.getUserHome(session); + boolean writeRoles = false; + if (userHome.hasProperty(ArgeoNames.ARGEO_REMOTE_ROLES)) { + Value[] roles = userHome.getProperty(ArgeoNames.ARGEO_REMOTE_ROLES) + .getValues(); + if (roles.length != userGroupIds.size()) + writeRoles = true; + else + for (int i = 0; i < roles.length; i++) + if (!roles[i].getString().equals(userGroupIds.get(i))) + writeRoles = true; + } else + writeRoles = true; + + if (writeRoles) { + session.getWorkspace().getVersionManager() + .checkout(userHome.getPath()); + String[] roleIds = userGroupIds.toArray(new String[userGroupIds + .size()]); + userHome.setProperty(ArgeoNames.ARGEO_REMOTE_ROLES, roleIds); + JcrUtils.updateLastModified(userHome); + session.save(); + session.getWorkspace().getVersionManager() + .checkin(userHome.getPath()); + } + + } + + public void releaseSession(Session session) { + if (log.isTraceEnabled()) + log.trace("Releasing JCR session " + session); + if (openSessionInView) { + JcrUtils.logoutQuietly(session); + if (log.isDebugEnabled()) + log.debug("Logged out remote JCR session " + session); + } + } + + public void init() { + if (log.isDebugEnabled()) + log.debug("Init session provider for web session " + webSessionId); + } + + public void destroy() { + if (log.isDebugEnabled()) + log.debug("Destroy session provider for web session " + + webSessionId); + + if (sessions != null) + for (String workspace : sessions.keySet()) { + Session session = sessions.get(workspace); + JcrUtils.logoutQuietly(session); + } + } + + /** + * If set to true a new session will be created each time (the default), + * otherwise a single session is cached by workspace and the object should + * be of scope session (not supported) + */ + public void setOpenSessionInView(Boolean openSessionInView) { + this.openSessionInView = openSessionInView; + } + + public void setSecurityWorkspace(String securityWorkspace) { + this.defaultWorkspace = securityWorkspace; + } + +} diff --git a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/SimpleWebdavHandlerMapping.java b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/SimpleWebdavHandlerMapping.java new file mode 100644 index 000000000..bd8d8041a --- /dev/null +++ b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/SimpleWebdavHandlerMapping.java @@ -0,0 +1,49 @@ +/* + * 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.jackrabbit.remote; + +import java.util.Properties; + +import javax.jcr.Repository; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; + +/** Handler mapping for WebDav */ +public class SimpleWebdavHandlerMapping extends + AbstractJackrabbitHandlerMapping { + private String configuration; + + protected HttpServlet createServlet(Repository repository, String pathPrefix) + throws ServletException { + + SimpleWebdavServlet servlet = new SimpleWebdavServlet(repository, + getSessionProvider()); + Properties initParameters = new Properties(); + initParameters.setProperty( + SimpleWebdavServlet.INIT_PARAM_RESOURCE_CONFIG, configuration); + initParameters + .setProperty( + SimpleWebdavServlet.INIT_PARAM_RESOURCE_PATH_PREFIX, + pathPrefix); + servlet.init(new DelegatingServletConfig(pathPrefix.replace('/', '_'), + initParameters)); + return servlet; + } + + public void setConfiguration(String configuration) { + this.configuration = configuration; + } +} diff --git a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/SimpleWebdavServlet.java b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/SimpleWebdavServlet.java new file mode 100644 index 000000000..f1ca0a9f2 --- /dev/null +++ b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/remote/SimpleWebdavServlet.java @@ -0,0 +1,60 @@ +/* + * 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.jackrabbit.remote; + +import java.io.IOException; + +import javax.jcr.Repository; +import javax.servlet.ServletException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jackrabbit.server.SessionProvider; +import org.apache.jackrabbit.webdav.DavException; +import org.apache.jackrabbit.webdav.DavResource; +import org.apache.jackrabbit.webdav.WebdavRequest; +import org.apache.jackrabbit.webdav.WebdavResponse; + +/** WebDav servlet whose repository is injected */ +public class SimpleWebdavServlet extends + org.apache.jackrabbit.webdav.simple.SimpleWebdavServlet { + private static final long serialVersionUID = -369787931175177080L; + + private final static Log log = LogFactory.getLog(SimpleWebdavServlet.class); + + private final Repository repository; + + public SimpleWebdavServlet(Repository repository, + SessionProvider sessionProvider) { + this.repository = repository; + setSessionProvider(sessionProvider); + } + + public Repository getRepository() { + return repository; + } + + @Override + protected boolean execute(WebdavRequest request, WebdavResponse response, + int method, DavResource resource) throws ServletException, + IOException, DavException { + if (log.isTraceEnabled()) + log.trace(request.getMethod() + "\t" + request.getPathInfo()); + boolean res = super.execute(request, response, method, resource); + return res; + } + +} diff --git a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/repository-fs.xml b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/repository-fs.xml new file mode 100644 index 000000000..609fc8b33 --- /dev/null +++ b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/repository-fs.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/repository-h2.xml b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/repository-h2.xml new file mode 100644 index 000000000..b6a92528a --- /dev/null +++ b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/repository-h2.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/repository-memory.xml b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/repository-memory.xml new file mode 100644 index 000000000..e552c33a7 --- /dev/null +++ b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/repository-memory.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.server.rap.webapp/bnd.bnd b/org.argeo.server.rap.webapp/bnd.bnd new file mode 100644 index 000000000..954f2d349 --- /dev/null +++ b/org.argeo.server.rap.webapp/bnd.bnd @@ -0,0 +1,24 @@ +Web-ContextPath: ui +Import-Package: org.springframework.beans.factory.config,\ +org.eclipse.equinox.http.servlet,\ +org.springframework.osgi.web.context.support,\ +org.springframework.security,\ +org.springframework.security.context,\ +org.springframework.security.intercept.web,\ +org.springframework.security.providers.anonymous,\ +org.springframework.security.ui,\ +org.springframework.security.ui.basicauth,\ +org.springframework.security.ui.logout,\ +org.springframework.security.ui.rememberme,\ +org.springframework.security.ui.webapp,\ +org.springframework.security.ui.preauth.x509,\ +org.springframework.security.userdetails,\ +org.springframework.security.util,\ +org.springframework.security.vote,\ +org.springframework.security.wrapper,\ +org.springframework.web.context,\ +org.springframework.web.filter,\ +org.springframework.web.servlet,\ +org.springframework.web.servlet.handler,\ +org.springframework.web.servlet.mvc,\ +* \ No newline at end of file diff --git a/org.argeo.server.rap.webapp/pom.xml b/org.argeo.server.rap.webapp/pom.xml index abf636f5e..8c61d3f0b 100644 --- a/org.argeo.server.rap.webapp/pom.xml +++ b/org.argeo.server.rap.webapp/pom.xml @@ -9,46 +9,4 @@ org.argeo.server.rap.webapp Commons Server RAP Webapp Integrates into OSGi HTTP registry - - - - org.apache.felix - maven-bundle-plugin - - - ui - - *, - - org.springframework.beans.factory.config, - - org.eclipse.equinox.http.servlet, - org.springframework.osgi.web.context.support, - org.springframework.security, - org.springframework.security.context, - org.springframework.security.intercept.web, - org.springframework.security.providers.anonymous, - org.springframework.security.ui, - org.springframework.security.ui.basicauth, - org.springframework.security.ui.logout, - org.springframework.security.ui.rememberme, - org.springframework.security.ui.webapp, - org.springframework.security.ui.preauth.x509, - org.springframework.security.userdetails, - org.springframework.security.util, - org.springframework.security.vote, - org.springframework.security.wrapper, - org.springframework.web.context, - org.springframework.web.filter, - org.springframework.web.servlet, - org.springframework.web.servlet.handler, - org.springframework.web.servlet.mvc, - - - - - - - - \ No newline at end of file