diff --git a/pmd-core/pom.xml b/pmd-core/pom.xml
index 7d06b05944..c1163fabac 100644
--- a/pmd-core/pom.xml
+++ b/pmd-core/pom.xml
@@ -101,6 +101,11 @@
runtime
+
+ com.github.tomakehurst
+ wiremock
+ test
+
junit
junit
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetReferenceId.java b/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetReferenceId.java
index dc15e14ed7..256b494665 100644
--- a/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetReferenceId.java
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetReferenceId.java
@@ -4,16 +4,20 @@
package net.sourceforge.pmd;
import java.io.File;
+import java.io.IOException;
import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang3.StringUtils;
-
import net.sourceforge.pmd.util.ResourceLoader;
import net.sourceforge.pmd.util.StringUtil;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+
/**
* This class is used to parse a RuleSet reference value. Most commonly used for specifying a
* RuleSet to process, or in a Rule 'ref' attribute value in the RuleSet XML. The RuleSet reference
@@ -119,7 +123,13 @@ public class RuleSetReferenceId {
// Damn this parsing sucks, but my brain is just not working to let me
// write a simpler scheme.
- if (isHttpUrl(id) || isFullRuleSetName(id)) {
+ if (isValidUrl(id)) {
+ // A full RuleSet name
+ external = true;
+ ruleSetFileName = StringUtils.strip(id);
+ allRules = true;
+ ruleName = null;
+ } else if (isFullRuleSetName(id)) {
// A full RuleSet name
external = true;
ruleSetFileName = id;
@@ -130,7 +140,20 @@ public class RuleSetReferenceId {
String tempRuleSetFileName = tempRuleName != null && id != null ?
id.substring(0, id.length() - tempRuleName.length() - 1) : id;
- if (isFullRuleSetName(tempRuleSetFileName)) {
+ if (isValidUrl(tempRuleSetFileName)) {
+ // remaining part is a xml ruleset file, so the tempRuleName is probably a real rule name
+ external = true;
+ ruleSetFileName = StringUtils.strip(tempRuleSetFileName);
+ ruleName = StringUtils.strip(tempRuleName);
+ allRules = tempRuleName == null;
+ } else if (isHttpUrl(id)) {
+ // it's a url, we can't determine whether it's a full ruleset or a single rule - so falling back to
+ // a full RuleSet name
+ external = true;
+ ruleSetFileName = StringUtils.strip(id);
+ allRules = true;
+ ruleName = null;
+ } else if (isFullRuleSetName(tempRuleSetFileName)) {
// remaining part is a xml ruleset file, so the tempRuleName is probably a real rule name
external = true;
ruleSetFileName = tempRuleSetFileName;
@@ -256,6 +279,25 @@ public class RuleSetReferenceId {
return false;
}
+
+ private static boolean isValidUrl(String name) {
+ if (isHttpUrl(name)) {
+ String url = StringUtils.strip(name);
+ try {
+ HttpURLConnection connection = (HttpURLConnection)new URL(url).openConnection();
+ connection.setRequestMethod("HEAD");
+ connection.setConnectTimeout(5000);
+ connection.setReadTimeout(5000);
+ int responseCode = connection.getResponseCode();
+ if (responseCode == 200) {
+ return true;
+ }
+ } catch (IOException e) {
+ return false;
+ }
+ }
+ return false;
+ }
private static boolean isFullRuleSetName(String name) {
diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetReferenceIdTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetReferenceIdTest.java
index be4726fdb5..80293da5cc 100644
--- a/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetReferenceIdTest.java
+++ b/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetReferenceIdTest.java
@@ -3,14 +3,28 @@
*/
package net.sourceforge.pmd;
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.findAll;
+import static com.github.tomakehurst.wiremock.client.WireMock.get;
+import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.head;
+import static com.github.tomakehurst.wiremock.client.WireMock.headRequestedFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching;
+import static com.github.tomakehurst.wiremock.client.WireMock.verify;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.File;
+import java.io.InputStream;
import java.util.List;
+import org.apache.commons.io.IOUtils;
import org.junit.Test;
+import com.github.tomakehurst.wiremock.junit.WireMockRule;
+
public class RuleSetReferenceIdTest {
private static void assertRuleSetReferenceId(final boolean expectedExternal, final String expectedRuleSetFileName,
@@ -83,12 +97,63 @@ public class RuleSetReferenceIdTest {
public void constructor_GivenHttpUrlId_SucceedsAndProcessesIdCorrectly() {
final String sonarRulesetUrlId =
- " http://localhost:9000/profiles/export?format=pmd&language=java&name=Sonar%2520way ";
+ "http://localhost:54321/profiles/export?format=pmd&language=java&name=Sonar%2520way";
- RuleSetReferenceId ruleSetReferenceId = new RuleSetReferenceId(sonarRulesetUrlId);
+ RuleSetReferenceId ruleSetReferenceId = new RuleSetReferenceId(" " + sonarRulesetUrlId + " ");
assertRuleSetReferenceId(true, sonarRulesetUrlId, true, null, sonarRulesetUrlId, ruleSetReferenceId);
}
+ @org.junit.Rule
+ public WireMockRule wireMockRule = new WireMockRule(0);
+
+ @Test
+ public void constructor_GivenHttpUrl_InputStream() throws Exception {
+ String path = "/profiles/export?format=pmd&language=java&name=Sonar%2520way";
+ String rulesetUrl = "http://localhost:" + wireMockRule.port() + path;
+ stubFor(head(urlEqualTo(path)).willReturn(aResponse().withStatus(200)));
+ stubFor(get(urlEqualTo(path)).willReturn(aResponse().withStatus(200).withHeader("Content-type", "text/xml").withBody("xyz")));
+
+ RuleSetReferenceId ruleSetReferenceId = new RuleSetReferenceId(" " + rulesetUrl + " ");
+ assertRuleSetReferenceId(true, rulesetUrl, true, null, rulesetUrl, ruleSetReferenceId);
+
+ InputStream inputStream = ruleSetReferenceId.getInputStream(RuleSetReferenceIdTest.class.getClassLoader());
+ String loaded = IOUtils.toString(inputStream, "UTF-8");
+ assertEquals("xyz", loaded);
+
+ verify(1, headRequestedFor(urlEqualTo(path)));
+ verify(0, headRequestedFor(urlEqualTo("/profiles")));
+ verify(1, getRequestedFor(urlEqualTo(path)));
+ assertEquals(1, findAll(headRequestedFor(urlMatching(".*"))).size());
+ assertEquals(1, findAll(getRequestedFor(urlMatching(".*"))).size());
+ }
+
+ @Test
+ public void constructor_GivenHttpUrl_SingleRule_InputStream() throws Exception {
+ String path = "/profiles/export?format=pmd&language=java&name=Sonar%2520way";
+ String completePath = path + "/DummyBasicMockRule";
+ String hostpart = "http://localhost:" + wireMockRule.port();
+ String basicRuleSet = IOUtils.toString(RuleSetReferenceId.class.getResourceAsStream("/rulesets/dummy/basic.xml"));
+
+ stubFor(head(urlEqualTo(completePath)).willReturn(aResponse().withStatus(404)));
+ stubFor(head(urlEqualTo(path)).willReturn(aResponse().withStatus(200).withHeader("Content-type", "text/xml")));
+ stubFor(get(urlEqualTo(path)).willReturn(aResponse().withStatus(200).withHeader("Content-type", "text/xml").withBody(basicRuleSet)));
+
+
+ RuleSetReferenceId ruleSetReferenceId = new RuleSetReferenceId(" " + hostpart + completePath + " ");
+ assertRuleSetReferenceId(true, hostpart + path, false, "DummyBasicMockRule", hostpart + completePath, ruleSetReferenceId);
+
+ InputStream inputStream = ruleSetReferenceId.getInputStream(RuleSetReferenceIdTest.class.getClassLoader());
+ String loaded = IOUtils.toString(inputStream, "UTF-8");
+ assertEquals(basicRuleSet, loaded);
+
+ verify(1, headRequestedFor(urlEqualTo(completePath)));
+ verify(1, headRequestedFor(urlEqualTo(path)));
+ verify(1, getRequestedFor(urlEqualTo(path)));
+ verify(0, getRequestedFor(urlEqualTo(completePath)));
+ assertEquals(2, findAll(headRequestedFor(urlMatching(".*"))).size());
+ assertEquals(1, findAll(getRequestedFor(urlMatching(".*"))).size());
+ }
+
@Test
public void testOneSimpleRuleSet() {
diff --git a/pom.xml b/pom.xml
index cead6de97a..550f2b1f6f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -714,6 +714,11 @@
slf4j-api
1.7.7
+
+ com.github.tomakehurst
+ wiremock
+ 1.52
+