forked from phoedos/pmd
[doc] Fix more external links
This commit is contained in:
parent
9f862f9ac9
commit
274497bbf4
@ -16,6 +16,6 @@ There are numerous ways of getting help:
|
||||
* You can also ask questions on [github discussions](https://github.com/pmd/pmd/discussions).
|
||||
|
||||
* Or you can join the [Mailing List](https://lists.sourceforge.net/lists/listinfo/pmd-devel) or browse
|
||||
through the archives ([archive1](http://java-pmd.30631.n5.nabble.com/), [archive2](http://web.archive.org/web/20160715035623/http://blog.gmane.org:80/gmane.comp.java.audit.pmd.devel)).
|
||||
through the [mailing list archive](https://sourceforge.net/p/pmd/mailman/pmd-devel/).
|
||||
|
||||
* Of course, you can also directly jump to our [source code on github](https://github.com/pmd/pmd).
|
||||
|
@ -2,13 +2,12 @@
|
||||
title: Developer Resources
|
||||
tags: [devdocs]
|
||||
permalink: pmd_devdocs_development.html
|
||||
last_updated: August 2017
|
||||
last_updated: March 2024
|
||||
---
|
||||
The next version of PMD will be developed in parallel with this release. We will release additional bugfix versions as needed.
|
||||
|
||||
## Source Code
|
||||
|
||||
The complete source code can be found on github:
|
||||
The complete source code can be found on Github:
|
||||
|
||||
* [github.com/pmd/pmd](https://github.com/pmd/pmd) - main PMD repository. Includes all the code to support all languages, including this documentation.
|
||||
* [github.com/pmd/pmd.github.io](https://github.com/pmd/pmd.github.io) - Contains the landing page [https://pmd.github.io](https://pmd.github.io)
|
||||
@ -18,7 +17,7 @@ The complete source code can be found on github:
|
||||
|
||||
## Continuous Integration
|
||||
|
||||
We use [Travis CI](https://travis-ci.com/pmd) as our ci service. The main repo and the eclipse plugin are built for
|
||||
We use [GitHub Actions](https://github.com/pmd/pmd/actions) as our ci service. The main repo and the eclipse plugin are built for
|
||||
every push. Each pull request is built as well.
|
||||
|
||||
The maven snapshot artifacts are deployed at [Sonatypes OSS snapshot repository](https://oss.sonatype.org/content/repositories/snapshots/net/sourceforge/pmd/pmd/).
|
||||
@ -27,7 +26,11 @@ Ready-to-use binary packages are uploaded to sourceforge at <https://sourceforge
|
||||
|
||||
## Documentation and Webpages
|
||||
|
||||
A [snapshot](http://pmd.sourceforge.net/snapshot) of the web site for the new version is generated travis-ci as well.
|
||||
Main documentation server is [docs.pmd-code.org](https://docs.pmd-code.org).
|
||||
|
||||
A [snapshot](http://docs.pmd-code.org/snapshot/) of the web site for the new version is generated by the ci job as well.
|
||||
|
||||
The latest release documentation is always available under [docs.pmd-code.org/latest](https://docs.pmd-code.org/latest/)
|
||||
|
||||
## Contributing
|
||||
|
||||
|
@ -6,6 +6,6 @@ tags: [languages, PmdCapableLanguage, CpdCapableLanguage]
|
||||
summary: "Modelica-specific features and guidance"
|
||||
---
|
||||
|
||||
[Modelica](https://modelica.org/modelicalanguage) is a language to model complex physical systems.
|
||||
[Modelica](https://modelica.org/language/) is a language to model complex physical systems.
|
||||
|
||||
{% include language_info.html name='Modelica' id='modelica' implementation='modelica::lang.modelica.ModelicaLanguageModule' supports_pmd=true supports_cpd=true since='6.21.0' %}
|
||||
|
@ -78,7 +78,7 @@ author: Tom Copeland <tom@infoether.org>
|
||||
mentions both PMD and CPD as useful code-checking tools.
|
||||
|
||||
* October 2005 - Levent Gurses' article "Improving Code Quality with PMD and Eclipse" in
|
||||
[EclipseZone](http://www.eclipsezone.com/articles/pmd/) talks about the PMD Eclipse plugin and explains many
|
||||
[EclipseZone](https://web.archive.org/web/20080807160502/http://www.eclipsezone.com/articles/pmd/) talks about the PMD Eclipse plugin and explains many
|
||||
different facets of PMD - XPath, writing rules, the AST, all that. Good stuff!
|
||||
|
||||
* June 2005 - Amit Chaturvedi's article "Java & Static Analysis" in
|
||||
@ -103,7 +103,7 @@ author: Tom Copeland <tom@infoether.org>
|
||||
|
||||
* June 2004 - [Open Source-Perlen](http://tinyurl.com/3dgpe) - A German article on PMD in Java Magazin
|
||||
|
||||
* June 2004 - [Improving Project Quality with PMD](http://jnb.ociweb.com/jnb/jnbJun2004.html) - Tom Wheeler's
|
||||
* June 2004 - [Improving Project Quality with PMD](https://web.archive.org/web/20211203041417/http://jnb.ociweb.com/jnb/jnbJun2004.html) - Tom Wheeler's
|
||||
"Java News Brief", June 2004 issue
|
||||
|
||||
* February 2004 - [Software Development](http://www.drdobbs.com/free-as-in-freedom/184415103) - Listed as one of
|
||||
|
@ -180,7 +180,7 @@ The tool comes with a rather extensive help text, simply running with `--help`!
|
||||
## Additional Java Runtime Options
|
||||
|
||||
PMD is executed via a Java runtime. In some cases, you might need to set additional runtime options, e.g.
|
||||
if you want to analyze a project, that uses one of OpenJDK's [Preview Language Features](http://openjdk.java.net/jeps/12).
|
||||
if you want to analyze a project, that uses one of OpenJDK's [JEP 12: Preview Language Features](https://openjdk.org/jeps/12).
|
||||
|
||||
Just set the environment variable `PMD_JAVA_OPTS` before executing PMD, e.g.
|
||||
|
||||
|
@ -529,7 +529,7 @@ CPD has been through three major incarnations:
|
||||
[here](http://www.onjava.com/pub/a/onjava/2003/03/12/pmd_cpd.html)).
|
||||
|
||||
* Then it was completely rewritten by Brian Ewins using the
|
||||
[Burrows-Wheeler transform](http://dogma.net/markn/articles/bwt/bwt.htm).
|
||||
[Burrows-Wheeler transform](https://en.wikipedia.org/wiki/Burrows%E2%80%93Wheeler_transform).
|
||||
|
||||
* Finally, it was rewritten by Steve Hawkins to use the
|
||||
[Karp-Rabin](http://www.nist.gov/dads/HTML/karpRabin.html) string matching algorithm.
|
||||
|
@ -20,7 +20,7 @@ sidebar: pmd_sidebar
|
||||
* For Windows: [Winzip](http://winzip.com) or the free [7-zip](http://www.7-zip.org/)
|
||||
* For Linux / Unix: [InfoZip](http://infozip.sourceforge.net/)
|
||||
|
||||
{% include note.html content="For executing the Designer (`pmd designer`) using [OpenJDK](http://jdk.java.net) or Java 11+, you need additionally [JavaFX](https://gluonhq.com/products/javafx/). Download it, extract it and set the environment variable JAVAFX_HOME pointing at that directory." %}
|
||||
{% include note.html content="For executing the Designer (`pmd designer`) using [OpenJDK](https://jdk.java.net) or Java 11+, you need additionally [JavaFX](https://gluonhq.com/products/javafx/). Download it, extract it and set the environment variable JAVAFX_HOME pointing at that directory." %}
|
||||
|
||||
|
||||
### Installation
|
||||
|
@ -57,8 +57,8 @@ pmd {
|
||||
|
||||
Source code for Gradles PMD Plugin is available here:
|
||||
|
||||
* [gradle/gradle code-quality](https://github.com/gradle/gradle/tree/master/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality)
|
||||
* [Pmd.java](https://github.com/gradle/gradle/blob/master/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/Pmd.java)
|
||||
* [PmdExtension.java](https://github.com/gradle/gradle/blob/master/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/PmdExtension.java)
|
||||
* [PmdPlugin.java](https://github.com/gradle/gradle/blob/master/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/PmdPlugin.java)
|
||||
* The default PMD version used by gradle: [DEFAULT_PMD_VERSION](https://github.com/gradle/gradle/blob/5e8d7b6b2eadf314767a4b3426db24e841b86ece/platforms/jvm/code-quality/src/main/groovy/org/gradle/api/plugins/quality/PmdPlugin.java#L67)
|
||||
* [gradle/gradle code-quality](https://github.com/gradle/gradle/tree/master/platforms/jvm/code-quality/src/main/groovy/org/gradle/api/plugins/quality)
|
||||
* [Pmd.java](https://github.com/gradle/gradle/blob/master/platforms/jvm/code-quality/src/main/groovy/org/gradle/api/plugins/quality/Pmd.java)
|
||||
* [PmdExtension.java](https://github.com/gradle/gradle/blob/master/platforms/jvm/code-quality/src/main/groovy/org/gradle/api/plugins/quality/PmdExtension.java)
|
||||
* [PmdPlugin.java](https://github.com/gradle/gradle/blob/master/platforms/jvm/code-quality/src/main/groovy/org/gradle/api/plugins/quality/PmdPlugin.java)
|
||||
* The default PMD version used by gradle: [DEFAULT_PMD_VERSION](https://github.com/gradle/gradle/blob/d6daeeb446e6a966c33efea5f3f5f1a2d96f6b8f/platforms/jvm/code-quality/src/main/groovy/org/gradle/api/plugins/quality/PmdPlugin.java#L66)
|
||||
|
@ -398,7 +398,7 @@ The rules have been moved into categories with PMD 6.
|
||||
|
||||
#### API Changes
|
||||
|
||||
See [Detailed Release Notes for PMD 7.0.0]({{ baseurl }}pmd_release_notes_pmd7.html#700).
|
||||
See [Detailed Release Notes for PMD 7]({{ baseurl }}pmd_release_notes_pmd7.html#700).
|
||||
|
||||
#### External Contributions
|
||||
* [#4093](https://github.com/pmd/pmd/pull/4093): \[apex] Summit-AST Apex module - Part 1 - [Edward Klimoshenko](https://github.com/eklimo) (@eklimo)
|
||||
|
@ -31,6 +31,9 @@ import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.concurrent.RunnableFuture;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
@ -66,20 +69,22 @@ public class DeadLinksChecker {
|
||||
// the link is actually pointing to a file in the pmd project
|
||||
private static final String LOCAL_FILE_PREFIX = "https://github.com/pmd/pmd/blob/master/";
|
||||
|
||||
// don't check links to PMD bugs/issues/pull-requests (performance optimization)
|
||||
// don't check links to PMD bugs/issues/pull-requests and some other sites (performance optimization)
|
||||
private static final List<String> IGNORED_URL_PREFIXES = Collections.unmodifiableList(Arrays.asList(
|
||||
"https://github.com/pmd/pmd/issues/",
|
||||
"https://github.com/pmd/pmd/pull/",
|
||||
"https://sourceforge.net/p/pmd/bugs/"
|
||||
"https://sourceforge.net/p/pmd/bugs/",
|
||||
"https://pmd.github.io/",
|
||||
"https://openjdk.org/jeps" // very slow...
|
||||
));
|
||||
|
||||
// prevent checking the same link multiple times
|
||||
private final Map<String, CompletableFuture<Integer>> urlResponseCache = new ConcurrentHashMap<>();
|
||||
private final Map<String, CompletableFuture<String>> urlResponseCache = new ConcurrentHashMap<>();
|
||||
|
||||
private final ExecutorService executorService = Executors.newCachedThreadPool();
|
||||
|
||||
|
||||
public void checkDeadLinks(Path rootDirectory) {
|
||||
public void checkDeadLinks(Path rootDirectory) throws InterruptedException {
|
||||
final Path pagesDirectory = rootDirectory.resolve("docs/pages");
|
||||
final Path docsDirectory = rootDirectory.resolve("docs");
|
||||
|
||||
@ -156,10 +161,7 @@ public class DeadLinksChecker {
|
||||
|
||||
Future<String> futureMessage =
|
||||
getCachedFutureResponse(linkTarget)
|
||||
.thenApply(c -> c >= 400)
|
||||
// It's important not to use the matcher in this mapper!
|
||||
// It may be exhausted at the time of execution
|
||||
.thenApply(dead -> dead ? String.format("%8d: %s", lineNo, linkText) : null);
|
||||
.thenApply(errorMessage -> errorMessage != null ? String.format("%8d: %s (%s)", lineNo, linkText, errorMessage) : null);
|
||||
|
||||
addDeadLink(fileToDeadLinks, mdFile, futureMessage);
|
||||
|
||||
@ -200,6 +202,8 @@ public class DeadLinksChecker {
|
||||
}
|
||||
|
||||
executorService.shutdown();
|
||||
LOG.info("Checking {} external links now...", checkedExternalLinks);
|
||||
Map<Path, List<String>> joined = joinFutures(fileToDeadLinks);
|
||||
|
||||
LOG.info("Scanned {} files for dead links.", scannedFiles);
|
||||
LOG.info(" Found {} external links, {} of those where checked.", foundExternalLinks, checkedExternalLinks);
|
||||
@ -208,15 +212,13 @@ public class DeadLinksChecker {
|
||||
LOG.info("External links weren't checked, set -D" + CHECK_EXTERNAL_LINKS_PROPERTY + "=true to enable it.");
|
||||
}
|
||||
|
||||
Map<Path, List<String>> joined = joinFutures(fileToDeadLinks);
|
||||
|
||||
if (joined.isEmpty()) {
|
||||
LOG.info("No errors found!");
|
||||
} else {
|
||||
LOG.warn("Found dead link(s):");
|
||||
for (Path file : joined.keySet()) {
|
||||
System.err.println(rootDirectory.relativize(file).toString());
|
||||
joined.get(file).forEach(LOG::warn);
|
||||
System.err.println(rootDirectory.relativize(file));
|
||||
joined.get(file).forEach(System.err::println);
|
||||
}
|
||||
throw new AssertionError("Dead links detected");
|
||||
}
|
||||
@ -276,9 +278,8 @@ public class DeadLinksChecker {
|
||||
while (captionMatcher.find()) {
|
||||
final String anchor = captionMatcher.group(1)
|
||||
.toLowerCase(Locale.ROOT)
|
||||
.replaceAll("'", "") // remove all apostrophes
|
||||
.replaceAll("[^a-z0-9_]+", "-") // replace all non-alphanumeric characters with dashes
|
||||
.replaceAll("^-+|-+$", ""); // trim leading or trailing dashes
|
||||
.replaceAll("'|\\.", "") // remove all apostrophes and dots
|
||||
.replaceAll("[^a-z0-9_]+", "-"); // replace all non-alphanumeric characters with dashes
|
||||
|
||||
htmlPages.add(pageUrl + "#" + anchor);
|
||||
}
|
||||
@ -308,46 +309,70 @@ public class DeadLinksChecker {
|
||||
}
|
||||
|
||||
|
||||
private CompletableFuture<Integer> getCachedFutureResponse(String url) {
|
||||
private CompletableFuture<String> getCachedFutureResponse(String url) {
|
||||
if (urlResponseCache.containsKey(url)) {
|
||||
LOG.info("response: HTTP {} (CACHED) on {}", urlResponseCache.get(url), url);
|
||||
return urlResponseCache.get(url);
|
||||
CompletableFuture<String> cachedFuture = urlResponseCache.get(url);
|
||||
if (cachedFuture.isDone()) {
|
||||
try {
|
||||
LOG.debug("response: HTTP {} (CACHED) on {}", cachedFuture.get(100, TimeUnit.MILLISECONDS), url);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
} catch (ExecutionException e) {
|
||||
LOG.info("response failed: (CACHED) on {}", url);
|
||||
} catch (TimeoutException e) {
|
||||
// actually, this shouldn't happen, as we checked with isDone() before
|
||||
LOG.info("response future timeout: (CACHED) on {}", url);
|
||||
}
|
||||
}
|
||||
return cachedFuture;
|
||||
} else {
|
||||
// process asynchronously
|
||||
CompletableFuture<Integer> futureResponse = CompletableFuture.supplyAsync(() -> computeHttpResponse(url), executorService);
|
||||
CompletableFuture<String> futureResponse = CompletableFuture.supplyAsync(() -> computeHttpResponse(url), executorService);
|
||||
urlResponseCache.put(url, futureResponse);
|
||||
return futureResponse;
|
||||
}
|
||||
}
|
||||
|
||||
// limit parallel requests to avoid 429 Too Many Requests
|
||||
private Semaphore semaphore = new Semaphore(3);
|
||||
|
||||
private int computeHttpResponse(String url) {
|
||||
private String computeHttpResponse(String url) {
|
||||
try {
|
||||
final HttpURLConnection httpURLConnection = (HttpURLConnection) new URL(url).openConnection();
|
||||
httpURLConnection.setRequestMethod("HEAD");
|
||||
httpURLConnection.setConnectTimeout(5000);
|
||||
httpURLConnection.setReadTimeout(15000);
|
||||
httpURLConnection.connect();
|
||||
final int responseCode = httpURLConnection.getResponseCode();
|
||||
semaphore.acquire();
|
||||
// logging to see something is going on...
|
||||
LOG.info("Checking {} now...", url);
|
||||
|
||||
final HttpURLConnection httpUrlConnection = (HttpURLConnection) new URL(url).openConnection();
|
||||
httpUrlConnection.setRequestMethod("HEAD");
|
||||
httpUrlConnection.setConnectTimeout((int) TimeUnit.SECONDS.toMillis(60));
|
||||
httpUrlConnection.setReadTimeout((int) TimeUnit.SECONDS.toMillis(60));
|
||||
httpUrlConnection.connect();
|
||||
int responseCode = httpUrlConnection.getResponseCode();
|
||||
|
||||
String response = "HTTP " + responseCode;
|
||||
if (httpURLConnection.getHeaderField("Location") != null) {
|
||||
response += ", Location: " + httpURLConnection.getHeaderField("Location");
|
||||
if (httpUrlConnection.getHeaderField("Location") != null) {
|
||||
response += ", Location: " + httpUrlConnection.getHeaderField("Location");
|
||||
}
|
||||
|
||||
LOG.debug("response: {} on {}", response, url);
|
||||
|
||||
// success (HTTP 2xx) or redirection (HTTP 3xx)
|
||||
return responseCode;
|
||||
// everything above 400 is an error
|
||||
if (responseCode >= 400) {
|
||||
LOG.debug("response failure: {} on {}", responseCode, url);
|
||||
return "HTTP " + responseCode + " " + httpUrlConnection.getResponseMessage();
|
||||
}
|
||||
|
||||
} catch (IOException ex) {
|
||||
// success (HTTP 2xx) or redirection (HTTP 3xx) is ok
|
||||
return null; // no error
|
||||
} catch (IOException | InterruptedException ex) {
|
||||
LOG.debug("response: {} on {} : {}", ex.getClass().getName(), url, ex.getMessage());
|
||||
return 599;
|
||||
return ex.getClass().getName() + ": " + ex.getMessage();
|
||||
} finally {
|
||||
semaphore.release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
public static void main(String[] args) throws IOException, InterruptedException {
|
||||
if (args.length != 1) {
|
||||
System.err.println("Wrong arguments!");
|
||||
System.err.println();
|
||||
|
@ -69,7 +69,7 @@ If the call to `setAccessible` is wrapped within a `PrivilegedAction`, then the
|
||||
is assumed to be deliberate and is not reported.
|
||||
|
||||
Note that with Java 17 the Security Manager, which is used for `PrivilegedAction` execution,
|
||||
is deprecated: [JEP 411: Deprecate the Security Manager for Removal](https://openjdk.java.net/jeps/411).
|
||||
is deprecated: [JEP 411: Deprecate the Security Manager for Removal](https://openjdk.org/jeps/411).
|
||||
For future-proof code, deliberate access alteration should be suppressed using the usual
|
||||
suppression methods (e.g. by using `@SuppressWarnings` annotation).
|
||||
</description>
|
||||
|
@ -236,7 +236,7 @@ public class DateStuff {
|
||||
<description>
|
||||
The FileInputStream and FileOutputStream classes contains a finalizer method which will cause garbage
|
||||
collection pauses.
|
||||
See [JDK-8080225](https://bugs.openjdk.java.net/browse/JDK-8080225) for details.
|
||||
See [JDK-8080225](https://bugs.openjdk.org/browse/JDK-8080225) for details.
|
||||
|
||||
The FileReader and FileWriter constructors instantiate FileInputStream and FileOutputStream,
|
||||
again causing garbage collection issues while finalizer methods are called.
|
||||
@ -777,11 +777,11 @@ if (s.indexOf('d') {}
|
||||
typeResolution="true"
|
||||
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#useiostreamswithapachecommonsfileitem">
|
||||
<description>
|
||||
Problem: Use of [FileItem.get()](https://commons.apache.org/proper/commons-fileupload/apidocs/org/apache/commons/fileupload/FileItem.html#get--)
|
||||
and [FileItem.getString()](https://commons.apache.org/proper/commons-fileupload/apidocs/org/apache/commons/fileupload/FileItem.html#getString--)
|
||||
Problem: Use of [FileItem.get()](https://javadoc.io/static/commons-fileupload/commons-fileupload/1.5/org/apache/commons/fileupload/FileItem.html#get--)
|
||||
and [FileItem.getString()](https://javadoc.io/static/commons-fileupload/commons-fileupload/1.5/org/apache/commons/fileupload/FileItem.html#getString--)
|
||||
could exhaust memory since they load the entire file into memory.
|
||||
|
||||
Solution: Use [FileItem.getInputStream()](https://commons.apache.org/proper/commons-fileupload/apidocs/org/apache/commons/fileupload/FileItem.html#getInputStream--)
|
||||
Solution: Use [FileItem.getInputStream()](https://javadoc.io/static/commons-fileupload/commons-fileupload/1.5/org/apache/commons/fileupload/FileItem.html#getInputStream--)
|
||||
and buffering.
|
||||
</description>
|
||||
<priority>3</priority>
|
||||
|
Loading…
x
Reference in New Issue
Block a user