Monday, November 24, 2014

Sending Mail along with attachments using Java

Following program can be used to send a mail using java:
I am using gmail smtp server here

package com;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.*;

import java.util.*;

public class SendMail {
// TODO: Change email ID and password
String d_email = "changeme@gmail.com"; // Give your complete mail ID here,
// like abc@gmail.com
String d_password = "changeme"; // Give your email ID password
String d_host = "smtp.gmail.com", d_port = "465";
String mail_to = "changeme@gmail.com";
String mail_subject = "Testing";
String mail_text = "Hey, this is the testing email.";

String[] filesToBeAttached = { "D:/Temp/two.pdf", "D:/Temp/one.zip",
"D:/Temp/three.pdf" };

public SendMail() {
Properties props = new Properties();
props.put("mail.debug", true);
props.put("mail.smtp.user", d_email);
props.put("mail.smtp.host", d_host);
props.put("mail.smtp.port", d_port);
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.auth", "true");
// props.put("mail.smtp.debug", "true");
props.put("mail.smtp.socketFactory.port", d_port);
props.put("mail.smtp.socketFactory.class",
"javax.net.ssl.SSLSocketFactory");
props.put("mail.smtp.socketFactory.fallback", "false");

try {
Authenticator auth = new SMTPAuthenticator();
Session session = Session.getInstance(props, auth);
session.setDebug(true);

MimeMessage msg = new MimeMessage(session);
msg.setText(mail_text);
msg.setSubject(mail_subject);
msg.setFrom(new InternetAddress(d_email));
msg.addRecipient(Message.RecipientType.TO, new InternetAddress(
mail_to));

// creates message part
MimeBodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setContent(mail_text, "text/html");

// creates multi-part
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyPart);


for (int i = 0; i < this.filesToBeAttached.length; i++) {
messageBodyPart = new MimeBodyPart();
FileDataSource fds = new FileDataSource(
this.filesToBeAttached[i]);
messageBodyPart.setDataHandler(new DataHandler(fds));
messageBodyPart.setFileName(fds.getName());
multipart.addBodyPart(messageBodyPart);

}

// sets the multi-part as e-mail's content
msg.setContent(multipart);

Transport.send(msg);
} catch (Exception mex) {
mex.printStackTrace();
}
}

private class SMTPAuthenticator extends javax.mail.Authenticator {
public PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(d_email, d_password);
}
}

public static void main(String[] args) {
new SendMail();
}
}

Sunday, October 26, 2014

JAX-WS: HelloWorld Example

Here I am going to give the detailed steps about creating an HelloWorld JAX-Webservice without any IDE.

Steps:

1. Create the following folder structure tomcat's webapps folder

tomcat/webapps

HelloWorldWS
___META-INF
______context.xml
___WEB-INF
______src
_________HelloWorld.java
______classes
______lib
_________activation-1.1.jar
_________webservices-api-2.1-b16.jar
_________webservices-extra-2.1-b16.jar
_________webservices-extra-api-2.1-b16.jar
_________webservices-rt-2.1-b16.jar
_________webservices-tools-2.1-b16.jar
______sun-jaxws.xml
______web.xml

2. HelloWorld.java:

package com.wservice.provider;

import javax.jws.WebService;

@WebService
public class HelloWorld {
public String greetMe(String name) {
return "Hello, Mr. " + name;
}
}

3. Open command prompt and cd to the WEB-INF/ directory

C:\Program Files\Apache Software Foundation\Tomcat 6.0\webapps\HelloWorldWs\WEB-INF>javac -d classes src\com\wservice\provider\HelloWorld.java

4. context.xml

<?xml version="1.0" encoding="UTF-8"?>
<Context antiJARLocking="true" path="/HelloWorldWs"/>

5. sun-jaxws.xml

<?xml version="1.0" encoding="UTF-8"?>
<endpoints version="2.0" xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime">
  <endpoint implementation="com.wservice.provider.HelloWorld" name="HelloWorldServlet" url-pattern="/greet"/>
