Example #1
0
  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);
  }
Example #2
0
 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);
 }
Example #3
0
 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);
     }
   }
 }
Example #4
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();
    }
  }