/** * 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.workspace; import javax.jcr.Node; import javax.jcr.NodeIterator; import javax.jcr.Property; import javax.jcr.PropertyIterator; import javax.jcr.RepositoryException; import javax.jcr.Session; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.UUID; /** * Simple workspace manager. This class will not work properly in clustered JCR environment. * * @author Matej Knopp */ public abstract class AbstractSimpleWorkspaceManager extends AbstractWorkspaceManager { private static final Collection<String> NODES_TO_LEAVE_WHEN_CLEANING = Arrays .asList(NODE_NAME, "jcr:system", "rep:policy"); private Set<String> availableWorkspaceNames; private List<String> deletedWorkspaceNames; public synchronized List<Workspace> getWorkspaces() { List<Workspace> result = new ArrayList<Workspace>(availableWorkspaceNames.size()); for (String s : availableWorkspaceNames) { result.add(new WorkspaceImpl(s)); } return result; } public Workspace createWorkspace() { Session session = null; try { synchronized (this) { if (deletedWorkspaceNames.size() > 0) { String id = deletedWorkspaceNames.get(deletedWorkspaceNames.size() - 1); deletedWorkspaceNames.remove(id); availableWorkspaceNames.add(id); session = createSession(id); Node node = (Node) session.getItem(NODE_PATH); node.setProperty(DELETED_PROPERTY, (String) null); node.getSession().save(); closeSession(session, true); session = null; return new WorkspaceImpl(id); } } String id = getWorkspaceId(UUID.randomUUID()); createWorkspace(id); synchronized (this) { session = createSession(id); Node node = session.getRootNode().addNode(NODE_NAME, "nt:unstructured"); node.addMixin("mix:lockable"); node.addNode(PROPERTIES_NODE, "nt:unstructured"); closeSession(session, true); session = null; availableWorkspaceNames.add(id); } return new WorkspaceImpl(id); } catch (RepositoryException e) { closeSession(session, false); throw new JcrException(e); } } public synchronized boolean workspaceExists(String workspaceId) { return availableWorkspaceNames.contains(workspaceId); } abstract protected void createWorkspace(String workspaceName); protected void delete(String workspaceId) throws RepositoryException { synchronized (this) { if (!availableWorkspaceNames.contains(workspaceId)) { throw new IllegalStateException("Workspace " + workspaceId + " either does not exist or was already deleted."); } } Session session = createSession(workspaceId); boolean saveSession = true; try { cleanWorkspace(session); session.save(); Node node = (Node) session.getItem(NODE_PATH); if (node.hasNode(PROPERTIES_NODE)) { node.getNode(PROPERTIES_NODE).remove(); } node.setProperty(DELETED_PROPERTY, true); node.getSession().save(); synchronized (this) { availableWorkspaceNames.remove(workspaceId); deletedWorkspaceNames.add(workspaceId); removeCachedWorkspaceAttributes(workspaceId); } } catch (RepositoryException e) { saveSession = false; throw e; } finally { closeSession(session, saveSession); } } private void cleanWorkspace(Session session) throws RepositoryException { Node root = session.getRootNode(); NodeIterator iterator = root.getNodes(); while (iterator.hasNext()) { Node node = iterator.nextNode(); if (!NODES_TO_LEAVE_WHEN_CLEANING.contains(node.getName())) { node.remove(); } } } @Override protected synchronized String getAttribute(String workspaceId, String key) { if (!availableWorkspaceNames.contains(workspaceId)) { throw new IllegalStateException("Trying to get attribute of workspace " + workspaceId + " that doesn't exist or was removed."); } return getCachedAttribute(workspaceId, key); } @Override protected Iterator<String> getAttributeKeys(String workspaceId) { if (!availableWorkspaceNames.contains(workspaceId)) { throw new IllegalStateException("Trying to get attribute keys of workspace " + workspaceId + " that doesn't exist or was removed."); } return getCachedAttributeKeys(workspaceId); } public AbstractSimpleWorkspaceManager initialize() { super.initialize(); Session session = null; try { availableWorkspaceNames = new HashSet<String>(); deletedWorkspaceNames = new ArrayList<String>(); List<String> accessibleWorkspaces = getAccessibleWorkspaceNames(); for (String workspace : accessibleWorkspaces) { if (isBrixWorkspace(workspace)) { session = createSession(workspace); if (session.itemExists(NODE_PATH)) { Node node = (Node) session.getItem(NODE_PATH); if (node.hasProperty(DELETED_PROPERTY) && node.getProperty(DELETED_PROPERTY).getBoolean() == true) { deletedWorkspaceNames.add(workspace); } else { availableWorkspaceNames.add(workspace); if (node.hasNode(PROPERTIES_NODE)) { Node properties = node.getNode(PROPERTIES_NODE); PropertyIterator iterator = properties.getProperties(); while (iterator.hasNext()) { Property property = iterator.nextProperty(); setCachedAttribute(workspace, property.getName(), property .getValue().getString()); } } } } closeSession(session, true); session = null; } } return this; } catch (RepositoryException e) { closeSession(session, false); throw new JcrException(e); } } abstract protected List<String> getAccessibleWorkspaceNames(); abstract protected Session createSession(String workspaceName); /** * Closes a session * * @param session session to close * @param saveSession whether or not session.save() should be called before the session is closed */ protected final void closeSession(Session session, boolean saveSession) { if (session != null && session.isLive()) { try { if (saveSession) { try { session.save(); } catch (RepositoryException e) { throw new JcrException(e); } } } finally { session.logout(); } } } protected synchronized void setAttribute(String workspaceId, String key, String value) { Session session = null; boolean saveSession = true; if (!availableWorkspaceNames.contains(workspaceId)) { throw new IllegalStateException("Can not set attribute '" + key + "' on deleted or non-existing workspace '" + workspaceId + "'."); } setCachedAttribute(workspaceId, key, value); try { session = createSession(workspaceId); Node node = (Node) session.getItem(NODE_PATH); Node properties; if (!node.hasNode(PROPERTIES_NODE)) { properties = node.addNode(PROPERTIES_NODE, "nt:unstructured"); } else { properties = node.getNode(PROPERTIES_NODE); } properties.setProperty(key, value); node.getSession().save(); } catch (RepositoryException e) { saveSession = false; throw new JcrException(e); } finally { closeSession(session, saveSession); } } }