</endpoints>

6. web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <listener>
        <listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>HelloWorldServlet</servlet-name>
        <servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>HelloWorldServlet</servlet-name>
        <url-pattern>/greet</url-pattern>
    </servlet-mapping>
</web-app>


Thats it on provider side...
Now restart the tomcat server and try accessing the below URL in browser:

http://localhost:8080/HelloWorldWs/greet?wsdl



CONSUMER:

1. Create the following folder structure, for standalone java program

HelloWorldClient
___src
______com.wservice.consumer
__________HelloWorldClientProg.java
___bin

2. Run the following command from HelloWorldClient/ folder

wsimport -s src -d bin -p com.wservice.provider http://localhost:8080/HelloWorldWs/greet?wsdl

This will generate a set of classes.


3. HelloWorldClientProg.java

package com.wservice.consumer;

import com.wservice.provider.HelloWorld;
import com.wservice.provider.HelloWorldService;

public class HelloWorldClientProg {
HelloWorldService service = null;

public HelloWorldClientProg() {
service = new HelloWorldService();
}

public void testService() {
HelloWorld servicePort = service.getHelloWorldPort();

String greetMsg = servicePort.greetMe("Suresh");

System.out.println("Web service call response: " + greetMsg);
}

public static void main(String arags[]) {
HelloWorldClientProg client = new HelloWorldClientProg();
client.testService();
}
}

This should call the respective web service running on tomcat server.

Sunday, September 28, 2014

Annotations: Java

Annotation is a tag, of interface type, which will be processed during compile-time or run-time.

The concept of "Annotations" in java is introduced in java 1.5.
These are inserted into the code to provide more information about the code(meta code)

Annotations can be processed by the compiler (or) annotation processing tools, which can be made available at run-time.
eg: Java predefined annotations are processed by "apt.exe" under jdk's bin folder
Servlet specific annotations are processed by a jar called "annotations-api.jar"

Advantages of using Annotations:
1. Provides a kind of information to the compiler, for eg: to detect programmer error(Override) or to suppress warnings
2. Compile-time and Deployment-time processing
3. Run-time processing

Types of Annotations:
There can be two types of annotations
1. Built-in annotations(Predefined)
2. Custom annotations(User-defined)

1. Built-in Annotations:
These are provided by Sun as part of java 1.5
There are 7 built-in annotations

  • Override
  • Deprecated
  • SuppressWarnings
  • Retention
  • Target
  • Documented
  • Inherited


@Override, @Deprecated, @SuprressWarnings - These 3 are called Regular Java Annotations and are used at compile-time.
Remaining 4 (Retention, Target, Documented, Inherited) are used to create custom annotations.

Regular Annotations:

1. @Override
This can be used by the compiler to check whether a method in sub-class is properly overriding its super-class method or not.
The Retention Policy for @Override annotation is SOURCE, which means this java annotation will be discarded completely after compiling the code and would not be included in .class file or byte code.

eg:
I want to override equals method in Object class, whose signature is:
public boolean equals(Object obj)

class OverrideDemo {
        @Override
        public boolean equals(OverrideDemo od) {
                return false;
        }
}

Compiler output:

If you replace equals method parameter "OverrideDemo" with "Object", it gets compiled without any errors.

2. @Deprecated:
This can be specified to all types - variables/classes/methods.

When this is specified for a method, it indicates the developer who are using those API methods, that this method should not be used and it is expected to be removed in future releases.

If developer still uses it, it gives a warning during compile-time.

eg:
@Deprecated
class ClassOne {
}

public class DeprecatedDemo {
        static public void main(String[] args) {
                ClassOne one = new ClassOne();
        }
}

Compiler output:


3. @SuppressWarnings:
This instructs the compiler to suppress warnings of a particular type that are shown during compilation time.

This can be applied only to Classes.

For this annotation type, we must pass the value which should be suppressed. If no value is passed, compiler flags it with following error.
annotation java.lang.SuppressWarnings is missing value

