I sometimes need to set a custom JVM Property for one or more Application Servers and dislike the tedium of setting them one-at-a-time through the console.
Here's a Jython script for wsadmin to add a JVM Custom Property to a specified Application Server, or to "all" application servers. It will also replace an existing property with a new value and description. Usage:
Update: the above only obtains the heap size if a custom value has been explicitly configured. From this other post, here's a mechanism which will obtain the maximum heap size otherwise (note there doesn't appear to be an attribute to obtain the minimum heap size):
Web Application Configuration
This is the basic annotation-based JAX-RS coding. See the below "Getting Started" article, Part 1 of the "RESTful Web services" article, and the Developing JAX-RS Web applications section of the WebSphere Feature Pack documentation.
It's a straightforward, portable way to define the URI Paths of your Resources, the HTTP Methods supported by them, the Parameters passed to them, the Content Types supplied by them, and more.
However, with object lifecycles now managed by JEE containers, like for JAX-WS or JAX-RS services, sometimes using Spring-managed beans is not as direct as I'd like. JEE 6's Cont
Most of my projects use Spring for other things as well, so I hadn't been willing to look down the CDI path just yet. However, I'm now working on some SOAP Web Service projects that don't yet use Spring, so I thought I'd give CDI a look.
What follows is the basics of configuring a "web" application that is both a JAX-WS service and a JAX-WS client to one or more other services. I need to inject both some interface implementation classes and some JEE Resource References into my service. In case documenting this particular example helps anyone else. Or just helps me clarify what I did and remember it in the future :-)
In my @WebService JAX-WS implementation class (or any other "service" / "servlet" class managed by the JEE container), I need to make use of a "business facade" interface implementation singleton. JEE 6 annotation @Inject enables this.
If I only have one such BusinessFacade implementation class defined in the application, this is sufficient to locate it. (Classes don't have to be annotated in order to have their instance(s) injectable as "Producers". They just have to meet some conventions: see Abou
If you have multiple implementation classes, you'll need to qualify the @Inject like with @Named.
By default, the "sco
Since I want this BusinessFacade instance to be a singleton, only initialized once for the whole application, I need to tell my implementation class that I want instances of it to have "Application" scope. I do that by annotating that class with @ApplicationScoped.
(@Singleton is from the EJB spec and is somewhat different from CDI's @App
Now, somewhere down my object chain, I have another object that calls another Web Service, via a JAX-WS client wrapper, and I need to inject the endpoint URL into that wrapper.
I manage that URL through a web.xml <resource-ref> that I can map to server Resource at deploy time:
To get that injected into my hand-written caller class, I use @Resource, specifying the same name used in <res-ref-name>:
Now, specific to JAX-WS client wrappers, I want to override the endpoint URL that was specified in the WSDL used to create the client code. The approach that seems cleanest to me is usin
The @PostConstruct annotation indicates a method (named whatever you want) to be called after a class instance is created. I'll use this to bind a (singleton) JAX-WS client wrapper (ServicePortType in the example) to the endpoint URL specified in the above injected @Resource:
private ServicePortType serviceEndpoint = null;
(Where Service and ServicePortType match whatever was generated from your WSDL.)
Note that I've annotated this particular class with @ApplicationScoped, so this @PostConstruct will only be called once. Another potential pattern would be to have this class not be a singleton but have the @PostConstruct method lazy-initialize and reuse a static ServicePortType instance.
Finally, logistically, your application must contain a beans.xml file in its WEB-INF directory in order for WebSphere to know to scan it for CDI annotations. This file can be completely empty.
While attempting to answer a question on StackOverflow, I experimented a little with some wsadmin commands, so I thought I'd record what I discovered. (I work with the Jython, rather than JACL, versions of the commands mostly because I like the idea of picking up a little of a new programming language which has other uses.)
In this particular case, I wanted to discover runtime System.properties values for a running JVM, of which many are not items you configure explicitly with WebSphere. Thus, after looking at the AdminConfig object and determining that it only had visibility into what you've configured, I determined that the AdminControl object was needed.
Still, here are some AdminConfig commands that I've used and will likely have reason to use again:
You can see where I previously used this approach to create JVM Custom Properties for Application Servers and to determine the (configured) maximum heap for a particular Application Server. (I'll return to that latter case later.)
The AdminControl scripting object is used for operational control. It communicates with MBeans that represent live objects running a WebSphere® server process.
These commands allowed me to locate and query runtime WebSphere objects:
Or skip straight to the JVM:
Or, returning to the maximum heap case from before, now I can see the maximum heap of a JVM even if I haven't explicitly configured one. Either of these variations, invoking a getter method, or getting an attribute, does the same thing:
Finally, here's a way to see which attributes and operations are available for a particular object:
I'm sure this information is in hundreds or thousands of other places, but as I had written it up for an internal team Wiki, I thought I'd repost here as well.
Perl is included by default in AIX, but most of the Modules are not, so the rest of this article deals with installing those.
Some Perl scripts make use of additional Modules, and there are Modules with many different capabilities, so be sure to look for existing Modules if you need to do anything that someone else might have had to do already.
Obtaining a Module
For instance, a script we created uses the Date::Simple module. After finding its page, you click the Download link on the right side to obtain what is actually a source package in .tar.gz format.
Module Installation from Source
These instructions are summarized from somewhere, I thought an earlier version of the generic installation instructions on the CPAN site. However, that site now describes a simpler approach using a cpanminus installation module. I'll have to try that out.
Decompress the file
This can be done as any user.
gunzip -c Date
Build the module
These steps can also be performed as any user.
By default, the Makefile will attempt to create an "XS" version of the Module, which means a version that uses native C code to improve performance. This means the "make" command will require access to a local C compiler.
If you don't have a C compiler or want to create a "pure-Perl" Module to copy around to various systems, you use the "noxs" option. The output of "perl Makefile.PL" will actually tell you to use this option if you see errors during the "make" step. If that occurs, the error will look something like:
cc_r -c -D_ALL_SOURCE -D_ANSI_C_SOURCE -D_POSIX_SOURCE -qmaxmem=-1 -qnoansialias
Install the module
This step needs to be performed as a user that can write to the Perl installation direction. Most likely "root".
Also watch for file permissions. By default this could make the module directory, subdirectories, and files be only readable by root.
It seems that in our current configuration the WebSphere plugin does not reliably stop sending requests to a Cluster member when it's been taken down. Or sometimes it seems to take an inordinate amount of time for it to do so, or sometimes it starts sending requests before a restarting member is fully operational.
A quick workaround is to manually edit the plugin's configuration file on each web server to comment-out the unwanted servers. The plugin will automatically detect and apply the changes within a minute or so and stop routing requests to those servers until you manually uncomment them.
Plugin Configuration File Location
On our AIX systems, the plugin configuration file is in a location like:
(If you're ever uncertain you're looking in the correct location, look for the WebS
Plugin Configuration File Contents
Within that file are many configuration items, most should never be manually edited, but the ones we care about for this purpose are the <PrimaryServers> elements within each <ServerCluster> element.
The ServerCluster's "Name" attribute will tell you which element to edit.
Then the PrimaryServers element in that ServerCluster will list each of the individual <Server> Cluster members which are also defined within ServerCluster.
Removing a specific server from Plugin dispatching
The only change we have to make is to comment-out the specific Server which we want to cease receiving requests. So to disable the TestApp-B server on serverB:
Following up on Part 1, here's an additional tip which I use frequently. That is, when I need to tunnel SSH through one machine to reach others, using a background proxy with SSH key authentication for the initial connection simplifies this 2-hop process.
Automatic proxying with Plink
The PuTTY installation also includes a command-line SSH program called Plink which can be used in a "background" mode. The PuTTY help describes how to use Plink as a local proxy program, creating a background tunnel for the main PuTTY window. This configuration is performed in the Window > Proxy tab:
Specify a Proxy type of local, and the standard SSH Port, 22.
In the Proxy hostname field, you enter a host to which you have direct access and on which you've configured key authentication, then you refer to that host via the %proxyhost variable in the plink command you provide as the local proxy:
\path\to\plink -l %user %proxyhost -nc %host:%port
The %host and %port variables represent the ultimate destination Host Name and Port fields from the main PuTTY Session tab (which, as usual, you can enter as needed or save under separate Sessions for each server).
%user and %proxyhost are from this configuration page.
Note: If your Default Settings PuTTY profile has a username (on the Connection > Data tab) or hostname configured in it, plink will use those automatically. Discovering that wasted a couple of hours for myself and a colleague. On the other hand, if the configured default username matches your username on the proxy server, you can completely omit the -l parameter from the plink command.
Tunneling additional Ports
Furthermore, this technique can be used in conjunction with "normal" SSH tunneling (Connection > SSH > Tunnels) in order to tunnel a localhost port through both hops. For instance, to tunnel the default WebSphere Application Server administration console port:
Then you connect your browser to http
You can similarly 2-hop tunnel X-Windows by enabling X11 Forwarding on PuTTY's Connection > SSH > X11 tab. (You'll need Windows X server like XMing.)
Any additional tips you've found useful? Better ways to accomplish these same tasks? I welcome your comments and suggestions.
Have you ever discovered that you no longer have the EAR file for the specific version of an Enterprise Application which is deployed on one of your systems?
It turns out WebSphere keeps a copy around that can be retrieved and re-deployed elsewhere. For the Network Deployment edition of WAS v6.1, you can find a deployed EAR file in:
(Note the ear name twice, first as a directory, then as a file.)
During investigation of some intermittent problems in one of our web applications, we observed some JSESSIONID cookie behavior that we couldn't explain, so I performed some investigation into the cookie's mechanics. I'll attempt to summarize in this article what I learned.
JSESSIONID Cookie Format
In a clustered environment, the JSESSIONID cookie is composed of the core Session ID and a few other components. Here's an example:
It's still unclear to me what the different values mean here, but searching our Proxy logs indicates that the vast majority of our Sessions, the Cache ID is 0001. For instance, a search of one day's log around 17:00 indicates the following number of cookies which contained a particular Cache ID:
For a particular Session ID, the Cache ID can definitely change mid-session, without any other changes. In particular, without the Clone/Partition ID changing. This does not indicate a switch to another Cluster member, but I don't know exactly what it does indicate. Based on the relative loads of our various systems, it seems possible that changing Cache IDs only occurs under heavy loads.
A Partition ID is appended to the cookie if memory-to-memory replication in peer-to-peer mode is utilized for Distributed Session management. Otherwise, a Clone ID is appended.
This will match one of the CloneID attributes in the Server elements within the web server's plugin-cfg.xml file. For instance 138888kcd in:
<Server CloneID="138888kcd" ConnectTimeout="10" Exte
If you use memory-to-memory Session replication, your cookies will contain Partition IDs rather than Clone IDs.
Partition IDs are similar in function to Clone IDs, but best I can tell there is no direct way to determine which values correspond to which cluster members. They are internally mapped by the WebSphere HAManager to specific Clone IDs, and that mapping is exchanged with the web server plug-in so that it can maintain Session affinity and find additional cluster members for failover. (The exchange takes place in private headers on each response from WAS back to the plug-in, and those headers are removed before the response is sent back to the client.)
Session Affinity and Failover
The Clone/Partition ID corresponds to whichever cluster member creates the Session, and the plug-in is responsible to send that Session to the same cluster member as long as it is available. From the Scalability Redbook:
Since the Servlet 2.3 specification, as implemented by WebSphere Application Server V5.0 and higher, only a single cluster member may control/access a given Session at a time. After a Session has been created, all following requests need to go to the same application server that created the Session. This Session affinity is provided by the plug-in.
If on a subsequent request the specified cluster member is unavailable, the plug-in will choose another cluster member and attempt to connect to that. If Distributed Sessions are configured, via database persistence or memory-to-memory replication, the Session will be resumed in-progress on that new member. If not, a new Session will be created and the user's progress will be lost.
If a new cluster member is able to resume the existing Session, it will append its own Clone/Partition ID to the existing JSESSIONID cookie. For instance:
Now the plug-in knows that 2 different cluster members could potentially service this Session. If the original member becomes available again, the Session will switch back to it.
Finally, note that according to the System Management Redbook:
WebSphere provides session affinity on a best-effort basis. There are narrow windows where session affinity fails. These windows are:
Referenced articles and Redbooks
Because I investigated this for a project, Linux (at least RHEL) mailx can use a remote SMTP server, thus enabling us to test whether that server allows email sending from our application.
mailx -S smtp
Where "-S smtp <smt
-v is "verbose"
body.txt is a local file that contains the body of the test message I'm sending.
The test was initially failing like this:
Resolving host <server-address> . . . done.
And success (eventually) looked like this:
Resolving host <smt
JAX-WS 2.2 is the latest version, and it's supported by WebSphere 8.5. However, it appears to sort-of want Java 7.
wsimport can either be run as a script or from Ant.
The script is part of the SDK now, even included with J2SE. The
The Ant task is actually provided by Sun classes, but they are included in WebSphere's jars as well. The
The jars required to run the Ant task are found in the WebS
If you want to try JAX-WS 2.2. under Java 6, you also need from the WebS
Create an Ant taskdef like this:
<!-- Ant task definition for wsimport -->
A sample <wsimport> task looks like this:
References and Articles
(Related to my earlier post
Found this useful tidbit today from IBM
This is a quick way to look at your IHS load over time.
Using IBM HTTP Server 6.1 and later diagnostic capabilities with WebSphere
This could be useful. Apache mod_status is available in IHS, and when it's enabled it provides information about the individual threads running under the httpd processes.
The information is provided as a simple web page via a URL (that of course can be protected by any of the various Apache mechanisms).
With the default httpd.conf file, only the following changes are required: