|
You are receiving this e-mail because you elected to receive e-mail from Sun Microsystems, Inc. To update your communications preferences, please see the link at the bottom of this message. We respect your privacy and post our privacy policy prominently on our Web site http://sun.com/privacy/ Please do not reply to the mailed version of the newsletter, this alias is not monitored. Feedback options are listed in the footer for both content and delivery issues. |
![]() |
||||||
|
||||||
| In this Issue | ||
Welcome to the Enterprise Java Technologies Tech Tips for December 20, 2005. Here you'll get tips on using enterprise Java technologies and APIs, such as those in Java 2 Platform, Enterprise Edition (J2EE) and Java Platform, Enterprise Edition 5 (Java EE 5). This issue covers: » Developing Web Services Using JAX-WS » Charset Conversions from Browser to Database These tips were developed using an open source implementation of Java EE 5 called GlassFish. You can download GlassFish from the GlassFish Project page. You can download the sample archive for the JAX-WS tip. Any use of this code and/or information below is subject to the license terms. See the Subscribe/Unsubscribe note at the end of this newsletter to subscribe to Tech Tips that focus on technologies and products in other Java platforms. |
||
| DEVELOPING WEB SERVICES USING JAX-WS | ||
by Manisha Umbarje Java API for XML Web Services (JAX-WS) 2.0, JSR 224, is an important part of the Java EE 5 platform. A follow-on release of Java API for XML-based RPC 1.1(JAX-RPC), JAX-WS simplifies the task of developing web services using Java technology. It addresses some of the issues in JAX-RPC 1.1 by providing support for multiple protocols such as SOAP 1.1, SOAP 1.2, XML, and by providing a facility for supporting additional protocols along with HTTP. JAX-WS uses JAXB 2.0 for data binding and supports customizations to control generated service endpoint interfaces. With its support for annotations, JAX-WS simplifies web service development and reduces the size of runtime Jar files. A sample package accompanies this tip. It demonstrates a simple web service that is accessed using JAX-WS 2.0 through a standalone Java client. The example is based on an open source implementation of the Java EE 5 SDK called GlassFish. The sample package includes the source code for the example, build scripts, and an ant build file. Let's start by doing some initial setup. If you haven't already done so, download GlassFish from the GlassFish Downloads page. (This tip was tested with Build 29 of GlassFish.) Then set the following environment variables:
Also, add the ant location to your
Then download the sample package and extract its contents. The main directory for this tip is Building the Web Service
With the initial setup done, it's time to build a web service.
In this example, the web service is developed from a
Write an endpoint implementation class
If you navigate down through the
package endpoint;
import javax.jws.WebService;
import javax.jws.WebMethod;
@WebService(
name="Calculator",
serviceName="CalculatorService",
targetNamespace="http://techtip.com/jaxws/sample"
)
public class Calculator {
public Calculator() {}
@WebMethod(operationName="add", action="urn:Add")
public int add(int i, int j) {
int k = i +j ;
System.out.println(i + "+" + j +" = " + k);
return k;
}
}
JAX-WS 2.0 relies heavily on the use of annotations as specified in A Metadata Facility for the Java Programming Language (JSR 175) and Web Services Metadata for the Java Platform (JSR 181), as well as additional annotations defined by the JAX-WS 2.0 specification.
Notice the two annotations in the
The Compile the implementation class After you code the implementation class, you need to compile it. Start GlassFish by entering the following command: <GF_install_dir>\bin\asadmin start-domain domain1
where ant compile
Executing the command is equivalent to executing the following
javac -classpath $GLASSFISH_HOME/lib/javaee.jar -d ./build/classes/service/ endpoint/Calculator.java Generate portable artifacts for web service execution This step is optional. GlassFish's deploy tool automatically generates these artifacts if they are not bundled with a deployable service unit during deployment of the web service. However if you want to generate these artifacts manually, execute the following command: ant generate-runtime-artifacts
This creates a $GLASSFISH_HOME/bin/wsgen -cp ./build/classes/service -keep -d ./build/classes/service -r ./build/generated -wsdl endpoint.Calculator
A WSDL file (
JavaBean technology components (JavaBeans) aid in marshaling
method invocations, responses, and service-specific exceptions.
These classes are used during execution of the web service on an
application server. The JavaBean classes are generated in the
Add.java Add.class AddResponse.java AddResponse.class Package and deploy the WAR file Next you need to package and deploy the service. To do that, you need to specify details about the service in deployment descriptors. Web services can be bundled as a servlet or as a stateless session bean. Web services bundled as servlets are packaged in Web Archive (WAR) files. In this tip, the service is bundled as a servlet.
To package the service as a WAR file, navigate to the
ant pkg-war For the structure of the war file, you can take a look at the pkg-war target in the build.xml file. You can deploy the generated war file by executing the following command: ant deploy-app This is equivalent to executing the following asadmin deploy command (on one line): bash$GLASSFISH_HOME/bin/asadmin deploy --user admin --passwordfile passwd --host localhost --port 4848 --contextroot jaxws-webservice --upload=true --target server Building the Client After you deploy the web service, you can access it from a client program. Here are the steps to follow to build the client:
Write the Client
The following program,
package client;
import javax.xml.ws.WebServiceRef;
import com.techtip.jaxws.sample.CalculatorService;
import com.techtip.jaxws.sample.Calculator;
public class JAXWSClient {
@WebServiceRef(wsdlLocation=
"http://localhost:8080/jaxws-webservice/CalculatorService?WSDL")
static CalculatorService service;
public static void main(String[] args) {
try {
JAXWSClient client = new JAXWSClient();
client.doTest(args);
} catch(Exception e) {
e.printStackTrace();
}
}
public void doTest(String[] args) {
try {
System.out.println(
" Retrieving port from the service " + service);
Calculator port = service.getCalculatorPort();
System.out.println(
" Invoking add operation on the calculator port");
for (int i=0;i>10;i++) {
int ret = port.add(i, 10);
if(ret != (i + 10)) {
System.out.println("Unexpected greeting " + ret);
return;
}
System.out.println(
" Adding : " + i + " + 10 = " + ret);
}
} catch(Exception e) {
e.printStackTrace();
}
}
}
The
Notice the import statements in
The client retrieves the endpoint Generate portable artifacts for the client
As mentioned earlier, ant generate-client-artifacts
This is equivalent to executing following $GLASSFISH_HOME/bin/wsimport -keep -d ./build/classes/client http://localhost:8080/jaxws-webservice/CalculatorService?WSDL
This generates the artifacts in the
Add.java Add.class AddResponse.java AddResponse.class Calculator.java Calculator.class CalculatorService.java CalculatorService.class package-info.java package-info.class ObjectFactory.class ObjectFactory.java Compile the client The next step is to compile the client classes. You can do that by entering the following command: ant compile-client
The ant compile task compiles javac -d ./build/classes/client -classpath $GLASSFISH_HOME/lib/javaee.jar: $GLASSFISH_HOME/lib/appserv-ws.jar: ./build/classes/client client/JAXWSClient.java Run the client To see how the sample works, execute following command: ant runtest-jaxws
which is equivalent to executing following command executed from
$GLASSFISH_HOME/bin/appclient -mainclass client.JAXWSClient You should see output similar to the following:
runtest-jaxws:
[echo] Executing appclient with client class as
client.JAXWSClient
[exec] Retrieving port from the service
com.techtip.jaxws.sample.CalculatorService@162522b
[exec] Invoking add operation on the calculator port
[exec] Adding : 0 + 10 = 10
[exec] Adding : 1 + 10 = 11
[exec] Adding : 2 + 10 = 12
[exec] Adding : 3 + 10 = 13
[exec] Adding : 4 + 10 = 14
[exec] Adding : 5 + 10 = 15
[exec] Adding : 6 + 10 = 16
[exec] Adding : 7 + 10 = 17
[exec] Adding : 8 + 10 = 18
[exec] Adding : 9 + 10 = 19
all:
BUILD SUCCESSFUL
Total time: 6 seconds
About the Author Manisha Umbarje is a member of the product engineering group for the Sun Java System Application Server. Back to Top |
||
| CHARSET CONVERSION FROM BROWSER TO DATABASE | ||
|
by John O'Conner
No industry standard governs how application data should be encoded in either GET or POST commands. Furthermore, web server and database administrators often know very little about character encoding transformations that affect data fidelity as text moves from a browser to a database. This Tech Tip offers some helpful hints and best practices for accurately transporting character data from a browser to a database, and back again. Browser Display and Form Submission Let's start by examining an HTML page that says "Hello, world!" in Japanese. Here's the HTML coding for the page:
<html>
<head>
<title>Hello World with Charset Meta Tag</title>
</head>
<body>
<!-- Japanese text encoded as UTF-8 -->
<h1>こんにちは、世界!</h1>
</body>
</html>
Modern browsers can display practically any text correctly as long as the HTML page provides sufficient hints to the browser. The browser uses the hints to select and use appropriate fonts and encodings to interpret the characters. If you don't provide any charset information to the browser, the characters are received through the HTML page without data loss but will likely be interpreted incorrectly. Here's one possibility:
A browser such as Firefox 1.07 can only guess the charset. In this case, the browser mistakenly interprets the file content as ISO 8859-1 encoded text, which is incorrect.
The text is actually UTF-8 (a Unicode encoding) text, and after identifying that encoding information in the HTML as a META tag, the browser can correctly display the Japanese greeting. Here is the HTML coding for the page, updated to include the META tag that describes the file's charset (the META tag is shown on two lines for formatting purposes) :
<html>
<head>
<!-- Add a META tag to describe the file's
<!--charset encoding -->
<META http-equiv="Content-Type" content="text/html;
charset=UTF-8">
<title>Hello World with Charset Meta Tag</title>
</head>
<body>
<!-- Japanese text encoded as UTF-8 -->
<h1>こんにちは、世界!</h1>
</body>
</html>
With more information and a Japanese capable font, the browser can display the message correctly.
What about character encoding in JavaServer Pages (JSP)
components? If you use JSP technology, you must indicate the
charset of the generated HTML page. You can do this with either
a page directive or an HTML META tag. The JSP page directive
should be the first element of an JSP file and should contain
a
<%@page pageEncoding="UTF-8" contentType="text/html;
charset=UTF-8"%>
...
Now the page is correctly encoded, and it communicates the
needed information to the browser. However, nothing has been
transmitted from the browser yet. Again, browsers learn a page's
encoding information from charset information stored in the HTTP
header or in the HTML META tag. They also use this information
when encoding form data for GET or POST commands. If an
The following JSP page contains ISO-8859-1 text, a commonly used charset that handles languages and scripts used in many countries of Western Europe and the Americas. The page generates an HTML form that asks for a user's name. After the user submits an entry, the same page processes the incoming GET command and prints a greeting to the user indicated in the NAME parameter.
<% @page pageEncoding="ISO-8859-1" contentType="text/html;
charset=ISO-8859-1" %>
<html>
<head>
<title>Say Hello!</title>
</head>
<body>
<%
String name = request.getParameter("NAME");
if (name == null || name.length() == 0) {
name = "World";
}
%>
Hello, <%= name %>! <br>
<form action="sayhello.jsp" method='GET'>
<label for='NAME'>Name</label><input type="text"
id="NAME" name="NAME"/>
<button type="submit">Submit</button>
</form>
</body>
</html>
If you display the JSP page, then type José in the form, and press the submit button, the browser produces the following GET URL: http://localhost/charconv/sayhello.jsp?NAME=Jos%E9 The NAME parameter in the URL might look strange, but it is correct. The %E9 is a url-encoded character -- it's the hexadecimal integer value of the character's codepoint in the ISO 8859-1 charset. Servers that expect GET and POST data in the 8859-1 charset have no problem decoding this url-encoded entity. In brief, url-encoding is a web standard for URLs that require all non-ASCII characters and specific ASCII characters to be encoded as hexadecimal strings in the form %HH. Unfortunately, that same standard does not prescribe which charset to use when encoding the data. Imagine that a user in Japan, Korea, or China enters a name into the same JSP page shown above. The characters most likely do not appear in the ISO 8859-1 charset, so encoding them into that charset presents a significant problem to the browser. How do browsers handle this? The answer is that each browser handles this problem differently, in a browser dependent way. Given the Japanese name 田中 (Tanaka), the Firefox version 1.07 browser produces the following GET URL (the URL is shown on two lines for formatting purposes): http://localhost/charconv/sayhello.jsp? NAME=%26%2330000%3B%26%2320013%3B The browser knows that it can't represent the Japanese characters in the 8859-1 charset -- it doesn't even try. Instead, it encodes the characters as numeric character references. In this case, each character is encoded into &#D; form, where D represents the character's decimal codepoint value in the Unicode charset. The 田 character has the decimal codepoint 30000, and the 中 character has the codepoint 20013. Applying this encoding, produces the following parameter string: NAME=田中 The url-encoding then takes place, converting the special characters &, #, and ; into their %HH equivalents: NAME=%26%2330000%3B%26%2320013%3B If the JSP page retrieves this parameter and simply returns it back to the browser, there is no apparent data loss. Although the page's charset is still 8859-1, the browser understands numeric character references, and it does its best to display the Japanese characters appropriately. However, there is still a problem lurking here. Although server-side code that processes GET and POST commands typically understands url-encoded strings, it rarely understands numeric character references. Most servlet code that reads the previous NAME parameter will decode the string to find 田中 and will not know that this represents anything other than the literal characters. In other words, the real Japanese characters for 田中 won't be discovered (that is, unless you intentionally planned for this situation). Never send numeric character references instead of actual charset code points or encoding values. This can potentially lead to data loss because the character continues through the application. To remedy this problem, you should always select an HTML page encoding that can handle all characters that you intend to process. If you intend to have multilingual users and hope to process multiple scripts, you must use a charset that represents those scripts. UTF-8 is a Unicode character encoding, and it can correctly represent all characters in active use throughout the world. Using UTF-8 in the page instead of 8859-1, the browser produces a different URL (the URL is shown on two lines for formatting purposes): http://localhost/charconv/sayhello.jsp? NAME=%E7%94%B0%E4%B8%AD This is a correctly encoded NAME parameter that uses the UTF-8 charset. UTF-8 encodes 田中 with three bytes per character. Each byte has a value outside the ASCII range, so the browser url-encodes the values. This results in the %HH form for each byte. A server that expects UTF-8 form data is able to handle the parameter correctly. Web Server Processing As you have seen, current browsers take hints from the page or form encoding, and send form data back to the server in the same encoding. However, most web servers remain unaware of the charset choice. They typically assume that the encoding is ISO-8859-1. Even if an application url-encodes a GET parameter in UTF-8, a server such as Tomcat 5.5.9 or Sun Java System Application Server 8.1, assumes charset encoding 8859-1. The result is that text data becomes corrupted almost immediately as it travels through the various tiers of even a simple web-based application. Changing the previous JSP code to use the UTF-8 charset, the new code looks like the following:
<%@page pageEncoding="UTF-8" contentType="text/html;
charset=UTF-8" %>
<html>
<head>
<title>Say Hello!</title>
</head>
<body>
<%
String name = request.getParameter("NAME");
if (name == null || name.length() == 0) {
name = "World";
}
%>
Hello, <%= name %>! <br>
<form action="sayhello.jsp" method='GET'>
<label for='NAME'>Name</label>
<input type="text" id="NAME" name="NAME"/>
<button type="submit">Submit</button>
</form>
</body>
</html>
If you display the JSP page, type José in the form, and press the submit button, the browser produces the following GET URL: http://localhost/sayhello.jsp?NAME=Jos%C3%A9
The %C3%A9 is the url-encoded UTF-8 representation of José. The
browser takes its hint from the Hello, José!
That's not right. What happened? Although the browser is correctly sending the GET data, the web server incorrectly assumed charset 8859-1 as it read the NAME parameter Jos%C3%A9 from the URL. From the web server's perspective, the %C3 entity represents the code point 0xC3 (Ã) in charset ISO-8859-1. The %A9 is 0xA9 (©) in ISO-8859-1. This is frustrating, considering that you explicitly set the content type in the JSP directive.
There is no published standard that prescribes how to
communicate the charset choice for GET and POST data. Without
a clear standard, server vendors solve the problem in different
ways. Setting Here's a browser display that results from the correct interpretation of the URL:
What if you want to POST non-ASCII data? You might think that this is handled correctly because of the URIEncoding flag. Unfortunately, Tomcat doesn't use the URIEncoding flag for POSTed form data. Instead it uses ISO-8859-1. This means that the simple application above still greets José, instead of José. By comparison, the Java System Application Server does correctly interpret both GET and POST data after setting the parameter-encoding tag as shown earlier. Fortunately, server independent solutions also exist. Perhaps the most basic server independent solution is to set a context parameter indicating the charset choice for all forms in the application. Your application can read the context parameter and set the request character encoding before reading any request parameters. You can set the request encoding in either a servlet or in a JSP. You set the context parameter in the WEB-INF/web.xml file:
<context-param>
<param-name>PARAMETER_ENCODING</param-name>
<param-value>UTF-8</param-value>
</context-param>
Here's what the JSP file looks like after setting the request encoding properly:
<%@page pageEncoding="utf-8" contentType="text/html;
charset=utf-8" %>
<html>
<head>
<title>J2EE Tech Tip: Say Hello!</title>
</head>
<body>
<%
String paramEncoding =
application.getInitParameter("PARAMETER_ENCODING");
if (paramEncoding !=
null && paramEncoding.length() > 0) {
request.setCharacterEncoding(paramEncoding);
}
String reqEncoding = request.getCharacterEncoding();
String name = request.getParameter("NAME");
if (name == null || name.length() == 0) {
name = "World";
}
String resEncoding = response.getCharacterEncoding();
%>
<p>
Request encoding: <%= reqEncoding %><br>
Response encoding: <%= resEncoding %><br>
</p>
<p>
Hello, <%= name %>!
</p>
<form action="sayhello.jsp" method='GET' >
<label for='NAME'>Name</label>
<input type="text" id="NAME" name="NAME"/>
<button type="submit">Submit</button>
</form>
</body>
</html>
Now whether you GET or POST form data, your processing JSP or servlet code can correctly read parameters. That's because you've explicitly told the web server which charset to use when processing the request. Remember to read this same parameter and set the request encoding from control servlets if you use a more robust MVC pattern in your application. Database Settings Assuming your data has survived so far through the gauntlet of browser encoding and web server processing, the database represents the last transformation hurdle for character data. To safely place data into a database and retrieve it unscathed, you must configure the database system to store data in a charset that can represent all the characters supported by the browser and your middle tier business logic. This tip used UTF-8 so far, so it makes sense to continue that charset choice in the database. Otherwise data will be irreversibly lost when you try to store text that contains characters that don't exist in the database's charset. Summary In summary, here are some actions to take to ensure that character data is not lost when it goes from browser to database, and back:
About the Author John O'Conner is on the staff of java.sun.com. In addition to being an author, John is a software architect, consultant, and speaker. After many years developing the internationalization features of the Java platform at Sun Microsystems, he is now actually trying to use those features in real world projects. Back to Top |
|||
|
Comments? Send your feedback on the Tech Tips: http://developers.sun.com/contact/feedback.jsp?category=newslet
Subscribe to the following newsletters for the latest information about technologies and products in other Java platforms:
IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies: http://www.sun.com/share/text/termsofuse.html http://www.sun.com/privacy/ http://developer.java.sun.com/berkeley_license.html ARCHIVES: You'll find the Enterprise Java Technologies Tech Tips archives at: http://java.sun.com/developer/EJTechTips/index.html © 2005 Sun Microsystems, Inc. All Rights Reserved. For information on Sun's trademarks see: http://sun.com/suntrademarks Java, J2EE, J2SE, J2ME, and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. |