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

com.opensymphony.xwork2.config.impl.AbstractMatcher Maven / Gradle / Ivy

There is a newer version: 6.4.0
Show newest version
/*
 * 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 com.opensymphony.xwork2.config.impl;

import com.opensymphony.xwork2.util.PatternMatcher;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.Serializable;
import java.util.*;

/**
 * 

Matches patterns against pre-compiled wildcard expressions pulled from * target objects. It uses the wildcard matcher from the Apache Cocoon * project. Patterns will be matched in the order they were added. The first * match wins, so more specific patterns should be defined before less specific * patterns. * * @since 2.1 */ public abstract class AbstractMatcher implements Serializable { /** *

The logging instance

*/ private static final Logger log = LogManager.getLogger(AbstractMatcher.class); /** *

Handles all wildcard pattern matching.

*/ PatternMatcher wildcard; /** *

The compiled patterns and their associated target objects

*/ List> compiledPatterns = new ArrayList<>(); ; public AbstractMatcher(PatternMatcher helper) { this.wildcard = (PatternMatcher) helper; } /** *

* Finds and precompiles the wildcard patterns. Patterns will be evaluated * in the order they were added. Only patterns that actually contain a * wildcard will be compiled. *

* *

* Patterns can optionally be matched "loosely". When the end of the pattern * matches \*[^*]\*$ (wildcard, no wildcard, wildcard), if the pattern * fails, it is also matched as if the last two characters didn't exist. The * goal is to support the legacy "*!*" syntax, where the "!*" is optional. *

* * @param name The pattern * @param target The object to associate with the pattern * @param looseMatch * To loosely match wildcards or not */ public void addPattern(String name, E target, boolean looseMatch) { Object pattern; if (!wildcard.isLiteral(name)) { if (looseMatch && (name.length() > 0) && (name.charAt(0) == '/')) { name = name.substring(1); } log.debug("Compiling pattern '{}'", name); pattern = wildcard.compilePattern(name); compiledPatterns.add(new Mapping(name, pattern, target)); if (looseMatch) { int lastStar = name.lastIndexOf('*'); if (lastStar > 1 && lastStar == name.length() - 1) { if (name.charAt(lastStar - 1) != '*') { pattern = wildcard.compilePattern(name.substring(0, lastStar - 1)); compiledPatterns.add(new Mapping(name, pattern, target)); } } } } } public void freeze() { compiledPatterns = Collections.unmodifiableList(new ArrayList>()); } /** *

Matches the path against the compiled wildcard patterns.

* * @param potentialMatch The portion of the request URI for selecting a config. * @return The action config if matched, else null */ public E match(String potentialMatch) { E config = null; if (compiledPatterns.size() > 0) { log.debug("Attempting to match '{}' to a wildcard pattern, {} available", potentialMatch, compiledPatterns.size()); Map vars = new LinkedHashMap(); for (Mapping m : compiledPatterns) { if (wildcard.match(vars, potentialMatch, m.getPattern())) { log.debug("Value matches pattern '{}'", m.getOriginalPattern()); config = convert(potentialMatch, m.getTarget(), vars); break; } } } return config; } /** *

Clones the target object and its children, replacing various * properties with the values of the wildcard-matched strings.

* * @param path The requested path * @param orig The original object * @param vars A Map of wildcard-matched strings * @return A cloned object with appropriate properties replaced with * wildcard-matched values */ protected abstract E convert(String path, E orig, Map vars); /** *

Replaces parameter values

* * @param orig The original parameters with placeholder values * @param vars A Map of wildcard-matched strings * * @return map with replaced parameters */ protected Map replaceParameters(Map orig, Map vars) { Map map = new LinkedHashMap<>(); //this will set the group index references, like {1} for (Map.Entry entry : orig.entrySet()) { map.put(entry.getKey(), convertParam(entry.getValue(), vars)); } //the values map will contain entries like name->"Lex Luthor" and 1->"Lex Luthor" //now add the non-numeric values for (Map.Entry entry: vars.entrySet()) { if (!NumberUtils.isCreatable(entry.getKey())) { map.put(entry.getKey(), entry.getValue()); } } return map; } /** *

Inserts into a value wildcard-matched strings where specified * with the {x} syntax. If a wildcard-matched value isn't found, the * replacement token is turned into an empty string. *

* * @param val The value to convert * @param vars A Map of wildcard-matched strings * @return The new value */ protected String convertParam(String val, Map vars) { if (val == null) { return null; } int len = val.length(); StringBuilder ret = new StringBuilder(); char c; String varVal; for (int x=0; x Stores a compiled wildcard pattern and the object it came * from.

*/ private static class Mapping implements Serializable { /** *

The original pattern.

*/ private String original; /** *

The compiled pattern.

*/ private Object pattern; /** *

The original object.

*/ private E config; /** *

Contructs a read-only Mapping instance.

* * @param original The original pattern * @param pattern The compiled pattern * @param config The original object */ public Mapping(String original, Object pattern, E config) { this.original = original; this.pattern = pattern; this.config = config; } /** *

Gets the compiled wildcard pattern.

* * @return The compiled pattern */ public Object getPattern() { return this.pattern; } /** *

Gets the object that contains the pattern.

* * @return The associated object */ public E getTarget() { return this.config; } /** *

Gets the original wildcard pattern.

* * @return The original pattern */ public String getOriginalPattern() { return this.original; } } }