Recommendations and Best Practices

Build and Version Info

To be able to have the build date and version of your apps at runtime, it is recommended to create a file named build.properties file in the src/main/resources folder with the following contents.

version=${pom.version}
build.date=${timestamp}

No need to modify the pom.xml file, it is already managed in the parent project.

Config

  • If you have multiple projects and you don’t want to place the Git repository configuration in each project, you can put the pre.config.properties in a commons-lib project, and create an app.config.properties in each project with the app.name key only with a unique name for the containing app.

  • To have more flexibility and security, you can replace your config.properties or pre.config.properties during the CICD process to have the right configuration to avoid exposing production and other environment configurations to the wrong people.

Exception Handling

  • If you have checked exceptions, always have only one catch statement.

  • Never catch Runtime exception.

  • In the catch statement just call JK.throw(e); the framework will handle the rest.

  • If you are handling an exception inside a method that should return value, it is safe to return null after JK.throw(e).

Project Structure for Web Apps

As shown in the below figure, below is the preferred project structure for J-Framework Web applications:

  1. Create the following folders in src/main/webapp:

    • resources.

    • admin.

    • login.

    • pages.

    • public.

  2. Templates: Create three facelet template files in src/main/webapps/WEB-INF/templates:

    • default.xhtml (look below for a proposed template).

    • empty.xhtml (look below for a proposed template).

    • error.xhtml (look below for a proposed template).

  3. CSS: In the resources created:

    • app.css: consists of the high layout of the app, mainly covering the styles in the default.xhtml template.

    • app.js: consists of the main Javascript functions and callbacks that are mainly required on the app which are most likely called references from default.xhtml template.

    • css/primefaces-fix.css: this file will include any overridden styles of prime-faces components on the app level, for specific page changes, you need to override in the page.css of that page.

    • css/root.css: this file shall contain the main theme variables, check the below example for more information.

    • css/components/component1.css: in the case of complex pages, it could be a good idea to create a css file for each component.

  4. Each page in the pages folder should contain page.css and page.js files next to the index.xhtml.

  5. On each page, and for consistency, make sure to:

    • Use ${request.contextPath} before any relative URL.

    • use ?reload=#{util.reloadRandom()} next to any static resources URL such as Javascript or css, to ensure a refresh in development time on each request for easier development.

  6. Pages Structure

    • Create a public/home folder for public pages access.

    • Create an admin folder for admin pages access.

    • Create a pages folder for protected pages.

    • Each page should be treated as a folder, where the folder is the page name, and inside that folder, we shall have index.xhtml which will be automatically triggered if we only put the folder name in the URL. For example, if you have an employee page, create an employee folder in the pages folder, then create an index.xhtml page inside that folder, the full path will be src/main/webapp/pages/employee/index.xhtml.

    • Create a home page at pages/home/index.xhtml to serve as the default page after the user logs in.

    • Create src/main/webapp/index.xhtml that redirects to pages/home/

project structure

JSF/Faces on Production

JSF may require important tuning to run smoothly in a Production environment with low overhead.

The needed configuration is discussed in my DZone Article

But mainly, you will need to create a production web.xml that is placed in the project during the CICD process, the final web.xml should look something like this:

<?xml version="1.0" encoding="UTF-8"?>
<web-app
        xmlns = "https://jakarta.ee/xml/ns/jakartaee"
        xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation = "https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
        version = "5.0"
        metadata-complete = "false">
	<context-param>
		<param-name>jakarta.faces.PROJECT_STAGE</param-name>
		<param-value>Production</param-value>
	</context-param>
	<context-param>
		<param-name>jakarta.faces.FACELETS_REFRESH_PERIOD</param-name>
		<param-value>-1</param-value>
	</context-param>
</web-app>

Commons-Lib

It is highly recommended to create a common-lib project that will include all the common classes, APIs, components, and utilities that are needed by all the system components.

This library shall be deployed to artifact management software such as Nexus.

Microservices

  • Try to create Microservices clients by extending JKServiceClient or JKMatureServiceClient, this will make it easier for developers to call the other methods transparently.

  • Service Clients shall be created by the Microservice developer.

  • Service Clients and Models should be placed in the commons-lib project to be available to all other developers and projects.

  • Microservice component testing should at least include:

    • Launching the API using JKWebApplication.run()

    • Calling all the exposed endpoints using the developed client.

Frameworks and libraries such as Mockito could be utilized to provide the needed data during test automation.

Logging

It is recommended to use logging as follows:

  • Public method: logger.info(); at the start of each method.

  • Non-public methods: logger.debug()

  • Most of the time you will not need to use logger.error() since it will be used internally by the framework in case of exceptions or failure.

  • It could be a good idea to have logger.info at the end of each public method for later performance tuning.

Code Refactoring

  • JK.fixMe(); to remember back to the code block that needs to be fixed later.

  • JK.implementMe(); to throw an exception when called reminding you to fix ASAP.