@Test
  public void shouldReturnFalseFromIsSameIfTheRepositoryInstanceIsDifferent() throws Exception {
    // Set up the store ...
    InMemoryRepositorySource source2 = new InMemoryRepositorySource();
    source2.setName("store");
    Graph store2 = Graph.create(source2, context);
    store2
        .importXmlFrom(AbstractJcrTest.class.getClassLoader().getResourceAsStream("cars.xml"))
        .into("/");
    JcrSession jcrSession2 = mock(JcrSession.class);
    when(jcrSession2.nodeTypeManager()).thenReturn(nodeTypes);
    when(jcrSession2.isLive()).thenReturn(true);
    SessionCache cache2 =
        new SessionCache(jcrSession2, store2.getCurrentWorkspaceName(), context, nodeTypes, store2);

    Workspace workspace2 = mock(Workspace.class);
    Repository repository2 = mock(JcrRepository.class);

    when(jcrSession2.getWorkspace()).thenReturn(workspace2);
    when(jcrSession2.getRepository()).thenReturn(repository2);
    when(workspace2.getName()).thenReturn("workspace1");

    // Use the same id and location ...
    javax.jcr.Node prius2 = cache2.findJcrNode(null, path("/Cars/Hybrid/Toyota Prius"));
    assertThat(prius2.isSame(prius), is(false));

    // Check the properties ...
    javax.jcr.Property model = prius.getProperty("vehix:model");
    javax.jcr.Property model2 = prius2.getProperty("vehix:model");
    assertThat(model.isSame(model2), is(false));
  }
  @Test
  @FixFor("MODE-2109 ")
  public void shouldOnlyAllowCloningInSomeCases() throws Exception {
    session.getWorkspace().createWorkspace("other");

    try {
      session.getRootNode().addNode("col1", "test:smallCollection");
      Node regular = session.getRootNode().addNode("regular");
      regular.addNode("regular1");
      session.save();

      // cloning a large collection is not allowed
      JcrWorkspace workspace = session.getWorkspace();
      try {
        workspace.clone(workspace.getName(), "/col1", "/regular", false);
        fail("Should not allow cloning");
      } catch (ConstraintViolationException e) {
        // expected
      }

      // clone a regular node into a large collection
      JcrSession otherSession = repository.login("other");
      Node col2 = otherSession.getRootNode().addNode("col2", "test:smallCollection");
      col2.addNode("child1");
      otherSession.save();

      otherSession.getWorkspace().clone(workspace.getName(), "/regular", "/col2/regular", false);
      NodeIterator nodes = otherSession.getNode("/col2").getNodes();
      assertEquals(2, nodes.getSize());
    } finally {
      session.getWorkspace().deleteWorkspace("other");
    }
  }
  private void fireSequencingEvent(
      AbstractJcrNode sequencedNode,
      List<AbstractJcrNode> outputNodes,
      JcrSession outputSession,
      String sequencerName)
      throws RepositoryException {

    RecordingChanges sequencingChanges =
        new RecordingChanges(
            outputSession.context().getProcessId(),
            outputSession.getRepository().repositoryKey(),
            outputSession.workspaceName());
    for (AbstractJcrNode outputNode : outputNodes) {
      sequencingChanges.nodeSequenced(
          sequencedNode.key(),
          sequencedNode.path(),
          outputNode.key(),
          outputNode.path(),
          work.getOutputPath(),
          work.getUserId(),
          work.getSelectedPath(),
          sequencerName);
    }

    repository.changeBus().notify(sequencingChanges);
  }
  @Test
  public void shouldBackupRepositoryWithMultipleWorkspaces() throws Exception {
    loadContent();
    Problems problems =
        session().getWorkspace().getRepositoryManager().backupRepository(backupDirectory);
    assertNoProblems(problems);

    // Make some changes that will not be in the backup ...
    session().getRootNode().addNode("node-not-in-backup");
    session().save();

    assertContentInWorkspace(repository(), "default", "/node-not-in-backup");
    assertContentInWorkspace(repository(), "ws2");
    assertContentInWorkspace(repository(), "ws3");

    // Start up a new repository
    ((LocalEnvironment) environment).setShared(true);
    RepositoryConfiguration config =
        RepositoryConfiguration.read("config/restore-repo-config.json").with(environment);
    JcrRepository newRepository = new JcrRepository(config);
    try {
      newRepository.start();

      // And restore it from the contents ...
      JcrSession newSession = newRepository.login();
      try {
        Problems restoreProblems =
            newSession.getWorkspace().getRepositoryManager().restoreRepository(backupDirectory);
        assertNoProblems(restoreProblems);
      } finally {
        newSession.logout();
      }

      // Check that the node that was added *after* the backup is not there ...
      assertContentNotInWorkspace(newRepository, "default", "/node-not-in-backup");

      // Before we assert the content, create a backup of it (for comparison purposes when
      // debugging) ...
      newSession = newRepository.login();
      try {
        Problems backupProblems =
            newSession.getWorkspace().getRepositoryManager().backupRepository(backupDirectory2);
        assertNoProblems(backupProblems);
      } finally {
        newSession.logout();
      }

      assertWorkspaces(newRepository, "default", "ws2", "ws3");

      assertContentInWorkspace(newRepository, null);
      assertContentInWorkspace(newRepository, "ws2");
      assertContentInWorkspace(newRepository, "ws3");
      queryContentInWorkspace(newRepository, null);
    } finally {
      newRepository.shutdown().get(10, TimeUnit.SECONDS);
    }
  }
  @Override
  public void createProjection(
      String absNodePath, String sourceName, String externalPath, String alias)
      throws RepositoryException {
    NodeKey key = session.getNode(absNodePath).key();

    WritableSessionCache internalSession = (WritableSessionCache) session.spawnSessionCache(false);
    internalSession.createProjection(key, sourceName, externalPath, alias);
    internalSession.save();
  }
 private void queryContentInWorkspace(JcrRepository newRepository, String workspaceName)
     throws RepositoryException {
   JcrSession session = newRepository.login();
   try {
     String statement = "SELECT [car:model], [car:year], [car:msrp] FROM [car:Car] AS car";
     Query query = session.getWorkspace().getQueryManager().createQuery(statement, Query.JCR_SQL2);
     QueryResult results = query.execute();
     assertThat(results.getRows().getSize(), is(13L));
   } finally {
     session.logout();
   }
 }
  /**
   * Registers a new node type or updates an existing node type using the specified definition and
   * returns the resulting {@link NodeType} object.
   *
   * <p>Typically, the object passed to this method will be a {@link NodeTypeTemplate} (a subclass
   * of {@link NodeTypeDefinition}) acquired from {@link
   * JcrNodeTypeManager#createNodeTypeTemplate()} and then filled-in with definition information.
   *
   * @param template the new node type to register
   * @param allowUpdate this flag is not used
   * @return the {@code newly created node type}
   * @throws InvalidNodeTypeDefinitionException if the {@code NodeTypeDefinition} is invalid
   * @throws NodeTypeExistsException if {@code allowUpdate} is false and the {@code
   *     NodeTypeDefinition} specifies a node type name that already exists
   * @throws UnsupportedRepositoryOperationException if {@code allowUpdate} is true; ModeShape does
   *     not allow updating node types at this time.
   * @throws AccessDeniedException if the current session does not have the {@link
   *     ModeShapePermissions#REGISTER_TYPE register type permission}.
   * @throws RepositoryException if another error occurs
   */
  @Override
  public NodeType registerNodeType(NodeTypeDefinition template, boolean allowUpdate)
      throws InvalidNodeTypeDefinitionException, NodeTypeExistsException,
          UnsupportedRepositoryOperationException, AccessDeniedException, RepositoryException {

    session.checkLive();
    try {
      session.checkPermission((Path) null, ModeShapePermissions.REGISTER_TYPE);
    } catch (AccessControlException ace) {
      throw new AccessDeniedException(ace);
    }
    return this.repositoryTypeManager.registerNodeType(template, !allowUpdate);
  }
  /**
   * Registers or updates the specified Collection of {@code NodeTypeDefinition} objects. This
   * method is used to register or update a set of node types with mutual dependencies. Returns an
   * iterator over the resulting {@code NodeType} objects.
   *
   * <p>The effect of the method is "all or nothing"; if an error occurs, no node types are
   * registered or updated.
   *
   * @param templates the new node types to register
   * @param allowUpdates this flag is not used
   * @return the {@code newly created node types}
   * @throws InvalidNodeTypeDefinitionException if a {@code NodeTypeDefinition} within the
   *     collection is invalid
   * @throws NodeTypeExistsException if {@code allowUpdate} is false and a {@code
   *     NodeTypeDefinition} within the collection specifies a node type name that already exists
   * @throws UnsupportedRepositoryOperationException if {@code allowUpdate} is true; ModeShape does
   *     not allow updating node types at this time.
   * @throws AccessDeniedException if the current session does not have the {@link
   *     ModeShapePermissions#REGISTER_TYPE register type permission}.
   * @throws RepositoryException if another error occurs
   */
  public NodeTypeIterator registerNodeTypes(
      Collection<NodeTypeDefinition> templates, boolean allowUpdates)
      throws InvalidNodeTypeDefinitionException, NodeTypeExistsException,
          UnsupportedRepositoryOperationException, AccessDeniedException, RepositoryException {

    session.checkLive();
    try {
      session.checkPermission((Path) null, ModeShapePermissions.REGISTER_TYPE);
    } catch (AccessControlException ace) {
      throw new AccessDeniedException(ace);
    }
    return new JcrNodeTypeIterator(
        repositoryTypeManager.registerNodeTypes(templates, !allowUpdates, false, true));
  }
  @Override
  public void removeProjection(String projectionPath) throws RepositoryException {
    CheckArg.isNotNull(projectionPath, "projectionPath");

    Path path = session.pathFactory().create(projectionPath);
    if (path.isRoot()) {
      throw new IllegalArgumentException(JcrI18n.invalidProjectionPath.text(projectionPath));
    }

    NodeKey federatedNodeKey = session.getNode(path.getParent().getString()).key();
    NodeKey externalNodeKey = session.getNode(path.getString()).key();

    WritableSessionCache internalSession = (WritableSessionCache) session.spawnSessionCache(false);
    internalSession.removeProjection(federatedNodeKey, externalNodeKey);
    internalSession.save();
  }
  private void assertWorkspaces(JcrRepository newRepository, String... workspaceNames)
      throws RepositoryException {
    Set<String> expectedNames = new HashSet<String>();
    for (String expectedName : workspaceNames) {
      expectedNames.add(expectedName);
    }

    Set<String> actualNames = new HashSet<String>();
    JcrSession session = newRepository.login();
    try {
      for (String actualName : session.getWorkspace().getAccessibleWorkspaceNames()) {
        actualNames.add(actualName);
      }
    } finally {
      session.logout();
    }

    assertThat(actualNames, is(expectedNames));
  }
 private void fireSequencingFailureEvent(
     AbstractJcrNode sequencedNode, JcrSession inputSession, Throwable cause, String sequencerName)
     throws RepositoryException {
   assert sequencedNode != null;
   assert inputSession != null;
   RecordingChanges sequencingChanges =
       new RecordingChanges(
           inputSession.context().getProcessId(),
           inputSession.getRepository().repositoryKey(),
           inputSession.workspaceName());
   sequencingChanges.nodeSequencingFailure(
       sequencedNode.key(),
       sequencedNode.path(),
       work.getOutputPath(),
       work.getUserId(),
       work.getSelectedPath(),
       sequencerName,
       cause);
   repository.changeBus().notify(sequencingChanges);
 }
  private void assertContentNotInWorkspace(
      JcrRepository newRepository, String workspaceName, String... paths)
      throws RepositoryException {
    JcrSession session =
        workspaceName != null ? newRepository.login(workspaceName) : newRepository.login();

    try {
      session.getRootNode();
      for (String path : paths) {
        try {
          session.getNode(path);
          fail("Should not have found '" + path + "'");
        } catch (PathNotFoundException e) {
          // expected
        }
      }
    } finally {
      session.logout();
    }
  }
  @Test
  public void shouldBackupAndRestoreRepositoryWithMultipleWorkspaces() throws Exception {
    // Load the content and verify it's there ...
    loadContent();
    assertContentInWorkspace(repository(), "default");
    assertContentInWorkspace(repository(), "ws2");
    assertContentInWorkspace(repository(), "ws3");

    // Make the backup, and check that there are no problems ...
    Problems problems =
        session().getWorkspace().getRepositoryManager().backupRepository(backupDirectory);
    assertNoProblems(problems);

    // Make some changes that will not be in the backup ...
    session().getRootNode().addNode("node-not-in-backup");
    session().save();

    // Check the content again ...
    assertContentInWorkspace(repository(), "default", "/node-not-in-backup");
    assertContentInWorkspace(repository(), "ws2");
    assertContentInWorkspace(repository(), "ws3");

    // Restore the content from the backup into our current repository ...
    JcrSession newSession = repository().login();
    try {
      Problems restoreProblems =
          newSession.getWorkspace().getRepositoryManager().restoreRepository(backupDirectory);
      assertNoProblems(restoreProblems);
    } finally {
      newSession.logout();
    }

    assertWorkspaces(repository(), "default", "ws2", "ws3");

    // Check the content again ...
    assertContentInWorkspace(repository(), "default");
    assertContentInWorkspace(repository(), "ws2");
    assertContentInWorkspace(repository(), "ws3");
    assertContentNotInWorkspace(repository(), "default", "/node-not-in-backup");
    queryContentInWorkspace(repository(), null);
  }
  /**
   * Registers the node types from the given {@code JcrNodeTypeSource}. This method is used to
   * register or update a set of node types with mutual dependencies. Returns an iterator over the
   * resulting {@code NodeType} objects.
   *
   * <p>The effect of the method is "all or nothing"; if an error occurs, no node types are
   * registered or updated.
   *
   * @param nodeTypes the iterable object containing the new node types to register
   * @return the {@code newly created node types}
   * @throws InvalidNodeTypeDefinitionException if a {@code NodeTypeDefinition} within the
   *     collection is invalid
   * @throws NodeTypeExistsException if {@code allowUpdate} is false and a {@code
   *     NodeTypeDefinition} within the collection specifies a node type name that already exists
   * @throws UnsupportedRepositoryOperationException if {@code allowUpdate} is true; ModeShape does
   *     not allow updating node types at this time.
   * @throws AccessDeniedException if the current session does not have the {@link
   *     ModeShapePermissions#REGISTER_TYPE register type permission}.
   * @throws RepositoryException if another error occurs
   */
  public NodeTypeIterator registerNodeTypes(Iterable<NodeTypeDefinition> nodeTypes)
      throws InvalidNodeTypeDefinitionException, NodeTypeExistsException,
          UnsupportedRepositoryOperationException, AccessDeniedException, RepositoryException {

    try {
      session.checkPermission((Path) null, ModeShapePermissions.REGISTER_TYPE);
    } catch (AccessControlException ace) {
      throw new AccessDeniedException(ace);
    }

    return new JcrNodeTypeIterator(this.repositoryTypeManager.registerNodeTypes(nodeTypes));
  }
 @Override
 public JcrNodeType getNodeType(String nodeTypeName)
     throws NoSuchNodeTypeException, RepositoryException {
   session.checkLive();
   Name ntName = context().getValueFactories().getNameFactory().create(nodeTypeName);
   JcrNodeType type = nodeTypes().getNodeType(ntName);
   if (type != null) {
     type = type.with(context(), session);
     return type;
   }
   throw new NoSuchNodeTypeException(JcrI18n.typeNotFound.text(nodeTypeName));
 }
  @Override
  public NodeTypeIterator getPrimaryNodeTypes() throws RepositoryException {
    session.checkLive();
    Collection<JcrNodeType> rawTypes = nodeTypes().getPrimaryNodeTypes();
    List<JcrNodeType> types = new ArrayList<JcrNodeType>(rawTypes.size());

    // Need to return a version of the node type with the current context
    for (JcrNodeType type : rawTypes) {
      types.add(type.with(context(), session));
    }

    return new JcrNodeTypeIterator(types);
  }
 private void setCreatedByIfNecessary(JcrSession outputSession, List<AbstractJcrNode> outputNodes)
     throws RepositoryException {
   // if the mix:created mixin is on any of the new nodes, we need to set the createdBy here,
   // otherwise it will be
   // set by the system session when it saves and it will default to "modeshape-worker"
   for (AbstractJcrNode node : outputNodes) {
     if (node.isNodeType(JcrMixLexicon.CREATED)) {
       node.setProperty(
           JcrLexicon.CREATED_BY,
           outputSession.getValueFactory().createValue(work.getUserId()),
           true,
           true);
     }
   }
 }
  /**
   * Registers or updates the specified array of {@code NodeTypeDefinition} objects. This method is
   * used to register or update a set of node types with mutual dependencies. Returns an iterator
   * over the resulting {@code NodeType} objects.
   *
   * <p>The effect of the method is "all or nothing"; if an error occurs, no node types are
   * registered or updated.
   *
   * @param ntds the new node types to register
   * @param allowUpdate must be {@code false}; ModeShape does not allow updating node types at this
   *     time
   * @return the {@code newly created node types}
   * @throws InvalidNodeTypeDefinitionException if a {@code NodeTypeDefinition} within the
   *     collection is invalid
   * @throws NodeTypeExistsException if {@code allowUpdate} is false and a {@code
   *     NodeTypeDefinition} within the collection specifies a node type name that already exists
   * @throws UnsupportedRepositoryOperationException if {@code allowUpdate} is true; ModeShape does
   *     not allow updating node types at this time.
   * @throws AccessDeniedException if the current session does not have the {@link
   *     ModeShapePermissions#REGISTER_TYPE register type permission}.
   * @throws RepositoryException if another error occurs
   */
  @Override
  public NodeTypeIterator registerNodeTypes(NodeTypeDefinition[] ntds, boolean allowUpdate)
      throws InvalidNodeTypeDefinitionException, NodeTypeExistsException,
          UnsupportedRepositoryOperationException, RepositoryException {

    try {
      session.checkPermission((Path) null, ModeShapePermissions.REGISTER_TYPE);
    } catch (AccessControlException ace) {
      throw new AccessDeniedException(ace);
    }

    return new JcrNodeTypeIterator(
        this.repositoryTypeManager.registerNodeTypes(
            Arrays.asList(ntds), !allowUpdate, false, true));
  }
  /**
   * Allows the collection of node types to be unregistered if they are not referenced by other node
   * types as supertypes, default primary types of child nodes, or required primary types of child
   * nodes.
   *
   * @param nodeTypeNames the names of the node types to be unregistered
   * @throws NoSuchNodeTypeException if any of the node type names do not correspond to a registered
   *     node type
   * @throws InvalidNodeTypeDefinitionException if any of the node types with the given names cannot
   *     be unregistered because they are the supertype, one of the required primary types, or a
   *     default primary type of a node type that is not being unregistered.
   * @throws AccessDeniedException if the current session does not have the {@link
   *     ModeShapePermissions#REGISTER_TYPE register type permission}.
   * @throws RepositoryException if any other error occurs
   */
  public void unregisterNodeTypes(Collection<String> nodeTypeNames)
      throws NoSuchNodeTypeException, InvalidNodeTypeDefinitionException, RepositoryException {
    NameFactory nameFactory = context().getValueFactories().getNameFactory();

    try {
      session.checkPermission((Path) null, ModeShapePermissions.REGISTER_TYPE);
    } catch (AccessControlException ace) {
      throw new AccessDeniedException(ace);
    }

    Collection<Name> names = new ArrayList<Name>(nodeTypeNames.size());
    for (String name : nodeTypeNames) {
      names.add(nameFactory.create(name));
    }

    // Unregister the node types, but perform a check to see if any of the node types are currently
    // being used.
    // Unregistering a node type that is being used will likely cause the system to become unstable.
    boolean failIfNodeTypesAreUsed = true;
    repositoryTypeManager.unregisterNodeType(names, failIfNodeTypesAreUsed);
  }
  @Test
  public void shouldReturnFalseFromIsSameIfTheNodeUuidIsDifferent() throws Exception {
    // Set up the store ...
    InMemoryRepositorySource source2 = new InMemoryRepositorySource();
    source2.setName("store");
    Graph store2 = Graph.create(source2, context);
    store2
        .importXmlFrom(AbstractJcrTest.class.getClassLoader().getResourceAsStream("cars.xml"))
        .into("/");
    JcrSession jcrSession2 = mock(JcrSession.class);
    when(jcrSession2.nodeTypeManager()).thenReturn(nodeTypes);
    when(jcrSession2.isLive()).thenReturn(true);
    SessionCache cache2 =
        new SessionCache(jcrSession2, store2.getCurrentWorkspaceName(), context, nodeTypes, store2);

    Workspace workspace2 = mock(Workspace.class);
    JcrRepository repository2 = mock(JcrRepository.class);
    RepositoryLockManager repoLockManager2 = mock(RepositoryLockManager.class);
    when(jcrSession2.getWorkspace()).thenReturn(workspace2);
    when(jcrSession2.getRepository()).thenReturn(repository2);
    when(workspace2.getName()).thenReturn("workspace1");

    WorkspaceLockManager lockManager =
        new WorkspaceLockManager(context, repoLockManager2, "workspace2", null);
    JcrLockManager jcrLockManager = new JcrLockManager(jcrSession2, lockManager);
    when(jcrSession2.lockManager()).thenReturn(jcrLockManager);

    // Use the same id and location; use 'Nissan Altima'
    // since the UUIDs will be different (cars.xml doesn't define on this node) ...
    javax.jcr.Node altima2 = cache2.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
    altima2.addMixin("mix:referenceable");
    altima.addMixin("mix:referenceable");
    String altimaUuid = altima.getIdentifier();
    String altimaUuid2 = altima2.getIdentifier();
    assertThat(altimaUuid, is(not(altimaUuid2)));
    assertThat(altima2.isSame(altima), is(false));

    // Check the properties ...
    javax.jcr.Property model = altima.getProperty("vehix:model");
    javax.jcr.Property model2 = altima2.getProperty("vehix:model");
    assertThat(model.isSame(model2), is(false));
  }
  @Test
  public void shouldReturnTrueFromIsSameIfTheNodeUuidAndWorkspaceNameAndRepositoryInstanceAreSame()
      throws Exception {
    // Set up the store ...
    InMemoryRepositorySource source2 = new InMemoryRepositorySource();
    source2.setName("store");
    Graph store2 = Graph.create(source2, context);
    store2
        .importXmlFrom(AbstractJcrTest.class.getClassLoader().getResourceAsStream("cars.xml"))
        .into("/");
    JcrSession jcrSession2 = mock(JcrSession.class);
    when(jcrSession2.nodeTypeManager()).thenReturn(nodeTypes);
    when(jcrSession2.isLive()).thenReturn(true);
    SessionCache cache2 =
        new SessionCache(jcrSession2, store2.getCurrentWorkspaceName(), context, nodeTypes, store2);

    Workspace workspace2 = mock(Workspace.class);
    when(jcrSession2.getWorkspace()).thenReturn(workspace2);
    when(jcrSession2.getRepository()).thenReturn(repository);
    when(workspace2.getName()).thenReturn("workspace1");

    WorkspaceLockManager lockManager =
        new WorkspaceLockManager(context, repoLockManager, "workspace2", null);
    JcrLockManager jcrLockManager = new JcrLockManager(jcrSession2, lockManager);
    when(jcrSession2.lockManager()).thenReturn(jcrLockManager);

    // Use the same id and location ...
    javax.jcr.Node prius2 = cache2.findJcrNode(null, path("/Cars/Hybrid/Toyota Prius"));
    prius2.addMixin("mix:referenceable");
    prius.addMixin("mix:referenceable");
    String priusUuid = prius.getIdentifier();
    String priusUuid2 = prius2.getIdentifier();
    assertThat(priusUuid, is(priusUuid2));
    assertThat(prius2.isSame(prius), is(true));

    // Check the properties ...
    javax.jcr.Property model = prius.getProperty("vehix:model");
    javax.jcr.Property model2 = prius2.getProperty("vehix:model");
    javax.jcr.Property year2 = prius2.getProperty("vehix:year");
    assertThat(model.isSame(model2), is(true));
    assertThat(model.isSame(year2), is(false));
  }
  @Override
  public void run() {
    JcrSession inputSession = null;
    JcrSession outputSession = null;
    final RunningState state = repository.runningState();
    final RepositoryStatistics stats = state.statistics();
    Sequencer sequencer = null;
    String sequencerName = null;
    try {
      // Create the required session(s) ...
      inputSession = state.loginInternalSession(work.getInputWorkspaceName());
      if (work.getOutputWorkspaceName() != null
          && !work.getOutputWorkspaceName().equals(work.getInputWorkspaceName())) {
        outputSession = state.loginInternalSession(work.getOutputWorkspaceName());
      } else {
        outputSession = inputSession;
      }

      // Get the sequencer ...
      sequencer = state.sequencers().getSequencer(work.getSequencerId());
      if (sequencer == null) return;
      sequencerName = sequencer.getName();

      // Find the selected node ...
      AbstractJcrNode selectedNode = inputSession.getNode(work.getSelectedPath());

      // Find the input that has changed and is to be sequenced ...
      Item inputItem = inputSession.getItem(work.getInputPath());
      Property changedProperty = null;
      if (inputItem instanceof Property) {
        changedProperty = (Property) inputItem;
      } else {
        Node changedNode = (Node) inputItem;
        // now look for a property that was changed or added ...
        changedProperty = changedNode.getProperty(work.getChangedPropertyName());
      }
      assert changedProperty != null;

      if (sequencer.hasAcceptedMimeTypes()) {
        // Get the MIME type, first by looking at the changed property's parent node
        // (or grand-parent node if parent is 'jcr:content') ...
        Node parent = changedProperty.getParent();
        String mimeType = null;
        if (parent.hasProperty(JcrConstants.JCR_MIME_TYPE)) {
          // The parent node has a 'jcr:mimeType' node ...
          Property property = parent.getProperty(JcrConstants.JCR_MIME_TYPE);
          if (!property.isMultiple()) {
            // The standard 'jcr:mimeType' property is single valued, but we're technically not
            // checking if
            // the property has that particular property definition (only by name) ...
            mimeType = property.getString();
          }
        } else if (parent.getName().equals(JcrConstants.JCR_CONTENT)) {
          // There is no 'jcr:mimeType' property, and since the sequenced property is on the
          // 'jcr:content' node,
          // get the parent (probably 'nt:file') node and look for the 'jcr:mimeType' property there
          // ...
          try {
            parent = parent.getParent();
            if (parent.hasProperty(JcrConstants.JCR_MIME_TYPE)) {
              Property property = parent.getProperty(JcrConstants.JCR_MIME_TYPE);
              if (!property.isMultiple()) {
                // The standard 'jcr:mimeType' property is single valued, but we're technically not
                // checking if
                // the property has that particular property definition (only by name) ...
                mimeType = property.getString();
              }
            }
          } catch (ItemNotFoundException e) {
            // must be the root ...
          }
        }
        if (mimeType == null
            && !changedProperty.isMultiple()
            && changedProperty.getType() == PropertyType.BINARY) {
          // Still don't know the MIME type of the property, so if it's a BINARY property we can
          // check it ...
          javax.jcr.Binary binary = changedProperty.getBinary();
          if (binary instanceof org.modeshape.jcr.api.Binary) {
            mimeType = ((org.modeshape.jcr.api.Binary) binary).getMimeType(parent.getName());
          }
        }

        // See if the sequencer accepts the MIME type ...
        if (mimeType != null && !sequencer.isAccepted(mimeType)) {
          return; // nope
        }
      }

      AbstractJcrNode outputNode = null;
      String primaryType = null;
      if (work.getSelectedPath().equals(work.getOutputPath())) {
        // The output is to go directly under the sequenced node ...
        outputNode =
            selectedNode.getName().equals(JcrConstants.JCR_CONTENT)
                ? selectedNode.getParent()
                : selectedNode;
        primaryType = selectedNode.getPrimaryNodeType().getName();
      } else {
        // Find the parent of the output if it exists, or create the node(s) along the path if not
        // ...
        Node parentOfOutput = null;
        try {
          parentOfOutput = outputSession.getNode(work.getOutputPath());
        } catch (PathNotFoundException e) {
          JcrTools tools = new JcrTools();
          parentOfOutput = tools.findOrCreateNode(outputSession, work.getOutputPath());
        }

        // Now determine the name of top node in the output, using the last segment of the selected
        // path ...
        String outputNodeName = computeOutputNodeName(selectedNode);

        // Remove any existing output (from a prior sequencing run on this same input) ...
        removeExistingOutputNodes(parentOfOutput, outputNodeName, work.getSelectedPath());

        // Create the output node
        if (parentOfOutput.isNew() && parentOfOutput.getName().equals(outputNodeName)) {
          // avoid creating a duplicate path with the same name
          outputNode = (AbstractJcrNode) parentOfOutput;
        } else {
          outputNode =
              (AbstractJcrNode)
                  parentOfOutput.addNode(outputNodeName, JcrConstants.NT_UNSTRUCTURED);
        }

        // and make sure the output node has the 'mode:derived' mixin ...
        outputNode.addMixin(DERIVED_NODE_TYPE_NAME);
        outputNode.setProperty(DERIVED_FROM_PROPERTY_NAME, work.getSelectedPath());
      }

      // Execute the sequencer ...
      DateTime now = outputSession.dateFactory().create();
      Sequencer.Context context =
          new SequencingContext(
              now, outputSession.getValueFactory(), outputSession.context().getMimeTypeDetector());
      if (inputSession.isLive() && (inputSession == outputSession || outputSession.isLive())) {
        final long start = System.nanoTime();

        try {
          if (sequencer.execute(changedProperty, outputNode, context)) {
            // Make sure that the sequencer did not change the primary type of the selected node ..
            if (selectedNode == outputNode
                && !selectedNode.getPrimaryNodeType().getName().equals(primaryType)) {
              String msg =
                  RepositoryI18n.sequencersMayNotChangeThePrimaryTypeOfTheSelectedNode.text();
              throw new RepositoryException(msg);
            }

            // find the new nodes created by the sequencing before saving, so we can properly fire
            // the events
            List<AbstractJcrNode> outputNodes = findOutputNodes(outputNode);

            // set the createdBy property (if it applies) to the user which triggered the
            // sequencing, not the context
            // of the saving session
            setCreatedByIfNecessary(outputSession, outputNodes);

            // outputSession
            outputSession.save();

            // fire the sequencing event after save (hopefully by this time the transaction has been
            // committed)
            fireSequencingEvent(selectedNode, outputNodes, outputSession, sequencerName);

            long durationInNanos = System.nanoTime() - start;
            Map<String, String> payload = new HashMap<String, String>();
            payload.put("sequencerName", sequencer.getClass().getName());
            payload.put("sequencedPath", changedProperty.getPath());
            payload.put("outputPath", outputNode.getPath());
            stats.recordDuration(
                DurationMetric.SEQUENCER_EXECUTION_TIME,
                durationInNanos,
                TimeUnit.NANOSECONDS,
                payload);
          }
        } catch (Throwable t) {
          fireSequencingFailureEvent(selectedNode, inputSession, t, sequencerName);
          // let it bubble down, because we still want to log it and update the stats
          throw t;
        }
      }
    } catch (Throwable t) {
      Logger logger = Logger.getLogger(getClass());
      if (work.getOutputWorkspaceName() != null) {
        logger.error(
            t,
            RepositoryI18n.errorWhileSequencingNodeIntoWorkspace,
            sequencerName,
            state.name(),
            work.getInputPath(),
            work.getInputWorkspaceName(),
            work.getOutputPath(),
            work.getOutputWorkspaceName());
      } else {
        logger.error(
            t,
            RepositoryI18n.errorWhileSequencingNode,
            sequencerName,
            state.name(),
            work.getInputPath(),
            work.getInputWorkspaceName(),
            work.getOutputPath());
      }
    } finally {
      stats.increment(ValueMetric.SEQUENCED_COUNT);
      stats.decrement(ValueMetric.SEQUENCER_QUEUE_SIZE);
      if (inputSession != null && inputSession.isLive()) inputSession.logout();
      if (outputSession != null && outputSession != inputSession && outputSession.isLive())
        outputSession.logout();
    }
  }
 private final ExecutionContext context() {
   return session.context();
 }
 @Override
 public NodeTypeIterator getAllNodeTypes() throws RepositoryException {
   session.checkLive();
   return new JcrNodeTypeIterator(nodeTypes().getAllNodeTypes());
 }
  private void assertContentInWorkspace(
      JcrRepository newRepository, String workspaceName, String... paths)
      throws RepositoryException {
    JcrSession session =
        workspaceName != null ? newRepository.login(workspaceName) : newRepository.login();

    try {
      session.getRootNode();
      session.getNode("/Cars");
      session.getNode("/Cars/Hybrid");
      session.getNode("/Cars/Hybrid/Toyota Prius");
      session.getNode("/Cars/Hybrid/Toyota Highlander");
      session.getNode("/Cars/Hybrid/Nissan Altima");
      session.getNode("/Cars/Sports/Aston Martin DB9");
      session.getNode("/Cars/Sports/Infiniti G37");
      session.getNode("/Cars/Luxury/Cadillac DTS");
      session.getNode("/Cars/Luxury/Bentley Continental");
      session.getNode("/Cars/Luxury/Lexus IS350");
      session.getNode("/Cars/Utility/Land Rover LR2");
      session.getNode("/Cars/Utility/Land Rover LR3");
      session.getNode("/Cars/Utility/Hummer H3");
      session.getNode("/Cars/Utility/Ford F-150");
      session.getNode("/Cars/Utility/Toyota Land Cruiser");
      for (String path : paths) {
        session.getNode(path);
      }
    } finally {
      session.logout();
    }
  }