My Interview Prep Flashcards
Java 7 I/O
//Create a new Path Path newFile = Paths.get("test1"); try { Files.deleteIfExists(newFile); newFile = Files.createFile(newFile); } catch (IOException ex) { System.out.println("Error creating file"); } System.out.println(Files.exists(newFile));
//Writing to file4 try(BufferedWriter writer = Files.newBufferedWriter( newFile, Charset.defaultCharset())){ writer.append("This is first line"); writer.newLine(); writer.flush(); }catch(IOException exception){ System.out.println("Error writing to file"); }
Bit manipulation
1=negative 0=positive 1&&1=1 1&&0=0 0&&0=0 1||1=1 1||0=1 0||0=0 0^0=0 (XOR) 0^1=1 1^1=0
tree traversal depth-first search
In depth-first order, we always attempt to visit the node farthest from the root node that we can, but with the caveat that it must be a child of a node we have already visited. Unlike a depth-first search on graphs, there is no need to remember all the nodes we have visited, because a tree cannot contain cycles.
tree traversal breadth-first search
level-order traversal
always attempts to visit the node closest to the root that it has not already visited.
Binary tree
tree where each node has no more than 2 children
array list vs linked list
Arrays have O(1) random access, but are really expensive to add stuff onto or remove stuff from.
Linked lists are really cheap to add or remove items anywhere and to iterate, but random access is O(n).
vector vs array list
You should normally use ArrayList - it offers better performance.
Vector has just one “advantage” - it is synchronised for concurrent modification. But it turns out that this feature isn’t very useful - if you are writing concurrent code, you typically need to lock at a much higher level of granularity than an individual collection class.
As a result, Vector is often considered deprecated nowadays.
hash map vs hash table
There are several differences between HashMap and Hashtable in Java:
Hashtable is synchronized, whereas HashMap is not. This makes HashMap better for non-threaded applications, as unsynchronized Objects typically perform better than synchronized ones.
Hashtable does not allow null keys or values. HashMap allows one null key and any number of null values.
One of HashMap’s subclasses is LinkedHashMap, so in the event that you’d want predictable iteration order (which is insertion order by default), you could easily swap out the HashMap for a LinkedHashMap. This wouldn’t be as easy if you were using Hashtable.
Hash tables
n computing, a hash table (also hash map) is a data structure used to implement an associative array, a structure that can map keys to values. A hash table uses a hash function to compute an index into an array of buckets or slots, from which the correct value can be found.
the hashing part is to transform a large space (of arbitrary length, usually strings, etc) and mapping it to a small space (of known size, usually numbers) for indexing.
Real World Example:
Hash & Co., founded in 1803 and lacking any computer technology had a total of 300 filing cabinets to keep the detailed information (the records) for their approximately 30,000 clients. Each file folder were clearly identified with its unique number from 0 to 299.
The filing clerks of that time had to quickly fetch and store client records for the working staff. The staff had decided that it would be more efficient to use a hashing methodology to store and retrieve their records.
To file a client record, filing clerks would use the unique client number written on the folder. Using this client number, they would modulate it by 300 (the hash key) in order to identify the filing cabinet it is contained in. When they opened the filing cabinet they would discover that it contained many folders ordered by client number. After identifying the correct location, they would simply slip it in.
Java primitives
n=# of bits
2^n-1 to
-2^(n-1) - 1
byte 8 bit
-128 to 127
short 16 bit int 32 bit long 64 bit float 32 bit double 64 bit boolean 1 bit char single 16-bit Unicode character
Merge sort
An example of merge sort. First divide the list into the smallest unit (1 element), then compare each element with the adjacent list to sort and merge the two adjacent lists. Finally all the elements are sorted and merged. avg O(n log(n))
Big O notation
Big O notation is used in Computer Science to describe the performance or complexity of an algorithm. Big O specifically describes the worst-case scenario, and can be used to describe the execution time required or the space used (e.g. in memory or on disk) by an algorithm.
O(1) describes an algorithm that will always execute in the same time (or space) regardless of the size of the input data set
O(N) describes an algorithm whose performance will grow linearly and in direct proportion to the size of the input data set
O(N2) represents an algorithm whose performance is directly proportional to the square of the size of the input data set. (ie 2 iterative for loops)
O(2N) denotes an algorithm whose growth will double with each additional element in the input data set. The execution time of an O(2N) function will quickly become very large
O(log N). The iterative halving of data sets described in the binary search example produces a growth curve that peaks at the beginning and slowly flattens out as the size of the data sets increments
NoSQL
A NoSQL database provides a mechanism for storage and retrieval of data that is modeled in means other than the tabular relations used in relational databases. Motivations for this approach include simplicity of design, horizontal scaling and finer control over availability. The data structure (e.g., tree, graph, key-value) differs from the RDBMS, and therefore some operations are faster in NoSQL and some in RDBMS
SocketPC (NetSpend)
custom partner connection service which acts as a client to NEO. SocketPC receives XML-like messages on a direct socket connection, parses them, and then invokes NEO
A socket is a software endpoint that establishes bidirectional communication between a server program and one or more client programs. The socket associates the server program with a specific hardware port on the machine where it runs so any client program anywhere in the network with a socket associated with that same port can communicate with the server program.
Java generics
List (String part the generic)
Quick sort
Quicksort is a divide and conquer algorithm. Quicksort first divides a large list into two smaller sub-lists: the low elements and the high elements. Quicksort can then recursively sort the sub-lists.
The steps are:
Pick an element, called a pivot, from the list.
Reorder the list so that all elements with values less than the pivot come before the pivot, while all elements with values greater than the pivot come after it (equal values can go either way). After this partitioning, the pivot is in its final position. This is called the partition operation.
Recursively apply the above steps to the sub-list of elements with smaller values and separately to the sub-list of elements with greater values.
The base case of the recursion is lists of size zero or one, which never need to be sorted.
avg O(n log(n))
Hungarian folk dance sort YouTube!
PaWS
The Partner Web Services (PaWS) enables larger partners to integrate their own POS systems with the Netspend system. Creates a war file that implements CXF web services using SOAP XML that is then deployed in a web service container such as tomcat or jetty.
Testing REST services
rest-assured Java DSL (domain specific language) for easy testing of REST services
REST clients
http clients for testing REST services:
Postman
REST Console
Restrictions on generics
Cannot Instantiate Generic Types with Primitive Types
Cannot Create Instances of Type Parameters
Cannot Declare Static Fields Whose Types are Type Parameters
Cannot Use Casts or instanceof With Parameterized Types
Cannot Create Arrays of Parameterized Types
Cannot Create, Catch, or Throw Objects of Parameterized Types
Cannot Overload a Method Where the Formal Parameter Types of Each Overload Erase to the Same Raw Type
Generics type erasure
Generics were introduced to the Java language to provide tighter type checks at compile time and to support generic programming. To implement generics, the Java compiler applies type erasure to:
Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.
Insert type casts if necessary to preserve type safety.
Generate bridge methods to preserve polymorphism in extended generic types.
Type erasure ensures that no new classes are created for parameterized types; consequently, generics incur no runtime overhead.
NEO
NetSpend Enterprise Objects - middle business-logic tier for the 3-Tier NetSpend application.
Neo is a collection of data objects and Enterprise Session Beans which run on the NetSpend production server.
NEO is structured using the following discrete layers:
Client Session
EJB
Model
NEO DAO
Types of linked lists
Singly-linked lists work by having each node pointing to the next node, with the tail node (or end node) pointing to nothing (or a null reference). Doubly-linked lists expand upon the singly-linked list, with each node pointing to the previous node as well as the next node. In doubly-linked lists, both the head node (first node) and the tail node point to nothing. Circularly-linked lists expand upon the singly-linked list differently than the doubly-linked list; instead of having the tail node pointing to nothing, it “circles” back around, pointing to the head element as the name suggests.
Queues
A queue is a container of objects (a linear collection) that are inserted and removed according to the first-in first-out (FIFO) principle. An excellent example of a queue is a line of students in the food court of the UC. New additions to a line made to the back of the queue, while removal (or serving) happens in the front. In the queue only two operations are allowed enqueue and dequeue. Enqueue means to insert an item into the back of the queue, dequeue means removing the front item
Stacks
A stack is a container of objects that are inserted and removed according to the last-in first-out (LIFO) principle. In the pushdown stacks only two operations are allowed: push the item into the stack, and pop the item out of the stack. A stack is a limited access data structure - elements can be added and removed from the stack only at the top. push adds an item to the top of the stack, pop removes the item from the top. A helpful analogy is to think of a stack of books; you can remove only the top book, also you can add a new book on the top.
Binary search
For binary search, the array should be arranged in ascending or descending order. In each step, the algorithm compares the search key value with the key value of the middle element of the array. A binary search halves the number of items to check with each iteration, so locating an item (or determining its absence) takes logarithmic time. A binary search is a dichotomic divide and conquer search algorithm. avg O(log (n))
Stack vs heap
Each time an object is created in Java it goes into the area of memory known as heap. The primitive variables are allocated in the stack if they are local method variables and in the heap if they are class member variables.
Threads share the heap spaces so it is not thread-safe and the threads have their own stack space which is thread-safe
1) Main difference between heap and stack is that stack memory is used to store local variables and function call, while heap memory is used to store objects in Java. No matter, where object is created in code e.g. as member variable, local variable or class variable, they are always created inside heap space in Java.
2) Each Thread in Java has there own stack which can be specified using -Xss JVM parameter, similarly you can also specify heap size of Java program using JVM option -Xms and -Xmx where -Xms is starting size of heap and -Xmx is maximum size of java heap. to learn more about JVM options see my post 10 JVM option Java programmer should know.
3) If there is no memory left in stack for storing function call or local variable, JVM will throw java.lang.StackOverFlowError, while if there is no more heap space for creating object, JVM will throw java.lang.OutOfMemoryError: Java Heap Space. Read more about how to deal with java.lang.OutOfMemoryError in my post 2 ways to solve OutOfMemoryError in Java.
4) If you are using Recursion, on which method calls itself, You can quickly fill up stack memory. Another difference between stack and heap is that size of stack memory is lot lesser than size of heap memory in Java.
5) Variables stored in stacks are only visible to the owner Thread, while objects created in heap are visible to all thread. In other words stack memory is kind of private memory of Java Threads, while heap memory is shared among all threads.
WAX
Affiliates and partners can use this web service to create card orders. An XML document is posted to a URL in the HTTP POST body and an XML response is returned in the HTTP response.
string intern() method
String.intern() on a series of strings will ensure that all strings having same contents share same memory. So if you have list of names where ‘john’ appears 1000 times, by interning you ensure only one ‘john’ is actually allocated memory. can increase speed but takes up memory
Java String encoding UTF ASCII, etc
public String pruebaEnconding() throws UnsupportedEncodingException { String xml = "String con acentos: á - é - í - ó - ú" ; return new String(xml.getBytes(), "ISO-8859-1"); }
Netspend # of employees
About 500
About 20 developers, 11 appdev
TSYS about 9,000
NetSpend versions
Java 7 JBoss 5.1.0.GA Apache 2.2 Tomcat 7.0.28 JUnit 4.11 Mockito 1.8 TopLINK 9.0.7 Slf4j 1.6.1
XML
Extensible Markup Language
a metamarkup (set of instructions on a manuscript or tags in an electronic document to determine styles of type, makeup of pages, and the like) language for text documents
* does not have a fixed set of tags and elements
<– mark-up
* XML is case-sensitive
DOM / SAX
Document Object Model / Simple API for XML
Which Java related websites do you use?
daringfireball.com reddit programming wired stackoverflow. java posse (podcast) joelonsoftware.com/
Do you have any role models in software development?
Rob Ratcliff (AustinJUG founder)
Martin Fowler (Refactoring: Improving the design of existing code and Refactoring to Patterns)
Joel Spolsky (Fog Creek Software / joelonsoftware.com)
Todd
Cheng
3 pillars of object orientation
Polymorphism
provision of a single interface to entities of different types. A polymorphic type is a type whose operations can also be applied to values of some other type, or types. The process used by objectoriented
programming languages to implement polymorphism is called dynamic binding
Inheritance inheritance is when an object or class is based on another object or class, using the same implementation; it is a mechanism for code reuse
Encapsulation
A language mechanism for restricting access to some of the object’s components.[3][4]
A language construct that facilitates the bundling of data with the methods (or other functions) operating on that data
methods to override for every bean
equals() (javadoc) must define an equality relation (it must be reflexive, symmetric, and transitive). In addition, it must be consistent (if the objects are not modified, then it must keep returning the same value). Furthermore, o.equals(null) must always return false.
hashCode() (javadoc) must also be consistent (if the object is not modified in terms of equals(), it must keep returning the same value).
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (a ^ (a»_space;> 32));
result = prime * result + (int) (b ^ (b»_space;> 32));
result = prime * result + c.hashCode();
return result;
}
public boolean equals(Object obj) { if (!(obj instanceof Apple)) return false; if (obj == this) return true; return this.color.equals(((Apple) obj).color); }
Read more: http://javarevisited.blogspot.com/2011/10/override-hashcode-in-java-example.html#ixzz2xmrOm5TA
The relation between the two methods is:
Whenever a.equals(b), then a.hashCode() must be same as b.hashCode()
transient
transient variables cannot be serialized
process vs thread
process is an execution of a program (eg JVM process) but a thread is a single execution sequence within the process
J2EE deployment structure (ear, war, jar)
MyApps.ear
-log4j.jar (3rd party jars)
-class files, properties files,configuration files etc
-META-INF
-application.xml (deployment descriptor)
-MANIFEST.MF
Manifest-Version: 1.0
Created-By: Apache Ant
-MyAppsCommon.jar , MyAppsUtil.jar
(shared by both EJB and Web modules)
-class files, properties files,configuration files etc
-MyAppsEJB.jar
-META-INF
-MANIFEST.MF
class-path: (log4j.jar MyAppsCommon.jar MyAppsUtil.jar)
ejb-jar.xml (deployment descriptor )
-ejb classes , non-ejb class etc
-MyAppsWeb.war
-JSP, HTML, CSS, GIF (can have sub-folders)
-META-INF
-MANIFEST.MF
class-path: (log4j.jar MyAppsCommon.jar MyAppsUtil.jar)
-WEB-INF
-web.xml (deployment descriptor)
-lib
-struts.jar, crimson.jar (3rd party jar files)
-classes
-class files
deployment descriptors
XML based text files with a “.xml” extension that describes a component’s deployments settings.
A J2EE application and each of its modules has its own deployment descriptor.
application.xml
deployment descriptor
a standard J2EE deployment descriptor, which includes the following structural
information: EJB jar modules, WEB war modules, etc. Also since EJB jar modules are
packaged as jars the same way dependency libraries like log4j.jar, commonUtil.jar etc are packaged, the
application.xml descriptor will distinguish between these two jar files by explicitly specifying the EJB jar
modules.
[?xml version="1.0" encoding="UTF-8"?] [!DOCTYPE application PUBLIC "-//Sun Microsystems, Inc.//DTD J2EE Application 1.2//EN" "http://java.sun.com/j2ee/dtds/application_1_2.dtd"] [application id="Application_ID"] [display-name]MyApps[/display-name] [module id="EjbModule_1"] [ejb]MyAppsEJB.jar[/ejb] [/module] [module id="WebModule_1"] [web] [web-uri]MyAppsWeb.war[/web-uri] [context-root]myAppsWeb[/context-root] [/web] [/module] [security-role id="SecurityRole_1"] [description]Management position[/description] [role-name]managger[/role-name] [/security-rol [/application]
ejb-jar.xml
deployment descriptor
standard deployment descriptor for an EJB module.
[[?xml version=”1.0” encoding=”UTF-8”?]
[!DOCTYPE ejb-jar PUBLIC “-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.1//EN”
“http://java.sun.com/j2ee/dtds/ejb-jar_1_1.dtd”]
[ejb-jar id=”ejb-jar_ID”]
[display-name]MyAppsEJB[/display-name]
[enterprise-beans]
[session id=”ContentService”]
[ejb-name]ContentService[/ejb-name]
[home]ejb.ContentServiceHome[/home]
[remote]ejb.ContentService[/remote]
[ejb-class]ejb.ContentServiceBean[/ejb-class]
[session-type]Stateless[/session-type]
[transaction-type]Container (vs Bean)[/transaction-type]
[/session]
[entity]
[ejb-name]Bid[/ejb-name]
[home]ejb.BidHome[/home]
[remote]ejb.Bid[/remote]
[ejb-class]ejb.BidBean[/ejb-class]
[persistence-type]Container[/persistence-type]
[prim-key-class]ejb.BidPK[/prim-key-class]
[reentrant]False[/reentrant]
[cmp-field][field-name]bid[/field-name][/cmp-field]
[cmp-field][field-name]bidder[/field-name][/cmp-field]
[cmp-field][field-name]bidDate[/field-name][/cmp-field]
[cmp-field][field-name]id[/field-name][/cmp-field]
[/entity]
[/enterprise-beans]
[!– OPTIONAL –]
[assembly-descriptor]
[!– OPTIONAL, can be many –]
[security-role]
[description]
Employee is allowed to …
[/description]
[role-name]employee[/role-name]
[/security-role]
[!– OPTIONAL. Can be many –]
[method-permission]
[!– Define role name in “security-role” –]
[!– Must be one or more –]
[role-name]employee[/role-name]
[!– Must be one or more –]
[method]
[ejb-name]ContentService[/ejb-name]
[!– * = all methods –]
[method-name][/method-name]
[/method]
[method]
[ejb-name]Bid[/ejb-name]
[method-name]findByPrimaryKey[/method-name]
[/method]
[/method-permission]
[!– OPTIONAL, can be many. How the container is to manage
transactions when calling an EJB’s business methods –]
[container-transaction]
[!– Can specify many methods at once here –]
[method]
[ejb-name]Bid[/ejb-name]
[method-name][/method-name]
[/method]
[!– NotSupported|Supports|Required|RequiresNew|Mandatory|Never –]
[trans-attribute]Required[/trans-attribute]
[/container-transaction]
[/assembly-descriptor]
[/ejb-jar]
garbage collection
automatic in Java (unlike C++)
cannot be forced but you can nicely ask the garbage collector to collect garbage
Each time an object is created in Java, it goes into the area of memory known as heap. The Java heap is called
the garbage collectable heap. The garbage collection cannot be forced. The garbage collector runs in low
memory situations. When it runs, it releases the memory allocated by an unreachable object. The garbage
collector runs on a low priority daemon (background) thread. You can nicely ask the garbage collector to collect
garbage by calling System.gc() but you can’t force it.
What is an unreachable object? An object’s life has no meaning unless something has reference to it. If you
can’t reach it then you can’t ask it to do anything. Then the object becomes unreachable and the garbage collector
will figure it out. Java automatically collects all the unreachable objects periodically and releases the memory
consumed by those unreachable objects to be used by the future reachable objects.
finalize()
method helps in garbage collection. A method that is invoked before an object is discarded by the
garbage collector, allowing it to clean up its state. Should not be used to release non-memory resources like
file handles, sockets, database connections etc because Java has only a finite number of these resources and
you do not know when the garbage collection is going to kick in to release these non-memory resources
through the finalize() method.
types of references
java.lang.ref package can be used to declare soft, weak and phantom references
Garbage Collector won’t remove a strong reference.
How to improve Java I/O performance
by using buffering (Internally a buffer array is used and instead of reading bytes individually from the underlying input stream enough bytes are read to fill the buffer. This generally results in faster performance as less reads are required on the underlying input stream.)
minimising access to the underlying hard disk and operating systems.
Use the NIO package for performance enhancing features like non-blocking I/O operation, buffers to hold data, and memory mapping of files
types of exceptions
checked and unchecked (RuntimeException)
should you catch Exception?
No
Exception handling in Java is polymorphic in nature. For example if you catch type Exception in your code then it
can catch or throw its descendent types like IOException as well. So if you catch the type Exception before the
type IOException then the type Exception block will catch the entire exceptions and type IOException block is
never reached. In order to catch the type IOException and handle it differently to type Exception, IOException
should be caught first (remember that you can’t have a bigger basket above a smaller basket).
Thread creation
Extend the Thread class class Counter extends Thread { //method where the thread execution will start public void run(){ //logic to execute in a thread } //let’s see how to start the threads public static void main(String[] args){ Thread t1 = new Counter(); Thread t2 = new Counter(); t1.start(); //start the first thread. This calls the run() method t2.start(); //this starts the 2nd thread. This calls the run() method } }
or implement the Runnable interface class Counter extends Base implements Runnable { //method where the thread execution will start public void run(){ //logic to execute in a thread } //let us see how to start the threads public static void main(String[] args){ Thread t1 = new Thread(new Counter()); Thread t2 = new Thread(new Counter()); t1.start(); //start the first thread. This calls the run() method t2.start(); //this starts the 2nd thread. This calls the run() method } }
The runnable interface is preferred, as it does not require your object to inherit a thread because when you need multiple inheritance, only interfaces can help you. In the above example we had to extend the Base class so implementing runnable interface is an obvious choice. Also note how the threads are started in each of the different cases as shown in the code sample.
synchronized
In Java programming, each object has a lock. A thread can acquire the lock for an object by using the
synchronized keyword. The synchronized keyword can be applied in method level (coarse grained lock – can
affect performance adversely) or block level of code (fine grained lock). Often using a lock on a method level is
too coarse. Why lock up a piece of code that does not access any shared resources by locking up an entire
method. Since each object has a lock, dummy objects can be created to implement block level synchronization.
The block level is more efficient because it does not lock the whole method
class MethodLevel { //shared among threads SharedResource x, y ; pubic void synchronized method1() { //multiple threads can't access } pubic void synchronized method2() { //multiple threads can't access } public void method3() { //not synchronized //multiple threads can access } }
class BlockLevel { //shared among threads SharedResource x, y ; //dummy objects for locking Object xLock = new Object(), yLock = new Object(); pubic void method1() { synchronized(xLock){ //access x here. thread safe } //do something here but don't use SharedResource x, y ; synchronized(xLock) { synchronized(yLock) { //access x,y here. thread safe } } //do something here but don't use SharedResource x, y ; } }
high-level thread states
- Runnable — waiting for its turn to be picked for execution by the thread schedular based on thread priorities.
- Running: The processor is actively executing the thread code. It runs until it becomes blocked, or voluntarily
gives up its turn with this static method Thread.yield(). Because of context switching overhead, yield() should
not be used very frequently. - Waiting: A thread is in a blocked state while it waits for some external processing such as file I/O to finish.
- Sleeping: Java threads are forcibly put to sleep (suspended) with this overloaded method:
Thread.sleep(milliseconds), Thread.sleep(milliseconds, nanoseconds); - Blocked on I/O: Will move to runnable after I/O condition like reading bytes of data etc changes.
- Blocked on synchronization: Will move to Runnable when a lock is acquired.
- Dead: The thread is finished working.
Thread wait(), notify(), notifyAll()
The wait(), notify(), and notifyAll() methods are used to provide an efficient way for threads to communicate with
each other. This communication solves the ‘consumer-producer problem’. This problem occurs when the
producer thread is completing work that the other thread (consumer thread) will use.
Example: If you imagine an application in which one thread (the producer) writes data to a file while a second
thread (the consumer) reads data from the same file. In this example the concurrent threads share the same
resource file. Because these threads share the common resource file they should be synchronized. Also these
two threads should communicate with each other because the consumer thread, which reads the file, should wait
until the producer thread, which writes data to the file and notifies the consumer thread that it has completed its
writing operation
class ConsumerProducer { private int count; public synchronized void consumer() { while (count == 0) { try { wait(); } catch (InterruptedException ie) { // keep trying } } count --; // consumed } private synchronized void produce() { count++; notify(); } }
Improve performance in Java by
- Pooling your valuable resources like threads, database and socket connections.
- Optimizing your I/O operations.
- Minimising network overheads, calls to Date, Calendar related classes, use of “casting” or runtime type
checking like “instanceof” in frequently executed methods/loops, JNI calls, etc - Managing your objects efficiently by caching or recycling them without having to rely on garbage collection.
- Using a StringBuffer as opposed to String and ArrayList or HashMap as oppose to Vector or Hashtable
- Applying multi-threading where applicable.
- Minimise any potential memory leaks.
PayPal
Unique integration with PayPal that entailed a meshing of PayPal APIs that are typically used independent of each other to accomplish a complex integrated feature set for the user that entailed using NetSpend’s servicing center / framework but 100% PayPal branding and authentication.
PayPal SSO via OpenID
PayPal Balance and email retrieval via OAuth
PayPal Account Creation via SOAP
PayPal Payments (Reload/TopUp) via SOAP
Silverpop
Replacing existing third party vendor for external emails with new vendor.
3rd party integration XML over HTTP
Database migration for new template ids/names
Integration tests to ensure no loss in functionality of over 60+ external emails (plus branded versions) - required additions to account creation DSL for account prepping
HTTP protocol
stateless protocol and state can be maintained between client requests using HttpSession, URL rewriting,
hidden fields and cookies. HttpSession is the recommended approach.
1) On client’s first request, the Web Container generates a unique session id and gives it back to the client with response
2) The client sends back the session id with each response
3) The Web Container uses this ID, finds the matching session with the ID and associates the session with the request.
idempotent
the property of certain operations in mathematics and computer science, that can be applied multiple times without changing the result beyond the initial application
ex. clustered EJBs are written with idempotent methods - can automatically recover from a server failure as long as it can reach another server
Servlet clustering
promotes high availability and scalability. The considerations for servlet clustering are:
- Objects stored in a session should be serializable to support in-memory replication of sessions. Also
consider the overhead of serializing very large objects. Test the performance to make sure it is acceptable. - Design for idempotence. Failure of a request or impatient users clicking again can result in duplicate
requests being submitted. So the Servlets should be able to tolerate duplicate requests. - Avoid using instance and static variables in read and write mode because different instances may exist
on different JVMs. Any state should be held in an external resource such as a database. - Avoid storing values in a ServletContext. A ServletContext is not serializable and also the different
instances may exist in different JVMs. - Avoid using java.io.* because the files may not exist on all backend machines. Instead use
getResourceAsStream().
Prepared statements vs statements
Prepared statements offer better performance as opposed to statements, as they are precompiled and reuse the
same execution plan with different arguments. Prepared statements are also more secure because they use bind
variables, which can prevent SQL injection attacks
EJB transaction attributes
Required:
Methods executed within a transaction. If client provides a transaction, it is used. If not, a new transaction is
generated. Commit at end of method that started the transaction. Which means a method that has Required
attribute set, but was called when the transaction has already started will not commit at the method
completion. Well suited for EJB session beans.
Mandatory:
Client of this EJB must create a transaction in which this method operates, otherwise an error will be
reported. Well-suited for entity beans.
RequiresNew:
Methods executed within a transaction. If client provides a transaction, it is suspended. If not a new
transaction is generated, regardless. Commit at end of method.
Supports:
Transactions are optional.
NotSupported:
Transactions are not supported. If provided, ignored.
Never:
Code in the EJB responsible for explicit transaction control.
How will you map objects to a relational database? How will you map class inheritance to relational data model?
There is an impedance mismatch between object and relational technology. Classes represent both data and behaviour whereas relational database tables just implement data. Inheritance class structure can be mapped to relational data model in one of the following ways:
Map class hierarchy to single database table: The whole class hierarchy can be stored in a single table by adding an additional column named “EmployeeType”. The column “EmployeeType” will hold the values “Permanent”, “Contract” and “SubContract”. New employee types can be added as required. Although this approach is straightforward it tends to break when you have combinations like an employee is of type both “Contractor” and “SubContractor”. So when you have combinations, you can use refactored table by replacing type code column “EmployeeType” with boolean values such as isPermanent, isContractor and isSubContractor.
Map each class to its own table: You create one table per class. The data for a permanent employee is stored in two tables (Employee and Permanent), therefore to retrieve this data you need to join these two tables. To support additional employee type say a Contractor, add a new table.
Map each concrete class to its own table: You create one table per concrete class. There are tables corresponding to each class like Permanent, Contractor and SubContractor. So join is not required. To support additional employee type, add a new table.
So which approach to use?
Easiest approach is to have one table per hierarchy and easy to refactor. If you need a “pure design approach” then use one table per class approach. Try to stay away from one table per concrete class approach because it makes refactoring difficult by copying data back and forth between tables.
No approach is ideal for all situations.
normalize vs denormalize table data
Normalize to reduce data redundancy and denormalize to improve performance: Normalized data
have the advantage of information being stored in one place only, reducing the possibility of inconsistent
data. Furthermore, highly normalized data are loosely coupled. But normalization comes at a
performance cost because to determine a piece of information you have to join multiple tables whereas
in a denormalized approach the same piece of information can be retrieved from a single row of a table.
Denormalization should be used only when performance testing shows that you need to improve
database access time for some of your tables.
Note: Creating a data model (logical, physical etc) before design model
how to improve performance of a J2EE application
- Manage and recycle your valuable resources like connections, threads etc by either pooling or caching.
- Use effective design patterns like session façade (client interface), DTOs (Data Transfer Objects), fast lane reader etc to minimise network
overheads. - Set appropriate timeouts for HttpSession objects.
- Use JDBC prepared statements as opposed to statements.
- Release database connections in a finally {} block when finished.
- Apply least restrictive but valid transaction isolation level.
- Batch database requests.
- Minimise serialization costs by marking references like file handles, database connections, etc which do not
require serialization by declaring them transient.
J2EE best practices
- Recycle your valuable resources by either pooling or caching.
- Automate your build process with tools like Ant, CruiseControl, and Maven etc, and continuously integrate your code into your build process.
- Build test cases first using tools like JUnit.
- Use standard J2EE packaging to improve portability.
- Apply appropriate proven design patterns
- Use proven frameworks like Struts, Spring, Hibernate, JSF, JUnit, Log4J, etc.
- Handle and propagate exceptions correctly.
- Avoid resource leaks by closing all database connections after you have used them.
How would you detect memory leaks in Java?
Detecting memory leaks:
- Use tools like JProbe, OptimizeIt etc to detect memory leaks.
- Use operating system process monitors like task manager on NT systems, ps, vmstat, iostat, netstat etc on
UNIX systems.
- Write your own utility class with the help of totalMemory() and freeMemory() methods in the Java Runtime
class. Place these calls in your code strategically for pre and post memory recording where you suspect to be
causing memory leaks. An even better approach than a utility class is using dynamic proxies (Refer Q11 in
How would you go about section…) or Aspect Oriented Programming (AOP) for pre and post memory
recording where you have the control of activating memory measurement only when needed. (Refer Q3 – Q5
in Emerging Technologies/Frameworks section).