Compare commits

..

No commits in common. "3cfbf9cf6ea3f967b8150eaa4a183b4c129a84fd" and "6f7ae313ce4c50bda1e0473ae8adf55817b71649" have entirely different histories.

9 changed files with 5 additions and 240 deletions

View File

@ -117,11 +117,3 @@ Followup: Excess payloads were being added to the welcome page
that caused HTTP "400" errors fetching resources. A fix has that caused HTTP "400" errors fetching resources. A fix has
been made, although the ultimate solution will probably be more been made, although the ultimate solution will probably be more
JSF-friendly. JSF-friendly.
## Minor release 2.0.1
This release can build an installable RPM for Red Hat-compatible
systems, including CentOS and its relatives and Fedora.
Just run ``mvn install`` and the RPM will be produced under the
``/target/rpm`` directory.

View File

@ -1,96 +0,0 @@
# GourmetJ application Architecture.
This is a Spring Boot self-hosted website built on standard JEE
components like JavaServer Faces (JSF) and the Java Persistence
Architecture (JPA). It is built and can be tested using Maven.
The Maven pom.xml file determines the build and what dependencies
it has. The core dependencies and their versions are determined
in the `dependencyManagement` section of the POM. Actual inclusion
of dependencies is done in the `dependencies` section.
Of the 3 dependencyManagement dependencies, the JoinFaces BOM is
the most important. It ensures that the proper version of Spring
Boot and its dependencies is brought into the `dependencies` as
well as allowing the option to select which JSF extension libraries
are to be used. For this project, PrimeFaces is the primary JSF
framework.
## Source Code components
Source code files come in 4 major types:
1. Spring/Spring Boot support
1. JSF Backing Beans
1. Data Persistence
1. General Utilities (for example data format converters and parsers)
### Spring and Spring Boot Support
The application code root package is `com.mousetech.gourmetj`. The
Spring configuration classes are located in this package. There
are two of them: `SpringPrimeFacesApplication'java`, which is the
main class for the app, and `SpringSecurityConfig.java`, which
defines security. Security credentials (userid/password) are taken
from an external password file whose location is defined by the
`application.yml` properties file. There are no security roles, and
all site pages are accessible without logging in except for the
ones that can modify the database (create/edit recipe).
Secondary Spring characteristics come from the `WelcomePageRedirect.java`
file which defines the site's welcome page (index.html).
A small bit of Spring Web in the `springweb.PicureController` class.
This Controller resolves the image URLs for recipe images and
thumbnails.
### JSF BackingBeans
The heart of the webapp is in JavaServer Faces Backing Beans which
provide the Models for their corresponding View Template (.xhtml)
files. The most important beans are the adminMain bean, which
generates the recipe list page and the recipeDetail bean, which
back the display and editing of a recipe. The CookieBean is
a utility class that allows keeping search information in user-side
cookies between user sessions and JSFUtils allows access to
HTTP/Servlet soecific resources in a way that isolates them from
the general application code. That allows platform independence
and easier unit testing.
### Persistence
Persistence is done via JPA and has 3 layers:
1. Service layer. This layer fetches and updates "working sets" of
related database entity objects. All service methods are
Transactions. Working sets passed in or out of the service layer
to the higher (business) layer of the app are detached objects,
so the Service layer also ensures detaching and re-attaching
(merging) as needed for the lower layer functions.
1. DAO layer. This layer does find/CRUD functions for a single
Entity type or sometimes a parent/child Entity set. I've coded this
using explicit logic in times past, but in this app, I've leveraged
Spring's Repository feature to let it write the grunt code.
1. Model layer. This layer contains the actual Entity classes,
which are all POJOs and have no executable logic except get/set.
### Utilities
Most utility services are in the ``utils`` package, except for
JSFUtils, which serves as a liason between JSF server-independent
code and server platform-specific services.
## Future considerations
There's probably still some lint in the POM and perhaps some dead
code from deadend solutions that weren't viable. That's how apps
are in the Real World.
Adding an I18N Bundle would probably be nice.
A Schema file was recently added to the project and it needs to
be checked for functionality. A similar `data.sql` is probably
needed to be able to fully set up a database from scratch. My
current copy was simply cloned from an existing database.

76
pom.xml
View File

@ -7,7 +7,7 @@
<groupId>com.mousetech.gourmet</groupId> <groupId>com.mousetech.gourmet</groupId>
<artifactId>gourmetj</artifactId> <artifactId>gourmetj</artifactId>
<version>2.0.1</version> <version>0.3.0</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>GourmetJ</name> <name>GourmetJ</name>
@ -17,7 +17,7 @@
<parent> <parent>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.3</version> <version>3.2.2</version>
<relativePath /> <!-- lookup parent from repository --> <relativePath /> <!-- lookup parent from repository -->
</parent> </parent>
@ -177,78 +177,6 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId> <artifactId>spring-boot-maven-plugin</artifactId>
</plugin> </plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>rpm-maven-plugin</artifactId>
<version>2.3.0</version>
<executions>
<execution>
<id>generate-rpm</id>
<goals>
<goal>rpm</goal>
</goals>
</execution>
</executions>
<configuration>
<license>GPL (c) 2024, mousetech.com</license>
<distribution>Gourmetj</distribution>
<group>Application/Collectors</group>
<packager>Tom Holloway</packager>
<prefix>/usr/local</prefix>
<changelogFile>src/changelog</changelogFile>
<defineStatements>
<defineStatement>_unpackaged_files_terminate_build 0</defineStatement>
</defineStatements>
<mappings>
<mapping>
<directory>/opt/mousetech/gourmetj</directory>
<filemode>750</filemode>
<username>gourmetj</username>
<groupname>gourmetj</groupname>
<sources>
<source>
<location>
target/${project.build.finalName}.jar</location>
</source>
<softlinkSource>
<destination>gourmetj.jar</destination>
<location>
${project.build.finalName}.jar</location>
</softlinkSource>
</sources>
</mapping>
<mapping>
<directory>/opt/mousetech/gourmetj</directory>
<configuration>true</configuration>
<filemode>440</filemode>
<username>gourmetj</username>
<groupname>gourmetj</groupname>
<sources>
<source>
<location>src/main/conf</location>
</source>
</sources>
</mapping>
<mapping>
<directory>/etc/systemd/system/</directory>
<directoryIncluded>false</directoryIncluded>
<configuration>true</configuration>
<filemode>440</filemode>
<sources>
<source>
<location>src/main/systemd/gourmetj.service</location>
</source>
</sources>
</mapping>
</mappings>
<preinstallScriptlet>
<script>echo "installing ${project.name} now"
/usr/bin/getent passwd gourmetj || /usr/sbin/useradd -r -d /opt/mousetech/gourmetj -s /sbin/nologin gourmetj
</script>
</preinstallScriptlet>
</configuration>
</plugin>
</plugins> </plugins>
</build> </build>
</project> </project>

View File

@ -1 +0,0 @@
# Application user password file

View File

@ -1,29 +0,0 @@
# THIS is the application properties used when testing in the IDE
# or running stand-alone from the command line.
# It augments/overrides application.yml in the JAR
joinfaces.jsf.webapp-resources-directory=/resources
server.servlet.session.timeout=30m
spring.thymeleaf.enabled=false
server.error.whitelabel.enabled=false
spring.datasource.url=jdbc:mysql://dbase/recipes
#jdbc:sqlite:${home}/recipes.db
spring.datasource.username=recipes
pring.datasource.password=yumyumyum
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
#Runtime lies and says no longer required, but it defaults to MySQL5.5.0!:
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
#org.sqlite.hibernate.dialect.SQLiteDialect
#spring.jpa.show-sql: true
# My special properties
gourmet.password.file=.gourmetpw
# This will override aplication.yml
#server.servlet.context-parameters.primefaces.THEME=le-frog
### HttpSession timeout (note effects on detailEdit idleMonitors)
server.servlet.session.timeout=35m

View File

@ -3,8 +3,6 @@ package com.mousetech.gourmetj;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.springframework.beans.factory.annotation.Value;
import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.ApplicationScoped;
import jakarta.faces.model.SelectItem; import jakarta.faces.model.SelectItem;
import jakarta.inject.Named; import jakarta.inject.Named;
@ -50,11 +48,4 @@ public class AppBean {
"Ingredient")); "Ingredient"));
return list; return list;
} }
@Value("${appVersion}")
String appVersion = "Not Supplied.";
public String getAppVersion() {
return appVersion;
}
} }

View File

@ -18,7 +18,7 @@
</h:head> </h:head>
<h:body> <h:body>
<h1> <h1>
<ui:insert name="title">Gourmet Recipe Manager (web version #{appBean.appVersion})</ui:insert> <ui:insert name="title">Gourmet Recipe Manager (web version)</ui:insert>
</h1> </h1>
<p:ajaxStatus onerror="PF('opError').show()"/> <p:ajaxStatus onerror="PF('opError').show()"/>
<ui:insert name="content"> <ui:insert name="content">
@ -28,11 +28,10 @@
</ui:insert> </ui:insert>
<!-- --> <!-- -->
<div id="footer"> <div id="footer">
<h:outputText value="Version #{appBean.appVersion}"/><br/>
(C) 2021, 2024 Tim Holloway, Licensed under (C) 2021, 2024 Tim Holloway, Licensed under
the Common Development and Distribution License (CDDL). the Common Development and Distribution License (CDDL).
<p>Based on Gourmet Recipe Manager by T. <p>Based on Gourmet Recipe Manager by T.
Hinkle.</p> Hinkle</p>
</div> </div>
<!-- --> <!-- -->
</h:body> </h:body>

View File

@ -21,9 +21,6 @@ spring:
ddl-auto: none ddl-auto: none
database-platform: org.hibernate.dialect.MySQLDialect database-platform: org.hibernate.dialect.MySQLDialect
# From Maven POM:
appVersion: "@project.version@"
# Tracking-modes prevent URL rewrite jsessionid on Primecases # Tracking-modes prevent URL rewrite jsessionid on Primecases
# resources. Which causes "400" errors on initial main.jsf fetch. # resources. Which causes "400" errors on initial main.jsf fetch.
server: server:

View File

@ -1,16 +0,0 @@
[Unit]
Description=Gourmet Recipe Manager
Documentation=https://gogs.mousetech.com/gourmetj
Requires=network-online.target
After=network-online.target
[Service]
Type=simple
User=gourmetj
WorkingDirectory=/opt/mousetech/gourmetj
ExecStart=/usr/bin/java -jar gourmetj.jar
#Restart=yes
[Install]
Alias=gourmetj.service