From 05a209168001b31e972e4371b5e60e3de3b546b2 Mon Sep 17 00:00:00 2001 From: Manfred Riem Date: Tue, 23 Jul 2024 16:35:46 -0500 Subject: [PATCH] Fixes #228 - Separate UI into its own module (#232) --- pom.xml | 5 + repo/pom.xml | 1 - ui/nbactions.xml | 28 + ui/pom.xml | 169 +++++ ui/settings.xml.template | 33 + ui/src/main/docker/Dockerfile | 6 + .../persian/rest/RestApplication.java | 48 ++ .../persian/rest/RestApplicationBean.java | 82 +++ .../persian/rest/RestDirectoryModel.java | 93 +++ .../manorrock/persian/rest/RestFileModel.java | 88 +++ .../manorrock/persian/rest/RestResource.java | 652 ++++++++++++++++++ .../persian/ui/UIApplicationBean.java | 82 +++ .../persian/ui/UIIndexController.java | 103 +++ .../persian/ui/UIMavenRepositoryModel.java | 81 +++ ui/src/main/webapp/WEB-INF/beans.xml | 7 + ui/src/main/webapp/WEB-INF/ui/404.xhtml | 18 + ui/src/main/webapp/WEB-INF/ui/template.xhtml | 28 + ui/src/main/webapp/WEB-INF/web.xml | 41 ++ ui/src/main/webapp/index.xhtml | 27 + ui/src/main/webapp/resources/css/default.css | 34 + ui/src/main/webapp/resources/css/layout.css | 63 ++ .../persian/rest/RestDirectoryModelTest.java | 81 +++ 22 files changed, 1769 insertions(+), 1 deletion(-) create mode 100644 ui/nbactions.xml create mode 100644 ui/pom.xml create mode 100644 ui/settings.xml.template create mode 100644 ui/src/main/docker/Dockerfile create mode 100644 ui/src/main/java/com/manorrock/persian/rest/RestApplication.java create mode 100644 ui/src/main/java/com/manorrock/persian/rest/RestApplicationBean.java create mode 100644 ui/src/main/java/com/manorrock/persian/rest/RestDirectoryModel.java create mode 100644 ui/src/main/java/com/manorrock/persian/rest/RestFileModel.java create mode 100644 ui/src/main/java/com/manorrock/persian/rest/RestResource.java create mode 100644 ui/src/main/java/com/manorrock/persian/ui/UIApplicationBean.java create mode 100644 ui/src/main/java/com/manorrock/persian/ui/UIIndexController.java create mode 100644 ui/src/main/java/com/manorrock/persian/ui/UIMavenRepositoryModel.java create mode 100644 ui/src/main/webapp/WEB-INF/beans.xml create mode 100644 ui/src/main/webapp/WEB-INF/ui/404.xhtml create mode 100644 ui/src/main/webapp/WEB-INF/ui/template.xhtml create mode 100644 ui/src/main/webapp/WEB-INF/web.xml create mode 100644 ui/src/main/webapp/index.xhtml create mode 100644 ui/src/main/webapp/resources/css/default.css create mode 100644 ui/src/main/webapp/resources/css/layout.css create mode 100644 ui/src/test/java/com/manorrock/persian/rest/RestDirectoryModelTest.java diff --git a/pom.xml b/pom.xml index 0cd47a2..787a524 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,12 @@ Manorrock.com http://www.manorrock.com + + + 24.7.0 + repo + ui diff --git a/repo/pom.xml b/repo/pom.xml index 3755f20..454b653 100644 --- a/repo/pom.xml +++ b/repo/pom.xml @@ -20,7 +20,6 @@ 4.0.3 5.10.0 23.5.0 - 24.4.0 21 webprofile diff --git a/ui/nbactions.xml b/ui/nbactions.xml new file mode 100644 index 0000000..2b75eb6 --- /dev/null +++ b/ui/nbactions.xml @@ -0,0 +1,28 @@ + + + + + run + + war + ear + ejb + + + package + piranha:run + + + + debug + + war + ear + ejb + + + package + piranha:run + + + diff --git a/ui/pom.xml b/ui/pom.xml new file mode 100644 index 0000000..33088a8 --- /dev/null +++ b/ui/pom.xml @@ -0,0 +1,169 @@ + + + + 4.0.0 + + com.manorrock.persian + project + 23.8.0-SNAPSHOT + + persian-ui + war + Manorrock Persian - UI + + Manorrock.com + http://www.manorrock.com + + + + 10.0.0 + 4.0.3 + 5.10.0 + 23.5.0 + + 21 + webprofile + 8080 + + UTF-8 + + 0.42.1 + 3.11.0 + 3.4.0 + + + persian-ui + + + cloud.piranha.maven.plugins + piranha-maven-plugin + ${piranha.version} + + + pre-integration-test + pre-integration-test + + start + + + ${piranha.distribution} + ${piranha.httpPort} + + + + post-integration-test + post-integration-test + + stop + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${java.version} + + + + org.apache.maven.plugins + maven-war-plugin + ${maven-war-plugin.version} + + false + + + + + + + + org.glassfish.jaxb + jaxb-runtime + ${jaxb-runtime.version} + compile + + + + org.eclipse.angus + angus-activation + + + + + + com.manorrock.oyena.lifecycle + oyena-lifecycle-action + ${oyena.version} + runtime + + + com.manorrock.oyena.lifecycle + oyena-lifecycle-cdi + ${oyena.version} + runtime + + + + jakarta.platform + jakarta.jakartaee-web-api + ${jakarta.jakartaee-web-api.version} + provided + + + + org.junit.jupiter + junit-jupiter-engine + ${junit.version} + test + + + + + docker + + + + io.fabric8 + docker-maven-plugin + ${docker-maven-plugin.version} + + + + persian + ghcr.io/manorrock/persian:%l + + + + linux/amd64 + linux/arm64 + + + ${basedir} + src/main/docker/Dockerfile + + + + + + + build + install + + build + + + + + + + + + diff --git a/ui/settings.xml.template b/ui/settings.xml.template new file mode 100644 index 0000000..aadc5b6 --- /dev/null +++ b/ui/settings.xml.template @@ -0,0 +1,33 @@ + + + + + + default + + true + + + + localhost + localhost + + true + always + ignore + + + true + always + ignore + + http://localhost:8080/repositories + default + + + + + diff --git a/ui/src/main/docker/Dockerfile b/ui/src/main/docker/Dockerfile new file mode 100644 index 0000000..90f7c24 --- /dev/null +++ b/ui/src/main/docker/Dockerfile @@ -0,0 +1,6 @@ +FROM ghcr.io/piranhacloud/webprofile:23.8.0 +COPY target/persian.war ROOT.war +USER root +RUN chown -R piranha:piranha /home/piranha +USER piranha +CMD ["java", "-jar", "piranha-dist-webprofile.jar", "--war-file", "ROOT.war", "--webapp-directory", "ROOT", "--verbose"] diff --git a/ui/src/main/java/com/manorrock/persian/rest/RestApplication.java b/ui/src/main/java/com/manorrock/persian/rest/RestApplication.java new file mode 100644 index 0000000..d2452b7 --- /dev/null +++ b/ui/src/main/java/com/manorrock/persian/rest/RestApplication.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2002-2024 Manorrock.com. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.manorrock.persian.rest; + +import java.util.HashSet; +import java.util.Set; +import jakarta.ws.rs.ApplicationPath; +import jakarta.ws.rs.core.Application; + +/** + * The Persian application. + * + * @author Manfred Riem (mriem@manorrock.com) + */ +@ApplicationPath("repositories") +public class RestApplication extends Application { + + @Override + public Set> getClasses() { + Set> classes = new HashSet<>(); + classes.add(RestResource.class); + return classes; + } +} diff --git a/ui/src/main/java/com/manorrock/persian/rest/RestApplicationBean.java b/ui/src/main/java/com/manorrock/persian/rest/RestApplicationBean.java new file mode 100644 index 0000000..61cfb13 --- /dev/null +++ b/ui/src/main/java/com/manorrock/persian/rest/RestApplicationBean.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2002-2024 Manorrock.com. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.manorrock.persian.rest; + +import jakarta.annotation.PostConstruct; +import jakarta.enterprise.context.ApplicationScoped; +import java.io.File; +import static java.util.logging.Level.INFO; +import java.util.logging.Logger; + +/** + * The one and only application bean. + * + * @author Manfred Riem (mriem@manorrock.com) + */ +@ApplicationScoped +public class RestApplicationBean { + + /** + * Stores the logger. + */ + private static final Logger LOGGER = Logger.getLogger(RestApplicationBean.class.getPackageName()); + + /** + * Stores the root directory. + */ + private File rootDirectory; + + /** + * Get the root directory. + * + * @return the root directory. + */ + public File getRootDirectory() { + return rootDirectory; + } + + /** + * Initialize the bean. + */ + @PostConstruct + public void initialize() { + String rootDirectoryFilename = System.getenv("PERSIAN_REPOSITORIES_DIRECTORY"); + if (rootDirectoryFilename == null) { + rootDirectoryFilename = System.getProperty("PERSIAN_REPOSITORIES_DIRECTORY", + System.getProperty("user.home") + "/.manorrock/persian/repositories"); + } + + if (LOGGER.isLoggable(INFO)) { + LOGGER.log(INFO, "Repositories directory: {0}", rootDirectoryFilename); + } + + rootDirectory = new File(rootDirectoryFilename); + if (!rootDirectory.exists()) { + rootDirectory.mkdirs(); + } + } +} diff --git a/ui/src/main/java/com/manorrock/persian/rest/RestDirectoryModel.java b/ui/src/main/java/com/manorrock/persian/rest/RestDirectoryModel.java new file mode 100644 index 0000000..9bcff70 --- /dev/null +++ b/ui/src/main/java/com/manorrock/persian/rest/RestDirectoryModel.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2002-2024 Manorrock.com. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.manorrock.persian.rest; + +import java.io.Serializable; +import java.util.List; +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlRootElement; + +/** + * A directory model. + * + * @author Manfred Riem (mriem@manorrock.com) + */ +@XmlRootElement(name = "directory") +public class RestDirectoryModel implements Serializable { + + /** + * Stores the serial version UID. + */ + private static final long serialVersionUID = 9123973478589393249L; + + /** + * Stores the files. + */ + private List files; + + /** + * Stores the directory name. + */ + private String name; + + /** + * Get the files. + * + * @return the files. + */ + @XmlElement(name = "file", type = RestFileModel.class) + public List getFiles() { + return files; + } + + /** + * Get the name. + * + * @return the name. + */ + public String getName() { + return name; + } + + /** + * Set the files. + * + * @param files the files. + */ + public void setFiles(List files) { + this.files = files; + } + + /** + * Set the name. + * + * @param name the name. + */ + public void setName(String name) { + this.name = name; + } +} diff --git a/ui/src/main/java/com/manorrock/persian/rest/RestFileModel.java b/ui/src/main/java/com/manorrock/persian/rest/RestFileModel.java new file mode 100644 index 0000000..3ae04fc --- /dev/null +++ b/ui/src/main/java/com/manorrock/persian/rest/RestFileModel.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2002-2024 Manorrock.com. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.manorrock.persian.rest; + +import java.io.Serializable; + +/** + * A file model. + * + * @author Manfred Riem (mriem@manorrock.com) + */ +public class RestFileModel implements Serializable { + + /** + * Stores the serial version UID. + */ + private static final long serialVersionUID = 4003044105012813335L; + + /** + * Stores the directory flag. + */ + private boolean directory; + + /** + * Stores the name. + */ + private String name; + + /** + * Get the name. + * + * @return the name. + */ + public String getName() { + return name; + } + + /** + * Is directory. + * + * @return true if a directory, false otherwise. + */ + public boolean isDirectory() { + return directory; + } + + /** + * Set directory. + * + * @param directory the directory flag. + */ + public void setDirectory(boolean directory) { + this.directory = directory; + } + + /** + * Set the name. + * + * @param name the name. + */ + public void setName(String name) { + this.name = name; + } +} diff --git a/ui/src/main/java/com/manorrock/persian/rest/RestResource.java b/ui/src/main/java/com/manorrock/persian/rest/RestResource.java new file mode 100644 index 0000000..0122f8b --- /dev/null +++ b/ui/src/main/java/com/manorrock/persian/rest/RestResource.java @@ -0,0 +1,652 @@ +/* + * Copyright (c) 2002-2024 Manorrock.com. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.manorrock.persian.rest; + +import jakarta.enterprise.context.RequestScoped; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.logging.Level; +import java.util.logging.Logger; +import jakarta.inject.Inject; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.PUT; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.StreamingOutput; + +/** + * A repo resource + * + * @author Manfred Riem (mriem@manorrock.com) + */ +@Path("{repositoryName}") +@RequestScoped +public class RestResource { + + /** + * Stores the logger. + */ + private static final Logger LOGGER = Logger.getLogger(RestResource.class.getName()); + + /** + * Stores the application bean. + */ + @Inject + private RestApplicationBean application; + + /** + * Get the base directory listing for the repository. + * + * @param repositoryName the repository name + * @return the director listing. + */ + @GET + @Path("") + public Response directory0(@PathParam("repositoryName") String repositoryName) { + Response result; + + try { + File file = new File(application.getRootDirectory(), repositoryName); + + if (file.exists()) { + RestDirectoryModel model = new RestDirectoryModel(); + model.setName(repositoryName); + ArrayList files = new ArrayList<>(); + for (File currentFile : file.listFiles()) { + String name = currentFile.getAbsolutePath().substring(file.getCanonicalPath().length() + 1); + name = name.replaceAll("&", "&"); + boolean show = true; + + if (System.getProperty("os.name").toLowerCase().contains("mac os") + && name.startsWith(".")) { + show = false; + } + + if (show) { + RestFileModel fileModel = new RestFileModel(); + fileModel.setName(name); + fileModel.setDirectory(currentFile.isDirectory()); + files.add(fileModel); + } + } + model.setFiles(files); + result = Response.ok(model).build(); + } else { + throw new WebApplicationException(Response.Status.NOT_FOUND); + } + } catch (IOException ioe) { + LOGGER.log(Level.WARNING, "Unable to read directory", ioe); + throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); + } + + return result; + } + + /** + * Get the directory listing for the given path. + * + * @param repositoryName the repository name. + * @param path the path. + * @return the view showing the directory listing. + */ + @GET + @Path("{path : .+}") + public Response directory1( + @PathParam("repositoryName") String repositoryName, + @PathParam("path") String path) { + Response result; + + try { + File file = new File(application.getRootDirectory(), repositoryName + File.separator + path); + + if (file.exists()) { + RestDirectoryModel model = new RestDirectoryModel(); + model.setName(repositoryName + File.separator + path); + ArrayList files = new ArrayList<>(); + for (File currentFile : file.listFiles()) { + String name = currentFile.getAbsolutePath().substring(file.getCanonicalPath().length() + 1); + name = name.replaceAll("&", "&"); + boolean show = true; + + if (System.getProperty("os.name").toLowerCase().contains("mac os") + && name.startsWith(".")) { + show = false; + } + + if (show) { + RestFileModel fileModel = new RestFileModel(); + fileModel.setName(name); + fileModel.setDirectory(currentFile.isDirectory()); + files.add(fileModel); + } + } + model.setFiles(files); + result = Response.ok(model).build(); + } else { + throw new WebApplicationException(Response.Status.NOT_FOUND); + } + } catch (IOException ioe) { + LOGGER.log(Level.WARNING, "Unable to read directory", ioe); + throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); + } + + return result; + } + + /** + * Download the artifact. + * + * @param repositoryName the repository name. + * @param groupId the group id (in slash format). + * @param artifactId the artifact id. + * @param version the version + * @param packaging the packaging. + * @return the artifact. + */ + @GET + @Path("{groupId : .+}/{artifactId}/{version}/{artifactId2}-{version2}.{packaging}") + @Produces({"application/octet-stream"}) + public StreamingOutput downloadArtifact( + @PathParam("repositoryName") String repositoryName, + @PathParam("groupId") String groupId, + @PathParam("artifactId") String artifactId, + @PathParam("version") String version, + @PathParam("packaging") String packaging) { + + File repoDir = new File(application.getRootDirectory(), repositoryName); + File file = new File(repoDir, groupId + File.separator + artifactId + File.separator + version + + File.separator + artifactId + "-" + version + "." + packaging); + + if (file.exists()) { + return (OutputStream outputStream) -> { + try (InputStream inputStream = new FileInputStream(file)) { + int nextByte; + while ((nextByte = inputStream.read()) != -1) { + outputStream.write(nextByte); + } + outputStream.flush(); + outputStream.close(); + } + }; + } else { + throw new WebApplicationException(404); + } + } + + /** + * Download the artifact MD5. + * + * @param repositoryName the repository name. + * @param groupId the group id (in slash format). + * @param artifactId the artifact id. + * @param version the version + * @param packaging the packaging. + * @return the artifact MD5. + */ + @GET + @Path("{groupId : .+}/{artifactId}/{version}/{artifactId2}-{version2}.{packaging}.md5") + @Produces({"application/octet-stream"}) + public StreamingOutput downloadArtifactMd5( + @PathParam("repositoryName") String repositoryName, + @PathParam("groupId") String groupId, + @PathParam("artifactId") String artifactId, + @PathParam("version") String version, + @PathParam("packaging") String packaging) { + + return (OutputStream outputStream) -> { + File repoDir = new File(application.getRootDirectory(), repositoryName); + File file = new File(repoDir, groupId + File.separator + artifactId + File.separator + version + + File.separator + artifactId + "-" + version + "." + packaging + ".md5"); + try (InputStream inputStream = new FileInputStream(file)) { + int nextByte; + while ((nextByte = inputStream.read()) != -1) { + outputStream.write(nextByte); + } + outputStream.flush(); + outputStream.close(); + } + }; + } + + /** + * Download the artifact SHA1. + * + * @param repositoryName the repository name. + * @param groupId the group id (in slash format). + * @param artifactId the artifact id. + * @param version the version + * @param packaging the packaging. + * @return the artifact SHA1. + */ + @GET + @Path("{groupId : .+}/{artifactId}/{version}/{artifactId2}-{version2}.{packaging}.sha1") + @Produces({"application/octet-stream"}) + public StreamingOutput downloadArtifactSha1( + @PathParam("repositoryName") String repositoryName, + @PathParam("groupId") String groupId, + @PathParam("artifactId") String artifactId, + @PathParam("version") String version, + @PathParam("packaging") String packaging) { + + return (OutputStream outputStream) -> { + File repoDir = new File(application.getRootDirectory(), repositoryName); + File file = new File(repoDir, groupId + File.separator + artifactId + File.separator + version + + File.separator + artifactId + "-" + version + "." + packaging + ".sha1"); + try (InputStream inputStream = new FileInputStream(file)) { + int nextByte; + while ((nextByte = inputStream.read()) != -1) { + outputStream.write(nextByte); + } + outputStream.flush(); + outputStream.close(); + } + }; + } + + /** + * Download the maven-metadata.xml. + * + * @param repositoryName the repository name. + * @param groupId the group id (in slash format). + * @param artifactId the artifact id. + * @param version the version. + * @return the maven-metadata.xml. + */ + @GET + @Path("{groupId : .+}/{artifactId}/{version}/maven-metadata.xml") + @Produces({"text/xml"}) + public StreamingOutput downloadMetadata( + @PathParam("repositoryName") String repositoryName, + @PathParam("groupId") String groupId, + @PathParam("artifactId") String artifactId, + @PathParam("version") String version) { + + return (OutputStream outputStream) -> { + File repoDir = new File(application.getRootDirectory(), repositoryName); + File file = new File(repoDir, groupId + File.separator + artifactId + File.separator + version + + File.separator + "maven-metadata.xml"); + + if (file.exists()) { + try (InputStream inputStream = new FileInputStream(file)) { + int nextByte; + while ((nextByte = inputStream.read()) != -1) { + outputStream.write(nextByte); + } + outputStream.flush(); + outputStream.close(); + } + } + }; + } + + /** + * Download the maven-metadata.xml MD5. + * + * @param repositoryName the repository name. + * @param groupId the group id (in slash format). + * @param artifactId the artifact id. + * @param version the version. + * @return the maven-metadata.xml,md5. + */ + @GET + @Path("{groupId : .+}/{artifactId}/{version}/maven-metadata.xml.md5") + @Produces({"text/xml"}) + public StreamingOutput downloadMetadataMd5( + @PathParam("repositoryName") String repositoryName, + @PathParam("groupId") String groupId, + @PathParam("artifactId") String artifactId, + @PathParam("version") String version) { + + return (OutputStream outputStream) -> { + File repoDir = new File(application.getRootDirectory(), repositoryName); + File file = new File(repoDir, groupId + File.separator + artifactId + File.separator + version + + File.separator + "maven-metadata.xml.md5"); + + if (file.exists()) { + try (InputStream inputStream = new FileInputStream(file)) { + int nextByte; + while ((nextByte = inputStream.read()) != -1) { + outputStream.write(nextByte); + } + outputStream.flush(); + outputStream.close(); + } + } + }; + } + + /** + * Download the maven-metadata.xml SHA-1. + * + * @param repositoryName the repository name. + * @param groupId the group id (in slash format). + * @param artifactId the artifact id. + * @param version the version. + * @return the maven-metadata.xml. + */ + @GET + @Path("{groupId : .+}/{artifactId}/{version}/maven-metadata.xml.sha1") + @Produces({"text/xml"}) + public StreamingOutput downloadMetadataSha1( + @PathParam("repositoryName") String repositoryName, + @PathParam("groupId") String groupId, + @PathParam("artifactId") String artifactId, + @PathParam("version") String version) { + + return (OutputStream outputStream) -> { + File repoDir = new File(application.getRootDirectory(), repositoryName); + File file = new File(repoDir, groupId + File.separator + artifactId + File.separator + version + + File.separator + "maven-metadata.xml.sha1"); + + if (file.exists()) { + try (InputStream inputStream = new FileInputStream(file)) { + int nextByte; + while ((nextByte = inputStream.read()) != -1) { + outputStream.write(nextByte); + } + outputStream.flush(); + outputStream.close(); + } + } + }; + } + + /** + * Upload an artifact. + * + * @param repositoryName the repository name. + * @param groupId the group id (in slash format). + * @param artifactId the artifactId. + * @param packaging the packaging. + * @param version the version. + * @param data the actual artifact binary data. + */ + @PUT + @Path("{groupId : .+}/{artifactId1}/{version1}/{artifactId2}-{version2}.{packaging}") + @Consumes({"application/octet-stream"}) + public void uploadArtifact( + @PathParam("repositoryName") String repositoryName, + @PathParam("groupId") String groupId, + @PathParam("artifactId1") String artifactId, + @PathParam("version1") String version, + @PathParam("packaging") String packaging, + byte[] data + ) { + + File directory = new File(application.getRootDirectory(), repositoryName + + File.separator + + groupId.replaceAll("/", File.separator) + + File.separator + + artifactId + + File.separator + + version); + + File file = new File(directory, artifactId + "-" + version + "." + packaging); + + if (!file.exists()) { + try { + if (!directory.exists()) { + directory.mkdirs(); + } + try (FileOutputStream fileOutputStream = new FileOutputStream(file)) { + fileOutputStream.write(data); + fileOutputStream.flush(); + } + } catch (IOException ex) { + throw new WebApplicationException(ex, 500); + } + } + } + + /** + * Upload an artifact's MD5. + * + * @param repositoryName the repository name. + * @param groupId the group id (in slash format). + * @param artifactId the artifactId. + * @param packaging the packaging. + * @param version the version. + * @param data the actual artifact binary data. + */ + @PUT + @Path("{groupId : .+}/{artifactId}/{version}/{artifactId2}-{version2}.{packaging}.md5") + @Consumes({"application/octet-stream"}) + public void uploadArtifactMd5( + @PathParam("repositoryName") String repositoryName, + @PathParam("groupId") String groupId, + @PathParam("artifactId") String artifactId, + @PathParam("version") String version, + @PathParam("packaging") String packaging, + byte[] data + ) { + + File directory = new File(application.getRootDirectory(), repositoryName + File.separator + + groupId.replaceAll("/", File.separator) + File.separator + + artifactId + File.separator + + version); + + File file = new File(directory, artifactId + "-" + version + "." + packaging + ".md5"); + + if (!file.exists()) { + try { + if (!directory.exists()) { + directory.mkdirs(); + } + try (FileOutputStream fileOutputStream = new FileOutputStream(file)) { + fileOutputStream.write(data); + fileOutputStream.flush(); + } + } catch (IOException ex) { + throw new WebApplicationException(ex, 500); + } + } + } + + /** + * Upload an artifact's SHA-1. + * + * @param repositoryName the repository name. + * @param groupId the group id (in slash format). + * @param artifactId the artifactId. + * @param packaging the packaging. + * @param version the version. + * @param data the actual artifact binary data. + */ + @PUT + @Path("{groupId : .+}/{artifactId}/{version}/{artifactId2}-{version2}.{packaging}.sha1") + @Consumes({"application/octet-stream"}) + public void uploadArtifactSha1( + @PathParam("repositoryName") String repositoryName, + @PathParam("groupId") String groupId, + @PathParam("artifactId") String artifactId, + @PathParam("version") String version, + @PathParam("packaging") String packaging, + byte[] data + ) { + + File directory = new File(application.getRootDirectory(), repositoryName + + File.separator + + groupId.replaceAll("/", File.separator) + + File.separator + + artifactId + File.separator + + version); + + File file = new File(directory, artifactId + "-" + version + "." + packaging + ".sha1"); + + if (!file.exists()) { + try { + if (!directory.exists()) { + directory.mkdirs(); + } + try (FileOutputStream fileOutputStream = new FileOutputStream(file)) { + fileOutputStream.write(data); + fileOutputStream.flush(); + } + } catch (IOException ex) { + throw new WebApplicationException(ex, 500); + } + } + } + + /** + * Upload the maven-metadata.xml. + * + * @param repositoryName the repository name. + * @param groupId the group id (in slash format). + * @param artifactId the artifact id. + * @param version the version. + * @param data the data. + */ + @PUT + @Path("{groupId : .+}/{artifactId}/{version}/maven-metadata.xml") + @Consumes({"text/xml"}) + public void uploadMetadata( + @PathParam("repositoryName") String repositoryName, + @PathParam("groupId") String groupId, + @PathParam("artifactId") String artifactId, + @PathParam("version") String version, + byte[] data + ) { + + File directory = new File(application.getRootDirectory(), repositoryName + + File.separator + + groupId.replaceAll("/", File.separator) + + File.separator + + artifactId); + + File file = new File(directory, "maven-metadata.xml"); + + if (!file.exists()) { + try { + if (!directory.exists()) { + directory.mkdirs(); + } + try (FileOutputStream fileOutputStream = new FileOutputStream(file)) { + fileOutputStream.write(data); + fileOutputStream.flush(); + } + } catch (IOException ex) { + throw new WebApplicationException(ex, 500); + } + } + } + + /** + * Upload the maven-metadata.xml,md5. + * + * @param repositoryName the repository name. + * @param groupId the group id (in slash format). + * @param artifactId the artifact id. + * @param version the version. + * @param data the data. + */ + @PUT + @Path("{groupId : .+}/{artifactId}/{version}/maven-metadata.xml.md5") + @Consumes({"text/xml"}) + public void uploadMetadataMd5( + @PathParam("repositoryName") String repositoryName, + @PathParam("groupId") String groupId, + @PathParam("artifactId") String artifactId, + @PathParam("version") String version, + byte[] data + ) { + + File directory = new File(application.getRootDirectory(), repositoryName + + File.separator + + groupId.replaceAll("/", File.separator) + + File.separator + + artifactId); + + File file = new File(directory, "maven-metadata.xml.md5"); + + if (!file.exists()) { + try { + if (!directory.exists()) { + directory.mkdirs(); + } + try (FileOutputStream fileOutputStream = new FileOutputStream(file)) { + fileOutputStream.write(data); + fileOutputStream.flush(); + } + } catch (IOException ex) { + throw new WebApplicationException(ex, 500); + } + } + } + + /** + * Upload the maven-metadata.xml SHA-1. + * + * @param repositoryName the repository name. + * @param groupId the group id (in slash format). + * @param artifactId the artifact id. + * @param version the version. + * @param data the data. + */ + @PUT + @Path("{groupId : .+}/{artifactId}/{version}/maven-metadata.xml.sha1") + @Consumes({"text/xml"}) + public void uploadMetadataSha1( + @PathParam("repositoryName") String repositoryName, + @PathParam("groupId") String groupId, + @PathParam("artifactId") String artifactId, + @PathParam("version") String version, + byte[] data + ) { + + File directory = new File(application.getRootDirectory(), repositoryName + + File.separator + + groupId.replaceAll("/", File.separator) + + File.separator + + artifactId); + + File file = new File(directory, "maven-metadata.xml.sha1"); + + if (!file.exists()) { + try { + if (!directory.exists()) { + directory.mkdirs(); + } + try (FileOutputStream fileOutputStream = new FileOutputStream(file)) { + fileOutputStream.write(data); + fileOutputStream.flush(); + } + } catch (IOException ex) { + throw new WebApplicationException(ex, 500); + } + } + } +} diff --git a/ui/src/main/java/com/manorrock/persian/ui/UIApplicationBean.java b/ui/src/main/java/com/manorrock/persian/ui/UIApplicationBean.java new file mode 100644 index 0000000..9e8dcaa --- /dev/null +++ b/ui/src/main/java/com/manorrock/persian/ui/UIApplicationBean.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2002-2024 Manorrock.com. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.manorrock.persian.ui; + +import jakarta.annotation.PostConstruct; +import jakarta.enterprise.context.ApplicationScoped; +import java.io.File; +import static java.util.logging.Level.INFO; +import java.util.logging.Logger; + +/** + * The one and only application bean. + * + * @author Manfred Riem (mriem@manorrock.com) + */ +@ApplicationScoped +public class UIApplicationBean { + + /** + * Stores the logger. + */ + private static final Logger LOGGER = Logger.getLogger(UIApplicationBean.class.getPackageName()); + + /** + * Stores the root directory. + */ + private File rootDirectory; + + /** + * Get the root directory. + * + * @return the root directory. + */ + public File getRootDirectory() { + return rootDirectory; + } + + /** + * Initialize the bean. + */ + @PostConstruct + public void initialize() { + String rootDirectoryFilename = System.getenv("PERSIAN_REPOSITORIES_DIRECTORY"); + if (rootDirectoryFilename == null) { + rootDirectoryFilename = System.getProperty("PERSIAN_REPOSITORIES_DIRECTORY", + System.getProperty("user.home") + "/.manorrock/persian/repositories"); + } + + if (LOGGER.isLoggable(INFO)) { + LOGGER.log(INFO, "Repositories directory: {0}", rootDirectoryFilename); + } + + rootDirectory = new File(rootDirectoryFilename); + if (!rootDirectory.exists()) { + rootDirectory.mkdirs(); + } + } +} diff --git a/ui/src/main/java/com/manorrock/persian/ui/UIIndexController.java b/ui/src/main/java/com/manorrock/persian/ui/UIIndexController.java new file mode 100644 index 0000000..01c797b --- /dev/null +++ b/ui/src/main/java/com/manorrock/persian/ui/UIIndexController.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2002-2024 Manorrock.com. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.manorrock.persian.ui; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.List; +import jakarta.annotation.PostConstruct; +import jakarta.inject.Named; +import jakarta.enterprise.context.RequestScoped; +import jakarta.inject.Inject; + +/** + * The index bean. + * + * @author Manfred Riem (mriem@manorrock.com) + */ +@Named(value = "indexController") +@RequestScoped +public class UIIndexController { + + /** + * Stores the application bean. + */ + @Inject + private UIApplicationBean application; + + /** + * Stores the repositories. + */ + private List repositories; + + /** + * Get the repositories. + * + * @return the repositories. + */ + public List getRepositories() { + return repositories; + } + + /** + * Initialize the bean. + */ + @PostConstruct + public void initialize() { + + File[] repositoryFilenames = application.getRootDirectory().listFiles(); + repositories = new ArrayList<>(); + if (repositoryFilenames != null) { + for (File repositoryFilename : repositoryFilenames) { + repositories.add(loadMavenRepository(repositoryFilename)); + } + } + } + + /** + * Load a Maven repository. + * + * @param file the file. + * @return the Maven repository. + */ + public UIMavenRepositoryModel loadMavenRepository(File file) { + UIMavenRepositoryModel repository = new UIMavenRepositoryModel(); + repository.setName(file.getName()); + long size = -1L; + try { + size = Files.walk(file.toPath()) + .filter(p -> p.toFile().isFile()) + .mapToLong(p -> p.toFile().length()) + .sum(); + } catch(IOException ioe) { + } + repository.setSize(size); + return repository; + } +} diff --git a/ui/src/main/java/com/manorrock/persian/ui/UIMavenRepositoryModel.java b/ui/src/main/java/com/manorrock/persian/ui/UIMavenRepositoryModel.java new file mode 100644 index 0000000..d13630d --- /dev/null +++ b/ui/src/main/java/com/manorrock/persian/ui/UIMavenRepositoryModel.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2002-2024 Manorrock.com. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.manorrock.persian.ui; + +/** + * A Maven repository. + * + * @author Manfred Riem (mriem@manorrock.com) + */ +public class UIMavenRepositoryModel { + + /** + * Stores the name. + */ + private String name; + + /** + * Stores the size. + */ + private long size; + + /** + * Get the name. + * + * @return the name. + */ + public String getName() { + return name; + } + + /** + * Get the size. + * + * @return the size. + */ + public long getSize() { + return size; + } + + /** + * Set the name. + * + * @param name the name. + */ + public void setName(String name) { + this.name = name; + } + + /** + * Set the size. + * + * @param size the size. + */ + public void setSize(long size) { + this.size = size; + } +} diff --git a/ui/src/main/webapp/WEB-INF/beans.xml b/ui/src/main/webapp/WEB-INF/beans.xml new file mode 100644 index 0000000..05298c8 --- /dev/null +++ b/ui/src/main/webapp/WEB-INF/beans.xml @@ -0,0 +1,7 @@ + + + + diff --git a/ui/src/main/webapp/WEB-INF/ui/404.xhtml b/ui/src/main/webapp/WEB-INF/ui/404.xhtml new file mode 100644 index 0000000..d70fe7a --- /dev/null +++ b/ui/src/main/webapp/WEB-INF/ui/404.xhtml @@ -0,0 +1,18 @@ + + + + + + + 404 + + + +

404

+

+ It looks like we cannot find what you are looking for. +

+ + diff --git a/ui/src/main/webapp/WEB-INF/ui/template.xhtml b/ui/src/main/webapp/WEB-INF/ui/template.xhtml new file mode 100644 index 0000000..27cd3e6 --- /dev/null +++ b/ui/src/main/webapp/WEB-INF/ui/template.xhtml @@ -0,0 +1,28 @@ + + + + + + + + + + <ui:insert name="title">Manorrock Persian</ui:insert> + + +
+ Manorrock Persian +
+
+ +
+
+ + Copyright (c) 2002-2024 Manorrock.com. All Rights Reserved. + +
+
+ diff --git a/ui/src/main/webapp/WEB-INF/web.xml b/ui/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..9a324c4 --- /dev/null +++ b/ui/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,41 @@ + + + + + Faces Servlet + jakarta.faces.webapp.FacesServlet + 1 + + + Oyena Action Servlet + jakarta.faces.webapp.FacesServlet + + jakarta.faces.LIFECYCLE_ID + com.manorrock.oyena.lifecycle.action.ActionLifecycle + + + + Faces Servlet + *.xhtml + + + Oyena Action Servlet + /ui/* + + + 30 + + + index.xhtml + + + 404 + /ui/404.xhtml + + diff --git a/ui/src/main/webapp/index.xhtml b/ui/src/main/webapp/index.xhtml new file mode 100644 index 0000000..3aa9687 --- /dev/null +++ b/ui/src/main/webapp/index.xhtml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + +
RepositorySize
+
+
+ + diff --git a/ui/src/main/webapp/resources/css/default.css b/ui/src/main/webapp/resources/css/default.css new file mode 100644 index 0000000..074581b --- /dev/null +++ b/ui/src/main/webapp/resources/css/default.css @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2002-2024, Manorrock.com. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#footer { + color: crimson; + font-size: 8px; + border-top-style: solid; + border-top-width: 1px; + text-align: center; + width: 100%; +} diff --git a/ui/src/main/webapp/resources/css/layout.css b/ui/src/main/webapp/resources/css/layout.css new file mode 100644 index 0000000..911561e --- /dev/null +++ b/ui/src/main/webapp/resources/css/layout.css @@ -0,0 +1,63 @@ + +#top { + border-bottom-style: solid; + border-bottom-width: 1px; + color: crimson; + font-size: 20px; + font-variant: small-caps; + margin: 0px 0px 10px 0px; + padding: 5px; + position: relative; +} + +#bottom { + border-top-style: solid; + border-top-width: 1px; + color: crimson; + font-size: 12px; + margin: 10px 0px 0px 0px; + padding: 5px; + position: relative; + text-align: center; +} + +#left { + float: left; + padding: 5px; + width: 150px; +} + +#right { + float: right; + padding: 5px; + width: 150px; +} + +.center_content { + position: relative; + padding: 5px; +} + +.left_content { + padding: 5px; + margin-left: 170px; +} + +.right_content { + padding: 5px; + margin: 0px 170px 0px 170px; +} + +#top a:link, #top a:visited { + color: white; + font-weight : bold; + text-decoration: none; +} + +#top a:link:hover, #top a:visited:hover { + color: black; + font-weight : bold; + text-decoration : underline; +} + + diff --git a/ui/src/test/java/com/manorrock/persian/rest/RestDirectoryModelTest.java b/ui/src/test/java/com/manorrock/persian/rest/RestDirectoryModelTest.java new file mode 100644 index 0000000..04dfcc6 --- /dev/null +++ b/ui/src/test/java/com/manorrock/persian/rest/RestDirectoryModelTest.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2002-2024 Manorrock.com. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.manorrock.persian.rest; + +import java.util.ArrayList; +import java.util.List; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import org.junit.jupiter.api.Test; + +/** + * The JUnit test for the RestDirectoryModel class. + * + * @author Manfred Riem (mriem@manorrock.com) + */ +public class RestDirectoryModelTest { + + /** + * Test getFiles method. + */ + @Test + public void testGetFiles() { + RestDirectoryModel model = new RestDirectoryModel(); + assertNull(model.getFiles()); + } + + /** + * Test getName method. + */ + @Test + public void testGetName() { + RestDirectoryModel model = new RestDirectoryModel(); + assertNull(model.getName()); + } + + /** + * Test setFiles method. + */ + @Test + public void testSetFiles() { + List files = new ArrayList<>(); + RestDirectoryModel model = new RestDirectoryModel(); + model.setFiles(files); + assertNotNull(model.getFiles()); + } + + /** + * Test setName method. + */ + @Test + public void testSetName() { + RestDirectoryModel model = new RestDirectoryModel(); + model.setName("TheName"); + assertEquals("TheName", model.getName()); + } +}