Category Archives: Java

Jetty’s start.jar forks a new JVM to run the app if logback module is enabled

Jetty is too smart. If there is any JVM option provided, Jetty will spawn a new JVM instance to do the real work, even if you don’t use “–exec” option in start.ini

And jetty’s logback module introduces a JVM option. See here

You will see:

-Dorg.eclipse.jetty.util.log.class?=org.eclipse.jetty.util.log.Slf4jLog 

So does it matter?

It matters a lot because all the JVM options you passed to start.jar will stay on the process of start.jar. They are not passed to the forked JVM process.

What’s the solution ?

Since you have to let it fork a new JVM because of logback, you can just put all the JVM options in start.ini. Like,


--exec
-server
-Xms2g
-Xmx2g
-XX:+UseZGC


Code snippet: Swagger + Spring Boot

compile 'io.springfox:springfox-swagger2:2.9.2'
compile 'io.springfox:springfox-swagger-ui:2.9.2'
/**
 See https://www.baeldung.com/swagger-2-documentation-for-spring-rest-api
 */
 @Configuration
 @EnableSwagger2
 public class SwaggerConfig {
 @Value("${enable.swagger}")  //You may want to disabled it in PROD
 boolean enableSwagger;
 @Bean
 public Docket api() {
     Docket api = new Docket(DocumentationType.SWAGGER_2)
             .select()
             .apis(RequestHandlerSelectors.basePackage("your.package"))
             .paths(PathSelectors.any())
             .build();
        ApiInfo apiInfo = new ApiInfoBuilder()		
                .version("xxx")
                .description("xxx")
                .termsOfServiceUrl("xxx")
                .title("Xxx Doc")
                .build();

        api.useDefaultResponseMessages(false).apiInfo(apiInfo);

        api.enable(enableSwagger);

        return api;
    }
}


Generate PDF from server side using Java

You can use OpenPDF to draw a PDF (the open source fork of iText). However, the learning curve of creating PDF with layouts and stuff is very high.

A more cost-effective solution is create an HTML version of it and convert it using Flying Saucer with its OpenPDF component

. As a Java developer you are already familiar with html + css, so doing that is quick.

There are some limitations and side effects of this approach

  • Your html must be XML/XHTML
  • Styles’ version must be no more than CSS 2.1. (So you can’t use flexbox layout)
  • No javascript
  • More: https://flyingsaucerproject.github.io/flyingsaucer/r8/guide/users-guide-R8.html#xil_6
  • The image quality seems worse than what you see on the html page, if there is any

And to create a PDF, your html can’t be too wide, otherwise content may be lost.

Typically, say you are creating an A4 PDF with margin of 0.1 inch on both left and right, the width of your html should not be more than (A4’s paper width – margin) * pixe density = (8.27inch – 0.1 inch * 2) * 96 DPI = 774 pixels

And here is how to set up the size and margin of the PDF in your html:

<head>
    <style>
        @page {
            margin-left: 9px;   /* about 0.1 inch */ 
            margin-right: 9px; 
            size: A4;
        }
    </style>
   ...

Gradle upload a custom-generated jar file to Nexus

Do this:

apply plugin: 'maven-publish'


   publishing {
        publications {
            maven( MavenPublication ) {
                artifact theTaskThatGeneratesJar
            }
        }
        repositories {
            maven {
                def releasesRepoUrl = http://.../repositories/releases/'
                def snapshotsRepoUrl = 'http://.../repositories/snapshots/'
                url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
                credentials {
                    username 'xxx'
                    password 'xxx'
                }
            }
        }

    }


Sending html emails with images inside

If the images are external image links that can be accessed by http url, then nothing speical needs to be done.

If the images are external image files, then you have 2 choices.

Embed the images as base64 strings. . This is simple. However email clients such as gmail will refuse to render them

Using cid. This is the most robust way. An example can be found here . In addition, you should set the content type of the image body part as "image/png", otherwise the email receipients will see there are attachments

     
              MimeBodyPart imagePart = new MimeBodyPart();
                DataSource fds = new FileDataSource(imageFile);
                imagePart.setDataHandler(new DataHandler(fds));
                imagePart.setHeader("Content-ID", "<" + imageFile.getName() + ">");
                imagePart.setHeader("Content-Type", "image/png");

Things to do for a serious Java website when using Elastic Beanstalk

Before you start

Get a domain

If you haven’t got one, you can buy one. You can get it from AWS Route 53

Get a SSL certificate for your domain

You can get it from AWS Certificate Manager.

Create an IAM User

You will need this user’s access key and access secret to run eb-cli

Create a keypair

You need this to ssh login to your EC2 instance

Some limitations to your code

  • You application should listen to port 5000. Beanstalks’ included nginx will map it to 80
  • Don’t let your app read from System.getProperty(), but from System.getEnv(), if you don’t want to add any other file other than your *.war/*.shaded-jar to upload to Beanstalk. Tnat’s because Beanstalk can take enviroment properties only by default
  • Let all your log4j loggers write to console instead of any file. Console outptu will be automatically collected by Beanstalk
  • Let your webapp have a health check url, which can be configured with Beanstalk’s load balancer

Create your beanstalk application

You can do this with the web console or eb-cli

After application created

  • Add a CNAME to your own domain. So www.yoursite.com will point to xxx.xxx-beanstalk.com
  • In Beanstalk’s load balancer, disable http 80 and enable https 443, use the SSL certificate your got from AWS Certificate Manager
  • Try ssh log-in using eb-cli’s “eb ssh”.
  • Set up the security group of your RDS, so that you can access it from your local machine

Quick log4j set up

<!-- pom.xml --> 


		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>1.7.7</version>
		</dependency>

		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>1.7.7</version>
		</dependency>


<!-- src/main/resources/log4j.xml --> 
  
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

	<appender name="my-file-appender" class="org.apache.log4j.FileAppender">
		<param name="file" value="some.file" />
		<param name="append" value="true" />
		<param name="encoding" value="UTF-8" />
		<layout class="org.apache.log4j.PatternLayout">
			<param name="ConversionPattern" value="%d %t %-5p %c - %m%n" />
		</layout>
	</appender>

	<appender name="console" class="org.apache.log4j.ConsoleAppender">
	    <layout class="org.apache.log4j.PatternLayout">
		<param name="ConversionPattern" value="%d %t %-5p %c - %m%n" />
	    </layout>
	</appender>

	<logger name="com.my.package">
		<level value="info" />  
		<appender-ref ref="my-file-appender" />
	</logger>	

	<root>
		<level value="warn" />
		<appender-ref ref="console" />
	</root>

</log4j:configuration>

If you don’t get expected result, add "-Dlog4j.debug" to your VM options and see the diagnotisc information