/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.apache.jackrabbit.test.api; import javax.jcr.Node; import javax.jcr.Repository; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.lock.LockException; import javax.jcr.nodetype.ConstraintViolationException; import javax.jcr.nodetype.NoSuchNodeTypeException; import javax.jcr.nodetype.NodeType; import javax.jcr.nodetype.NodeTypeIterator; import javax.jcr.nodetype.NodeTypeManager; import javax.jcr.version.VersionException; import org.apache.jackrabbit.test.AbstractJCRTest; import org.apache.jackrabbit.test.NotExecutableException; /** * <code>SetPrimaryType</code>... */ public class NodeSetPrimaryTypeTest extends AbstractJCRTest { // TODO: test if node definition is properly reset // TODO: test if child items are properly reset upon changing definition // TODO: test if conflicts are properly detected /** * Tests a successful call to <code>Node.setPrimaryType(String)</code> */ public void testSetPrimaryType() throws RepositoryException { Session session = testRootNode.getSession(); Session otherSession = null; String nonExistingMixinName = NodeMixinUtil.getNonExistingMixinName(session); Node node = testRootNode.addNode(nodeName1, testNodeType); superuser.save(); // TODO improve. retrieve settable node type name from config. NodeTypeManager manager = session.getWorkspace().getNodeTypeManager(); NodeTypeIterator nts = manager.getPrimaryNodeTypes(); while (nts.hasNext()) { NodeType nt = nts.nextNodeType(); String ntName = nt.getName(); if (!nt.isAbstract() && !ntFrozenNode.equals(ntName)) { try { node.setPrimaryType(ntName); // property value must be adjusted immediately assertEquals("The value of the jcr:primaryType property must change upon setPrimaryType.", ntName, node.getProperty(jcrPrimaryType).getString()); // save changes -> reflected upon Node.getPrimaryNodeType and Property.getValue superuser.save(); assertEquals("Node.getPrimaryNodeType must reflect the changes made.", ntName, node.getPrimaryNodeType().getName()); assertEquals("The value of the jcr:primaryType property must change upon setPrimaryType.", ntName, node.getProperty(jcrPrimaryType).getString()); otherSession = getHelper().getReadOnlySession(); assertEquals("Node.getPrimaryNodeType must reflect the changes made.", ntName, otherSession.getNode(node.getPath()).getPrimaryNodeType().getName()); assertEquals("The value of the jcr:primaryType property must change upon setPrimaryType.", ntName, otherSession.getNode(node.getPath()).getProperty(jcrPrimaryType).getString()); // was successful return; } catch (ConstraintViolationException e) { // may happen as long as arbitrary primary types are used for testing -> ignore } finally { if (otherSession != null) { otherSession.logout(); } // revert any unsaved changes. session.refresh(false); } } } } /** * Passing the current primary type to {@link Node#setPrimaryType(String)} * must always succeed. * * @throws RepositoryException */ public void testSetCurrentType() throws RepositoryException { Session session = testRootNode.getSession(); Node node = testRootNode.addNode(nodeName1, testNodeType); superuser.save(); node.setPrimaryType(testNodeType); superuser.save(); } /** * Passing the current primary type to {@link Node#setPrimaryType(String)} * to a new node must always succeed. * * @throws RepositoryException */ public void testSetCurrentTypeOnNew() throws RepositoryException { Session session = testRootNode.getSession(); Node node = testRootNode.addNode(nodeName1, testNodeType); node.setPrimaryType(testNodeType); superuser.save(); } /** * Tests if <code>Node.setPrimaryType(String)</code> throws a * <code>NoSuchNodeTypeException</code> if the * name of an existing node type is passed. */ public void testAddNonExisting() throws RepositoryException { Session session = testRootNode.getSession(); NodeTypeManager manager = session.getWorkspace().getNodeTypeManager(); String nonExistingMixinName = "abc"; while (manager.hasNodeType(nonExistingMixinName)) { nonExistingMixinName += "_"; } Node node = testRootNode.addNode(nodeName1, testNodeType); try { node.setPrimaryType(nonExistingMixinName); // ev. only detected upon save superuser.save(); fail("Node.setPrimaryType(String) must throw a NoSuchNodeTypeException if no nodetype exists with the given name."); } catch (NoSuchNodeTypeException e) { // success } } /** * Tests if <code>Node.setPrimaryType(String)</code> throws a * <code>ConstraintViolationException</code> if the * name of a mixin type is passed */ public void testSetMixinAsPrimaryType() throws RepositoryException { Session session = testRootNode.getSession(); NodeTypeManager manager = session.getWorkspace().getNodeTypeManager(); NodeTypeIterator nts = manager.getMixinNodeTypes(); while (nts.hasNext()) { try { Node node = testRootNode.addNode(nodeName1, testNodeType); node.setPrimaryType(nts.nextNodeType().getName()); fail("Node.setPrimaryType(String) must throw ConstraintViolationException if the specified node type name refers to a mixin."); } catch (ConstraintViolationException e) { // success } finally { // reset the changes. session.refresh(false); } } } /** * Tests if <code>Node.setPrimaryType(String)</code> throws a * <code>ConstraintViolationException</code> if the * name of a mixin type is passed */ public void testSetAbstractAsPrimaryType() throws RepositoryException { Session session = testRootNode.getSession(); NodeTypeManager manager = session.getWorkspace().getNodeTypeManager(); NodeTypeIterator nts = manager.getPrimaryNodeTypes(); while (nts.hasNext()) { NodeType nt = nts.nextNodeType(); if (nt.isAbstract()) { try { Node node = testRootNode.addNode(nodeName1, testNodeType); node.setPrimaryType(nt.getName()); fail("Node.setPrimaryType(String) must throw ConstraintViolationException if the specified node type name refers to an abstract node type."); } catch (ConstraintViolationException e) { // success } finally { // reset the changes. session.refresh(false); } } } } /** * Tests if <code>Node.setPrimaryType(String)</code> throws a * <code>LockException</code> if <code>Node</code> is locked. */ public void testLocked() throws NotExecutableException, RepositoryException { Session session = testRootNode.getSession(); if (!isSupported(Repository.OPTION_LOCKING_SUPPORTED)) { throw new NotExecutableException("Locking is not supported."); } // create a node that is lockable Node node = testRootNode.addNode(nodeName1, testNodeType); // or try to make it lockable if it is not ensureMixinType(node, mixLockable); testRootNode.getSession().save(); String primaryTypeName = getPrimaryTypeName(session, node); if (primaryTypeName == null) { throw new NotExecutableException("No testable node type found"); } // remove first slash of path to get rel path to root String pathRelToRoot = node.getPath().substring(1); // access node through another session to lock it Session session2 = getHelper().getSuperuserSession(); try { Node node2 = session2.getRootNode().getNode(pathRelToRoot); node2.lock(true, true); try { // implementation specific: either throw LockException upon // addMixin or upon save. node.setPrimaryType(primaryTypeName); node.save(); fail("Node.setPrimaryType(String) must throw a LockException if the node is locked."); } catch (LockException e) { // success } // unlock to remove node at tearDown() node2.unlock(); } finally { session2.logout(); } } /** * Tests if <code>Node.setPrimaryType(String)</code> throws a * <code>VersionException</code> if <code>Node</code> is checked-in. */ public void testCheckedIn() throws NotExecutableException, RepositoryException { Session session = testRootNode.getSession(); if (!isSupported(Repository.OPTION_VERSIONING_SUPPORTED)) { throw new NotExecutableException("Versioning is not supported."); } // create a node that is versionable Node node = testRootNode.addNode(nodeName1, testNodeType); // or try to make it versionable if it is not ensureMixinType(node, mixVersionable); superuser.save(); String primaryTypeName = getPrimaryTypeName(session, node); if (primaryTypeName == null) { throw new NotExecutableException("No testable node type found"); } node.checkin(); try { node.setPrimaryType(primaryTypeName); fail("Node.setPrimaryType(String) must throw a VersionException if the node is checked-in."); } catch (VersionException e) { // success } } private static String getPrimaryTypeName(Session session, Node node) throws RepositoryException { NodeTypeManager manager = session.getWorkspace().getNodeTypeManager(); NodeTypeIterator nts = manager.getPrimaryNodeTypes(); while (nts.hasNext()) { String name = nts.nextNodeType().getName(); if (!name.equals(node.getPrimaryNodeType().getName())) { return name; } } return null; } }