/* * Copyright 2011 <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a> * * 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.ocpsoft.rewrite.param; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; import org.ocpsoft.common.util.Assert; import org.ocpsoft.rewrite.bind.Binding; import org.ocpsoft.rewrite.context.EvaluationContext; import org.ocpsoft.rewrite.event.Rewrite; import org.ocpsoft.rewrite.exception.ParameterizationException; import org.ocpsoft.rewrite.param.RegexParameterizedPatternParser.RegexGroup; import org.ocpsoft.rewrite.util.ParameterUtils; import org.ocpsoft.rewrite.util.ParseTools.CaptureType; import org.ocpsoft.rewrite.util.ParseTools.CapturingGroup; /** * An {@link org.ocpsoft.rewrite.param.Parameterized} regular expression {@link Pattern}. * * @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a> */ public class RegexParameterizedPatternBuilder implements ParameterizedPatternBuilder { private static final String DEFAULT_PARAMETER_PATTERN = ".*"; private final String pattern; private final char[] chars; private final List<RegexGroup> groups = new ArrayList<RegexGroup>(); private final String defaultParameterPattern; private ParameterStore store; private RegexParameterizedPatternParser parser = null; RegexParameterizedPatternBuilder(String pattern, RegexParameterizedPatternParser parser) { this(pattern); this.parser = parser; } /** * Create a new {@link RegexParameterizedPatternBuilder} instance with the default * {@link org.ocpsoft.rewrite.bind.parse.CaptureType#BRACE} and parameter compiledPattern of ".*". */ public RegexParameterizedPatternBuilder(final String pattern) { this(CaptureType.BRACE, DEFAULT_PARAMETER_PATTERN, pattern); } /** * Create a new {@link RegexParameterizedPatternBuilder} instance with the default {@link CaptureType#BRACE}. */ public RegexParameterizedPatternBuilder(final String parameterPattern, final String pattern) { this(CaptureType.BRACE, parameterPattern, pattern); } /** * Create a new {@link RegexParameterizedPatternBuilder} instance with the default parameter regex of ".*". */ public RegexParameterizedPatternBuilder(final CaptureType type, final String pattern) { this(type, DEFAULT_PARAMETER_PATTERN, pattern); } /** * Create a new {@link RegexParameterizedPatternBuilder} instance. */ public RegexParameterizedPatternBuilder(final CaptureType type, final String defaultParameterPattern, final String pattern) { Assert.notNull(pattern, "Pattern must not be null"); this.defaultParameterPattern = defaultParameterPattern; this.pattern = pattern; this.chars = pattern.toCharArray(); this.groups.addAll(RegexParameterizedPatternParser.getGroups(type, chars)); } @Override public String build(final Rewrite event, final EvaluationContext context) throws ParameterizationException { return build(event, context, null); } @Override public String build(final Rewrite event, final EvaluationContext context, final Transposition<String> transposition) throws ParameterizationException { return build(extractBoundValues(event, context, transposition)); } @Override public String build(final List<Object> values) throws ParameterizationException { if ((values == null && groups.size() != 0) || (groups.size() != values.size())) { throw new ParameterizationException("Must supply [" + groups.size() + "] values to build output string."); } StringBuilder builder = new StringBuilder(); CapturingGroup last = null; int index = 0; for (RegexGroup param : groups) { CapturingGroup capture = param.getCapture(); if ((last != null) && (last.getEnd() < capture.getStart())) { builder.append(Arrays.copyOfRange(chars, last.getEnd() + 1, capture.getStart())); } else if ((last == null) && (capture.getStart() > 0)) { builder.append(Arrays.copyOfRange(chars, 0, capture.getStart())); } builder.append(values.get(index++)); last = capture; } if ((last != null) && (last.getEnd() < chars.length)) { builder.append(Arrays.copyOfRange(chars, last.getEnd() + 1, chars.length)); } else if (last == null) { builder.append(chars); } String result = builder.toString(); // if (!getParser().matches(result)) // { // throw new IllegalStateException("Generated a value that does not match constraints."); // } return result; } @Override public String build(final Map<String, Object> values) throws ParameterizationException { StringBuilder builder = new StringBuilder(); CapturingGroup last = null; for (RegexGroup param : groups) { CapturingGroup capture = param.getCapture(); if ((last != null) && (last.getEnd() < capture.getStart())) { builder.append(Arrays.copyOfRange(chars, last.getEnd() + 1, capture.getStart())); } else if ((last == null) && (capture.getStart() > 0)) { builder.append(Arrays.copyOfRange(chars, 0, capture.getStart())); } if (!values.containsKey(param.getName())) throw new ParameterizationException("No value supplied for parameter [" + param.getName() + "] when building pattern [" + getPattern() + "]."); builder.append(values.get(param.getName())); last = capture; } if ((last != null) && (last.getEnd() < chars.length)) { builder.append(Arrays.copyOfRange(chars, last.getEnd() + 1, chars.length)); } else if (last == null) { builder.append(chars); } String result = builder.toString(); // if (!getParser().matches(result)) // { // throw new IllegalStateException("Generated a value that does not match constraints."); // } return result; } /** * Extract bound values from configured {@link Binding} instances. Return a {@link Map} of the extracted key-value * pairs. Before storing the values in the map, this method applies the supplied {@link Transposition} instance. */ private Map<String, Object> extractBoundValues(final Rewrite event, final EvaluationContext context, Transposition<String> transposition) { Map<String, Object> result = new LinkedHashMap<String, Object>(); for (RegexGroup group : groups) { Parameter<?> parameter = store.get(group.getName()); Object value = null; // TODO TEST ME!!! if (context.getState().isEvaluating()) value = ((ParameterValueStore) context.get(ParameterValueStore.class)).retrieve(parameter); if (value == null || context.getState().isPerforming()) { Object retrieved = ParameterUtils.performRetrieval(event, context, parameter); if (retrieved != null) value = retrieved; } if (value == null) throw new ParameterizationException("The value of required parameter [" + group.getName() + "] was null."); if (transposition != null) value = transposition.transpose(event, context, value.toString()); result.put(group.getName(), value); } return result; } @Override public String toString() { return new String(chars); } @Override public String getPattern() { return pattern; } @Override public ParameterizedPatternParser getParser() { if (parser == null) { parser = new RegexParameterizedPatternParser(this, defaultParameterPattern, pattern); parser.setParameterStore(store); } return parser; } @Override public Set<String> getRequiredParameterNames() { Set<String> result = new LinkedHashSet<String>(); for (RegexGroup group : groups) { result.add(group.getName()); } return result; } @Override public void setParameterStore(ParameterStore store) { this.store = store; } @Override public boolean isParameterComplete(Rewrite event, EvaluationContext context) { try { extractBoundValues(event, context, null); return true; } catch (ParameterizationException e) { return false; } } }