blob: 9e2fa1c034c444be2cc72ee74d4f85bf83070eae [file] [log] [blame]
/**
* 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 org.apache.camel.impl;
import java.util.concurrent.atomic.AtomicLong;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.camel.CamelContext;
import org.apache.camel.spi.ManagementNameStrategy;
import org.apache.camel.util.ObjectHelper;
/**
* Default implementation of {@link ManagementNameStrategy}
* <p/>
* This implementation will by default use a name pattern as <tt>#name#</tt> and in case
* of a clash, then the pattern will fallback to be using the counter as <tt>#name#-#counter#</tt>.
*/
public class DefaultManagementNameStrategy implements ManagementNameStrategy {
private static final Pattern INVALID_PATTERN = Pattern.compile(".*#\\w+#.*");
private static final AtomicLong NAME_COUNTER = new AtomicLong();
private final CamelContext camelContext;
private final String defaultPattern;
private final String nextPattern;
private String name;
private String namePattern;
public DefaultManagementNameStrategy(CamelContext camelContext) {
this(camelContext, null, "#name#-#counter#");
}
public DefaultManagementNameStrategy(CamelContext camelContext, String defaultPattern, String nextPattern) {
this.camelContext = camelContext;
this.defaultPattern = defaultPattern;
this.nextPattern = nextPattern;
}
@Override
public String getNamePattern() {
return namePattern;
}
@Override
public void setNamePattern(String namePattern) {
this.namePattern = namePattern;
}
@Override
public String getName() {
if (name == null) {
String pattern = getNamePattern();
if (pattern == null) {
// fallback and use the default pattern which is the same name as the CamelContext has been given
pattern = defaultPattern != null ? defaultPattern : camelContext.getManagementStrategy().getManagementAgent().getManagementNamePattern();
}
name = resolveManagementName(pattern, camelContext.getName(), true);
}
return name;
}
@Override
public String getNextName() {
if (isFixedName()) {
// use the fixed name
return getName();
} else {
// or resolve a new name
String pattern = getNamePattern();
if (pattern == null) {
// use a pattern that has a counter to ensure unique next name
pattern = nextPattern;
}
return resolveManagementName(pattern, camelContext.getName(), true);
}
}
@Override
public boolean isFixedName() {
// the name will be fixed unless there is a counter token
String pattern = getNamePattern();
if (pattern == null) {
// we are not fixed by default
return false;
}
return !pattern.contains("#counter#");
}
/**
* Creates a new management name with the given pattern
*
* @param pattern the pattern
* @param name the name
* @return the management name
* @throws IllegalArgumentException if the pattern or name is invalid or empty
*/
public String resolveManagementName(String pattern, String name, boolean invalidCheck) {
ObjectHelper.notEmpty(pattern, "pattern");
ObjectHelper.notEmpty(name, "name");
// must quote the names to have it work as literal replacement
name = Matcher.quoteReplacement(name);
// replace tokens
String answer = pattern;
if (pattern.contains("#counter#")) {
// only increment the counter on-demand
answer = pattern.replaceFirst("#counter#", "" + nextNameCounter());
}
// camelId and name is the same tokens
answer = answer.replaceFirst("#camelId#", name);
answer = answer.replaceFirst("#name#", name);
// allow custom name resolution as well. For example with camel-core-osgi we have a custom
// name strategy that supports OSGI specific tokens such as #bundleId# etc.
answer = customResolveManagementName(pattern, answer);
// are there any #word# combos left, if so they should be considered invalid tokens
if (invalidCheck && INVALID_PATTERN.matcher(answer).matches()) {
throw new IllegalArgumentException("Pattern is invalid: " + pattern);
}
return answer;
}
/**
* Strategy to do any custom resolution of the name
*
* @param pattern the pattern
* @param answer the current answer, which may have custom patterns still to be resolved
* @return the resolved name
*/
protected String customResolveManagementName(String pattern, String answer) {
return answer;
}
private static long nextNameCounter() {
// we want to be 1-based, so increment first
return NAME_COUNTER.incrementAndGet();
}
/**
* To reset the counter, should only be used for testing purposes.
*
* @param value the counter value
*/
public static void setCounter(int value) {
NAME_COUNTER.set(value);
}
}