eg:
import java.util.List;
import java.util.ArrayList;

public class ListDemo {
        static public void main(String[] args) {
                List list = new ArrayList();
                list.add("one");
        }
}

Compiler output:


Now if you modify the code as below, to remove "unchecked" or "unsafe" warnings, compiler will not flag any warning.

import java.util.List;
import java.util.ArrayList;

@SuppressWarnings(value="unchecked")
public class ListDemo {
        static public void main(String[] args) {
                List list = new ArrayList();
                list.add("one");
        }
}

Meta Annotations:
These are used to create custom java annotations.
These are part of "java.lang.annotation" package.

1. @Retention:
Retention Policy: The Retention policy determines at which point of time, an annotation should be discarded.

There are 3 types of retention policies, which are specified using an enum class "java.lang.annotation.RetentionPolicy".

  • SOURCE: Annotations are to be discarded by the compiler.
  • CLASS: Annotations are to be recorded in the class file by the compiler but need not be retained by the VM at run time.  This is the default behavior.
  • RUNTIME: Annotations are to be recorded in the class file by the compiler and retained by the VM at run time, so they may be read reflectively.
2. @Target:
This is a meta annotation that defines the target type or type of programming element.
Allowed target types are defined in the enum class "java.lang.annotation.ElementType", which are: TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE.

3. @Documented:
4. @Inherited:

Marker Annotation:
An annotation type with no elements is termed a marker annotation type.

Single Member Annotation:
An annotation with only single member is termed as "Single Member Annotation", whose value can be specified directly or with an attribute called "value".


Marker Annotation Example:

package com;

import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;

@Retention(RetentionPolicy.RUNTIME)
@interface MyMarkerAnnotation {
}

enum AnnotationType {
METHOD, CLASS;
}

@Deprecated
class TestMarkerAnnoationClass {
@MyMarkerAnnotation
@Deprecated
public void markerMethod() {

}
}

public class MarkerAnnotationDemo {

public void testMarkerMethod(String methodName, Class methodClass,
Class annotClass) throws Exception {
try {
Method method = methodClass.getMethod(methodName, null);

boolean annotPresent = method.isAnnotationPresent(annotClass);

if (annotPresent)
System.out.println(methodName + "() has annotation of type: "
+ annotClass.getName());
else
throw new Exception("No such Annotation present");
} catch (SecurityException se) {

} catch (NoSuchMethodException nsme) {

}
}

public void printAnnotations(String clsName, String methName,
AnnotationType annotType) {
try {
if (annotType.equals(AnnotationType.CLASS)) {
Class cls = Class.forName(clsName);
Annotation[] annots = cls.getAnnotations();

System.out.print("Annotations for: " + annotType + " are:");
for (Annotation annot : annots)
System.out.print(" " + annot);
System.out.println();
} else if (annotType.equals(AnnotationType.METHOD)) {
Class cls = Class.forName(clsName);
Method method = cls.getMethod(methName, null);

Annotation[] annots = method.getAnnotations();

System.out.print("Annotations for method: " + methName
+ " of class: " + clsName + " are:");
for (Annotation annot : annots)
System.out.print(" " + annot);
System.out.println();
}
} catch (Exception e) {
e.printStackTrace();
}
}

static public void main(String[] args) throws Exception {
MarkerAnnotationDemo demo = new MarkerAnnotationDemo();

demo.testMarkerMethod("markerMethod", TestMarkerAnnoationClass.class,
MyMarkerAnnotation.class);
// demo.testMarkerMethod("markerMethod", String.class);

demo.printAnnotations("com.TestMarkerAnnoationClass", null,
AnnotationType.CLASS);
demo.printAnnotations("com.TestMarkerAnnoationClass", "markerMethod",
AnnotationType.METHOD);
}
}

