diff --git a/src/main/java/fr/packageviewer/LoggerManager.java b/src/main/java/fr/packageviewer/LoggerManager.java index c7b17e6..18240a3 100644 --- a/src/main/java/fr/packageviewer/LoggerManager.java +++ b/src/main/java/fr/packageviewer/LoggerManager.java @@ -2,15 +2,37 @@ package fr.packageviewer; import java.util.logging.*; +/** + * The LoggerManager class allows for basic debug output management using + * Java's default logging class. + * + * @author R.Thomas + * @version 1.0 + */ public class LoggerManager { - + /** + * Default log level, should be INFO + */ private static final Level DEFAULT_LOG_LEVEL = Level.INFO; - public static Logger getLogger(String name){ + /** + * Static factory for the Logger class + * + * @param name String, of the logger to create + * @return Logger, a new logger + */ + public static Logger getLogger(String name) { return getLogger(name, DEFAULT_LOG_LEVEL); } - public static Logger getLogger(String name, Level level){ + /** + * Main static factory for the Logger class + * + * @param name String, name of the logger to create + * @param level Level, the level of severity of the logger + * @return Logger, a new logger + */ + public static Logger getLogger(String name, Level level) { Logger logger = Logger.getLogger(name); logger.setLevel(level); diff --git a/src/main/java/fr/packageviewer/Pair.java b/src/main/java/fr/packageviewer/Pair.java index 1a5763d..75db71f 100644 --- a/src/main/java/fr/packageviewer/Pair.java +++ b/src/main/java/fr/packageviewer/Pair.java @@ -1,34 +1,74 @@ package fr.packageviewer; -public class Pair { +/** + * The Pair class stores two objects of distinct type + * + * @author R.Thomas + * @version 1.0 + */ +public class Pair { private K first; private V second; + /** + * Empty Constructor for the Pair class + */ public Pair() { } + /** + * Main Constructor for the Pair class + * + * @param first, the first object to be stored + * @param second the second object to be stored + */ public Pair(K first, V second) { this.first = first; this.second = second; } + /** + * Getter for the attribute first + * + * @return the object stored in the attribute first + */ public K getFirst() { return first; } + /** + * Setter for the attribute first + * + * @param first Store the given object in the attribute first + */ public void setFirst(K first) { this.first = first; } + /** + * Getter for the attribute second + * + * @return the object stored in the attribute second + */ public V getSecond() { return second; } + /** + * Setter for the attribute second + * + * @param second Store the given object in the attribute second + */ public void setSecond(V second) { this.second = second; } + /** + * Returns a string reprensentation of the pair + * + * @return String, string reprensentation of the pair + */ @Override public String toString() { return "Pair{key=%s,value=%s}".formatted(first, second); diff --git a/src/main/java/fr/packageviewer/distribution/ArchDistribution.java b/src/main/java/fr/packageviewer/distribution/ArchDistribution.java index 4fb7367..1737f00 100644 --- a/src/main/java/fr/packageviewer/distribution/ArchDistribution.java +++ b/src/main/java/fr/packageviewer/distribution/ArchDistribution.java @@ -15,85 +15,108 @@ import fr.packageviewer.pack.SearchedPackage; import fr.packageviewer.parser.AsyncRequestsParser; import org.json.*; +/** + * This class handles package requests for Arch linux. All return objects in + * this class are wrapped by a CompletableFuture to ensure async workload. + * + * @author C.Marla, R.Thomas + * @version 1.0 + */ public class ArchDistribution extends AsyncRequestsParser implements Distribution { + /** + * Logger object used to split debug output and the application output + */ private static final Logger logger = LoggerManager.getLogger("ArchDistribution"); - private static String trimAfterCharacters(String str, String trimAfterCharacters){ - for(char c : trimAfterCharacters.toCharArray()){ + /** + * This method remove all characters in the first string passed as + * parametter after one of the character in the second string if found + * in the first string + * + * @param str String, the string to trim + * @param trimAfterCharacters String, the character that delimits our string + * @return + */ + private static String trimAfterCharacters(String str, String trimAfterCharacters) { + for (char c : trimAfterCharacters.toCharArray()) { int index = str.indexOf(c); - if(index>0)str = str.substring(index); + if (index > 0) + str = str.substring(index); } return str; } -/** - * Will return the String json of the package from the Arch Linux API - * @param packageName the package name to get the json from - * @return json of the package - */ + /** + * This function return a package from arch package api in the form of a Pair + * Composed of a Package object, and a set of string containing the names of + * the dependecies of the package. + * + * @param packageName String, The package's exact name + * @return Pair of Package and Set of String + */ + @Override + public CompletableFuture>> getPackageFromAPI(String packageName) { + // create a new http client + HttpClient client = HttpClient.newHttpClient(); + // and create its url + HttpRequest request = HttpRequest + .newBuilder(URI.create("https://archlinux.org/packages/search/json/?name=" + packageName)).build(); -@Override -public CompletableFuture>> getPackageFromAPI(String packageName) { - // create a new http client - HttpClient client = HttpClient.newHttpClient(); - // and create its url - HttpRequest request = HttpRequest.newBuilder(URI.create("https://archlinux.org/packages/search/json/?name="+packageName)).build(); + CompletableFuture>> futureResult = new CompletableFuture<>(); + client.sendAsync(request, HttpResponse.BodyHandlers.ofString()).thenAccept(result -> { - CompletableFuture>> futureResult = new CompletableFuture<>(); - client.sendAsync(request, HttpResponse.BodyHandlers.ofString()).thenAccept(result ->{ + JSONObject json = new JSONObject(result.body()); - JSONObject json = new JSONObject(result.body()); + JSONArray resultsArrayJson = json.getJSONArray("results"); + if (resultsArrayJson.length() == 0) { + // unknown package, probably an abstract dependency + futureResult.complete(null); + return; + } + JSONObject resultJson = resultsArrayJson.getJSONObject(0); - JSONArray resultsArrayJson = json.getJSONArray("results"); - if(resultsArrayJson.length()==0){ - // unknown package, probably an abstract dependency + // get infos + + Set dependenciesNames = new HashSet<>(); + for (Object dependency : resultJson.getJSONArray("depends")) { + dependenciesNames.add(trimAfterCharacters((String) dependency, "<>=")); + } + futureResult.complete(new Pair<>( + new Package( + resultJson.getString("pkgname"), + resultJson.getString("pkgver"), + resultJson.getString("repo"), + resultJson.getString("pkgdesc"), + "arch"), + dependenciesNames)); + }).exceptionally(error -> { + error.printStackTrace(); + logger.warning("Error while fetching package %s from the API : \n%s".formatted(packageName, error)); futureResult.complete(null); - return; - } - JSONObject resultJson = resultsArrayJson.getJSONObject(0); + return null; + }); - // get infos + return futureResult; - Set dependenciesNames = new HashSet<>(); - for(Object dependency : resultJson.getJSONArray("depends")){ - dependenciesNames.add(trimAfterCharacters((String)dependency, "<>=")); - } - futureResult.complete(new Pair<>( - new Package( - resultJson.getString("pkgname"), - resultJson.getString("pkgver"), - resultJson.getString("repo"), - resultJson.getString("pkgdesc"), - "arch" - ), - dependenciesNames - )); - }).exceptionally(error ->{ - error.printStackTrace(); - logger.warning("Error while fetching package %s from the API : \n%s".formatted(packageName, error)); - futureResult.complete(null); - return null; - }); + } - return futureResult; - -} - -/** - * Search for a package and return a list of packages - * @param packageName the package name to search - * @return - */ - public CompletableFuture> searchPackage(String packageName){ + /** + * Search for a package matching a pattern and return a list of packages and + * return a list of string matching this pattern. + * + * @param packageName String, the pattern to search in the repositories + * @return List of SearchedPackage objects + */ + public CompletableFuture> searchPackage(String packageName) { HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create("https://archlinux.org/packages/search/json/?q="+packageName)) + .uri(URI.create("https://archlinux.org/packages/search/json/?q=" + packageName)) .build(); CompletableFuture> futureSearchedPackages = new CompletableFuture<>(); - client.sendAsync(request, HttpResponse.BodyHandlers.ofString()).thenAccept(result->{ + client.sendAsync(request, HttpResponse.BodyHandlers.ofString()).thenAccept(result -> { List searchedPackagesList = new ArrayList<>(); JSONObject json = new JSONObject(result.body()); @@ -104,22 +127,19 @@ public CompletableFuture>> getPackageFromAPI(String pa JSONObject searchResultJson = (JSONObject) searchResultObj; // add package into to list searchedPackagesList.add(new SearchedPackage( - searchResultJson.getString("pkgname"), - searchResultJson.getString("pkgver"), - searchResultJson.getString("repo"), - searchResultJson.getString("pkgdesc"), - "arch" - )); + searchResultJson.getString("pkgname"), + searchResultJson.getString("pkgver"), + searchResultJson.getString("repo"), + searchResultJson.getString("pkgdesc"), + "arch")); } - futureSearchedPackages.complete(searchedPackagesList); - }).exceptionally(error->{ + futureSearchedPackages.complete(searchedPackagesList); + }).exceptionally(error -> { error.printStackTrace(); futureSearchedPackages.complete(Collections.emptyList()); return null; }); - - return futureSearchedPackages; } diff --git a/src/main/java/fr/packageviewer/distribution/Distribution.java b/src/main/java/fr/packageviewer/distribution/Distribution.java index 7e8cb6d..255f000 100644 --- a/src/main/java/fr/packageviewer/distribution/Distribution.java +++ b/src/main/java/fr/packageviewer/distribution/Distribution.java @@ -7,7 +7,32 @@ import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Future; +/** + * This interface specifies the methods needed by a distribtion to be parsable. + * + * @author R.Thomas + * @version 1.0 + */ public interface Distribution { + /** + * Search for a package matching a pattern and return a list of packages and + * return a list of string matching this pattern. + * + * @param packageName String, the pattern to search in the repositories + * @return List of SearchedPackage objects + */ Future> searchPackage(String packageName); + + /** + * This function returns a fully completed package containing all + * information about the package identified by it's exact name passed as + * parametter, the package contains in its dependency list fully formed + * packages that also contains its dependencies, the dependency depth is + * specified by the parametter with the same name. + * + * @param packageName String, The package's exact name + * @param depth int, the depth of the dependency tree + * @return Package, the fully completed package + */ Future getPackageTree(String packageName, int depth); } diff --git a/src/main/java/fr/packageviewer/distribution/FedoraDistribution.java b/src/main/java/fr/packageviewer/distribution/FedoraDistribution.java index 8de585e..b11f86d 100644 --- a/src/main/java/fr/packageviewer/distribution/FedoraDistribution.java +++ b/src/main/java/fr/packageviewer/distribution/FedoraDistribution.java @@ -14,23 +14,41 @@ import fr.packageviewer.pack.Package; import fr.packageviewer.pack.SearchedPackage; import fr.packageviewer.LoggerManager; +/** + * This class handles package requests for Fedora. All return objects in + * this class are wrapped by a CompletableFuture to ensure async workload. + * + * @author S.Djalim, R.Thomas + * @version 1.0 + */ public class FedoraDistribution extends AsyncRequestsParser implements Distribution { + /** + * Logger object used to split debug output and the application output + */ private static final Logger logger = LoggerManager.getLogger("FedoraDistribution"); + /** + * This function return a package from Fedora metadata api in the form of a + * Pair Composed of a Package object, and a set of string containing the + * names of the dependecies of the package. + * + * @param packageName String, The package's exact name + * @return Pair of Package and Set of String + */ protected CompletableFuture>> getPackageFromAPI(String packageName) { // create a new http client HttpClient client = HttpClient.newHttpClient(); // and create its url - String url = "https://mdapi.fedoraproject.org/rawhide/pkg/"+packageName+""; + String url = "https://mdapi.fedoraproject.org/rawhide/pkg/" + packageName + ""; HttpRequest request = HttpRequest.newBuilder(URI.create(url)).build(); CompletableFuture>> futureResult = new CompletableFuture<>(); - client.sendAsync(request, HttpResponse.BodyHandlers.ofString()).thenAccept(result->{ + client.sendAsync(request, HttpResponse.BodyHandlers.ofString()).thenAccept(result -> { String body = result.body(); - if(body.contains("404: Not Found")) { + if (body.contains("404: Not Found")) { futureResult.complete(null); return; } @@ -71,7 +89,14 @@ public class FedoraDistribution extends AsyncRequestsParser implements Distribut // if there's an error, return an empty string return futureResult; } - + + /** + * Search for a package matching a pattern and return a list of packages and + * return a list of string matching this pattern. + * + * @param packageName String, the pattern to search in the repositories + * @return List of SearchedPackage objects + */ @Override public CompletableFuture> searchPackage(String packageName) { @@ -84,7 +109,7 @@ public class FedoraDistribution extends AsyncRequestsParser implements Distribut CompletableFuture> futureSearchedPackages = new CompletableFuture<>(); - client.sendAsync(request, HttpResponse.BodyHandlers.ofString()).thenAccept(result->{ + client.sendAsync(request, HttpResponse.BodyHandlers.ofString()).thenAccept(result -> { JSONObject json = new JSONObject(result.body()); List searchedPackagesList = new ArrayList<>(); @@ -112,7 +137,7 @@ public class FedoraDistribution extends AsyncRequestsParser implements Distribut } futureSearchedPackages.complete(searchedPackagesList); - }).exceptionally(error->{ + }).exceptionally(error -> { error.printStackTrace(); futureSearchedPackages.complete(Collections.emptyList()); return null; diff --git a/src/main/java/fr/packageviewer/pack/Package.java b/src/main/java/fr/packageviewer/pack/Package.java index c05a4e5..34a23a1 100644 --- a/src/main/java/fr/packageviewer/pack/Package.java +++ b/src/main/java/fr/packageviewer/pack/Package.java @@ -4,25 +4,73 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +/** + * The Package class stores all metadata needed for a fully completed package. + * + * @author C.Marla, R.Thomas, S.Djalim + * @version 1.0 + */ public class Package extends SearchedPackage { + /** + * List of package storing all of the dependencies of the package + */ private final List deps; + /** + * Getter for the deps attribute + * + * @return List, List of package storing all of the dependencies of the package + */ public List getDeps() { return deps; } + /** + * This method adds to the dependency list the package passed as parametter. + * + * @param pack Package, the package to add as dependency + */ public void addDep(Package pack) { deps.add(pack); } + /** + * Second constructor for the Package class, allows to create a package + * without supplying a list of dependencies. + * + * @param name String, name of the package + * @param version String, version of the package + * @param repo String, repository where the package is located + * @param description String, description of the package + * @param distribution String, the distribution where this specific package + * belongs + */ public Package(String name, String version, String repo, String description, String distribution) { this(name, version, repo, description, distribution, new ArrayList<>()); } - public Package(String name, String version, String repo, String description, String distribution, List deps) { + + /** + * Main constructor for the Package class + * + * @param name String, name of the package + * @param version String, version of the package + * @param repo String, repository where the package is located + * @param description String, description of the package + * @param distribution String, the distribution where this specific package + * belongs + * @param deps List of Package, dependencies of the package + */ + public Package(String name, String version, String repo, String description, String distribution, + List deps) { super(name, version, repo, description, distribution); this.deps = deps; } + /** + * Returns a string reprensentation of the package + * + * @return String, string reprensentation of the package + */ @Override public String toString() { return "Package{%s,deps=%s}".formatted(super.toString(), deps); diff --git a/src/main/java/fr/packageviewer/pack/SearchedPackage.java b/src/main/java/fr/packageviewer/pack/SearchedPackage.java index 528748d..3ec3f45 100644 --- a/src/main/java/fr/packageviewer/pack/SearchedPackage.java +++ b/src/main/java/fr/packageviewer/pack/SearchedPackage.java @@ -1,32 +1,89 @@ package fr.packageviewer.pack; +/** + * The SearchedPackage class stores metadata found when searching for a + * package. + * + * @author C.Marla, R.Thomas, S.Djalim + * @version 1.0 + */ public class SearchedPackage { + /** + * Name of the package + */ private final String name; + /** + * Version of the package + */ private final String version; + /** + * Repository where the package is located + */ private final String repo; + /** + * Description of the package + */ private final String description; + /** + * Distribution where this specific package belongs + */ private final String distribution; + /** + * Getter for the name attribute + * + * @return String, the name of the package + */ public String getName() { return name; } + /** + * Getter for the version attribute + * + * @return String, the version of the package + */ public String getVersion() { return version; } + /** + * Getter for the repo attribute + * + * @return String, repository where the package is located + */ public String getRepo() { return repo; } + /** + * Getter for the description attribute + * + * @return String, Description of the package + */ public String getDescription() { return description; } + /** + * Getter for the distribution attribute + * + * @return String, distribution where this specific package belongs + */ public String getDistribution() { return distribution; } + /** + * Constructor for the SearchedPackage class + * + * @param name String, name of the package + * @param version String, version of the package + * @param repo String, repository where the package is located + * @param description String, description of the package + * @param distribution String, the distribution where this specific package + * belongs + */ public SearchedPackage(String name, String version, String repo, String description, String distribution) { this.name = name; this.version = version; @@ -35,8 +92,14 @@ public class SearchedPackage { this.distribution = distribution; } + /** + * Returns a string reprensentation of the package + * + * @return String, string reprensentation of the package + */ @Override public String toString() { - return "SearchedPackage{name=%s,version=%s,repo=%s,description=%s,distribution=%s}".formatted(name, version, repo, description, distribution); + return "SearchedPackage{name=%s,version=%s,repo=%s,description=%s,distribution=%s}".formatted(name, version, + repo, description, distribution); } } diff --git a/src/main/java/fr/packageviewer/parser/AsyncRequestsParser.java b/src/main/java/fr/packageviewer/parser/AsyncRequestsParser.java index 9156c55..de4defe 100644 --- a/src/main/java/fr/packageviewer/parser/AsyncRequestsParser.java +++ b/src/main/java/fr/packageviewer/parser/AsyncRequestsParser.java @@ -11,12 +11,42 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.logging.Logger; +/** + * This abstract class defines the method that a distribution will use + * in order to get a package and fill its dependency list. It does all that + * in an asyncron manner + * + * @author R.Thomas + * @version 1.0 + * + */ public abstract class AsyncRequestsParser { - + /** + * Logger object used to split debug output and the application output + */ private static final Logger logger = LoggerManager.getLogger("AsyncRequestsParser"); + /** + * This function returns a package from the distribution's api in the form + * of a Pair Composed of a Package object and a set of string containing + * the names of the dependecies of the package. + * + * @param packageName String, The package's exact name + * @return Pair of Package and Set of String + */ protected abstract CompletableFuture>> getPackageFromAPI(String name); + /** + * This function returns a fully completed package containing all + * information about the package identified by it's exact name passed as + * parametter, the package contains in its dependency list fully formed + * packages that also contains its dependencies, the dependency depth is + * specified by the parametter with the same name. + * + * @param packageName String, The package's exact name + * @param depth int, the depth of the dependency tree + * @return Package, the fully completed package + */ public CompletableFuture getPackageTree(String packageName, int depth) { // parse the json var futurePackage = new CompletableFuture(); @@ -31,7 +61,7 @@ public abstract class AsyncRequestsParser { return CompletableFuture.completedFuture(null); } futureRequest.thenAccept(result -> { - if(result==null){ + if (result == null) { logger.fine("Completing callback INVALID for package %s (depth=%s)".formatted(packageName, depth)); futurePackage.complete(null); return; @@ -39,7 +69,6 @@ public abstract class AsyncRequestsParser { Package pack = result.getFirst(); Set dependenciesNames = result.getSecond(); - // if we're at the maximum depth, return the package without its dependencies if (depth == 0) { logger.fine("Completing callback NODEP for package %s (depth=%s)".formatted(packageName, depth)); @@ -71,7 +100,8 @@ public abstract class AsyncRequestsParser { futurePackage.complete(pack); }).exceptionally(error -> { error.printStackTrace(); - logger.warning("Error while manipulating package %s (depth=%s) : \n%s".formatted(packageName, depth, error)); + logger.warning( + "Error while manipulating package %s (depth=%s) : \n%s".formatted(packageName, depth, error)); futurePackage.complete(null); return null; });