Skip to content
This repository has been archived by the owner on Jun 3, 2024. It is now read-only.

Reporter Bean Parser rejects attributes that declare namespaces (e.g. xmlns:context="...") #103

Open
wants to merge 4 commits into
base: v3.0-maintenance
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.ryantenney.metrics</groupId>
<artifactId>metrics-spring</artifactId>
<version>3.0.4</version>
<version>3.0.5-SNAPSHOT</version>
<packaging>bundle</packaging>
<name>Metrics Spring Integration</name>
<description>Spring integration for Coda Hale's Metrics Library</description>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
/**
* An annotation for marking a method as a gauge, which caches the result for a specified time.
*
* <p/>
* Given a method like this:
* <pre><code>
* {@literal @}CachedGauge(name = "queueSize", timeout = 30, timeoutUnit = TimeUnit.SECONDS)
Expand All @@ -33,7 +32,6 @@
* }
*
* </code></pre>
* <p/>
*
* A gauge for the defining class with the name queueSize will be created which uses the annotated method's
* return value as its value, and which caches the result for 30 seconds.
Expand Down
3 changes: 1 addition & 2 deletions src/main/java/com/ryantenney/metrics/annotation/Counted.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,14 @@
/**
* An annotation for marking a method of an annotated object as counted.
*
* <p/>
* Given a method like this:
* <pre><code>
* {@literal @}Counted(name = "fancyName")
* public String fancyName(String name) {
* return "Sir Captain " + name;
* }
* </code></pre>
* <p/>
*
* A counter for the defining class with the name {@code fancyName} will be created and each time the
* {@code #fancyName(String)} method is invoked, the counter will be marked.
*/
Expand Down
5 changes: 1 addition & 4 deletions src/main/java/com/ryantenney/metrics/annotation/Metric.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,22 @@
/**
* An annotation requesting that a metric be injected or registered.
*
* <p/>
* Given a field like this:
* <pre><code>
* {@literal @}Metric
* public Histogram histogram;
* </code></pre>
* <p/>
*
* A meter of the field's type will be created and injected into Spring-managed beans after construction
* but before initialization. It will be up to the user to interact with the metric. This annotation
* can be used on fields of type Meter, Timer, Counter, and Histogram.
*
* <p>
* This may also be used to register a metric, which is useful for creating a histogram with
* a custom Reservoir.
* <pre><code>
* {@literal @}Metric
* public Histogram uniformHistogram = new Histogram(new UniformReservoir());
* </code></pre>
* </p>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,12 @@
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.health.HealthCheckRegistry;
import com.ryantenney.metrics.spring.MetricsBeanPostProcessorFactory;
import org.springframework.context.annotation.Configuration;

/**
* This is the main class providing the configuration behind the Metrics Java config.
* It is typically imported by adding {@link EnableMetrics @EnableMetrics} to an
* application {@link Configuration @Configuration} class.
* application {@link Configuration } class.
*
* @see MetricsConfigurer
* @see MetricsConfigurerAdapter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
Expand Down Expand Up @@ -204,13 +206,25 @@ public boolean optional(String key, String pattern, String message) {
return false;
}

public void rejectUnmatchedProperties() {
if (!allowedProperties.containsAll(properties.keySet())) {
final Set<String> unmatchedProperties = new HashSet<String>(properties.keySet());
unmatchedProperties.removeAll(allowedProperties);
throw new ValidationException("Properties " + Arrays.toString(unmatchedProperties.toArray()) + " are not permitted on this element.");
}
}
private static final Pattern namespacePattern = Pattern.compile("[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*:[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*");

public void rejectUnmatchedProperties() {
Set<String> unmatchedProperties = new HashSet<String>(properties.keySet());

// Remove any attrs from other namespaces.
for (Iterator<String> propNameItr = unmatchedProperties.iterator(); propNameItr.hasNext();) {
String propName = propNameItr.next();
if (namespacePattern.matcher(propName).matches()) {
propNameItr.remove();
}
}

if (!allowedProperties.containsAll(unmatchedProperties)) {
unmatchedProperties.removeAll(allowedProperties);
throw new ValidationException("Properties " + Arrays.toString(unmatchedProperties.toArray()) + " are not permitted on this element.");
}
}


private String errorMessage(String key, String message) {
return "Attribute '" + key + "'" + (message != null ? ": " + message : "");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/**
* Copyright (C) 2012 Ryan W Tenney ([email protected])
*
* 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 com.ryantenney.metrics.spring.reporter;

import java.util.HashMap;
import java.util.Map;

import org.junit.Test;

import static org.junit.Assert.fail;

/**
* Test for {@link AbstractReporterElementParser#validate(java.util.Map)}
*
* @author Dana P'Simer&lt;[email protected]&gt;
*/
public class AbstractReporterElementParserTest {

AbstractReporterElementParser target = new AbstractReporterElementParser() {

@Override
public String getType() {
return "test";
}

@Override
protected void validate(AbstractReporterElementParser.ValidationContext c) {
c.require("required");
c.require("requiredRegex", "[0-9]*");
c.optional("optional");
c.optional("optionalRegex", "[a-zA-z]*", "Must be only alphabetic characters");
c.rejectUnmatchedProperties();
}
};

@Test
public void testValidate() {
Map<String, String> properties = new HashMap<String, String>();
properties.put("required", "requiredValue");
properties.put("requiredRegex", "42");
properties.put("optionalRegex", "abcd");
target.validate(properties);
}

@Test
public void testValidateNotRequired() {
Map<String, String> properties = new HashMap<String, String>();
properties.put("optionalRegex", "abcd");
try {
target.validate(properties);
fail();
} catch (AbstractReporterElementParser.ValidationException ex) {
}
}

@Test
public void testValidateBadRequired() {
Map<String, String> properties = new HashMap<String, String>();
properties.put("required", "requiredValue");
properties.put("requriedRegex", "42");
properties.put("optionalRegex", "abcd");
try {
target.validate(properties);
fail();
} catch (AbstractReporterElementParser.ValidationException ex) {
}
}

@Test
public void testValidateBadOptional() {
Map<String, String> properties = new HashMap<String, String>();
properties.put("required", "requiredValue");
properties.put("optionalRegex", "a5bcd");
try {
target.validate(properties);
fail();
} catch (AbstractReporterElementParser.ValidationException ex) {
}
}

@Test
public void testValidateWithNamespaceDefinitions() {
Map<String, String> properties = new HashMap<String, String>();
properties.put("xmlns:foo", "http://foo.com/foo http://foo.com/foo/v1/foo.xsd");
properties.put("required", "requiredValue");
properties.put("requiredRegex", "42");
properties.put("optionalRegex", "abcd");
target.validate(properties);
}
}