Output:
markerMethod() has annotation of type: com.MyMarkerAnnotation
Annotations for: CLASS are: @java.lang.Deprecated()
Annotations for method: markerMethod of class: com.TestMarkerAnnoationClass are: @com.MyMarkerAnnotation() @java.lang.Deprecated()


Single Member Annotation Example:

package com;

import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;

@Retention(RetentionPolicy.RUNTIME)
@interface SingleMemberAnnotation {
String name();
}

class TestSingleMemberAnnot {
@SingleMemberAnnotation(name="Suresh Reddy")
public void singleMemMethod() {
}
}

public class SingleMemberAnnotDemo {
public void testSingleMemberMethod() throws Exception {
Class cls = Class.forName("com.TestSingleMemberAnnot");
Method method = cls.getMethod("singleMemMethod", null);

SingleMemberAnnotation singleMemAnnot = (SingleMemberAnnotation) method
.getAnnotation(SingleMemberAnnotation.class);

System.out.println(singleMemAnnot.name());
}

static public void main(String[] args) throws Exception {
SingleMemberAnnotDemo demo = new SingleMemberAnnotDemo();
demo.testSingleMemberMethod();
}
}

Output:
Suresh Reddy


Single Member Annotation with default value Example:
package com;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;

@Retention(RetentionPolicy.RUNTIME)
@interface DefaultValAnnotation {
public String name() default "Reddy";
}

class DefaultValAnnotClass {
@DefaultValAnnotation()
public void testDefaultValMethod() {

}

@DefaultValAnnotation(name="Suresh Reddy")
public void testDefaultValMethod1() {

}
}

public class DefaultValAnnotDemo {
public void testSingleMemberMethod() throws Exception {
Class cls = Class.forName("com.DefaultValAnnotClass");
Method method = cls.getMethod("testDefaultValMethod", null);

DefaultValAnnotation singleMemAnnot = (DefaultValAnnotation) method
.getAnnotation(DefaultValAnnotation.class);

System.out.println(singleMemAnnot.name());

Method method1 = cls.getMethod("testDefaultValMethod1", null);

DefaultValAnnotation singleMemAnnot1 = (DefaultValAnnotation) method1
.getAnnotation(DefaultValAnnotation.class);

System.out.println(singleMemAnnot1.name());
}

static public void main(String[] args) throws Exception {
DefaultValAnnotDemo demo = new DefaultValAnnotDemo();
demo.testSingleMemberMethod();
}

}

Output:
Reddy
Suresh Reddy

Wednesday, September 17, 2014

JVM Interview Questions

1. Which byte order(Little Endian or Big Endian) JVM uses?

Java used network byte order (which is big endian)

Lets say there are four memory addresses for lower to higher: 1000, 1001, 1002, 1003
and an integer of 32 bits(4 bytes) needs to be stored in these addresses.
integer in HEX format is: 10 AB 5B H4

Little Endian: Least significant byte will be stored in smallest address.
So value - address mapping will be: 10 > 1003, AB > 1002, 5B > 1001, H4 > 1000

Big Endian: Most significant byte will be stored in smallest address.
So value - address mapping will be: 10 > 1000, AB > 1001, 5B > 1002, H4 > 1003

Tuesday, September 9, 2014

Type Conversion in assignments

Its very important to understand when implicit type conversion happens and when we need explicit conversion, in case of primitive types.

Implicit narrowing conversion for primitives assignment happens in situations where ALL of the following conditions are satisfied:
1. The source value/variable(so it should be final) is a CONSTANT EXPRESSION of types: byte/short/char/int
2. The target variable must be of type: byte/short/char
3. The value of the source is determined to be in the range of the target type during compile time.

eg:

Implicit conversions:
short s1 = 11;
short s2 = 'b';
char c1 = 33;
char c2 = (byte) 36;
byte b1 = 45;
byte b2 = (short) 43;
final int i1 = 22;
byte b3 = i1;

Explicit Conversion cases:
int i2 = -20;
final int i3 = i2;
final int i4 = 200;

