This chapter describes how to program the JWS file that implements the WebLogic Web services using Java API for XML-based RPC (JAX-RPC).
This chapter includes the following topics:
There are two ways to program a WebLogic Web service from scratch:
Annotate a standard EJB or Java class with Web service Java annotations, as defined by JSR-181, the JAX-WS specification, and by the WebLogic Web services programming model.
Combine a standard EJB or Java class with the various XML descriptor files and artifacts specified by JSR-109 (such as, deployment descriptors, WSDL files, data mapping descriptors, data binding artifacts for user-defined data types, and so on).
Oracle strongly recommends using option 1 above. Instead of authoring XML metadata descriptors yourself, the WebLogic Ant tasks and run time will generate the required descriptors and artifacts based on the annotations you include in your JWS. Not only is this process much easier, but it keeps the information about your Web service in a central location, the JWS file, rather than scattering it across many Java and XML files.
The Java Web Service (JWS) annotated file is the core of your Web service. It contains the Java code that determines how your Web service behaves. A JWS file is an ordinary Java class file that uses Java metadata annotations to specify the shape and characteristics of the Web service. The JWS annotations you can use in a JWS file include the standard ones defined by the Web Services Metadata for the Java Platform specification (JSR-181), described at http://www.jcp.org/en/jsr/detail?id=181
, plus a set of additional annotations based on the type of Web service you are building—JAX-WS or JAX-RPC. For a complete list of JWS annotations that are supported for JAX-WS and JAX-RPC Web services, see "Web Service Annotation Support" in Oracle Fusion Middleware WebLogic Web Services Reference for Oracle WebLogic Server.
When programming the JWS file, you include annotations to program basic Web service features. The annotations are used at different levels, or targets, in your JWS file. Some are used at the class-level to indicate that the annotation applies to the entire JWS file. Others are used at the method-level and yet others at the parameter level.
When you program your JWS file, you must follow a set of requirements, as specified by the Web Services Metadata for the Java Platform specification (JSR-181) at http://www.jcp.org/en/jsr/detail?id=181
. In particular, the Java class that implements the Web service:
Must be an outer public class, must not be declared final
, and must not be abstract
.
Must have a default public constructor.
Must not define a finalize()
method.
Must include, at a minimum, a @WebService
JWS annotation at the class level to indicate that the JWS file implements a Web service.
May reference a service endpoint interface by using the @WebService.endpointInterface
annotation. In this case, it is assumed that the service endpoint interface exists and you cannot specify any other JWS annotations in the JWS file other than @WebService.endpointInterface
, @WebService.serviceName
and @WebService.targetNamespace
.
If JWS file does not implement a service endpoint interface, all public methods other than those inherited from java.lang.Object
will be exposed as Web service operations. This behavior can be overridden by using the @WebMethod
annotation to specify explicitly the public methods that are to be exposed. If a @WebMethod
annotation is present, only the methods to which it is applied are exposed.
The following procedure describes the typical steps for programming a JWS file that implements a Web service.
Note:
It is assumed that you have created a JWS file and now want to add JWS annotations to it.
For more information about each of the JWS annotations, see "JWS Annotation Reference" in Oracle Fusion Middleware WebLogic Web Services Reference for Oracle WebLogic Server. See Oracle Fusion Middleware Programming Advanced Features of JAX-RPC Web Services for Oracle WebLogic Server for information on using other JWS annotations to program more advanced features, such as Web service reliable messaging, conversations, SOAP message handlers, and so on.
Table 4-1 Steps to Program the JWS File
# |
Step | Description |
---|---|---|
1 |
Import the standard JWS annotations that will be used in your JWS file. |
The standard JWS annotations are in either the import javax.jws.WebMethod; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; |
2 |
Import the WebLogic-specific annotations used in your JWS file. |
The WebLogic-specific annotations are in the import weblogic.jws.WLHttpTransport; |
3 |
Add the standard required |
See Specifying that the JWS File Implements a Web Service (@WebService Annotation). |
4 |
Add the standard |
In particular, use this annotation to specify whether the Web service is document-literal, RPC-encoded, and so on. See Specifying the Mapping of the Web Service to the SOAP Message Protocol (@SOAPBinding Annotation). Although this JWS annotation is not required, Oracle recommends you explicitly specify it in your JWS file to clarify the type of SOAP bindings a client application uses to invoke the Web service. |
5 |
Add the WebLogic-specific |
See Specifying the Context Path and Service URI of the Web Service (@WLHttpTransport Annotation). Although this JWS annotation is not required, Oracle recommends you explicitly specify it in your JWS file so that it is clear what URL a client application uses to invoke the Web service. |
6 |
Add the standard |
Optionally specify that the operation takes only input parameters but does not return any value by using the standard |
7 |
Add |
See Customizing the Mapping Between Operation Parameters and WSDL Elements (@WebParam Annotation). |
8 |
Add |
|
9 |
Add your business code. |
Add your business code to the methods to make the WebService behave as required. |
The following sample JWS file shows how to implement a simple Web service.
package examples.webservices.simple; // Import the standard JWS annotation interfaces import javax.jws.WebMethod; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; // Import the WebLogic-specific JWS annotation interfaces import weblogic.jws.WLHttpTransport; // Standard JWS annotation that specifies that the porType name of the Web // Service is "SimplePortType", the service name is "SimpleService", and the // targetNamespace used in the generated WSDL is "http://example.org" @WebService(name="SimplePortType", serviceName="SimpleService", targetNamespace="http://example.org") // Standard JWS annotation that specifies the mapping of the service onto the // SOAP message protocol. In particular, it specifies that the SOAP messages // are document-literal-wrapped. @SOAPBinding(style=SOAPBinding.Style.DOCUMENT, use=SOAPBinding.Use.LITERAL, parameterStyle=SOAPBinding.ParameterStyle.WRAPPED) // WebLogic-specific JWS annotation that specifies the context path and // service URI used to build the URI of the Web Service is // "simple/SimpleService" @WLHttpTransport(contextPath="simple", serviceUri="SimpleService", portName="SimpleServicePort") /** * This JWS file forms the basis of simple Java-class implemented WebLogic * Web Service with a single operation: sayHello * */ public class SimpleImpl { // Standard JWS annotation that specifies that the method should be exposed // as a public operation. Because the annotation does not include the // member-value "operationName", the public name of the operation is the // same as the method name: sayHello. @WebMethod() public String sayHello(String message) { System.out.println("sayHello:" + message); return "Here is the message: '" + message + "'"; } }
Use the standard @WebService
annotation to specify, at the class level, that the JWS file implements a Web service, as shown in the following code excerpt:
@WebService(name="SimplePortType", serviceName="SimpleService", targetNamespace="http://example.org")
In the example, the name of the Web service is SimplePortType
, which will later map to the wsdl:portType
element in the WSDL file generated by the jwsc
Ant task. The service name is SimpleService
, which will map to the wsdl:service
element in the generated WSDL file. The target namespace used in the generated WSDL is http://example.org
.
You can also specify the following additional attributes of the @WebService
annotation:
endpointInterface
—Fully qualified name of an existing service endpoint interface file. This annotation allows the separation of interface definition from the implementation. If you specify this attribute, the jwsc
Ant task does not generate the interface for you, but assumes you have created it and it is in your CLASSPATH.
portname
—Name that is used in the wsdl:port
.
None of the attributes of the @WebService
annotation is required. See the Web Services Metadata for the Java Platform (JSR 181) at http://www.jcp.org/en/jsr/detail?id=181
for the default values of each attribute.
It is assumed that you want your Web service to be available over the SOAP message protocol; for this reason, your JWS file should include the standard @SOAPBinding
annotation, at the class level, to specify the SOAP bindings of the Web service (such as, RPC-encoded or document-literal-wrapped), as shown in the following code excerpt:
@SOAPBinding(style=SOAPBinding.Style.DOCUMENT, use=SOAPBinding.Use.LITERAL, parameterStyle=SOAPBinding.ParameterStyle.WRAPPED)
In the example, the Web service uses document-wrapped-style encodings and literal message formats, which are also the default formats if you do not specify the @SOAPBinding
annotation.
You can also use the WebLogic-specific @weblogic.jws.soap.SOAPBinding
annotation to specify the SOAP binding at the method level; the attributes are the same as the standard @javax.jws.soap.SOAPBinding
annotation.
You use the parameterStyle
attribute (in conjunction with the style=SOAPBinding.Style.DOCUMENT
attribute) to specify whether the Web service operation parameters represent the entire SOAP message body, or whether the parameters are elements wrapped inside a top-level element with the same name as the operation.
Table 4-2 Attributes of the @SOAPBinding Annotation
Attribute | Possible Values | Default Value |
---|---|---|
style |
SOAPBinding.Style.RPC SOAPBinding.Style.DOCUMENT |
SOAPBinding.Style.DOCUMENT |
use |
SOAPBinding.Use.LITERAL SOAPBinding.Use.ENCODED |
SOAPBinding.Use.LITERAL |
parameterStyle |
SOAPBinding.ParameterStyle.BARE SOAPBinding.ParameterStyle.WRAPPED |
SOAPBinding.ParameterStyle.WRAPPED |
Use the WebLogic-specific @WLHttpTransport
annotation to specify the context path and service URI sections of the URL used to invoke the Web service over the HTTP transport, as well as the name of the port in the generated WSDL, as shown in the following code excerpt:
@WLHttpTransport(contextPath="simple", serviceUri="SimpleService", portName="SimpleServicePort")
In the example, the name of the port in the WSDL (in particular, the name
attribute of the <port>
element) file generated by the jwsc
Ant task is SimpleServicePort
. The URL used to invoke the Web service over HTTP includes a context path of simple
and a service URI of SimpleService
, as shown in the following example:
http://host:port/simple/SimpleService
For reference documentation on this and other WebLogic-specific annotations, see "JWS Annotation Reference" in the WebLogic Web Services Reference.
Use the standard @WebMethod
annotation to specify that a method of the JWS file should be exposed as a public operation of the Web service, as shown in the following code excerpt:
public class SimpleImpl { @WebMethod(operationName="sayHelloOperation") public String sayHello(String message) { System.out.println("sayHello:" + message); return "Here is the message: '" + message + "'"; } ...
In the example, the sayHello()
method of the SimpleImpl
JWS file is exposed as a public operation of the Web service. The operationName
attribute specifies, however, that the public name of the operation in the WSDL file is sayHelloOperation
. If you do not specify the operationName
attribute, the public name of the operation is the name of the method itself.
You can also use the action
attribute to specify the action of the operation. When using SOAP as a binding, the value of the action
attribute determines the value of the SOAPAction
header in the SOAP messages.
You can specify that an operation not return a value to the calling application by using the standard @Oneway
annotation, as shown in the following example:
public class OneWayImpl { @WebMethod() @Oneway() public void ping() { System.out.println("ping operation"); } ...
If you specify that an operation is one-way, the implementing method is required to return void
, cannot use a Holder class as a parameter, and cannot throw any checked exceptions.
None of the attributes of the @WebMethod
annotation is required. See the Web Services Metadata for the Java Platform (JSR 181) at http://www.jcp.org/en/jsr/detail?id=181
for the default values of each attribute, as well as additional information about the @WebMethod
and @Oneway
annotations.
If none of the public methods in your JWS file are annotated with the @WebMethod
annotation, then by default all public methods are exposed as Web service operations.
Use the standard @WebParam
annotation to customize the mapping between operation input parameters of the Web service and elements of the generated WSDL file, as well as specify the behavior of the parameter, as shown in the following code excerpt:
public class SimpleImpl { @WebMethod() @WebResult(name="IntegerOutput", targetNamespace="http://example.org/docLiteralBare") public int echoInt( @WebParam(name="IntegerInput", targetNamespace="http://example.org/docLiteralBare") int input) { System.out.println("echoInt '" + input + "' to you too!"); return input; } ...
In the example, the name of the parameter of the echoInt
operation in the generated WSDL is IntegerInput
; if the @WebParam
annotation were not present in the JWS file, the name of the parameter in the generated WSDL file would be the same as the name of the method's parameter: input
. The targetNamespace
attribute specifies that the XML namespace for the parameter is http://example.org/docLiteralBare
; this attribute is relevant only when using document-style SOAP bindings where the parameter maps to an XML element.
You can also specify the following additional attributes of the @WebParam
annotation:
mode
—The direction in which the parameter is flowing (WebParam.Mode.IN
, WebParam.Mode.OUT
, or WebParam.Mode.INOUT
). The OUT and INOUT modes may be specified only for parameter types that conform to the JAX-RPC definition of Holder
types. OUT and INOUT modes are only supported for RPC-style operations or for parameters that map to headers.
header
—Boolean attribute that, when set to true
, specifies that the value of the parameter should be retrieved from the SOAP header, rather than the default body.
None of the attributes of the @WebParam
annotation is required. See the Web Services Metadata for the Java Platform (JSR 181) at http://www.jcp.org/en/jsr/detail?id=181
for the default value of each attribute.
Use the standard @WebResult
annotation to customize the mapping between the Web service operation return value and the corresponding element of the generated WSDL file, as shown in the following code excerpt:
public class Simple { @WebMethod() @WebResult(name="IntegerOutput", targetNamespace="http://example.org/docLiteralBare") public int echoInt( @WebParam(name="IntegerInput", targetNamespace="http://example.org/docLiteralBare") int input) { System.out.println("echoInt '" + input + "' to you too!"); return input; } ...
In the example, the name of the return value of the echoInt
operation in the generated WSDL is IntegerOutput
; if the @WebResult
annotation were not present in the JWS file, the name of the return value in the generated WSDL file would be the hard-coded name return
. The targetNamespace
attribute specifies that the XML namespace for the return value is http://example.org/docLiteralBare
; this attribute is relevant only when using document-style SOAP bindings where the return value maps to an XML element.
None of the attributes of the @WebResult
annotation is required. See the Web Services Metadata for the Java Platform (JSR 181) at http://www.jcp.org/en/jsr/detail?id=181
for the default value of each attribute.
The following sections describe how to access run-time information about a Web service:
Using JwsContext to Access Run-Time Information—Use the Web service context to access and change run-time information about the service in your JWS file.
Using the Stub Interface to Access Run-Time Information—Get and set properties on the Stub interface in the client file.
When a client application invokes a WebLogic Web service that was implemented with a JWS file, WebLogic Server automatically creates a context that the Web service can use to access, and sometimes change, run-time information about the service. Much of this information is related to conversations, such as whether the current conversation is finished, the current values of the conversational properties, changing conversational properties at run time, and so on. (See "Creating Conversational Web Services" in Oracle Fusion Middleware Programming Advanced Features of JAX-RPC Web Services for Oracle WebLogic Server for information about conversations and how to implement them.) Some of the information accessible via the context is more generic, such as the protocol that was used to invoke the Web service (HTTP/S or JMS), the SOAP headers that were in the SOAP message request, and so on.
You can use annotations and WebLogic Web service APIs in your JWS file to access run-time context information, as described in the following sections.
The following example shows a simple JWS file that uses the context to determine the protocol that was used to invoke the Web service. The code in bold is discussed in the programming guidelines described following the example.
package examples.webservices.jws_context; import javax.jws.WebMethod; import javax.jws.WebService; import weblogic.jws.WLHttpTransport; import weblogic.jws.Context; import weblogic.wsee.jws.JwsContext; import weblogic.wsee.jws.Protocol; @WebService(name="JwsContextPortType", serviceName="JwsContextService", targetNamespace="http://example.org") @WLHttpTransport(contextPath="contexts", serviceUri="JwsContext", portName="JwsContextPort") /** * Simple web service to show how to use the @Context annotation. */ public class JwsContextImpl { @Context private JwsContext ctx; @WebMethod() public String getProtocol() { Protocol protocol = ctx.getProtocol(); System.out.println("protocol: " + protocol); return "This is the protocol: " + protocol; } }
Use the following guidelines in your JWS file to access the run-time context of the Web service, as shown in the code in bold in the preceding example:
Import the @weblogic.jws.Context
JWS annotation:
import weblogic.jws.Context;
Import the weblogic.wsee.jws.JwsContext
API, as well as any other related APIs that you might use (the example also uses the weblogic.wsee.jws.Protocol
API):
import weblogic.wsee.jws.JwsContext; import weblogic.wsee.jws.Protocol;
See the weblogic.wsee.*
packages in the Oracle Fusion Middleware Oracle WebLogic Server API Reference for more documentation about the context-related APIs.
Annotate a private variable, of data type weblogic.wsee.jws.JwsContext
, with the field-level @Context
JWS annotation:
@Context private JwsContext ctx;
WebLogic Server automatically assigns the annotated variable (in this case, ctx
) with a run-time implementation of JwsContext
the first time the Web service is invoked, which is how you can later use the variable without explicitly initializing it in your code.
Use the methods of the JwsContext
class to access run-time information about the Web service. The following example shows how to get the protocol that was used to invoke the Web service.
Protocol protocol = ctx.getProtocol();
See Methods of the JwsContext for the full list of available methods.
The following table summarizes the methods of the JwsContext
that you can use in your JWS file to access run-time information about the Web service. See weblogic.wsee.*
packages in the Oracle Fusion Middleware Oracle WebLogic Server API Reference for detailed reference information about JwsContext
, and other context-related APIs, as Protocol
and ServiceHandle
.
Table 4-3 Methods of JwsContext
Method | Returns | Description |
---|---|---|
isFinished() |
boolean |
Returns a boolean value specifying whether the current conversation is finished, or if it is still continuing. Use this method only in conversational Web services, or those that have been annotated with the |
finishConversation() |
void |
Finishes the current conversation. This method is equivalent to a client application invoking a method that has been annotated with the Use this method only in conversational Web services, or those that have been annotated with the |
setMaxAge(java.util.Date) |
void |
Sets a new maximum age for the conversation to an absolute This method is equivalent to the Use this method only in conversational Web services, or those that have been annotated with the |
setMaxAge(String) |
void |
Sets a new maximum age for the conversation by specifying a Valid values for the
For example, to specify a maximum age of ten minutes, use the following syntax:
This method is equivalent to the Use this method only in conversational Web services, or those that have been annotated with the |
getMaxAge() |
long |
Returns the maximum allowed age, in seconds, of a conversation. Use this method only in conversational Web services, or those that have been annotated with the |
getCurrentAge() |
long |
Returns the current age, in seconds, of the conversation. Use this method only in conversational Web services, or those that have been annotated with the |
resetIdleTime() |
void |
Resets the timer which measures the number of seconds since the last activity for the current conversation. Use this method only in conversational Web services, or those that have been annotated with the |
setMaxIdleTime(long) |
void |
Sets the number of seconds that the conversation can remain idle before WebLogic Server finishes it due to client inactivity. This method is equivalent to the Use this method only in conversational Web services, or those that have been annotated with the |
setMaxIdleTime(String) |
void |
Sets the number of seconds, specified as a Valid values for the
For example, to specify a maximum idle time of ten minutes, use the following syntax: ctx.setMaxIdleTime("10 minutes") This method is equivalent to the Use this method only in conversational Web services, or those that have been annotated with the |
getMaxIdleTime() |
long |
Returns the number of seconds that the conversation is allowed to remain idle before WebLogic Server finishes it due to client inactivity. Use this method only in conversational Web services, or those that have been annotated with the |
getCurrentIdleTime() |
long |
Gets the number of seconds since the last client request, or since the conversation's maximum idle time was reset. Use this method only in conversational Web services, or those that have been annotated with the |
getCallerPrincipal() |
java.security.Principal |
Returns the security principal associated with the operation that was just invoked, assuming that basic authentication was performed. |
isCallerInRole(String) |
boolean |
Returns |
getService() |
weblogic.wsee.jws.ServiceHandle |
Returns an instance of |
getLogger(String) |
weblogic.wsee.jws.util.Logger |
Gets an instance of the |
getInputHeaders() |
org.w3c.dom.Element[] |
Returns an array of the SOAP headers associated with the SOAP request message of the current operation invoke. |
setUnderstoodInputHeaders(boolean) |
void |
Indicates whether input headers should be understood. |
getUnderstoodInputHeaders() |
boolean |
Returns the value that was most recently set by a call to setUnderstoodInputHeader. |
setOutputHeaders(Element[]) |
void |
Specifies an array of SOAP headers that should be associated with the outgoing SOAP response message sent back to the client application that initially invoked the current operation. |
getProtocol() |
weblogic.wsee.jws.Protocol |
Returns the protocol (such as HTTP/S or JMS) used to invoke the current operation. |
Thejavax.xml.rpc.Stub
interface enables you to dynamically configure the Stub instance in your Web service client file. For more information, see http://download.oracle.com/javaee/5/api/javax/xml/rpc/Stub.html
. For example, you can set the target service endpoint dynamically for the port
Stub instance, as follows:
ComplexService service = new ComplexService_Impl (args[0] + "?WSDL" ); ComplexPortType port = service.getComplexServicePort(); ((Stub)port)._setProperty(Stub.ENDPOINT_ADDRESS_PROPERTY, "http://localhost:8010/MyContext/MyService");
For more information about developing Web service clients, see Chapter 6, "Invoking Web Services."
The following table summarizes the methods of the Stub
interface that you can use in your JWS file to access run-time information about the Web service.
Table 4-4 Methods of Stub Interface
Method | Returns | Description |
---|---|---|
_getProperty() |
java.lang.Object |
Gets the value of the specified configuration property. |
_getPropertyNames() |
java.util.Iterator |
Returns an Iterator view of the names of the properties that can be configured on the |
_setProperty() |
void |
Sets the name and value of a configuration property for the |
The following table defined the javax.xml.rpc.Stub
property values that you can access from the Stub instance.
Table 4-5 Properties of Stub Interface
Property | Type | Description |
---|---|---|
ENDPOINT_ADDRESS_PROPERTY |
java.lang.String |
Target service endpoint address. |
PASSWORD_PROPERTY |
java.lang.String |
Password used for authentication. |
SESSION_MAINTAIN_PROPERTY |
java.lang.String |
Flag specifying whether to participate in a session with a service endpoint. |
USERNAME_PROPERTY |
java.lang.String |
User name used for authentication. |
The jwsc
Ant task always chooses a plain Java object as the underlying implementation of a Web service when processing your JWS file.
Sometimes, however, you might want the underlying implementation of your Web service to be a stateless session EJB so as to take advantage of all that EJBs have to offer, such as instance pooling, transactions, security, container-managed persistence, container-managed relationships, and data caching. If you decide you want an EJB implementation for your Web service, then follow the programming guidelines in the following section.
Note:
JAX-RPC supports EJB 2.x only; it does not support EJB 3.0.
The general guideline is to always use EJBGen annotations in your JWS file to automatically generate, rather than manually create, the EJB Remote and Home interface classes and deployment descriptor files needed when implementing an EJB. EJBGen annotations work in the same way as JWS annotations: they follow the JDK 5.0 metadata syntax and greatly simplify your programming tasks.
For more information on EJBGen, see "EJBGen Reference" in Oracle Fusion Middleware Programming WebLogic Enterprise JavaBeans for Oracle WebLogic Server.
Follow these guidelines when explicitly implementing a stateless session EJB in your JWS file. See Example of a JWS File That Implements an EJB for an example; the relevant sections are shown in bold:
Import the standard Java Platform, Enterprise Edition (Java EE) Version 5 EJB classes:
import javax.ejb.SessionBean; import javax.ejb.SessionContext;
Import the EJBGen annotations, all of which are in the weblogic.ejbgen
package. At a minimum you need to import the @Session
annotation; if you want to use additional EJBGen annotations in your JWS file to specify the shape and behavior of the EJB, see the "EJBGen Reference" in Oracle Fusion Middleware Programming WebLogic Enterprise JavaBeans for Oracle WebLogic Server for the name of the annotation you should import.
import weblogic.ejbgen.Session;
At a minimum, use the @Session
annotation at the class level to specify the name of the EJB:
@Session(ejbName="TransactionEJB")
@Session
is the only required EJBGen annotation when used in a JWS file. You can, if you want, use other EJBGen annotations to specify additional features of the EJB.
Ensure that the JWS class implements SessionBean
:
public class TransactionImpl implements SessionBean {...
You must also include the standard EJB methods ejbCreate()
, ejbActivate()
and so on, although you typically do not need to add code to these methods unless you want to change the default behavior of the EJB:
public void ejbCreate() {} public void ejbActivate() {} public void ejbRemove() {} public void ejbPassivate() {} public void setSessionContext(SessionContext sc) {}
If you follow all these guidelines in your JWS file, the jwsc
Ant task later compiles the Web service into an EJB and packages it into an EJB JAR file inside of the Enterprise Application.
The following example shows a simple JWS file that implement a stateless session EJB. The relevant code is shown in bold.
package examples.webservices.transactional; import javax.ejb.SessionBean; import javax.ejb.SessionContext; import javax.jws.WebMethod; import javax.jws.WebService; import weblogic.jws.WLHttpTransport; import weblogic.jws.Transactional; import weblogic.ejbgen.Session; @Session(ejbName="TransactionEJB") @WebService(name="TransactionPortType", serviceName="TransactionService", targetNamespace="http://example.org") @WLHttpTransport(contextPath="transactions", serviceUri="TransactionService", portName="TransactionPort") /** * This JWS file forms the basis of simple EJB-implemented WebLogic * Web Service with a single operation: sayHello. The operation executes * as part of a transaction. * */ public class TransactionImpl implements SessionBean { @WebMethod() @Transactional(value=true) public String sayHello(String message) { System.out.println("sayHello:" + message); return "Here is the message: '" + message + "'"; } // Standard EJB methods. Typically there's no need to override the methods. public void ejbCreate() {} public void ejbActivate() {} public void ejbRemove() {} public void ejbPassivate() {} public void setSessionContext(SessionContext sc) {} }
The methods of the JWS file that are exposed as Web service operations do not necessarily take built-in data types (such as Strings and integers) as parameters and return values, but rather, might use a Java data type that you create yourself. An example of a user-defined data type is TradeResult
, which has two fields: a String
stock symbol and an integer number of shares traded.
If your JWS file uses user-defined data types as parameters or return values of one or more of its methods, you must create the Java code of the data type yourself, and then import the class into your JWS file and use it appropriately. The jwsc
Ant task will later take care of creating all the necessary data binding artifacts, such as the corresponding XML Schema representation of the Java user-defined data type, the JAX-RPC type mapping file, and so on.
Follow these basic requirements when writing the Java class for your user-defined data type:
Define a default constructor, which is a constructor that takes no parameters.
Define both getXXX()
and setXXX()
methods for each member variable that you want to publicly expose.
Make the data type of each exposed member variable one of the built-in data types, or another user-defined data type that consists of built-in data types.
These requirements are specified by JAX-RPC; for more detailed information and the complete list of requirements, see the JAX-RPC specification at http://java.net/projects/jax-rpc/
.
The jwsc
Ant task can generate data binding artifacts for most common XML and Java data types. For the list of supported user-defined data types, see Supported User-Defined Data Types. See Supported Built-In Data Types for the full list of supported built-in data types.
The following example shows a simple Java user-defined data type called BasicStruct
:
package examples.webservices.complex; /** * Defines a simple JavaBean called BasicStruct that has integer, String, * and String[] properties */ public class BasicStruct { // Properties private int intValue; private String stringValue; private String[] stringArray; // Getter and setter methods public int getIntValue() { return intValue; } public void setIntValue(int intValue) { this.intValue = intValue; } public String getStringValue() { return stringValue; } public void setStringValue(String stringValue) { this.stringValue = stringValue; } public String[] getStringArray() { return stringArray; } public void setStringArray(String[] stringArray) { this.stringArray = stringArray; } }
The following snippets from a JWS file show how to import the BasicStruct
class and use it as both a parameter and return value for one of its methods; for the full JWS file, see Sample ComplexImpl.java JWS File:
package examples.webservices.complex; // Import the standard JWS annotation interfaces import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebResult; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; // Import the WebLogic-specific JWS annotation interface import weblogic.jws.WLHttpTransport; // Import the BasicStruct JavaBean import examples.webservices.complex.BasicStruct; @WebService(serviceName="ComplexService", name="ComplexPortType", targetNamespace="http://example.org") ... public class ComplexImpl { @WebMethod(operationName="echoComplexType") public BasicStruct echoStruct(BasicStruct struct) { return struct; } }
When you write the error-handling Java code in methods of the JWS file, you can either throw your own user-defined exceptions or throw a javax.xml.rpc.soap.SOAPFaultException
exception. If you throw a SOAPFaultException
, WebLogic Server maps it to a SOAP fault and sends it to the client application that invokes the operation.
If your JWS file throws any type of Java exception other than SOAPFaultException
, WebLogic Server tries to map it to a SOAP fault as best it can. However, if you want to control what the client application receives and send it the best possible exception information, you should explicitly throw a SOAPFaultException
exception or one that extends the exception. See the JAX-RPC specification at http://java.net/projects/jax-rpc/
for detailed information about creating and throwing your own user-defined exceptions.
The following excerpt describes the SOAPFaultException
class:
public class SOAPFaultException extends java.lang.RuntimeException { public SOAPFaultException (QName faultcode, String faultstring, String faultactor, javax.xml.soap.Detail detail ) {...} public Qname getFaultCode() {...} public String getFaultString() {...} public String getFaultActor() {...} public javax.xml.soap.Detail getDetail() {...} }
Use the SOAP with Attachments API for Java 1.1 (SAAJ) javax.xml.soap.SOAPFactory.createDetail()
method to create the Detail
object, which is a container for DetailEntry
objects that provide detailed application-specific information about the error.
You can use your own implementation of the SOAPFactory
, or use Oracle 's, which can be accessed in the JWS file by calling the static method weblogic.wsee.util.WLSOAPFactory.createSOAPFactory()
which returns a javax.xml.soap.SOAPFactory object
. Then at run time, use the -Djavax.xml.soap.SOAPFactory
flag to specify Oracle's SOAPFactory
implementation as shown:
-Djavax.xml.soap.SOAPFactory=weblogic.xml.saaj.SOAPFactoryImpl
The following JWS file shows an example of creating and throwing a SOAPFaultException
from within a method that implements an operation of your Web service; the sections in bold highlight the exception code:
package examples.webservices.soap_exceptions; import javax.xml.namespace.QName; import javax.xml.soap.Detail; import javax.xml.soap.SOAPException; import javax.xml.soap.SOAPFactory; import javax.xml.rpc.soap.SOAPFaultException; // Import the @WebService annotation import javax.jws.WebService; // Import WLHttpTransport import weblogic.jws.WLHttpTransport; @WebService(serviceName="SoapExceptionsService", name="SoapExceptionsPortType", targetNamespace="http://example.org") @WLHttpTransport(contextPath="exceptions", serviceUri="SoapExceptionsService", portName="SoapExceptionsServicePort") /** * This JWS file forms the basis of simple Java-class implemented WebLogic * Web Service with a single operation: sayHelloWorld * */ public class SoapExceptionsImpl { public SoapExceptionsImpl() { } public void tirarSOAPException() { Detail detail = null; try { SOAPFactory soapFactory = SOAPFactory.newInstance(); detail = soapFactory.createDetail(); } catch (SOAPException e) { // do something } QName faultCode = null; String faultString = "the fault string"; String faultActor = "the fault actor"; throw new SOAPFaultException(faultCode, faultString, faultActor, detail); } }
The preceding example uses the default implementation of SOAPFactory
.
Note:
If you create and throw your own exception (rather than use SOAPFaultException
) and two or more of the properties of your exception class are of the same data type, then you must also create setter methods for these properties, even though the JAX-RPC specification does not require it. This is because when a WebLogic Web service receives the exception in a SOAP message and converts the XML into the Java exception class, there is no way of knowing which XML element maps to which class property without the corresponding setter methods.
From within your JWS file you can invoke another Web service, either one deployed on WebLogic Server or one deployed on some other application server, such as .NET. The steps to do this are similar to those described in Invoking a Web Service from a Java SE Client, except that rather than running the clientgen
Ant task to generate the client stubs, you include a <clientgen>
child element of the jwsc
Ant task that builds the invoking Web service to generate the client stubs instead. You then use the standard JAX-RPC APIs in your JWS file.
See Invoking a Web Service from Another Web Service for detailed instructions.
The following sections describe additional miscellaneous features you can program by specifying particular JWS annotations in your JWS file or using WebLogic Web services APIs:
SOAP Message Transmission Optimization Mechanism/XML-binary Optimized Packaging (MTOM/XOP) describes a method for optimizing the transmission of XML data of type xs:base64Binary
in SOAP messages. When the transport protocol is HTTP, MIME attachments are used to carry that data while at the same time allowing both the sender and the receiver direct access to the XML data in the SOAP message without having to be aware that any MIME artifacts were used to marshal the xs:base64Binary
data. The binary data optimization process involves encoding the binary data, removing it from the SOAP envelope, compressing it and attaching it to the MIME package, and adding references to that package in the SOAP envelope.
The MTOM specification does not require that, when MTOM is enabled, the Web service run time use XOP binary optimization when transmitting base64binary
data. Rather, the specification allows the run time to choose to do so. This is because in certain cases the run time may decide that it is more efficient to send base64binary
data directly in the SOAP Message; an example of such a case is when transporting small amounts of data in which the overhead of conversion and transport consumes more resources than just inlining the data as is. The WebLogic Web services implementation for MTOM for JAX-RPC service, however, always uses MTOM/XOP when MTOM is enabled.
Support for MTOM/XOP in WebLogic JAX-RPC Web services is implemented using the pre-packaged WS-Policy file Mtom.xml
. WS-Policy files follow the WS-Policy specification, described at http://www.w3.org/TR/ws-policy
; this specification provides a general purpose model and XML syntax to describe and communicate the policies of a Web service, in this case the use of MTOM/XOP to send binary data. The installation of the pre-packaged Mtom.xml
WS-Policy file in the types
section of the Web service WSDL is as follows (provided for your information only; you cannot change this file):
<wsp:Policy wsu:Id="myService_policy"> <wsp:ExactlyOne> <wsp:All> <wsoma:OptimizedMimeSerialization xmlns:wsoma="http://schemas.xmlsoap.org/ws/2004/09/policy/optimizedmimeserialization" /> </wsp:All> </wsp:ExactlyOne> </wsp:Policy>
When you deploy the compiled JWS file to WebLogic Server, the dynamic WSDL will automatically contain the following snippet that references the MTOM WS-Policy file; the snippet indicates that the Web service uses MTOM/XOP:
<wsdl:binding name="BasicHttpBinding_IMtomTest" type="i0:IMtomTest"> <wsp:PolicyReference URI="#myService_policy" /> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
You can associate the Mtom.xml
WS-Policy file with a Web service at development-time by specifying the @Policy
metadata annotation in your JWS file. Be sure you also specify the attachToWsdl=true
attribute to ensure that the dynamic WSDL includes the required reference to the Mtom.xml
file; see the example below.
You can associate the Mtom.xml
WS-Policy file with a Web service at deployment time by modifying the WSDL to add the Policy to the types section just before deployment.
In addition, you can attach the file at run time using by the Administration Console; for details, see "Associate a WS-Policy file with a Web Service" in the Oracle Fusion Middleware Oracle WebLogic Server Administration Console Help. This section describes how to use the JWS annotation.
Note:
In this release of WebLogic Server, the only supported Java data type when using MTOM/XOP is byte[]
; other binary data types, such as image
, are not supported.
In addition, this release of WebLogic Server does not support using MTOM with deprecated 9.x security policies.
To send binary data using MTOM/XOP, follow these steps:
Use the WebLogic-specific @weblogic.jws.Policy
annotation in your JWS file to specify that the pre-packaged Mtom.xml
file should be applied to your Web service, as shown in the following simple JWS file (relevant code shown in bold):
package examples.webservices.mtom; import javax.jws.WebMethod; import javax.jws.WebService; import weblogic.jws.WLHttpTransport; import weblogic.jws.Policy; @WebService(name="MtomPortType", serviceName="MtomService", targetNamespace="http://example.org") @WLHttpTransport(contextPath="mtom", serviceUri="MtomService", portName="MtomServicePort") @Policy(uri="policy:Mtom.xml", attachToWsdl=true) public class MtomImpl { @WebMethod public String echoBinaryAsString(byte[] bytes) { return new String(bytes); }
Use the Java byte[]
data type in your Web service operations as either a return value or input parameter whenever you want the resulting SOAP message to use MTOM/XOP to send or receive the binary data. See the implementation of the echoBinaryAsString
operation above for an example; this operation simply takes as input an array of byte
and returns it as a String
.
The WebLogic Web services run time has built in MTOM/XOP support which is enabled if the WSDL for which the clientgen
Ant task generates client-side artifacts specifies MTOM/XOP support. In your client application itself, simply invoke the operations as usual, using byte[]
as the relevant data type.
See the SOAP Message Transmission Optimization Mechanism specification at http://www.w3.org/TR/2005/REC-soap12-mtom-20050125
for additional information about the MTOM/XOP feature itself as well as the version of the specification supported by WebLogic JAX-RPC Web services.
Using the @weblogic.jws.StreamAttachments
JWS annotation, you can specify that a Web service use a streaming API when reading inbound SOAP messages that include attachments, rather than the default behavior in which the service reads the entire message into memory. This feature increases the performance of Web services whose SOAP messages are particular large.
See "weblogic.jws.StreamAttachments" in the Oracle Fusion Middleware WebLogic Web Services Reference for Oracle WebLogic Server for an example of specifying that attachments should be streamed.
WebLogic Web services use, by default, Version 1.1 of Simple Object Access Protocol (SOAP) as the message format when transmitting data and invocation calls between the Web service and its client. WebLogic Web services support both SOAP 1.1 and the newer SOAP 1.2, and you are free to use either version.
To specify that the Web service use Version 1.2 of SOAP, use the class-level @weblogic.jws.Binding
annotation in your JWS file and set its single attribute to the value Binding.Type.SOAP12,
as shown in the following example (relevant code shown in bold):
package examples.webservices.soap12; import javax.jws.WebMethod; import javax.jws.WebService; import weblogic.jws.WLHttpTransport; import weblogic.jws.Binding; @WebService(name="SOAP12PortType", serviceName="SOAP12Service", targetNamespace="http://example.org") @WLHttpTransport(contextPath="soap12", serviceUri="SOAP12Service", portName="SOAP12ServicePort") @Binding(Binding.Type.SOAP12) /** * This JWS file forms the basis of simple Java-class implemented WebLogic * Web Service with a single operation: sayHello. The class uses SOAP 1.2 * as its binding. * */ public class SOAP12Impl { @WebMethod() public String sayHello(String message) { System.out.println("sayHello:" + message); return "Here is the message: '" + message + "'"; } }
Other than set this annotation, you do not have to do anything else for the Web service to use SOAP 1.2, including changing client applications that invoke the Web service; the WebLogic Web services run time takes care of all the rest.
See "weblogic.jws.Binding" in the Oracle Fusion Middleware WebLogic Web Services Reference for Oracle WebLogic Server for additional information about this annotation.
When a client application invokes a WebLogic Web service operation, the operation invocation takes place outside the context of a transaction, by default. If you want the operation to run inside a transaction, specify the @weblogic.jws.Transactional
annotation in your JWS file, and set the boolean value
attribute to true
, as shown in the following example (relevant code shown in bold):
package examples.webservices.transactional; import javax.jws.WebMethod; import javax.jws.WebService; import weblogic.jws.WLHttpTransport; import weblogic.jws.Transactional; @WebService(name="TransactionPojoPortType", serviceName="TransactionPojoService", targetNamespace="http://example.org") @WLHttpTransport(contextPath="transactionsPojo", serviceUri="TransactionPojoService", portName="TransactionPojoPort") /** * This JWS file forms the basis of simple WebLogic * Web Service with a single operation: sayHello. The operation executes * as part of a transaction. * */ public class TransactionPojoImpl { @WebMethod() @Transactional(value=true) public String sayHello(String message) { System.out.println("sayHello:" + message); return "Here is the message: '" + message + "'"; } }
If you want all operations of a Web service to run inside of a transaction, specify the @Transactional
annotation at the class-level. If you want only a subset of the operations to be transactional, specify the annotation at the method-level. If there is a conflict, the method-level value overrides the class-level.
See "weblogic.jws.Transactional" in the Oracle Fusion Middleware WebLogic Web Services Reference for Oracle WebLogic Server for information about additional attributes.
If your Web service uses HTTP as its transport protocol, you can use the "weblogic.wsee.connection.transport.servlet.HttpTransportUtils"
API in the Oracle Fusion Middleware Oracle WebLogic Server API Referenceto get the javax.servlet.http.HttpServletRequest
and javax.servlet.http.HttpServletResponse
objects from the JAX-RPC ServletEndpointContext
object, as shown in the following example (relevant code shown in bold and explained after the example):
package examples.webservices.http_transport_utils; import javax.xml.rpc.server.ServiceLifecycle; import javax.xml.rpc.server.ServletEndpointContext; import javax.xml.rpc.ServiceException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.jws.WebMethod; import javax.jws.WebService; import weblogic.jws.WLHttpTransport; import weblogic.wsee.connection.transport.servlet.HttpTransportUtils; @WebService(name="HttpTransportUtilsPortType", serviceName="HttpTransportUtilsService", targetNamespace="http://example.org") @WLHttpTransport(contextPath="servlet", serviceUri="HttpTransportUtils", portName="HttpTransportUtilsPort") public class HttpTransportUtilsImpl implements ServiceLifecycle { private ServletEndpointContext wsctx = null; public void init(Object context) throws ServiceException { System.out.println("ServletEndpointContext inited..."); wsctx = (ServletEndpointContext)context; } public void destroy() { System.out.println("ServletEndpointContext destroyed..."); wsctx = null; } @WebMethod() public String getServletRequestAndResponse() { HttpServletRequest request = HttpTransportUtils.getHttpServletRequest(wsctx.getMessageContext()); HttpServletResponse response = HttpTransportUtils.getHttpServletResponse(wsctx.getMessageContext()); System.out.println("HttpTransportUtils API used successfully."); return "HttpTransportUtils API used successfully"; } }
The important parts of the preceding example are as follows:
Import the required JAX-RPC and Servlet classes:
import javax.xml.rpc.server.ServiceLifecycle; import javax.xml.rpc.server.ServletEndpointContext; import javax.xml.rpc.ServiceException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
Import the WebLogic HttpTransportUtils
class:
import weblogic.wsee.connection.transport.servlet.HttpTransportUtils;
Because you will be querying the JAX-RPC message context, your JWS file must explicitly implement ServiceLifecycle
:
public class HttpTransportUtilsImpl implements ServiceLifecycle
Create a variable of data type ServletEndpointContext
:
private ServletEndpointContext wsctx = null;
Because the JWS file implements ServiceLifecycle
, you must also implement the init
and destroy
lifecycle methods:
public void init(Object context) throws ServiceException { System.out.println("ServletEndpointContext inited..."); wsctx = (ServletEndpointContext)context; } public void destroy() { System.out.println("ServletEndpointContext destroyed..."); wsctx = null; }
Finally, in the method that implements the Web service operation, use the ServletEndpointContext
object to get the HttpServletRequest
and HttpServletResponse
objects:
HttpServletRequest request = HttpTransportUtils.getHttpServletRequest(wsctx.getMessageContext()); HttpServletResponse response = HttpTransportUtils.getHttpServletResponse(wsctx.getMessageContext());
The following list provides some best practices when programming the JWS file:
When you create a document-literal-bare Web service, use the @WebParam
JWS annotation to ensure that all input parameters for all operations of a given Web service have a unique name. Because of the nature of document-literal-bare Web services, if you do not explicitly use the @WebParam
annotation to specify the name of the input parameters, WebLogic Server creates one for you and run the risk of duplicating the names of the parameters across a Web service.
In general, document-literal-wrapped Web services are the most interoperable type of Web service.
Use the @WebResult
JWS annotation to explicitly set the name of the returned value of an operation, rather than always relying on the hard-coded name return
, which is the default name of the returned value if you do not use the @WebResult
annotation in your JWS file.
Use SOAPFaultExceptions
in your JWS file if you want to control the exception information that is passed back to a client application when an error is encountered while invoking a the Web service.
Even though it is not required, Oracle recommends you always specify the portName
attribute of the WebLogic-specific @WLHttpTransport
annotation in your JWS file. If you do not specify this attribute, the jwsc
Ant task will generate a port name for you when generating the WSDL file, but this name might not be very user-friendly. A consequence of this is that the getXXX()
method you use in your client applications to invoke the Web service will not be very well-named. To ensure that your client applications use the most user-friendly methods possible when invoking the Web service, specify a relevant name of the Web service port by using the portName
attribute.