Java EE 5
A very nice medium-long article that introduces the features and technologies of the Java EE 5 platform.
"Elvis" stands for medium-skilled developer. This step-by-step tutorial uses Eclipse to create a web application starting from the database. Glassfish is the open-source application server which is also the codebase for Sun JSAS, our app server.
Similar to the Horstmann's Elvis meets Glassfish tutorial, this time using Netbeans instead of Eclipse.
This is a huge 1350 page official tutorial from Sun that is sold on print for $50. It is also available online for free as HTML and as a 13 MB-only PDF download. This tutorial is the final word on Java EE 5.
Started as a Sun internal project, for developing a programming language to program smart appliances (embedded systems).
Security, distributed programming, networking, garbage collection, threading considered important from the start.
Sun announced Java, and the HotJava web browser. Netscape announced it will support Java on the internet.
First release of Java: JDK 1.0.
JDK: Java Development Kit.
Note: Sun tried to rename "JDK" to the more general term "SDK" (Software Development Kit), but this term did not catch on in the developer community, so Sun went back to using "JDK" again.
Note 2: At the lab, we have Java EE 5 SDK installed at the directory /opt/SDK. This is not Java SE SDK also known as JDK.
Changed the Java language significantly.
Very easy to understand and use.
You could define your own annotations but this is not very easy to do.
Unlike standard language constructs, annotations use reflection, and can react to changes in code within the annotated item.
In Java EE 5, entities use annotations very effectively.
For example, an @Entity annotation on a class causes byproduct code to be created for the class and all its public getXyz methods (or public xyz fields).
Allows types such as Map<String, Vector<String>>. This map uses string keys, and the values are vectors of strings.
Backwards-compatible with older collections (in the above case, compatible with Maps which don't define their key and value types).
Advantage: Can work with old code where developers had the discipline to always limit key and value types.
Disadvantage: Errors will be only discovered at runtime, during implicit dynamic typecasting.
This is the version of Java SE we will use.
Note: Version numbers of Java technologies (EE, SE, JSP, EJB) change independently and versions are backwards-compatible.
So:
It is generally recommended that the latest version be used, as Sun has continually improved the performance of Java throughout its releases.
End users who need to run Java applications only need a JRE (Java Runtime Environment), to run Java from bytecode (*.class and *.jar).
We develop Java applications, so we need a JDK (Java Development Kit), to compile Java from source code (*.java).
JDK includes JRE, as well as many executables (most notably "javac") needed to develop Java software.
If you can find "java" but not "javac" on a machine, you may have a JRE but may be lacking a JDK.
JRE can also be used to run applets within browsers (but you would still need to download a plugin for your browser).
We first write the source code.
One file contains one public class, but may also contain non-public (package-visible) classes, nested classes, and anonymous classes.
Source code is compiled to bytecode
For each class (public or otherwise), one *.class file is created
Bytecode is between platform-specific executable and the original source code.
Bytecode is platform-independent, and is usually smaller than the source code.
Bytecode used to be interpreted, which caused loops to run very slowly.
With the advent of JIT (Just-in-time) compilation, bytecode execution is at times even faster than precompiled executable, because some JIT compiler optimizations are more efficient than what can be achieved by precompilation.
JIT compilation and execution happens in the JVM, the Java Virtual Machine.
Directories match package hierarcy, and each .java file contains one public class by the same name.
For example, com/ibm/db/Connection.java:
package com.ibm.db;
...
public class Connection {
...
}
package com.ibm.db;
import java.util.List;
/** Handles one database connection by one client. */
public class Connection {
private List tables;
static class ConnectionPort { ... }
}
The directory structure of *.class files must mirror that of *.java files and the package hierarchy.
But instead of being in the same directory, *.class files are better kept in separate mirrored directory structure.
This allows separation of source code from bytecode.
There may be multiple top-level directories which contain possibly separate package and class hierarchies.
During execution (with the "java" command), any class may refer to any other class that is anywhere in the class path.
All references outside the class are resolved at runtime (but interface compatibility is checked at compile time).
Example: CLASSPATH contains /bin and /class directory. The class file /bin/com/ibm/db/Main.class may refer to "net.sun.util.MemoryMap" which may be under class (rather than bin) directory, under /class/net/sun/util/MemoryMap.class.
CLASSPATH in Linux:
echo $CLASSPATH # Displays the class path
export CLASSPATH=/bin:/class # Sets the class path (in bash, but not in csh or tcsh)
Objects are passed by "reference"; actually, their pointers (with embedded type information) are passed.
This means, all objects are shared.
This means, if you return an array, the client can modify its elements without your permission.
References cannot be passed from one JVM to another JVM.
Because of this, distributed programming (as with RMI = "Remote Method Invocation") uses pass-by-copy and requires "serializable objects".
// This code produces 11 String objects, "", "0", "01", "012" ... "0123456789"
String a = "";
for(int i = 0; i < 10; i++)
a = a + i;
// This code modifies a single StringBuilder object
StringBuilder buf = new StringBuilder();
for(int i = 0; i < 10; i++)
buf.append(i);
String a = buf.toString();
Note: StringBuilder and StringBuffer are functionally equivalent but StringBuilder is not thread-safe and is faster. Here, buf is a local variable, and thread-safety is not required, so it is safe and preferable to use a StringBuilder.
Immutability of strings means that Strings can easily be shared without any danger.
// This code uses a single "interned" String object
// a, b, and c all refer to the same String object (discovered in compile-time)
String a = "same";
String b = "same";
String c = "sam" + "e";
You can check performance simply by using System.currentTimeMillis() to time a process.
You should consider timing more than once and averaging (but not the same exact process; it may cause caching at some level and may run faster than usual).
You can look at the details of execution by examining bytecode with the command "javap -c ClassName"
These exceptions (any subclass of RuntimeException) may occur anywhere.
These exceptions need not be declared (by a throws clause in method signature) before they are thrown (by a throw command within the method).
These exceptions need not be, but may be caught within any method.
You may create RuntimeExceptions, but this is almost never what you ought to do.
Select "java.rmi" on top left and bottom left windows (each one). Scroll below the three tables (interfaces, classes and exceptions). Read the package description. Can RMI be used to call methods between JVMs (which may be on different machines)?
If you know the class name, you can just scroll down to it. On top left select "All Classes". On bottom left, scroll down to "Date". We are not interested in SQL Date class. Select the other one. Does this class represent a date or a time? How many of its constructors are "deprecated" (not recommended to be used; will not be supported in the future), and which classes now handle these operations?
Collections are under java.util package. Select java.util on the top left. Select List on the bottom left. In Java a class may only have one superclass. Can interfaces have multiple superinterfaces? What does java.util.List suggest?
Go to java.util.list as in example 3. Click on the first subclass. Is this a fully implemented class that can be instantiated, or a partially implemented (abstract) class?
Now find Stack, which is a type of List. How many ancestor classes (superclasses and their superclasses) does Stack have (look at its inheritance hierarchy)?
Go to Index (at the top of the right page). Find the "matches" method for regular expression matching. Which classes have such a method to match regular expressions?
These three methods in three classes actually call each other A -> B -> C. Which one is the top-level utility method? Which one is the bottom-level implementation? (you need to click on the method names to view their documentations)
There is a collection class called Vector. Find its API. Is it a type of Map or a type of List? You can see its four constructors and many methods.
But the table only lists methods that were overridden by Vector. For example, Vector has a size method and an iterator method. Find the documentation for both. The iterator method was not overridden by Vector, so its documentation is mentioned after all methods in the summary table, as a method inherited from a superclass (as well as an interface).
~ java.sun.com > J2se > Javadoc > Writingdoccomments
Keeps documentation and code in sync.
It is easy to write Javadocs.
You should write Javadocs, at the class level for all classes.
You should write javadocs at least for the most important methods of each class.
Learn to use links such as "{@link Xyz}" (can be inlined with text) and "@see Xyz" (must be listed on separate lines.
Generating from the command line: Use javadoc
Generating from Netbeans: Select Project. Use Build -> Generate Javadoc
Code must compile (can't have compilation errors). If code does not compile anywhere, you may not be able to create javadocs.
Ideally, generate javadocs for the whole project, not just a few classes or packages. Rich interconnectedness of API documentation is its most useful feature.
It is "required" by the javadoc standards that you document all method arguments, but failure to do so does not halt javadoc creation.
JavaBeans are reusable Java classes that contain properties that are retrieved and set using getter/setter methods with standardized naming schemes.
Enterprise JavaBeans (EJBs) are significantly more involved than plain old JavaBeans. They are not the same!!
Here is a JavaBean with one mutable (boolean present) and one immutable (String name) property:
public class User {
public String getName() { ... }
public boolean isPresent() { ... }
public boolean setPresent() { ... }
}
Fancy name, simple meaning: Plain Old Java Object: Any Java class, instantiated. Emphasizes that components need not extend an existing inheritance hierarchy in order to plug in to a framework.
As Java only allows single inheritance (from classes, but multiple from interfaces), it is important to be able to use your own inheritance hierarchy while plugging in to a framework.
In J2EE, you could not select your inheritance hierarcy for Entity Beans (EJBs), but in Java EE 5, Entity Objects are POJOs, so you may use any Java file you have as an entity.
Note also that entities are no longer "entity beans"; they are not EJBs anymore and they may be used outside Java EE 5 as well.
JAR stands for Java Archive.
JAR files use ZIP compression over a whole directory tree to generate a single .jar file.
You may add JAR files in your CLASSPATH to make classes accessible from each other.
Whether or not a JAR file is executable, you may execute any class within the JAR file (assuming the class has a main method).
Libraries in Java are packaged as JAR files. Note that libraries need not have any executable classes.
Manifest file contains information about the JAR file and its contents
Location of manifest file inside the JAR file: META-INF/MANIFEST.MF
Manifest file contains main executable class if this JAR file is executable. This file is often just a single line:
Main-Class: com.oracle.db.Run
Executable JAR files can be started by a command like this:
java -jar mydb.jar
JAR files can be digitally signed, again using this manifest file. A signed JAR file can be checked to make sure that no file in it has been modified since the JAR file was signed.
In Java names (package and class names, which are the same as directory and file names) are case-sensitive. WinZip ignores case while unzipping, so it is not suitable for Java deployment. Use Sun's "jar" command instead.
Note that you should also be sensitive about case yourself. Otherwise, your case-ignoring Windows Java program may run only on Windows due to OS ignoring case while fetching class files (for example, your "net.xyz.Main" class request would match "NET\xyz\main.class" on Windows, but not anywhere else)
WAR files contain one special directory called WEB-INF, that is accessible to deployed web application, but not directly accessible by the end user.
WEB-INF/web.xml
web.xml contains servlet-name to servlet-class mappings as well as servlet-name to url-pattern mappings.
For example a servlet called CustomerMgt may be defined in a class called com.ppl.cust.CustomerManagementServlet, and may match the URL pattern /customer-mgt.
This file is only needed if servlets are used. If the WAR file only contains JSP pages, web.xml is not necessary.
WEB-INF/*.tld and , and WEB-INF/tags/*.tag
The *.tld tag library descriptor files are for tag libraries that you have defined for this web application. The tag library implementations are held under tags/ directory in *.tag files
WEB-INF/lib/*.jar, WEB-INF/classes/.../*.class
Libraries and classes visible to JSPs and servlets, but not directly accessible by clients over the internet through the web application server.
Both of these may also contain other resources such as image files. Putting them here hides them from the end-user.
<?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">
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>
index.jsp
</welcome-file>
</welcome-file-list>
<ejb-local-ref>
<ejb-ref-name>ContentLocal</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<local-home/>
<local>net.kanat.wiki.session.ContentLocal</local>
<ejb-link>ContentBean</ejb-link>
</ejb-local-ref>
</web-app>
<servlet>
<servlet-name>X</servlet-name>
<servlet-class>org.xyz.common.X</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>X</servlet-name>
<url-pattern>*.x3</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>helloWorld</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
Applications compiled into WAR files can be deployed on both:
Auto-deployment (as in Tomcat) allows you to deploy a web application by just copying your WAR file to a Tomcat directory. A background process detects new/changed WAR files and deploys them.
Re-deployment of a WAR file requires recreation/update of the WAR file, even if you have changed a very small part of the WAR file. Today, JAR files are often updated incrementally, so this process need not be very inefficient (recompression of all unchanged files is not necessary).
<?xml version="1.0" encoding="UTF-8"?>
<application version="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/application_5.xsd">
<display-name>Wiki</display-name>
<module>
<web>
<web-uri>Wiki-war.war</web-uri>
<context-root>/Wiki-war</context-root>
</web>
</module>
<module>
<java>Wiki-app-client.jar</java>
</module>
<module>
<ejb>Wiki-ejb.jar</ejb>
</module>
</application>
Java EE applications are considered heavier compared to web applications.
These applications combine EJBs (Enterprise JavaBeans) and web applications (that use JSP, Servlets, and JSF).
Upon deployment of an EAR file, all the Web components and EJBs within the EAR file (packaged in separate WAR and EJB JAR files) are also deployed.
An enterprise application (compiled into an EAR file) may only be deployed on an Enterprise Application Server.
META-INF/entity.xml (in JAR, EJB JAR and EAR files)
WEB-INF/classes/META-INF/entity.xml (in WAR files)
Note: If your DB keeps getting reset to be empty, you have "drop-and-create-tables" instead of just "create-tables"
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="wikiPersister" transaction-type="JTA">
<provider>oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider</provider>
<jta-data-source>wikidb</jta-data-source>
<properties>
<property name="toplink.ddl-generation" value="create-tables"/>
</properties>
</persistence-unit>
</persistence>
Developed to use lightweight components (POJOs: Plain old Java objects)
Less focus on CORBA and distributed design; simpler and more efficient when server side is not distributed.
Specification was co-authored by lighter-weight Hibernate framework creator Gavin King
EJB 3.0 is a radical departure from older EJBs
Annotations, configuration-by-exception and dependency-inversion simplify within-Java EE 5 and outside-Java EE 5 deployment.
Java EE 5, with the introduction of EJB 3.0, makes life much easier for the developer.
The most important simplification of developer task comes from JPA (Java Persistence API) that automates object-relational mapping.
This means you may never have to mention SQL to create your web application that uses SQL.
Entities are simple Java objects (POJOs) that are mapped to SQL tables. This allows the developer to create and modify entities without worrying about automatically handled read/write to/from the database.
Heavy-weight framework to handle "plumbing" (all necessary low-level activities) required to do distributed programming across different languages, platforms and geographical locations.
Uses both remote object references and pass-by-value copied structures.
Disadvantage of remote object references: Each method call incurs a network communication penalty.
Limitations of pass-by-value: Changes made to the copied object in the client won't be propagated to the original owner of the object (unless copied back). Multiple copies may cause multiple incompatible versions of the object, synchronization issues.
Structures that are passed by value are "marshalled" (serialized), sent across the network, and "unmarshalled".
Remote object references require tie-in structures called "Stubs" that imitate the interface of the remote object, and convert every call to a CORBA remote call across the network.
java.rmi.RemoteException
Any remote invocation may fail due to network problems. This means any remotely called method may throw (due to underlying RMI) RemoteExceptions.
Remote Method Invocation is Java's Java-language-only distributed programming framework.
RMI was not originally compatible with CORBA, but it was later retrofitted to become compatible.
RMI uses serialization to marshal objects, and uses Stubs, Home (factory) and Remote interfaces.
EJBs in J2EE (before EJB 3.0) required explicit handling of RMI calls. EJB 3.0 in Java EE 5 makes RMI mostly invisible.
Consider four roles:
These roles are performed in this order. Each role should provision for all the roles at the same and later levels.
There are requirements that mainly serve developers. There are others that serve deployers, and yet others that make life easier for end-users.
Architects need to focus on all these requirements. Deployers may only have to know of and take care of the requirements that aid end-users as well as other future deployers.
Scalability manifests itself as performance (overall performance and interactivity) issues when too many clients connect.
The solution is often scaling up hardware and making sure software can use the new hardware efficiently.
Large tasks should not be burdened by too much distributed communication, inefficient algorithms, or waiting for resources that may not be required for the task.
These are external to Java source code.
A deployer who only has access to Java bytecode (*.class files) can still change these configuration files.
Configuration file declarations override annotations.
Preferably, features that may possibly be changed during deployment should only be declared in configuration files.
Standard configuration files such as ejb-jar.xml, application.xml, web.xml were mentioned earlier in Java Application Packaging and Deployment.
Vendor-specific configuration files also exist. Try not to use these, to keep your software portable.
A component that lives within a container requests a resource (with a given type and possibly a name) from the container, declaratively.
Container either creates the resource anew or uses reference to existing resource if resource was already created.
Container initializes a field variable of the component, directly, to refer to desired resource.
Component itself does not initialize the field, but may use it in its methods.
Java EE 5 defines a standard that assures portability to other vendors' Java EE 5 application servers.
Here we are not just talking about portability to other OSes and platforms. Multi-platform deployability is already supplied by most vendors.
Scalability can be achieved through proper use of stateless/stateful session beans and other components.
EJBs, JSPs, Servlets, JSP Tag Libraries, JSF, use of JavaBeans in web applications all focus on creating reusable components.
Java Persistence API is a new and very significant addition to enterprise Java development.
Oracle's TopLink Essentials for object-relational mapping is the reference implementation of Java Persistence API. There is much under the hood to make the mapping easy and straightforward to use.
Links
Please remember that the same client, requesting the same service may be served by different stateless session beans at different times, and different clients requesting the same service may be served by the same stateless session bean.
JPA uses annotations, a Java 5 language feature, in order to convert simple Java classes (POJOs) into entities that can easily be stored in and retrieved from a database.
Where default properties suffice, this is as easy as adding an "@Entity" annotation to the class and an "@Id" annotation to the getter method of the primary Id property of the class (this corresponds to the primary key of the table).
One entity class corresponds to one table. The name of the entity is capitalized to get the table name in the database (of course, this default behavior can be changed). Each persisted entity object of this entity class corresponds to one row of this table.
Persistent fields and properties (default behavior) map to columns. Properties are defined through the corresponding get/set methods. For example, existence of a "getBookName" method corresponds to a "bookName" property.
Again, this can be customized; methods that look like but are not property methods can be annotated to not be persisted as a column in the database.
Alternatively, field-based mapping can be used and fields that are not to be persisted can then be annotated as such (by default, static and transient fields are not persisted).
The property (or field) in the entity class that corresponds to the primary key in the table (which must be unique) must be annotated with the @Id annotation. Every entity class should have an Id property (or field).
Annotations and entity relationships are inherited through standard Java class inheritance hierarchy. Entity inheritance can be handled by using common tables or by using separate tables for superclass and subclass.
Entities that are retrieved from the database can be sent to methods or modified directly.
Such entity objects are "detached entities". They need to be merged back with the database before "persisting" them:
entityManager.merge(myEntity);
myEntityManager.persist(myEntity);
Default behavior is quite often sufficient, but JPA allows a lot of customization for intermediate/advanced database users.
One common use is directly making queries to the database from an object-oriented viewpoint, using the JPQL (Java Persistence Query Language), which is an object-oriented version of SQL.
@Entity
public class Page {
@Id
private String addr;
private String content;
private int numHits;
public Page() { ... } // a no-arg constructor is required
}
@Entity marks this class as an entity; a table by the name "PAGE" will be created in runtime.
@Id marks a unique identifier which may not be the same in any two distinct Page objects that are persisted.
Even though the fields are private, the container can access and modify their values to keep in sync with the DB.
Yes, the content and numHits fields are also persisted (stored in the DB).
If you don't want to persist a field, you can just use @Transient annotation before it (for example, above numHits declaration above).
@Transient
private int numHits;
Alternatively, you could declare numHits using the Java keyword "transient":
private transient int numHits
Container directly modifies the fields in this case.
Any transient fields that depend on persistent fields cannot be initialized because no method is called.
@Entity
@NamedQuery(name="getAllPageAddrs", query="select p.addr from Page p")
public class Page implements Serializable {
private String addr;
private String content;
private int numHits;
public Page() { /* does nothing */ }
@Id
public String getAddr() { ... }
public void setAddr(String addr) { ... }
@Lob
public String getContent() { ... }
public void setContent(String content) { ... }
@Transient
public int getNumHits() { ... }
public void setNumHits(int value) { ... }
}
If you are using method access, only use annotations on get methods; don't mix these with field annotations for entities.
In this case, the container will call our methods to initialize and retrieve the property values addr and content.
content property is now defined as a large object. For a String, this means it can hold up to 64 KB of text data.
numHits does not correspond to a column in the PAGE table in the database. It should really be generated by a @PostLoad-annotated method that initializes the entity, as in:
@PostLoad
resetNumHits() { numHits = 0; }
Other entity life-cycle callback methods include @PrePersist, @PostPersist, @PreRemove, @PostRemove, @PreUpdate, and @PostUpdate.
NamedQuery allows JPQL to be used for queries. JPQL is like SQL, but is object-oriented ("Page" p and "." in p.addr are JPQL features)
// Some EJB annotation (@Stateful, @Stateless, or @MessageDriven
public class MyBean {
@PersistenceContext
private EntityManager em; // Container will initialize this object; you need not
...
public Page getPage(String addr) {
Page myPage = (Page)em.find(Page.class, addr);
// omitted here: Handle exceptions and the null case
return myPage;
}
...
}
There are many intermediate and advanced features that allow low-level configuration of object-relational mapping betweem entity objects and relational DBs.
We will later look at some intermediate-level features such as:
Stateful session beans handle sessions created by clients so that they need not reenter their information, preferences and choices on every page. For this purpose, stateful session beans is really the only option, so that client information (called "conversational state) can be stored within the session established with the client.
If the client does not interact with the server for a specified period of time, the session bean is passivated (stored on the file system). Passivated session beans expire after a period of time and get deleted.
If the client interacts before expiration, the passivated session bean is reactivated from file system storage and brought back to life so that the client can continue the session.
You can catch important events in the stateful session bean life cycle by using the annotations @PostConstruct, @PrePassivate, @PostActivate and @PostDestroy. The methods that contain these annotations will be called when the corresponding event takes place.
For example, expiration and removal cause @PreDestroy-annotated method to be called before session bean destruction.
Do not use the same annotation for more than one method; the results may be unpredictable.
@Stateful
public class ContentBean implements ContentRemote, ContentLocal {
@PersistenceContext()
private EntityManager em;
/** Creates a new instance of ContentBean */
public ContentBean() {
}
....
}
Stateless Session Beans do not really handle a client session. As they can't hold client state, any stateless session bean can be used to handle a request from any client.
Usually, a pool of such stateless session beans are created to handle client requests.
Clients are served by randomly picked stateless session beans.
Same client may get different stateless session beans on two requests.
Different clients may get the same stateless session bean on two requests.
Ideally, all state information is stored outside the stateless session beans (through persistence or JavaBeans, for example).
@Stateless
public class SearchEngineBean implements SearchEngineRemote {
@PersistenceContext
private EntityManager em; // Container will initialize this object; you need not
public SearchEngineBean() { }
public Links findPages(String keyword) {
return (Links)em.find(Links.class, keyword);
}
}
Message-driven beans handle asynchronous requests.
For example, a purchase request may be handled asynchronously. Upon completion of the request, the message-driven bean may send a confirmation email to the client.
The key here is that the client does not need to wait until the request is processed.
Entity beans are now replaced with Entity objects created using Java Persistence API (JPA), which allows the enterprise javabean container to handle the persistence of the entities.
Entity objects (unlike the old Entity Beans) can also be used in Web Applications and standalone applications. This is the main reason the name "bean" was dropped from entities.
The client application may use RMI explicitly (programmatically) to connect to the Java EE 5 application.
Alternatively, an "Application Client Container" may be used.
Application client containers provide features similar to (but much limited in comparison with) application server containers.
Within an application client container, metadata annotations and dependency injection can be used to get an EJB reference.
Glassfish-based Sun JSAS application server that we use at the lab has the ability to use Java Web Start to automate deployment of an application client within an application client container.
We saw JSPs (JavaServer Pages) in the last lecture. JSPs mix HTML and Java, as in:
<h1><% out.println("Hello, World!"); %></h1>
JSP also allows definition of custom tag libraries to access often-used functionality through html-like tags.
Using tag libraries allow separation of presentation and business logic.
Tag libraries minimize Java code size and total size within JSP pages, which reduces the risk of a web designer accidentally injecting a bug while modifying the page design.
Servlets often handle HTTP requests from browsers in order to create dynamic web pages. The Servlet technology is not limited to HTTP, but we will mostly focus on using Servlets with HTTP.
A Servlet handles requests by creating responses. In dynamic web pages, requests are page requests (possibly with form data that is passed using POST, or less likely, using GET). In this case, responses are dynamically created web pages, so usually contain HTML (possibly with CSS) and may contain Javascript.
Often, clients need to pass some information to the server that must be stored while the client continues to use the services provided by the server. This requires a session to be created. Java Servlets can handle session creation to store values of variables in one page and to access it from another page.
Servlets prefer to use cookies to create a unique session ID which is stored in the cookie on the client side. The actual session variables and values are never stored on the client side, as this would not be safe from tempering. When cookies are not available, the web application server will handle session IDs by passing session ID values to every page request. This is handled transparently; you never have to directly manipulate cookies for session-handling.
The actual session variables and values are stored on the server side, keyed to the session ID. Sessions that are not attended for a long time will expire.
Other than session, Servlets can also store variables in application context, and access them globally across all requests, all clients and sessions.
The preferred method to process forms is using HTTP POST. It is not recommended to use HTTP GET. In an HttpServlet, you can choose to handle (or not handle) GET and POST requests separately, or using a single method to handle both. The methods doGet and doPost both receive an HttpServletRequest, use an HttpServletResponse to generate the response, and may throw ServletExceptions (mostly thrown by the container) and IOExceptions.
When the client posts form data, it is received by a Servlet or a JSP page as parameters in the request (accessed by request.getParameter("name")).
On the server side, other attributes can be added to the request by using request.setAttribute("name", "John"). For example, a servlet can set an attribute and then forward the request to a JSP page using getServletContext().getRequestDispatcher("nextpage.jsp").forward(request, response). In that JSP page, this attribute can now be read using request.getAttribute("name").
Servlets are deployed using a WAR file (web archive) that contains all the necessary class files, resources (images, static HTML pages, audio, external library jar files), and the web.xml configuration file under the WEB-INF directory.
In Netbeans, this configuration file can be modified in its original XML form, or by using a graphical user interface. XML form display shows the simplicity when the file is short, and the GUI allows you to see what other options are available (but left as default in the current configuration file).
JSTL stands for JavaServer Pages Standard Tag Library.
JSTL has tags for common tasks related to internationalization, iterations/loops, conditionals, database access, and XML processing.
User input validation.
Control flow between web pages served. This is declaratively defined through rules such as "from login page, we go to welcome page if login was successful".
Creation and reuse of user interfaces (that may use Javascript on the client).
Web services that are available on a Java EE 5 application server can be called across the network in Web Service clients.
Such clients are most probably desktop applications, but could also be remote web applications.
The client need not be Java (if it is, RMI would be more efficient).