short s3 = (short) i2; //since i2 is not a constant expression
char c3 = (char) i3; //since i3 value cannot be determined, as it is depending on i2
char c4 = (char) i2; //since i2 is not a constant expression
byte b4 = (byte) 128; //int value not in range
byte b5 = (byte) i4; //final value of i4 variable is not in range

Logical Puzzles

Q: Fill the following structure with numbers from 1 to 8.
No number should have its next number as its adjacent(up/down/left/right/diagonal)



Answer:

2
6 8 5
4 1 3
7

Monday, August 25, 2014

Core Java Interview questions

1. Difference between shallow copying and deep copying?

Shallow copy:
All the primitives are copied
All the references are pointed to the existing object
So if the data in original object references are changed, new object data also gets effected, as it is also pointing to the same reference.

How to create shallow copy of an object:
Object's class clone() method does shallow copying.

  public Object clone() {
    try {
      return super.clone();
    } catch (CloneNotSupportedException e) {
      return null;
    }
  }

Deep copy:
All the primitives are copied
All the references to objects are created again.
This is like creating an object again.
So even if the data in original object references are changed, new copy data will not be effected.

How to create deep copy:

public Object() {
   Person person = new Person("Suresh", 26);
 
   return person;
}

2. Given two .java files:
A.java
class A {
     static public void main(String[] args) {
          System.out.println("main() method of class A");
     }
}

B.java
class B extends A {
}

Both the classes are compiled and they do not have any compilation errors.
What is the output of the following command?
> java B

Answer: main() method of class A
Since class B inherits from A, it looks for main() method in its superclass, when it is not found in it.

3. What does the SOP prints here?
int b = 10;
System.out.println((b=3) + b);

Answer:
6
Rule is that: binary operator has left associative, means LHS operand of binary operator is fully evaluated before the right hand operand.

4. Given:
int[] a = {10, 20, 30, 40, 50};
int index = 4;
a[index] = index = 2;

What is the value of index and array "a" elements?

Answer:
index = 2;
array: a = {10, 20, 30, 40, 2}

Its evaluated as:
a[index] = index = 2;
a[4] = index = 2;
a[4] = 2;

Rule is that assignment operator has right associative.

5. What is the value of the b after the following statements?
byte b = 28;
b = b + 10;

Ans: Compilation Error
Any arithmetic operation with Integer variables will give an "int" result, which can't be assigned directly to "byte" here. We must use explicit casting.

6. How to create a immutable class (like String, Wrapper classes)?

a. Class should not have any setter methods
b. make all the fields private and final. private makes them not to be accessed by outside the class. final ensures even accidentally also the fields data wont be changed
c. Dont allow subclasses to override the class methods. So make the class as final.
d. If there is any field which is mutable, its getter should return a new object of that field. So that its value wont be changed in our actual immutable object.

7. Whats the output of the following program?
public class ThreadDemo {
static public void main(String[] args) {
Thread.currentThread().setDaemon(true);
System.out.println(Thread.currentThread().isDaemon());
}
}

Answer:
Runtime Exception: IllegalThreadStateException.

main() thread is already started and it is running state.
we cannot use setDaemon() on a thread which is already in running state.

8. Method Overloading/Overriding possibilities?
class A {
  public void nonSt() { }
  public static void st() { }
}

class B {
 public void nonSt() { } //valid
 public static void st() { } //valid

 public static void nonSt() { } //invalid
 public void st() { } //invalid
}

Sunday, August 24, 2014

log4j

log4j: Logging for Java
-open source logging tool from apache.

Log Levels:

There are 8 levels
  • ALL
  • TRACE
  • DEBUG
  • INFO
  • WARN
  • ERROR
  • FATAL
  • OFF

The specified level and all higher level messages will be printed.
For example, if the level is set to INFO, then only INFO,WARN, ERROR and FATAL messages are printed and TRACE, DEBUG messages are skipped.

Steps to configure Logger in your class programmatically:
1. Get logger instance on your class
Logger logger = Logger.getLogger(Test.class);

