All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.modeshape.jcr.sequencer.SequencerPathExpression Maven / Gradle / Ivy

There is a newer version: 5.4.1.Final
Show newest version
/*
 * ModeShape (http://www.modeshape.org)
 *
 * 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.modeshape.jcr.sequencer;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
import org.modeshape.common.annotation.Immutable;
import org.modeshape.common.util.CheckArg;
import org.modeshape.common.util.HashCode;
import org.modeshape.common.util.ObjectUtil;
import org.modeshape.jcr.RepositoryI18n;
import org.modeshape.jcr.sequencer.PathExpression.WorkspacePath;

/**
 * An expression that defines a selection of some change in the repository that signals a sequencing operation should be run, and
 * the location where the sequencing output should be placed. Sequencer path expressions are used to determine whether information
 * in the repository needs to be sequenced.
 * 

* A simple example is the following: * *

 *     /a/b/c@title => /d/e/f
 * 
* * which means that a sequencer (that uses this expression in its configuration) should be run any time there is a new or modified * title property on the /a/b/c node, and that the output of the sequencing should be placed at * /d/e/f. *

*/ @Immutable public class SequencerPathExpression implements Serializable { /** */ private static final long serialVersionUID = 229464314137494765L; /** * The pattern used to break the initial input string into the two major parts, the selection and output expressions. Group 1 * contains the selection expression, and group 2 contains the output expression. */ private static final Pattern TWO_PART_PATTERN = Pattern.compile("((?:[^=]|=(?!>))+)(?:=>(.+))?"); protected static final String DEFAULT_OUTPUT_EXPRESSION = "."; private static final String PARENT_PATTERN_STRING = "[^/]+/\\.\\./"; // [^/]+/\.\./ private static final Pattern PARENT_PATTERN = Pattern.compile(PARENT_PATTERN_STRING); private static final String REPLACEMENT_VARIABLE_PATTERN_STRING = "(?" + this.outputExpression; } /** * Determine if this path expression applies to content within the supplied workspace name. * * @param workspaceName the name of the workspace; may not be null * @return true if this path expression matches the workspace name, or false otherwise */ public final boolean appliesToWorkspace( String workspaceName ) { return selectExpression.matchesWorkspace(workspaceName); } /** * Obtain a Matcher that can be used to convert the supplied workspace key and absolute path into an output workspace name and * and output path. * * @param absolutePath the path in the workspace; may not be null * @return the matcher; never null */ public Matcher matcher( String absolutePath ) { PathExpression.Matcher inputMatcher = selectExpression.matcher(absolutePath); String outputPath = null; WorkspacePath wsPath = null; if (inputMatcher.matches()) { // Grab the named groups ... Map replacements = new HashMap(); for (int i = 0, count = inputMatcher.groupCount(); i <= count; ++i) { replacements.put(i, inputMatcher.group(i)); } // Grab the selected path ... String selectedPath = inputMatcher.getSelectedNodePath(); // Find the output path using the groups from the match pattern ... wsPath = PathExpression.parsePathInWorkspace(this.outputExpression); if (wsPath != null) { if (wsPath.workspaceName == null) wsPath = wsPath.withWorkspaceName(inputMatcher.getSelectedWorkspaceName()); outputPath = wsPath.path; if (!DEFAULT_OUTPUT_EXPRESSION.equals(outputPath)) { java.util.regex.Matcher replacementMatcher = REPLACEMENT_VARIABLE_PATTERN.matcher(outputPath); // CHECKSTYLE IGNORE check FOR NEXT 1 LINES StringBuffer sb = new StringBuffer(); if (replacementMatcher.find()) { do { String variable = replacementMatcher.group(1); String replacement = replacements.get(Integer.valueOf(variable)); if (replacement == null) replacement = replacementMatcher.group(0); replacementMatcher.appendReplacement(sb, replacement); } while (replacementMatcher.find()); replacementMatcher.appendTail(sb); outputPath = sb.toString(); } // Make sure there is a trailing '/' ... if (!outputPath.endsWith("/")) outputPath = outputPath + "/"; // Replace all references to "/./" with "/" ... outputPath = outputPath.replaceAll("/\\./", "/"); // Remove any path segment followed by a parent reference ... java.util.regex.Matcher parentMatcher = PARENT_PATTERN.matcher(outputPath); while (parentMatcher.find()) { outputPath = parentMatcher.replaceAll(""); // Make sure there is a trailing '/' ... if (!outputPath.endsWith("/")) outputPath = outputPath + "/"; parentMatcher = PARENT_PATTERN.matcher(outputPath); } // Remove all multiple occurrences of '/' ... outputPath = outputPath.replaceAll("/{2,}", "/"); // Remove the trailing '/@property' ... outputPath = outputPath.replaceAll("/@[^/\\[\\]]+$", ""); // Remove a trailing '/' ... outputPath = outputPath.replaceAll("/$", ""); // If the output path is blank, then use the default output expression ... if (outputPath.length() == 0) outputPath = DEFAULT_OUTPUT_EXPRESSION; } if (DEFAULT_OUTPUT_EXPRESSION.equals(outputPath)) { // The output path is the default expression, so use the selected path ... outputPath = selectedPath; } wsPath = wsPath.withPath(outputPath); } } return new Matcher(inputMatcher, wsPath); } @Immutable public static class Matcher { private final PathExpression.Matcher inputMatcher; private final WorkspacePath outputPath; private final int hc; protected Matcher( PathExpression.Matcher inputMatcher, WorkspacePath outputPath ) { this.inputMatcher = inputMatcher; this.outputPath = outputPath; this.hc = HashCode.compute(super.hashCode(), this.outputPath); } public boolean matches() { return inputMatcher.matches() && this.outputPath != null; } /** * @return inputPath */ public String getInputPath() { return inputMatcher.getInputPath(); } /** * Get the {@link #getInputPath() input path} in standard JCR form. * * @return the JCR form of the input path; null only if {@link #getInputPath()} is null */ public String getJcrInputPath() { // Conver the input path (which has a '@' to denote a property) to a standard JCR path ... String inputPath = getInputPath(); if (inputPath == null) return null; int index = inputPath.lastIndexOf("/@"); if (index != -1) { inputPath = inputPath.substring(0, index) + '/' + inputPath.substring(index + 2); } return inputPath; } /** * @return selectPattern */ public String getSelectedPath() { return inputMatcher.getSelectedNodePath(); } /** * Get the path in the repository where the sequenced content should be placed. * * @return outputPath the output path, or null if this matcher does not match the input */ public String getOutputPath() { return this.outputPath != null ? this.outputPath.path : null; } /** * Get the name of the workspace where the sequenced content should be placed. * * @return outputPath the output path, or null if this matcher does not match the input */ public String getOutputWorkspaceName() { return this.outputPath != null ? this.outputPath.workspaceName : null; } @Override public int hashCode() { return this.hc; } @Override public boolean equals( Object obj ) { if (obj == this) return true; if (obj instanceof SequencerPathExpression.Matcher) { SequencerPathExpression.Matcher that = (SequencerPathExpression.Matcher)obj; if (!super.equals(that)) return false; return ObjectUtil.isEqualWithNulls(this.outputPath, that.outputPath); } return false; } @Override public String toString() { return inputMatcher + " => " + this.outputPath; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy