Java API for XML-Based RPC (JAX-RPC) is a Legacy Web Services Java API, it uses SOAP and HTTP to do RPCs over the network and enables building of Web services and Web applications based on the SOAP 1.1 specification, Java SE 1.4 or lower, or when rpc/encoded style must be used.
You can use the JAX-RPC programming model to develop SOAP-based web service clients and endpoints. JAX-RPC enables clients to invoke web services developed across heterogeneous platforms. Likewise, JAX-RPC web service endpoints can be invoked by heterogeneous clients. JAX-RPC requires SOAP and WSDL standards for this cross-platform interoperability.
JAX-RPC lets people develop a web service endpoint using either a Servlet or Enterprise JavaBeans (EJB) component model. The endpoint is then deployed on either the Web or EJB container, based on the corresponding component model. Endpoints are described using a Web Services Description Language (WSDL) document.(This WSDL document can be published in a public or private registry, though this is not required). A client then uses this WSDL document and invokes the web service endpoint.
JAX-RPC in J2ee 1.4 supports 4 types of stubs and invocations: static stub, dynamic proxy, Dynamic Invocation Interface (DII) and Application client.
Static Stub Client
Web service client makes a call through a stub, a local object that acts as a proxy for the remote service. Because the stub is created by wscompile at development time (as opposed to runtime), it is usually called a static stub.
Example: Invoking a Stub Client
Stub stub = (Stub) (new MyHelloService_Impl().getHelloIFPort());
stub._setProperty (javax.xml.rpc.Stub.ENDPOINT_ADDRESS_PROPERTY,endpoint_address_string);
HelloIF hello = (HelloIF)stub;
System.out.println(hello.sayHello("Duke!"));
Dynamic Proxy Client
In contrast, the client call a remote procedure through a dynamic proxy, a class that is created during runtime. Although the source code for the static stub client relies on an implementation-specific class, the code for the dynamic proxy client does not have this limitation.
Example: Dynamic Proxy
javax.xml.rpc.Service service = ServiceFactory.newInstance().createService(...);
com.example.StockQuoteProvider sqp = (com.example.StockQuoteProvider)service.getPort(portName, StockQuoteProvider.class);
float price = sqp.getLastTradePrice("ACME");
Dynamic Invocation Interface Client
With the dynamic invocation interface (DII), a client can call a remote procedure even if the signature of the remote procedure or the name of the service is unknown until runtime. In contrast to a static stub or dynamic proxy client, a DII client does not require runtime classes generated by wscompile.
Example: Dynamic Invocation Interface
javax.xml.rpc.Service service = ServiceFactory.newInstance().createService(...);
javax.xml.rpc.Call call = service.createCall(portName, "getLastTradePrice");
// This example assumes that addParameter and setReturnType methods are not required to be called
Object[] inParams = new Object[] {"ACME"};
Float quotePrice = (Float)call.invoke(inParams);
Application Client
Unlike the stand-alone clients, for an application client, because it's a J2EE component, an application client can locate a local web service by invoking the JNDI lookup method.
Example: Application Client
Context ic = new InitialContext();
MyHelloService myHelloService = (MyHelloService)
ic.lookup("java:comp/env/service/MyJAXRPCHello");
appclient.HelloIF helloPort = myHelloService.getHelloIFPort();
((Stub)helloPort)._setProperty(Stub.ENDPOINT_ADDRESS_PROPERTY,args[0]);
System.out.println(helloPort.sayHello("Jake!"));
Service Endpoint Model
JAX-RPC supports a client model for the service consumer, and a service endpoint model for the service producer.
Application-Level Interaction Modes
JAX-RPC specifies three client application interaction models:
* Synchronous request-response two-way RPC
* Asynchronous (non-blocking) request-response two-way RPC
* One-way RPC
JAX-WS
JAX-WS 2.0 is the successor of JAX-RPC 1.1 - the Java API for XML-based Web services. If possible, JAX-WS should be used instead as it is based on the most recent industry standards.
What remains the same?
Before we itemize the differences between JAX-RPC 1.1 and JAX-WS 2.0, we should first discuss what is the same.
* JAX-WS still supports SOAP 1.1 over HTTP 1.1, so interoperability will not be affected. The same messages can still flow across the wire.
* JAX-WS still supports WSDL 1.1, so what you've learned about that specification is still useful. A WSDL 2.0 specification is nearing completion, but it was still in the works at the time that JAX-WS 2.0 was finalized.
What is different?
* SOAP 1.2
JAX-RPC and JAX-WS support SOAP 1.1. JAX-WS also supports SOAP 1.2.
* XML/HTTP
The WSDL 1.1 specification defined an HTTP binding, which is a means by which you can send XML messages over HTTP without SOAP. JAX-RPC ignored the HTTP binding. JAX-WS adds support for it.
* WS-I's Basic Profiles
JAX-RPC supports WS-I's Basic Profile (BP) version 1.0. JAX-WS supports BP 1.1. (WS-I is the Web services interoperability organization.)
* New Java features
o JAX-RPC maps to Java 1.4. JAX-WS maps to Java 5.0. JAX-WS relies on many of the features new in Java 5.0.
o Java EE 5, the successor to J2EE 1.4, adds support for JAX-WS, but it also retains support for JAX-RPC, which could be confusing to today's Web services novices.
* The data mapping model
o JAX-RPC has its own data mapping model, which covers about 90 percent of all schema types. Those that it does not cover are mapped to javax.xml.soap.SOAPElement.
o JAX-WS's data mapping model is JAXB. JAXB promises mappings for all XML schemas.
* The interface mapping model
JAX-WS's basic interface mapping model is not extensively different from JAX-RPC's; however:
o JAX-WS's model makes use of new Java 5.0 features.
o JAX-WS's model introduces asynchronous functionality.
* The dynamic programming model
o JAX-WS's dynamic client model is quite different from JAX-RPC's. Many of the changes acknowledge industry needs:
+ It introduces message-oriented functionality.
+ It introduces dynamic asynchronous functionality.
o JAX-WS also adds a dynamic server model, which JAX-RPC does not have.
* MTOM (Message Transmission Optimization Mechanism)
JAX-WS, via JAXB, adds support for MTOM, the new attachment specification. Microsoft never bought into the SOAP with Attachments specification; but it appears that everyone supports MTOM, so attachment interoperability should become a reality.
* The handler model
o The handler model has changed quite a bit from JAX-RPC to JAX-WS.
o JAX-RPC handlers rely on SAAJ 1.2. JAX-WS handlers rely on the new SAAJ 1.3 specification.
Reference Origination Link: http://www.ibm.com/developerworks/webservices/library/ws-tip-jaxwsrpc.html
28 January 2012
27 January 2012
ReadWrite Locks in Java
A read / write lock is more sophisticated lock than the Lock implementations shown in the text Locks in Java. Imagine you have an application that reads and writes some resource, but writing it is not done as much as reading it is. Two threads reading the same resource does not cause problems for each other, so multiple threads that want to read the resource are granted access at the same time, overlapping. But, if a single thread wants to write to the resource, no other reads nor writes must be in progress at the same time. To solve this problem of allowing multiple readers but only one writer, you will need a read / write lock.
Java 5 comes with read / write lock implementations in the java.util.concurrent package. Even so, it may still be useful to know the theory behind their implementation.
Here is a list of the topics covered in this text:
1. Read / Write Lock Java Implementation
2. Read / Write Lock Reentrance
3. Read Reentrance
4. Write Reentrance
5. Read to Write Reentrance
6. Write to Read Reentrance
7. Fully Reentrant Java Implementation
8. Calling unlock() from a finally-clause
2. Read / Write Lock Reentrance
3. Read Reentrance
4. Write Reentrance
5. Read to Write Reentrance
6. Write to Read Reentrance
7. Fully Reentrant Java Implementation
8. Calling unlock() from a finally-clause
Read / Write Lock Java Implementation
First let’s summarize the conditions for getting read and write access to the resource:
Read Access If no threads are writing, and no threads have requested write access.
Write Access If no threads are reading or writing.
Read Access If no threads are writing, and no threads have requested write access.
Write Access If no threads are reading or writing.
If a thread wants to read the resource, it is okay as long as no threads are writing to it, and no threads have requested write access to the resource. By up-prioritizing write-access requests we assume that write requests are more important than read-requests. Besides, if reads are what happens most often, and we did not up-prioritize writes, starvation could occur. Threads requesting write access would be blocked until all readers had unlocked the ReadWriteLock. If new threads were constantly granted read access the thread waiting for write access would remain blocked indefinately, resulting in starvation. Therefore a thread can only be granted read access if no thread has currently locked the ReadWriteLock for writing, or requested it locked for writing.
A thread that wants write access to the resource can be granted so when no threads are reading nor writing to the resource. It doesn’t matter how many threads have requested write access or in what sequence, unless you want to guarantee fairness between threads requesting write access.
With these simple rules in mind we can implement a ReadWriteLock as shown below:
public class ReadWriteLock{
private int readers = 0;
private int writers = 0;
private int writeRequests = 0;
public synchronized void lockRead() throws InterruptedException{
while(writers > 0 || writeRequests > 0){
wait();
}
readers++;
}
public synchronized void unlockRead(){
readers--;
notifyAll();
}
public synchronized void lockWrite() throws InterruptedException{
writeRequests++;
while(readers > 0 || writers > 0){
wait();
}
writeRequests--;
writers++;
}
public synchronized void unlockWrite() throws InterruptedException{
writers--;
notifyAll();
}
}
The ReadWriteLock has two lock methods and two unlock methods. One lock and unlock method for read access and one lock and unlock for write access.
The rules for read access are implemented in the lockRead() method. All threads get read access unless there is a thread with write access, or one or more threads have requested write access.
The rules for write access are implemented in the lockWrite() method. A thread that wants write access starts out by requesting write access (writeRequests++). Then it will check if it can actually get write access. A thread can get write access if there are no threads with read access to the resource, and no threads with write access to the resource. How many threads have requested write access doesn’t matter.
It is worth noting that both unlockRead() and unlockWrite() calls notifyAll() rather than notify(). To explain why that is, imagine the following situation:
Inside the ReadWriteLock there are threads waiting for read access, and threads waiting for write access. If a thread awakened by notify() was a read access thread, it would be put back to waiting because there are threads waiting for write access. However, none of the threads awaiting write access are awakened, so nothing more happens. No threads gain neither read nor write access. By calling noftifyAll() all waiting threads are awakened and check if they can get the desired access.
Calling notifyAll() also has another advantage. If multiple threads are waiting for read access and none for write access, and unlockWrite() is called, all threads waiting for read access are granted read access at once – not one by one.
Read / Write Lock Reentrance
The ReadWriteLock class shown earlier is not reentrant. If a thread that has write access requests it again, it will block because there is already one writer – itself. Furthermore, consider this case:
1. Thread 1 gets read access.
2. Thread 2 requests write access but is blocked because there is one reader.
3. Thread 1 re-requests read access (re-enters the lock), but is blocked because there is a write request
In this situation the previous ReadWriteLock would lock up – a situation similar to deadlock. No threads requesting neither read nor write access would be granted so.
To make the ReadWriteLock reentrant it is necessary to make a few changes. Reentrance for readers and writers will be dealt with separately.
Read Reentrance
To make the ReadWriteLock reentrant for readers we will first establish the rules for read reentrance:
A thread is granted read reentrance if it can get read access (no writers or write requests), or if it already has read access (regardless of write requests).
To determine if a thread has read access already a reference to each thread granted read access is kept in a Map along with how many times it has acquired read lock. When determing if read access can be granted this Map will be checked for a reference to the calling thread. Here is how the lockRead() and unlockRead() methods looks after that change:
public class ReadWriteLock{
private Map readingThreads =
new HashMap();
private int writers = 0;
private int writeRequests = 0;
public synchronized void lockRead() throws InterruptedException{
Thread callingThread = Thread.currentThread();
while(! canGrantReadAccess(callingThread)){
wait();
}
readingThreads.put(callingThread,
(getAccessCount(callingThread) + 1));
}
public synchronized void unlockRead(){
Thread callingThread = Thread.currentThread();
int accessCount = getAccessCount(callingThread);
if(accessCount == 1){ readingThreads.remove(callingThread); }
else { readingThreads.put(callingThread, (accessCount -1)); }
notifyAll();
}
private boolean canGrantReadAccess(Thread callingThread){
if(writers > 0) return false;
if(isReader(callingThread) return true;
if(writeRequests > 0) return false;
return true;
}
private int getReadAccessCount(Thread callingThread){
Integer accessCount = readingThreads.get(callingThread);
if(accessCount == null) return 0;
return accessCount.intValue();
}
private boolean isReader(Thread callingThread){
return readingThreads.get(callingThread) != null;
}
}
As you can see read reentrance is only granted if no threads are currently writing to the resource. Additionally, if the calling thread already has read access this takes precedence over any writeRequests.
Write Reentrance
Write reentrance is granted only if the thread has already write access. Here is how the lockWrite() and unlockWrite() methods look after that change:
public class ReadWriteLock{
private Map readingThreads =
new HashMap();
private int writeAccesses = 0;
private int writeRequests = 0;
private Thread writingThread = null;
public synchronized void lockWrite() throws InterruptedException{
writeRequests++;
Thread callingThread = Thread.currentThread();
while(! canGrantWriteAccess(callingThread)){
wait();
}
writeRequests--;
writeAccesses++;
writingThread = callingThread;
}
public synchronized void unlockWrite() throws InterruptedException{
writeAccesses--;
if(writeAccesses == 0){
writingThread = null;
}
notifyAll();
}
private boolean canGrantWriteAccess(Thread callingThread){
if(hasReaders()) return false;
if(writingThread == null) return true;
if(!isWriter(callingThread)) return false;
return true;
}
private boolean hasReaders(){
return readingThreads.size() > 0;
}
private boolean isWriter(Thread callingThread){
return writingThread == callingThread;
}
}
Notice how the thread currently holding the write lock is now taken into account when determining if the calling thread can get write access.
Read to Write Reentrance
Sometimes it is necessary for a thread that have read access to also obtain write access. For this to be allowed the thread must be the only reader. To achieve this the writeLock() method should be changed a bit. Here is what it would look like:
public class ReadWriteLock{
private Map readingThreads =
new HashMap();
private int writeAccesses = 0;
private int writeRequests = 0;
private Thread writingThread = null;
public synchronized void lockWrite() throws InterruptedException{
writeRequests++;
Thread callingThread = Thread.currentThread();
while(! canGrantWriteAccess(callingThread)){
wait();
}
writeRequests--;
writeAccesses++;
writingThread = callingThread;
}
public synchronized void unlockWrite() throws InterruptedException{
writeAccesses--;
if(writeAccesses == 0){
writingThread = null;
}
notifyAll();
}
private boolean canGrantWriteAccess(Thread callingThread){
if(isOnlyReader(callingThread)) return true;
if(hasReaders()) return false;
if(writingThread == null) return true;
if(!isWriter(callingThread)) return false;
return true;
}
private boolean hasReaders(){
return readingThreads.size() > 0;
}
private boolean isWriter(Thread callingThread){
return writingThread == callingThread;
}
private boolean isOnlyReader(Thread thread){
return readers == 1 && readingThreads.get(callingThread) != null;
}
}
Now the ReadWriteLock class is read-to-write access reentrant.
Write to Read Reentrance
Sometimes a thread that has write access needs read access too. A writer should always be granted read access if requested. If a thread has read access no other threads can have read nor write access, so it is not dangerous. Here is how the canGrantReadAccess() method will look with that change:
public class ReadWriteLock{
private boolean canGrantReadAccess(Thread callingThread){
if(isWriter(callingThread)) return true;
if(writingThread != null) return false;
if(isReader(callingThread) return true;
if(writeRequests > 0) return false;
return true;
}
}
Fully Reentrant ReadWriteLock
Below is the fully reentran ReadWriteLock implementation. I have made a few refactorings to the access conditions to make them easier to read, and thereby easier to convince yourself that they are correct.
public class ReadWriteLock{
private Map readingThreads =
new HashMap();
private int writeAccesses = 0;
private int writeRequests = 0;
private Thread writingThread = null;
public synchronized void lockRead() throws InterruptedException{
Thread callingThread = Thread.currentThread();
while(! canGrantReadAccess(callingThread)){
wait();
}
readingThreads.put(callingThread,
(getReadAccessCount(callingThread) + 1));
}
private boolean canGrantReadAccess(Thread callingThread){
if( isWriter(callingThread) ) return true;
if( hasWriter() ) return false;
if( isReader(callingThread) ) return true;
if( hasWriteRequests() ) return false;
return true;
}
public synchronized void unlockRead(){
Thread callingThread = Thread.currentThread();
if(!isReader(callingThread)){
throw new IllegalMonitorStateException("Calling Thread does not" +
" hold a read lock on this ReadWriteLock");
}
int accessCount = getReadAccessCount(callingThread);
if(accessCount == 1){ readingThreads.remove(callingThread); }
else { readingThreads.put(callingThread, (accessCount -1)); }
notifyAll();
}
public synchronized void lockWrite() throws InterruptedException{
writeRequests++;
Thread callingThread = Thread.currentThread();
while(! canGrantWriteAccess(callingThread)){
wait();
}
writeRequests--;
writeAccesses++;
writingThread = callingThread;
}
public synchronized void unlockWrite() throws InterruptedException{
if(!isWriter(Thread.currentThread()){
throw new IllegalMonitorStateException("Calling Thread does not" +
" hold the write lock on this ReadWriteLock");
}
writeAccesses--;
if(writeAccesses == 0){
writingThread = null;
}
notifyAll();
}
private boolean canGrantWriteAccess(Thread callingThread){
if(isOnlyReader(callingThread)) return true;
if(hasReaders()) return false;
if(writingThread == null) return true;
if(!isWriter(callingThread)) return false;
return true;
}
private int getReadAccessCount(Thread callingThread){
Integer accessCount = readingThreads.get(callingThread);
if(accessCount == null) return 0;
return accessCount.intValue();
}
private boolean hasReaders(){
return readingThreads.size() > 0;
}
private boolean isReader(Thread callingThread){
return readingThreads.get(callingThread) != null;
}
private boolean isOnlyReader(Thread callingThread){
return readingThreads.size() == 1 &&
readingThreads.get(callingThread) != null;
}
private boolean hasWriter(){
return writingThread != null;
}
private boolean isWriter(Thread callingThread){
return writingThread == callingThread;
}
private boolean hasWriteRequests(){
return this.writeRequests > 0;
}
}
Calling unlock() From a finally-clause
When guarding a critical section with a ReadWriteLock, and the critical section may throw exceptions, it is important to call the readUnlock() and writeUnlock() methods from inside a finally-clause. Doing so makes sure that the ReadWriteLock is unlocked so other threads can lock it. Here is an example:
lock.lockWrite();
try{
//do critical section code, which may throw exception
} finally {
lock.unlockWrite();
}
This little construct makes sure that the
ReadWriteLock
is unlocked in case an exception is thrown from the code in the critical section. If unlockWrite()
was not called from inside a finally
-clause, and an exception was thrown from the critical section, the ReadWriteLock
would remain write locked forever, causing all threads callinglockRead()
or lockWrite()
on that ReadWriteLock
instance to halt indefinately. The only thing that could unlock the ReadWriteLock
again would be if the ReadWriteLock
is reentrant, and the thread that had it locked when the exception was thrown, later succeeds in locking it, executing the critical section and calling unlockWrite()
again afterwards. That would unlock the ReadWriteLock
again. But why wait for that to happen, if it happens? CallingunlockWrite()
from a finally
-clause is a much more robust solution.Original link: http://www.javaol.net/2011/02/read-write-locks-in-java/
Enum in Java
Disadvantages of global variable in Java
public static final int SEASON_WINTER = 0;
public static final int SEASON_SPRING = 1;
public static final int SEASON_SUMMER = 2;
public static final int SEASON_FALL = 3;
This pattern has many problems, such as:
- Not typesafe - Since a season is just an
int
you can pass in any other int value where a season is required, or add two seasons together (which makes no sense). - No namespace - You must prefix constants of an int enum with a string (in this case
SEASON_
) to avoid collisions with other int enum types. - Brittleness - Because int enums are compile-time constants, they are compiled into clients that use them. If a new constant is added between two existing constants or the order is changed, clients must be recompiled. If they are not, they will still run, but their behavior will be undefined.
- Printed values are uninformative - Because they are just ints, if you print one out all you get is a number, which tells you nothing about what it represents, or even what type it is
Enum
In 5.0, the Java™ programming language gets linguistic support for enumerated types. In their simplest form, these enums look just like their C, C++, and C# counterparts:
enum Season { WINTER, SPRING, SUMMER, FALL }
But appearances can be deceiving. Java programming language enums are far more powerful than their counterparts in other languages, which are little more than glorified integers. The new
enum
declaration defines a full-fledged class (dubbed an enum type). In addition to solving all the problems mentioned above, it allows you to add arbitrary methods and fields to an enum type, to implement arbitrary interfaces, and more. Enum types provide high-quality implementations of all the Object methods. They are Comparable and Serializable, and the serial form is designed to withstand arbitrary changes in the enum type.public class Card { public enum Rank { DEUCE, THREE, FOUR, FIVE,
SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE }
public enum Suit { CLUBS, DIAMONDS, HEARTS, SPADES }
private final Rank rank;
private final Suit suit;
private Card(Rank rank, Suit suit) {
this.rank = rank;
this.suit = suit;
}
public Rank rank() { return rank; }
public Suit suit() { return suit; }
public String toString() { return rank + " of " + suit; }
private static final List<Card> protoDeck = new ArrayList<Card>();
// Initialize prototype deck
static {
for (Suit suit : Suit.values())
for (Rank rank : Rank.values())
protoDeck.add(new Card(rank, suit));
}
public static ArrayList<Card> newDeck() {
return new ArrayList<Card>(protoDeck); // Return copy of prototype deck
}
}
ThetoString
method forCard
takes advantage of thetoString
methods forRank
andSuit
. Note that theCard
class is short (about 25 lines of code). If the typesafe enums (Rank
andSuit
) had been built by hand, each of them would have been significantly longer than the entireCard
class.
The (private) constructor of
Card
takes two parameters, a Rank
and a Suit
. If you accidentally invoke the constructor with the parameters reversed, the compiler will politely inform you of your error. Contrast this to the int
enum pattern, in which the program would fail at run time.Note that each enum type has a static
values
method that returns an array containing all of the values of the enum type in the order they are declared. This method is commonly used in combination with the for-each loop to iterate over the values of an enumerated type.The following example is a simple program called
Deal
that exercises Card
. It reads two numbers from the command line, representing the number of hands to deal and the number of cards per hand. Then it creates a new deck of cards, shuffles it, and deals and prints the requested hands.import java.util.*;you want to add data and behavior to an enum. For example consider the planets of the solar system. Each planet knows its mass and radius, and can calculate its surface gravity and the weight of an object on the planet. Here is how it looks:
public class Deal {
public static void main(String args[]) {
int numHands = Integer.parseInt(args[0]);
int cardsPerHand = Integer.parseInt(args[1]);
List<Card> deck = Card.newDeck();
Collections.shuffle(deck);
for (int i=0; i < numHands; i++)
System.out.println(deal(deck, cardsPerHand));
}
public static ArrayList<Card> deal(List<Card> deck, int n) {
int deckSize = deck.size();
List<Card> handView = deck.subList(deckSize-n, deckSize);
ArrayList<Card> hand = new ArrayList<Card>(handView);
handView.clear();
return hand;
}
}
$ java Deal 4 5
[FOUR of HEARTS, NINE of DIAMONDS, QUEEN of SPADES, ACE of SPADES, NINE of SPADES]
[DEUCE of HEARTS, EIGHT of SPADES, JACK of DIAMONDS, TEN of CLUBS, SEVEN of SPADES]
[FIVE of HEARTS, FOUR of DIAMONDS, SIX of DIAMONDS, NINE of CLUBS, JACK of CLUBS]
[SEVEN of HEARTS, SIX of CLUBS, DEUCE of DIAMONDS, THREE of SPADES, EIGHT of CLUBS]
public enum Planet {
MERCURY (3.303e+23, 2.4397e6),
VENUS (4.869e+24, 6.0518e6),
EARTH (5.976e+24, 6.37814e6),
MARS (6.421e+23, 3.3972e6),
JUPITER (1.9e+27, 7.1492e7),
SATURN (5.688e+26, 6.0268e7),
URANUS (8.686e+25, 2.5559e7),
NEPTUNE (1.024e+26, 2.4746e7),
PLUTO (1.27e+22, 1.137e6);
private final double mass; // in kilograms
private final double radius; // in meters
Planet(double mass, double radius) {
this.mass = mass;
this.radius = radius;
}
public double mass() { return mass; }
public double radius() { return radius; }
// universal gravitational constant (m3 kg-1 s-2)
public static final double G = 6.67300E-11;
public double surfaceGravity() {
return G * mass / (radius * radius);
}
public double surfaceWeight(double otherMass) {
return otherMass * surfaceGravity();
}
}
The enum typePlanet
contains a constructor, and each enum constant is declared with parameters to be passed to the constructor when it is created.
Here is a sample program that takes your weight on earth (in any unit) and calculates and prints your weight on all of the planets (in the same unit):
public static void main(String[] args) {
double earthWeight = Double.parseDouble(args[0]);
double mass = earthWeight/EARTH.surfaceGravity();
for (Planet p : Planet.values())
System.out.printf("Your weight on %s is %f%n",
p, p.surfaceWeight(mass));
}
$ java Planet 175
Your weight on MERCURY is 66.107583
Your weight on VENUS is 158.374842
Your weight on EARTH is 175.000000
Your weight on MARS is 66.279007
Your weight on JUPITER is 442.847567
Your weight on SATURN is 186.552719
Your weight on URANUS is 158.397260
Your weight on NEPTUNE is 199.207413
Your weight on PLUTO is 11.703031
The idea of adding behavior to enum constants can be taken one step further. You can give each enum constant a different behavior for some method. One way to do this by switching on the enumeration constant. Here is an example with an enum whose constants represent the four basic arithmetic operations, and whose eval
method performs the operation:
public enum Operation {
PLUS, MINUS, TIMES, DIVIDE;
// Do arithmetic op represented by this constant
double eval(double x, double y){
switch(this) {
case PLUS: return x + y;
case MINUS: return x - y;
case TIMES: return x * y;
case DIVIDE: return x / y;
}
throw new AssertionError("Unknown op: " + this);
}
}
This works fine, but it will not compile without the throw statement, which is not terribly pretty. Worse, you must remember to add a new case to the switch statement each time you add a new constant to Operation. If you forget, the eval method with fail, executing the aforementioned throw statementThere is another way give each enum constant a different behavior for some method that avoids these problems. You can declare the method abstract in the enum type and override it with a concrete method in each constant. Such methods are known asconstant-specific methods. Here is the previous example redone using this technique:public enum Operation {
PLUS { double eval(double x, double y) { return x + y; } },
MINUS { double eval(double x, double y) { return x - y; } },
TIMES { double eval(double x, double y) { return x * y; } },
DIVIDE { double eval(double x, double y) { return x / y; } };
// Do arithmetic op represented by this constant
abstract double eval(double x, double y);
}
Configure hibernate with struts
A tutorial to show how to integrate Hibernate with in a web application developed with Apache Struts 1.x.Steps of the integration :
- Create a new Hibernate Struts plug-in file to set the Hibernate session factory in servlet context, and include this file in struts-config.xml file.
- In Struts, get the Hibernate session factory from servlet context, and do whatever Hibernate task you want
package com.mkyong.common.plugin;
import java.net.URL;
import javax.servlet.ServletException;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.action.PlugIn;
import org.apache.struts.config.ModuleConfig;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernatePlugin implements PlugIn {
private Configuration config;
private SessionFactory factory;
private String path = "/hibernate.cfg.xml";
private static Class clazz = HibernatePlugin.class;
public static final String KEY_NAME = clazz.getName();
public void setPath(String path) {
this.path = path;
}
public void init(ActionServlet servlet, ModuleConfig modConfig)
throws ServletException {
try {
//save the Hibernate session factory into serlvet context
URL url = HibernatePlugin.class.getResource(path);
config = new Configuration().configure(url);
factory = config.buildSessionFactory();
servlet.getServletContext().setAttribute(KEY_NAME, factory);
} catch (MappingException e) {
throw new ServletException();
} catch (HibernateException e) {
throw new ServletException();
}
}
public void destroy() {
try {
factory.close();
} catch (HibernateException e) {
e.printStackTrace();
}
}
}
2. struts-config.xml
Include the Hibernate Struts plug-in into the Struts configuration file (struts-config.xml).<struts-config>
...
<plug-in className="com.mkyong.common.plugin.HibernatePlugin">
<set-property property="path" value="/hibernate.cfg.xml"/>
</plug-in>
...
<struts-config>
3. Get the Hibernate session factory
In Struts action class, you can get the Hibernate session factory from servlet context.servlet.getServletContext().getAttribute(HibernatePlugin.KEY_NAME);and do whatever Hibernate task as normal.package com.mkyong.customer.action;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import com.mkyong.common.plugin.HibernatePlugin;
import com.mkyong.customer.form.CustomerForm;
import com.mkyong.customer.model.Customer;
public class AddCustomerAction extends Action{
public ActionForward execute(ActionMapping mapping,ActionForm form,
HttpServletRequest request,HttpServletResponse response)
throws Exception {
SessionFactory sessionFactory =
(SessionFactory) servlet.getServletContext()
.getAttribute(HibernatePlugin.KEY_NAME);
Session session = sessionFactory.openSession();
CustomerForm customerForm = (CustomerForm)form;
Customer customer = new Customer();
//copy customerform to model
BeanUtils.copyProperties(customer, customerForm);
//save it
customer.setCreatedDate(new Date());
session.beginTransaction();
session.save(customer);
session.getTransaction().commit();
return mapping.findForward("success");
}
}
22 January 2012
REST Vs SOAP
REST
RESTs sweet spot is when you are exposing a public API over the internet to handle CRUD operations on data. REST is focused on accessing named resources through a single consistent interface.
SOAP
SOAP brings it’s own protocol and focuses on exposing pieces of application logic (not data) as services. SOAP exposes operations. SOAP is focused on accessing named operations, each implement some business logic through different interfaces.
Though SOAP is commonly referred to as “web services” this is a misnomer. SOAP has very little if anything to do with the Web. REST provides true “Web services” based on URIs and HTTP.
By way of illustration here are few calls and their appropriate home with commentary.
getUser(User);
This is a rest operation as you are accessing a resource (data).
switchCategory(User, OldCategory, NewCategory)
This is a SOAP operation as you are performing an operation.
Yes, either could be done in either SOAP or REST. The purpose is to illustrate the conceptual difference.
Why REST?
Here are a few reasons why REST is almost always the right answer.
Since REST uses standard HTTP it is much simpler in just about ever way. Creating clients, developing APIs, the documentation is much easier to understand and there aren’t very many things that REST doesn’t do easier/better than SOAP.
REST permits many different data formats where as SOAP only permits XML. While this may seem like it adds complexity to REST because you need to handle multiple formats, in my experience it has actually been quite beneficial. JSON usually is a better fit for data and parses much faster. REST allows better support for browser clients due to it’s support for JSON.
REST has better performance and scalability. REST reads can be cached, SOAP based reads cannot be cached.
It’s a bad argument (by authority), but it’s worth mentioning that Yahoo uses REST for all their services including Flickr and del.ici.ous. Amazon and Ebay provide both though Amazon’s internal usage is nearly all REST source. Google used to provide only SOAP for all their services, but in 2006 they deprecated in favor of REST source.
Why SOAP?
Here are a few reasons you may want to use SOAP.
WS-Security
While SOAP supports SSL (just like REST) it also supports WS-Security which adds some enterprise security features. Supports identity through intermediaries, not just point to point (SSL). It also provides a standard implementation of data integrity and data privacy. Calling it “Enterprise” isn’t to say it’s more secure, it simply supports some security tools that typical internet services have no need for, in fact they are really only needed in a few “enterprise” scenarios.
WS-AtomicTransaction
Need ACID Transactions over a service, you’re going to need SOAP. While REST supports transactions, it isn’t as comprehensive and isn’t ACID compliant. Fortunately ACID transactions almost never make sense over the internet. REST is limited by HTTP itself which can’t provide two-phase commit across distributed transactional resources, but SOAP can. Internet apps generally don’t need this level of transactional reliability, enterprise apps sometimes do.
WS-ReliableMessaging
Rest doesn’t have a standard messaging system and expects clients to deal with communication failures by retrying. SOAP has successful/retry logic built in and provides end-to-end reliability even through SOAP intermediaries.
Summary
In Summary, SOAP is clearly useful, and important. For instance, if I was writing an iPhone application to interface with my bank I would definitely need to use SOAP. All three features above are required for banking transactions. For example, if I was transferring money from one account to the other, I would need to be certain that it completed. Retrying it could be catastrophic if it succeed the first time, but the response failed.
RESTs sweet spot is when you are exposing a public API over the internet to handle CRUD operations on data. REST is focused on accessing named resources through a single consistent interface.
SOAP
SOAP brings it’s own protocol and focuses on exposing pieces of application logic (not data) as services. SOAP exposes operations. SOAP is focused on accessing named operations, each implement some business logic through different interfaces.
Though SOAP is commonly referred to as “web services” this is a misnomer. SOAP has very little if anything to do with the Web. REST provides true “Web services” based on URIs and HTTP.
By way of illustration here are few calls and their appropriate home with commentary.
getUser(User);
This is a rest operation as you are accessing a resource (data).
switchCategory(User, OldCategory, NewCategory)
This is a SOAP operation as you are performing an operation.
Yes, either could be done in either SOAP or REST. The purpose is to illustrate the conceptual difference.
Why REST?
Here are a few reasons why REST is almost always the right answer.
Since REST uses standard HTTP it is much simpler in just about ever way. Creating clients, developing APIs, the documentation is much easier to understand and there aren’t very many things that REST doesn’t do easier/better than SOAP.
REST permits many different data formats where as SOAP only permits XML. While this may seem like it adds complexity to REST because you need to handle multiple formats, in my experience it has actually been quite beneficial. JSON usually is a better fit for data and parses much faster. REST allows better support for browser clients due to it’s support for JSON.
REST has better performance and scalability. REST reads can be cached, SOAP based reads cannot be cached.
It’s a bad argument (by authority), but it’s worth mentioning that Yahoo uses REST for all their services including Flickr and del.ici.ous. Amazon and Ebay provide both though Amazon’s internal usage is nearly all REST source. Google used to provide only SOAP for all their services, but in 2006 they deprecated in favor of REST source.
Why SOAP?
Here are a few reasons you may want to use SOAP.
WS-Security
While SOAP supports SSL (just like REST) it also supports WS-Security which adds some enterprise security features. Supports identity through intermediaries, not just point to point (SSL). It also provides a standard implementation of data integrity and data privacy. Calling it “Enterprise” isn’t to say it’s more secure, it simply supports some security tools that typical internet services have no need for, in fact they are really only needed in a few “enterprise” scenarios.
WS-AtomicTransaction
Need ACID Transactions over a service, you’re going to need SOAP. While REST supports transactions, it isn’t as comprehensive and isn’t ACID compliant. Fortunately ACID transactions almost never make sense over the internet. REST is limited by HTTP itself which can’t provide two-phase commit across distributed transactional resources, but SOAP can. Internet apps generally don’t need this level of transactional reliability, enterprise apps sometimes do.
WS-ReliableMessaging
Rest doesn’t have a standard messaging system and expects clients to deal with communication failures by retrying. SOAP has successful/retry logic built in and provides end-to-end reliability even through SOAP intermediaries.
Summary
In Summary, SOAP is clearly useful, and important. For instance, if I was writing an iPhone application to interface with my bank I would definitely need to use SOAP. All three features above are required for banking transactions. For example, if I was transferring money from one account to the other, I would need to be certain that it completed. Retrying it could be catastrophic if it succeed the first time, but the response failed.
Subscribe to:
Posts (Atom)