2. Create a Layout(determines the format of the print message)
Layout layout = new PatternLayout();

3. Create an Appender passing the layout
Appender appender = new FileAppender(layout, "file.log");

4. Add the Appender reference to the class Logger
logger.addAppender(appender);

5. Set the log level of the Logger
logger.setLevel(Level.INFO);

Thats it...Now you can write log messages, with different levels.
logger.info("This is an info message");
logger.warn("This is a warning message");

Main Components:
1. org.apache.log4j.Logger(class)
It is the main class to handle log messages
2. org.apache.log4j.Layout(abstract class)
It is used to display log messages in our own styles and formats
3. org.apache.log4j.Appender(interface)
It is used to display logger messages in different repositories.

If no appenders added to Logger, then we get a warning message saying "No appenders could be found for logger (<class>)."
Layouts:
1. SimpleLayout (%p - %m%n)
2. HtmlLayout
3. XmlLayout
4. PatternLayout (we can use any customized pattern here)

Patterns:
Few useful pattern strings:
%d  : Date
%m : Message
%n  : new line
%p  : Priority/Level
%t  : Thread
%c  : Class name 
%L  : Line number

Please have a look at the below link, for all available patterns:
http://logging.apache.org/log4j/2.x/manual/layouts.html#Patterns

Appenders:
1. ConsoleAppender
2. FileAppender
3. RollingFileAppender (Controls number of log files and size of each file)
4. JDBCAppender (Writes messages to database)
5. JMSAppender (sends messages over queues)
6. SMTPAppender (Sends mail for each message)

Declarative Approach to configure Log4j:
Two ways
1. log4j.xml
2. log4j.properties

If both xml and properties files are present, then log4j.xml takes higher priority.

1. log4j.xml:
eg:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
    <appender name="ConsoleApp" class="org.apache.log4j.ConsoleAppender">
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%L [%m][%p][%d]%n" />
        </layout>
    </appender>
    <appender name="FileApp" class="org.apache.log4j.FileAppender">
        <param name="file" value="profile.log" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="[%m][%p][%d][%t]%n" />
        </layout>
    </appender>
    <root>
        <level value="trace" />
        <appender-ref ref="FileApp" />
        <appender-ref ref="ConsoleApp" />
    </root>
    <logger name="com.Log4jTest">
        <level value="warn" />
        <appender-ref ref="ConsoleApp" />
    </logger>
    <logger name="com.test">
        <level value="trace" />
        <appender-ref ref="ConsoleApp" />
    </logger>
</log4j:configuration>


2. log4j.properties:
eg:

# Define the root logger with appender file
log4j.rootLogger = DEBUG, FileApp

# Define the file appender with file name
log4j.appender.FileApp=org.apache.log4j.FileAppender
log4j.appender.FileApp.File=log.out

# Define the layout for file appender
log4j.appender.FileApp.layout=org.apache.log4j.PatternLayout
log4j.appender.FileApp.layout.conversionPattern=%L [%d] [%t] [%p] %m%n



Adding multiple appenders:

<root>
   <level value="trace" />
   <appender-ref ref="FileApp" />
   <appender-ref ref="ConsoleApp" />
</root>


Different log level for different packages:

<logger name="com.Log4jTest">
   <level value="warn" />
   <appender-ref ref="ConsoleApp" />
</logger>
<logger name="com.test">
   <level value="trace" />
   <appender-ref ref="ConsoleApp" />
</logger>


Configurators:

1. BasicConfigurator:
This does not require any log4j file.

Logger logger = Logger.getLogger(Log4jTest.class);
BasicConfigurator.configure();


This used ConsoleAppender and PatternLayout with pattern "%r [%t] %p %c %x - %m%n"

2. DomConfigurator:
This is used to specify the log4j xml configuration file.
File name can be anything


3. PropertyConfigurator:
This is used to specify the log4j properties configuration file.
File name can be anything.