001/*******************************************************************************
002 * This software is provided as a supplement to the authors' textbooks on digital
003 * image processing published by Springer-Verlag in various languages and editions.
004 * Permission to use and distribute this software is granted under the BSD 2-Clause
005 * "Simplified" License (see http://opensource.org/licenses/BSD-2-Clause).
006 * Copyright (c) 2006-2023 Wilhelm Burger, Mark J. Burge. All rights reserved.
007 * Visit https://imagingbook.com for additional details.
008 ******************************************************************************/
009package imagingbook.core.jdoc;
010
011import java.net.MalformedURLException;
012import java.net.URISyntaxException;
013import java.net.URL;
014import java.util.Objects;
015
016/**
017 * Classes implementing this interface provide a URL that links to the associated JavaDoc page (returned by method
018 * {@link #getJavaDocUrl()}). This is mainly intended as help information in user dialogs of ImageJ plugins.
019 */
020public interface JavaDocHelp {
021
022    /**
023     * Returns a JavaDoc URL for this object's class.
024     * @return a JavaDoc URL
025     */
026    public default String getJavaDocUrl() {
027        String url = getJavaDocUrl(this.getClass());
028        if (Objects.isNull(url)) {
029            throw new RuntimeException("no JavaDoc URL available");
030        }
031        return url;
032    }
033
034    /**
035     * Returns the JavaDoc URL for the specified class, which is obtained from the value of {@link JavaDocBaseUrl}
036     * annotations present at the PACKAGE level (in file {@code package-info.java}). Note that there is no guarantee
037     * that the associated JavaDoc exists at the resulting address (this is not checked by unit tests).
038     *
039     * @param clazz a class reference
040     * @return a string with the web URL for the JavaDoc information of the specified class
041     */
042    public static String getJavaDocUrl(Class<?> clazz) {
043        // Module mod = clazz.getModule();
044        Package pkg = clazz.getPackage();
045        String baseUrl = null;
046
047        if (pkg != null && pkg.isAnnotationPresent(JavaDocBaseUrl.class)) {
048            baseUrl = pkg.getAnnotation(JavaDocBaseUrl.class).value();
049            // baseUrl is assumed to end with '/'
050            if (!baseUrl.endsWith("/")) {
051                throw new RuntimeException("JavaDocBaseUrl value must end with '/': " + baseUrl);
052            }
053        }
054
055        if (baseUrl == null) {
056            return null;
057        }
058        else {
059            String classCName = clazz.getCanonicalName();
060            String url = baseUrl + classCName.replace('.', '/') + ".html";
061            // valid URL is checked during testing!
062            return url;
063        }
064    }
065
066    /**
067     * Checks if the specified string is a valid URL. Does the standard (non-perfect) URL/URI check followed by some
068     * additional checks that could indicate likely definition errors.
069     *
070     * @param url the  string to be checked
071     * @return true iff a valid URL
072     */
073    public static boolean isValidURL(String url) {
074        try {
075            new URL(url).toURI();
076        } catch (URISyntaxException | MalformedURLException e) {
077            return false;
078        }
079        // do additional checks on url:
080        {   // check for multiple "//"s
081            int k1 = url.indexOf("//"); // there must be at least one "//"
082            if (k1 < 0)
083                return false;
084            int k2 = url.indexOf("//", k1 + 2);
085            if (k2 > 0)                 // there must not be another "//"
086                return false;
087            if (url.contains(".."))
088                return false;
089        }
090        return true;
091    }
092
093    // public static void main(String[] args) {
094    //     String[] urls = {
095    //             "https://www.geeksforgeeks.org/",
096    //             "https://www.geeksforgeeks..org/foo/3",
097    //             "http://www.geeksforgeeks.org//check-if-url-is-valid-or-not-in-java/",
098    //             "http//foo",
099    //             "imagingbook.com"
100    //     };
101    //     for (String url : urls) {
102    //         boolean passed = isValidURL(url);
103    //         System.out.println(passed + " | " + url);
104    //     }
105    // }
106
107    // true | https://www.geeksforgeeks.org/
108    // false | https://www.geeksforgeeks..org/foo/3
109    // false | http://www.geeksforgeeks.org//check-if-url-is-valid-or-not-in-java/
110    // false | http//foo
111    // false | imagingbook.com
112
113}