JAR Manifest File

JAR files support a wide range of functionality, including electronic signing, version control, package sealing, and others. What gives a JAR file this versatility? The answer is the JAR file’s manifest.

The manifest is a special file that can contain information about the files packaged in a JAR file. By tailoring this “meta” information that the manifest contains, you enable the JAR file to serve a variety of purposes.

Default Manifest

  • When you create a JAR file, it automatically receives a default manifest file. There can be only one manifest file in an archive, and it always has the below pathname
META-INF/MANIFEST.MF
  • When you create a JAR file, the default manifest file simply contains the following:
Manifest-Version: 1.0
Created-By: 1.7.0_06 (Oracle Corporation)
  • The manifest can also contain information about the other files that are packaged in the archive.
  • Exactly what file information should be recorded in the manifest depends on how you intend to use the JAR file.
  • The default manifest makes no assumptions about what information it should record about other files.

Modifying a Manifest File

  • The Jar tool automatically puts a default manifest with the pathname META-INF/MANIFEST.MF into any JAR file you create. 
  • You can enable special JAR file functionality, such as package sealing, by modifying the default manifest. 
  •  Typically, modifying the default manifest involves adding special-purpose headers to the manifest that allow the JAR file to perform a particular desired function.

The basic command has this format:

jar cfm jar-file manifest-addition input-file(s)
  • The c option indicates that you want to create a JAR file.
  • The m option indicates that you want to merge information from an existing file into the manifest file of the JAR file you’re creating.
  • The f option indicates that you want the output to go to a file (the JAR file you’re creating) rather than to standard output.
  • manifest-addition is the name (or path and name) of the existing text file whose contents you want to add to the contents of JAR file’s manifest.
  • jar-file is the name that you want the resulting JAR file to have.
  • The input-file(s) argument is a space-separated list of one or more files that you want to be placed in your JAR file.

Setting an Application’s Entry Point

  • If you have an application bundled in a JAR file, you need some way to indicate which class within the JAR file is your application’s entry point. You provide this information with the Main-Class header in the manifest, which has the general form:
Main-Class: classname
  • The value classname is the name of the class that is your application’s entry point.
  • Recall that the entry point is a class having a method with signature public static void main(String[] args).
  • After you have set the Main-Class header in the manifest, you then run the JAR file using the following form of the java command:
java -jar JAR-name
  • The main method of the class specified in the Main-Class header is executed.

Example :

We want to execute the main method in the class MyClass in the package MyPackage when we run the JAR file.

We first create a text file named Manifest.txt with the following contents:

Main-Class: MyPackage.MyClass

Read Me :

https://docs.oracle.com/javase/tutorial/deployment/jar/modman.html
  • Warning: The text file must end with a new line or carriage return. The last line will not be parsed properly if it does not end with a new line or carriage return.

We then create a JAR file named MyJar.jar by entering the following command:

jar cfm MyJar.jar Manifest.txt MyPackage/*.class

This creates the JAR file with a manifest with the following contents:

Manifest-Version: 1.0
Created-By: 1.7.0_06 (Oracle Corporation)
Main-Class: MyPackage.MyClass

When you run the JAR file with the following command, the main method of MyClass executes:

java -jar MyJar.jar

Setting an Entry Point with the JAR Tool

The ‘e’ flag (for ‘entrypoint’) creates or overrides the manifest’s Main-Class attribute. It can be used while creating or updating a JAR file. Use it to specify the application entry point without editing or creating the manifest file.
For example, this command creates app.jar where the Main-Class attribute value in the manifest is set to MyApp:

jar cfe app.jar MyApp MyApp.class

You can directly invoke this application by running the following command:

java -jar app.jar

If the entrypoint class name is in a package it may use a ‘.’ (dot) character as the delimiter. For example, if Main.class is in a package called foo the entry point can be specified in the following ways:

jar cfe Main.jar foo.Main foo/Main.class

Adding Classes to the JAR File’s Classpath

You may need to reference classes in other JAR files from within a JAR file.

For example, in a typical situation an applet is bundled in a JAR file whose manifest references a different JAR file (or several different JAR files) that serves as utilities for the purposes of that applet.

You specify classes to include in the Class-Path header field in the manifest file of an applet or application. The Class-Path header takes the following form:

Class-Path: jar1-name jar2-name directory-name/jar3-name

By using the Class-Path header in the manifest, you can avoid having to specify a long -classpath flag when invoking Java to run the your application.

Note: The Class-Path header points to classes or JAR files on the local network, not JAR files within the JAR file or classes accessible over Internet protocols. To load classes in JAR files within a JAR file into the class path, you must write custom code to load those classes. For example, if MyJar.jar contains another JAR file called MyUtils.jar, you cannot use the Class-Path header in MyJar.jar’s manifest to load classes in MyUtils.jar into the class path.

An Example

We want to load classes in MyUtils.jar into the class path for use in MyJar.jar. These two JAR files are in the same directory.

We first create a text file named Manifest.txt with the following contents:

Class-Path: MyUtils.jar

Warning: The text file must end with a new line or carriage return. The last line will not be parsed properly if it does not end with a new line or carriage return.


We then create a JAR file named MyJar.jar by entering the following command:

jar cfm MyJar.jar Manifest.txt MyPackage/*.class

This creates the JAR file with a manifest with the following contents:

Manifest-Version: 1.0
Class-Path: MyUtils.jar
Created-By: 1.7.0_06 (Oracle Corporation)

The classes in MyUtils.jar are now loaded into the class path when you run MyJar.jar.

ReadMe : https://docs.oracle.com/javase/tutorial/deployment/jar/packageman.html

JAR Create/View/Update – Command Line

What is JAR?

  • JAR stands for Java Archival

What is Archival ?

  • Grouping of files together in a single file is called archive

How to create JAR ?

  • Using JAR command ( C for create JAR)
jar c <class-file-name1>
  • But using above command the JAR contents is writtren into Standard Output, to write the content into a file (f for file) f attribute has to be used
jar cf <jar-file> <class-file-name1>
  • You can add v attribute to show verbose output
jar cfv <jar-file> <class-file-name1>
  • You can also add a directory instead of file as JAR attribute
jar cfv <jar-file> <dir>
  • As you can see in above example bin directory got included in the jar and if you do not want to the parent bin folder to be see inside jar to you direct JAR command to cd to a directory and then pull files. (-C command achieves this )

jar cfv <jar-file> -C bin/ .

  • You can add m attribute (m for creating manifest file) for creating the manifest file inside JAR.(Purpose of manifest file is to create a runnable jar)

View JAR contents using below command

jar tf <jar-file-name>
  • Extract a file from JAR using below command
jar xf jar-file <file-to-be-extracted-1>
  • Update the contents of JAR
jar uf jar-file input-file(s)
  • Executing a executable JAR (Executable i.e entry in Manifest file)
java -jar JarExample.jar "arg1" 
  • Executing a non executable JAR
java -cp JarExample.jar com.demo.FileDemo "args1"

Java Compile – Command Line

Why Compile?

  • .java files are converted into .class files which are bytecodes
  • This compilation is done by using javac command which stands for java-compiler
  • These bytecodes can be executed by JVM at runtime.

How to compile bunch of .java files together :

  • First create a file with the names of all .java files using below command
find . -type f -iname "*.java" > source.txt
  • Then compile it using javac command
javac @source.txt
  • You can provide the jar in the class path using -cp attribute
javac -cp "lib/*" @source.txt
  • Verbose output can be triggered using -verbose attribute
javac -verbose -cp "lib/*" @source.txt
  • You can put all the .class files into bin directory using -d attribute
javac -verbose -cp "lib/*" -d bin @source.txt

Log4j2

Jars

'org.apache.logging.log4j:log4j-api:2.13.3'
'org.apache.logging.log4j:log4j-core:2.13.3'

Sample Code :

package com.log4j2demo;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Demo {
	private static final Logger LOGGER = LogManager.getLogger(Demo.class);
	public static void main(String[] args) {
		System.out.println("Hello");
		LOGGER.debug("This is a debug statement");
		LOGGER.info("This is Info Log");
		LOGGER.error("This is Error Log", new NullPointerException());
		LOGGER.fatal("This is Fatal Log");
		LOGGER.trace("This is trace Log");
	}
}

Log4j2.properties (on class path)

status = error 
#The level of internal Log4j events that should be logged to the console. 
#"trace", "debug", "info", "warn", "error" and "fatal"

name = PropertiesConfig
#The name of the configuration.
 
property.filename = /home/tyson/Desktop/MoveScript/debug.log
#Make sure to change log file path as per your need
 
filters = threshold
filter.threshold.type = ThresholdFilter
filter.threshold.level = debug
#https://logging.apache.org/log4j/log4j-2.3/manual/filters.html (Accept/Deny/Threshold)
#Literally Filtering Logs

#appenders = rolling
 
appender.rolling.type = RollingFile
appender.rolling.name = RollingFile
appender.rolling.fileName = ${filename}
appender.rolling.append = true
#  ${filename} will be replaced by property.filename values
appender.rolling.filePattern = /home/tyson/Desktop/MoveScript/debug-backup-%d{yyyy-MM-dd}-%i.log
appender.rolling.layout.type = PatternLayout
appender.rolling.layout.pattern = %d{yyyy-MM-dd HH:mm:ss} %-5p %c{2}:%L - %m%n
# %d is the date
# %-5p is the priority
# %c{1} Logger name (org.apache.commons.Foo) and reslt (Foo)
# %L for line
# %m for message
# %n for /n
#reference https://logging.apache.org/log4j/2.x/manua%l/layouts.html#PatternLayout
appender.rolling.policies.type = Policies
appender.rolling.policies.time.type = TimeBasedTriggeringPolicy
appender.rolling.policies.time.interval = 1
#Interval depends on the pattern specified (appender.rolling.filePattern) last value if mm then 1 minutes HH then 1H
appender.rolling.policies.time.modulate = true
appender.rolling.policies.size.type = SizeBasedTriggeringPolicy
appender.rolling.policies.size.size=10MB
appender.rolling.strategy.type = DefaultRolloverStrategy
appender.rolling.strategy.max = 20
#appender.rolling.append
 
loggers = rolling
logger.rolling.name = com.log4j2demo
#Make sure to change the package structure as per your application
logger.rolling.level = debug
logger.rolling.additivity = true
#The rolling file appender will be displayed on console as well
logger.rolling.appenderRef.rolling.ref = RollingFile

#Read Me
# https://logging.apache.org/log4j/2.x/manual/configuration.html#ConfigurationSyntax
# Layput https://logging.apache.org/log4j/2.x/manual/layouts.html

Move Script

moveFile.sh

#! /bin/bash
move_config=/home/tyson/Desktop/MoveScript/script/move.config
echo Move Script executed on `date`

file_type=$1
if [ -z $file_type ]; then
    echo Please provide a file type to be moved
    exit 1 
fi

file_move_config=$(grep -w ^$file_type= $move_config)
if [ -z $file_move_config ]; then
    echo IncorrectFile Type provided
    echo Kindly refere $move_config file to correct the input
    exit 1
fi

source=$(echo $file_move_config | awk -F'=' '{print $3}')
destination=$(echo $file_move_config | awk -F'=' '{print $2}')
archive=$(echo $file_move_config | awk -F'=' '{print $4}')
echo ---------------------------------------------
echo Source      : $source
echo Destination : $destination
echo Archive     : $archive

if [[ ! -d $source || ! -d $destination || ! -d $archive ]]; then
    echo Once of the source, destination or archive directory is missing hence cannot move the files
    echo Source      : $source
    echo Destination : $destination
    echo Archive     : $archive
    exit 1
fi

echo ---------------------------------------------

for entry in "$source"/* ; do
    if [ -f $entry ] ; then
        echo $entry
        copy_command="cp $entry $destination/$(basename $entry)"
        move_command="mv $entry $archive/$(basename $entry)_$(date '+%Y%m%d-%H%M%S')"
        echo $copy_command
        echo $move_command
        # [[ $copy_command ]] &amp;&amp; [[ $move_command ]] || echo "Failed to move"
        ($copy_command) &amp;&amp; ($move_command) || echo "Failed to move"
    fi
done

move.config

#Synatx: Name=Destination=Source=Archive
A=/home/tyson/Desktop/MoveScript/CommonDir/A=/home/tyson/Desktop/MoveScript/Files/A/Sent=/home/tyson/Desktop/MoveScript/Files/A/Archive
B=/home/tyson/Desktop/MoveScript/CommonDir/B=/home/tyson/Desktop/MoveScript/Files/B/Sent=/home/tyson/Desktop/MoveScript/Files/B/Archive
C=/home/tyson/Desktop/MoveScript/CommonDir/C=/home/tyson/Desktop/MoveScript/Files/C/Sent=/home/tyson/Desktop/MoveScript/Files/C/Archive

All about Brackets & Quotes in Shell Script

Brackets

if [ CONDITION ]    Test construct  
if [[ CONDITION ]]  Extended test construct  
Array[1]=element1   Array initialization  
[a-z]               Range of characters within a Regular Expression
$[ expression ]     A non-standard &amp; obsolete version of $(( expression )) [1]

Curly Braces

${variable}                             Parameter substitution  
${!variable}                            Indirect variable reference  
{ command1; command2; . . . commandN; } Block of code  
{string1,string2,string3,...}           Brace expansion  
{a..z}                                  Extended brace expansion  
{}                                      Text replacement, after find and xargs

Parentheses

( command1; command2 )             Command group executed within a subshell  
Array=(element1 element2 element3) Array initialization  
result=$(COMMAND)                  Command substitution, new style  
>(COMMAND)                         Process substitution  
<(COMMAND)                         Process substitution 

Double Parentheses

(( var = 78 ))            Integer arithmetic   
var=$(( 20 + 5 ))         Integer arithmetic, with variable assignment   
(( var++ ))               C-style variable increment   
(( var-- ))               C-style variable decrement   
(( var0 = var1<98?9:21 )) C-style ternary operation

Example :

~:$ echo $SHELL
/bin/bash

~:$ echo ${#SHELL}
9

~:$ ARRAY=(one two three)

~:$ echo ${#ARRAY}
3

~:$ echo ${TEST:-test}
test

~:$ echo $TEST


~:$ export TEST=a_string

~:$ echo ${TEST:-test}
a_string

~:$ echo ${TEST2:-$TEST}
a_string

~:$ echo $TEST2


~:$ echo ${TEST2:=$TEST}
a_string

~:$ echo $TEST2
a_string

~:$ export STRING="thisisaverylongname"

~:$ echo ${STRING:4}
isaverylongname

~:$ echo ${STRING:6:5}
avery

~:$ echo ${ARRAY[*]}
one two one three one four

~:$ echo ${ARRAY[*]#one}
two three four

~:$ echo ${ARRAY[*]#t}
one wo one hree one four

~:$ echo ${ARRAY[*]#t*}
one wo one hree one four

~:$ echo ${ARRAY[*]##t*}
one one one four

~:$ echo $STRING
thisisaverylongname

~:$ echo ${STRING%name}
thisisaverylong

~:$ echo ${STRING/name/string}
thisisaverylongstring

Read Me:

https://stackoverflow.com/questions/2188199/how-to-use-double-or-single-brackets-parentheses-curly-braces

http://mywiki.wooledge.org/BashFAQ/031