Compare commits
	
		
			No commits in common. "3cfbf9cf6ea3f967b8150eaa4a183b4c129a84fd" and "6f7ae313ce4c50bda1e0473ae8adf55817b71649" have entirely different histories.
		
	
	
		
			3cfbf9cf6e
			...
			6f7ae313ce
		
	
		
| 
						 | 
				
			
			@ -117,11 +117,3 @@ Followup: Excess payloads were being added to the welcome page
 | 
			
		|||
that caused HTTP "400" errors fetching resources. A fix has
 | 
			
		||||
been made, although the ultimate solution will probably be more
 | 
			
		||||
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.
 | 
			
		||||
| 
						 | 
				
			
			@ -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
									
									
									
									
									
								
							
							
						
						
									
										76
									
								
								pom.xml
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -7,7 +7,7 @@
 | 
			
		|||
 | 
			
		||||
    <groupId>com.mousetech.gourmet</groupId>
 | 
			
		||||
    <artifactId>gourmetj</artifactId>
 | 
			
		||||
    <version>2.0.1</version>
 | 
			
		||||
    <version>0.3.0</version>
 | 
			
		||||
    <packaging>jar</packaging>
 | 
			
		||||
 | 
			
		||||
    <name>GourmetJ</name>
 | 
			
		||||
| 
						 | 
				
			
			@ -17,7 +17,7 @@
 | 
			
		|||
    <parent>
 | 
			
		||||
        <groupId>org.springframework.boot</groupId>
 | 
			
		||||
        <artifactId>spring-boot-starter-parent</artifactId>
 | 
			
		||||
        <version>3.2.3</version>
 | 
			
		||||
        <version>3.2.2</version>
 | 
			
		||||
        <relativePath /> <!-- lookup parent from repository -->
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -177,78 +177,6 @@
 | 
			
		|||
                <groupId>org.springframework.boot</groupId>
 | 
			
		||||
                <artifactId>spring-boot-maven-plugin</artifactId>
 | 
			
		||||
            </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>
 | 
			
		||||
    </build>
 | 
			
		||||
    
 | 
			
		||||
</project>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1 +0,0 @@
 | 
			
		|||
# Application user password 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
 | 
			
		||||
| 
						 | 
				
			
			@ -3,8 +3,6 @@ package com.mousetech.gourmetj;
 | 
			
		|||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import org.springframework.beans.factory.annotation.Value;
 | 
			
		||||
 | 
			
		||||
import jakarta.enterprise.context.ApplicationScoped;
 | 
			
		||||
import jakarta.faces.model.SelectItem;
 | 
			
		||||
import jakarta.inject.Named;
 | 
			
		||||
| 
						 | 
				
			
			@ -49,12 +47,5 @@ public class AppBean {
 | 
			
		|||
			new SelectItem(RecipeSearchType.rst_BY_INGREDIENT.ordinal(),
 | 
			
		||||
					"Ingredient"));
 | 
			
		||||
		return list;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	@Value("${appVersion}")
 | 
			
		||||
	String appVersion = "Not Supplied.";
 | 
			
		||||
	
 | 
			
		||||
	public String getAppVersion() {
 | 
			
		||||
		return appVersion;
 | 
			
		||||
	}
 | 
			
		||||
	}	
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,7 +18,7 @@
 | 
			
		|||
            </h:head>
 | 
			
		||||
            <h:body>
 | 
			
		||||
                <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>
 | 
			
		||||
                <p:ajaxStatus onerror="PF('opError').show()"/>
 | 
			
		||||
                <ui:insert name="content">
 | 
			
		||||
| 
						 | 
				
			
			@ -28,11 +28,10 @@
 | 
			
		|||
                </ui:insert>
 | 
			
		||||
                <!--  -->
 | 
			
		||||
                <div id="footer">
 | 
			
		||||
                    <h:outputText value="Version #{appBean.appVersion}"/><br/>
 | 
			
		||||
                    (C) 2021, 2024 Tim Holloway, Licensed under
 | 
			
		||||
                     the Common Development and Distribution License (CDDL).
 | 
			
		||||
                    <p>Based on Gourmet Recipe Manager by T.
 | 
			
		||||
                        Hinkle.</p>
 | 
			
		||||
                        Hinkle</p>
 | 
			
		||||
                </div>
 | 
			
		||||
                <!--  -->
 | 
			
		||||
            </h:body>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,9 +21,6 @@ spring:
 | 
			
		|||
      ddl-auto: none
 | 
			
		||||
    database-platform: org.hibernate.dialect.MySQLDialect
 | 
			
		||||
 | 
			
		||||
# From Maven POM:
 | 
			
		||||
appVersion: "@project.version@"
 | 
			
		||||
 | 
			
		||||
# Tracking-modes prevent URL rewrite jsessionid on Primecases
 | 
			
		||||
# resources. Which causes "400" errors on initial main.jsf fetch.
 | 
			
		||||
server:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user