/** * 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.brixcms.plugin.hierarchical; import java.util.Collection; import java.util.Collections; import java.util.List; import org.apache.wicket.Component; import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.model.IModel; import org.brixcms.Brix; import org.brixcms.BrixNodeModel; import org.brixcms.Plugin; import org.brixcms.auth.Action; import org.brixcms.auth.Action.Context; import org.brixcms.jcr.JcrNodeWrapperFactory; import org.brixcms.jcr.RepositoryInitializer; import org.brixcms.jcr.api.JcrNode; import org.brixcms.jcr.api.JcrSession; import org.brixcms.jcr.wrapper.BrixNode; import org.brixcms.plugin.hierarchical.admin.HierarchicalNodeManagerPanel; import org.brixcms.plugin.hierarchical.admin.NodeEditorPlugin; import org.brixcms.plugin.hierarchical.admin.NodeTreeParentComponent; import org.brixcms.plugin.hierarchical.auth.AccessHierarchicalNodePluginAction; import org.brixcms.plugin.hierarchical.folder.ManageFolderNodeTabFactory; import org.brixcms.plugin.hierarchical.nodes.SimpleFolderNode; import org.brixcms.plugin.hierarchical.nodes.TitledNode; import org.brixcms.plugin.site.ManageNodeTabFactory; import org.brixcms.plugin.site.SitePlugin; import org.brixcms.plugin.site.auth.SiteNodeAction; import org.brixcms.plugin.site.auth.SiteNodeAction.Type; import org.brixcms.registry.ExtensionPoint; import org.brixcms.registry.ExtensionPointRegistry; import org.brixcms.web.tab.AbstractWorkspaceTab; import org.brixcms.web.tab.IBrixTab; import org.brixcms.workspace.Workspace; /** * The HierarchicalNodePlugin was created as an abstract parent plugin to make * it easy to create new plugins that focus on editing hierarchical nodes. It is * largely based off of the work of the {@link SitePlugin}. The * {@link SitePlugin} had many great features that were desired in other * plugins, but it was not built for reuse in other plugins. Therefore, this was * created, and hopefully at some point the {@link SitePlugin} can be refactored * to use this as a parent. * * You will notice that use of this plugin requires certain dependencies on * classes belonging to the {@link SitePlugin}. I tried reusing whatever classes * could easily be reused. Unfortunately, many of them had to be rewritten * because of hard-coded dependencies on the {@link SitePlugin} class itself. * So, there is some reuse of interfaces, mainly. * * @author Jeremy Thomerson */ @SuppressWarnings("deprecation") public abstract class HierarchicalNodePlugin implements Plugin { public static final String NAMESPACE = "brixhierarchicalnode"; public static final String NS_PREFIX = NAMESPACE + ":"; private final Brix brix; public HierarchicalNodePlugin(Brix brix) { this.brix = brix; } protected void initializeExtensionPoints(Brix brix) { ExtensionPointRegistry registry = brix.getConfig().getRegistry(); registry.register(RepositoryInitializer.POINT, new HierarchicalRepoInitializer()); registry.register(JcrNodeWrapperFactory.POINT, TitledNode.FACTORY); registry.register(getManageNodeTabFactoryExtensionPoint(), new ManageFolderNodeTabFactory(getPluginLocator())); } protected abstract IModel<String> getTabName(); protected abstract String getRootNodeName(); protected abstract HierarchicalPluginLocator getPluginLocator(); protected abstract ExtensionPoint<? extends NodeEditorPlugin> getNodeEditorPluginExtensionPoint(); protected abstract ExtensionPoint<ManageNodeTabFactory> getManageNodeTabFactoryExtensionPoint(); protected int getTabPriority() { return 0; } public BrixNode getRootNode(String workspaceID) { JcrSession workspaceSession = getBrix().getCurrentSession(workspaceID); return (BrixNode) workspaceSession.getItem(getRootNodePath()); } public NodeEditorPlugin getNodeEditorPluginForType(String nodeType) { for (NodeEditorPlugin plugin : getNodeEditorPlugins()) { if (plugin.getNodeType().equals(nodeType)) { return plugin; } } return null; } public Collection<? extends NodeEditorPlugin> getNodeEditorPlugins() { return brix.getConfig().getRegistry().lookupCollection(getNodeEditorPluginExtensionPoint()); } public Collection<? extends ManageNodeTabFactory> getManageNodeTabFactories() { return brix.getConfig().getRegistry().lookupCollection(getManageNodeTabFactoryExtensionPoint()); } public String getRootNodePath() { return brix.getRootPath() + "/" + getRootNodeName(); } public Brix getBrix() { return brix; } public void refreshNavigationTree(Component component) { NodeTreeParentComponent panel = findContainer(component); if (panel != null) { panel.updateTree(); } else { throw new IllegalStateException("Can't call refreshNaviagtionTree with component outside of the hierarchy."); } } public void selectNode(Component component, BrixNode node, boolean refreshTree) { NodeTreeParentComponent panel = findContainer(component); if (panel != null) { panel.selectNode(node); panel.updateTree(); } else { throw new IllegalStateException("Can't call selectNode with component outside of the hierarchy."); } } private NodeTreeParentComponent findContainer(Component component) { if (component instanceof NodeTreeParentComponent) { return (NodeTreeParentComponent) component; } else { return component.findParent(NodeTreeParentComponent.class); } } public boolean canViewNode(BrixNode node, Context context) { Action action = new SiteNodeAction(context, Type.NODE_VIEW, node); return brix.getAuthorizationStrategy().isActionAuthorized(action); } public boolean canViewNodeChildren(BrixNode node, Context context) { Action action = new SiteNodeAction(context, Type.NODE_VIEW_CHILDREN, node); return brix.getAuthorizationStrategy().isActionAuthorized(action); } public boolean canEditNode(BrixNode node, Context context) { if (!isNodeEditable(node)) { return false; } Action action = new SiteNodeAction(context, Type.NODE_EDIT, node); return brix.getAuthorizationStrategy().isActionAuthorized(action); } public boolean canDeleteNode(BrixNode node, Context context) { if (!isNodeEditable(node)) { return false; } Action action = new SiteNodeAction(context, Type.NODE_DELETE, node); return brix.getAuthorizationStrategy().isActionAuthorized(action); } public boolean canRenameNode(BrixNode node, Context context) { if (!isNodeEditable(node)) { return false; } Action action = new SiteNodeAction(context, Type.NODE_DELETE, node); return brix.getAuthorizationStrategy().isActionAuthorized(action); } public boolean canAddNodeChild(BrixNode node, Context context) { if (!isNodeEditable(node)) { return false; } Action action = new SiteNodeAction(context, Type.NODE_ADD_CHILD, node); return brix.getAuthorizationStrategy().isActionAuthorized(action); } private boolean isNodeEditable(BrixNode node) { if (node.isNodeType("mix:versionable") && !node.isCheckedOut()) { return false; } if (node.isLocked() && node.getLock().getLockToken() == null) { return false; } return true; } /* Implemented (Plugin) interface methods */ public List<Workspace> getWorkspaces(Workspace currentWorkspace, boolean isFrontend) { return null; } public void initWorkspace(Workspace workspace, JcrSession workspaceSession) { JcrNode root = (JcrNode) workspaceSession.getItem(brix.getRootPath()); JcrNode pluginRoot = null; if (root.hasNode(getRootNodeName())) { pluginRoot = root.getNode(getRootNodeName()); } else { pluginRoot = root.addNode(getRootNodeName(), SimpleFolderNode.JCR_PRIMARY_TYPE); } if (pluginRoot != null) { if (!pluginRoot.isNodeType(BrixNode.JCR_TYPE_BRIX_NODE)) { pluginRoot.addMixin(BrixNode.JCR_TYPE_BRIX_NODE); } } } public boolean isPluginWorkspace(Workspace workspace) { return false; } public List<IBrixTab> newTabs(IModel<Workspace> workspaceModel) { IBrixTab tab = new NodeTreeEditorTab(getTabName(), workspaceModel, getPluginLocator(), getTabPriority()); return Collections.singletonList(tab); } /* end of implemented (Plugin) interface methods */ static class NodeTreeEditorTab extends AbstractWorkspaceTab { private final HierarchicalPluginLocator pluginLocator; public NodeTreeEditorTab(IModel<String> title, IModel<Workspace> workspaceModel, HierarchicalPluginLocator pluginLocator, int priority) { super(title, workspaceModel, priority); this.pluginLocator = pluginLocator; } @Override public Panel newPanel(String panelId, IModel<Workspace> workspaceModel) { BrixNode rootNode = pluginLocator.getPlugin().getRootNode(workspaceModel.getObject().getId()); return new HierarchicalNodeManagerPanel(panelId, workspaceModel, new BrixNodeModel(rootNode), pluginLocator); } @Override public boolean isVisible() { final Action action = new AccessHierarchicalNodePluginAction(pluginLocator, getWorkspaceModel().getObject()); return Brix.get().getAuthorizationStrategy().isActionAuthorized(action); } } }