@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);
    }
  }
  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();
    }
  }
 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();
   }
 }
  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 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);
  }
Example #7
0
  @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();
    }
  }