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 Jyth
wsadmin -f addJvmProperty.
Server version: IBM_
At this version of WebSphere, JAX-RS 1.1 is supported, but that doesn't include any REST Client support. JAX-RS 2.0 apparently does, but that's not yet available here on WAS 8.5.5 Full Profile. It i
Those steps are actually pretty clear and comprehensive. I'll give quick examples of the mostly-default code I used. (Showing full class packages inline, just once, for simplicity.)
Another form of each operation does not throw that Exception, but allows you to manually check the ClientResponse yourself. This is how the example in the above WAS documentation does things. (Note that even those methods do seem to throw Clie
Speaking of POST, here's what that looks like. With a JSON payload as well.
Adding HTTP Basic Authentication
From another WebSphere Knowledge Center article, Secu
JSON Beans and Seri
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.
Since I can tell that I don't fully understand this myself, I'll start by pointing to these articles which more fully & authoritatively describe SPF's purpose, behavior, and effects:
The first concept to understand is that SMTP email contains an "envelope" with an "envelope sender address" (sometimes called the "return-path" and technically the SMTP MAIL FROM command) that is separate from the "From" header in the message itself (a.k.a. the "header sender address").
The envelope sender address is what actually receives bounces, BTW. It's sent, and potentially checked, before the email message itself (including the header) is even delivered. The header sender address is what a user's email client typically displays, and it obviously doesn't always match the domain of the SMTP server which actually originated the message.
Sender Policy Framework
SPF, then, is an attempt to prevent forging of the envelope sender, not the header sender.
SPF is a combination of "sender" and "receiver" actions. The domain owner publishes a special kind of DNS record indicating which servers are authorized to send emails from its users. The receivers then verify that the IP address from which the email originated is in that authorized list for the domain.
So the purpose of SPF isn't to allow anotherdomain.com servers to send email on behalf of somedomain.com, the original requirement I was investigating; that can be done without SPF. Its purpose is the opposite: to tell receivers (who check) not to accept email which claims to come from somedomain.com (that is, with an envelope sender address of somedomain.com) unless the actual originating server's IP address is one listed as authorized to do so.
The primary goal seems to be reducing the amount of SPAM claiming to originate at somedomain.com.
Sender Addresses in JavaMail
Note that JavaMail by default uses the header sender ("From" address) also as the envelope sender address, but this doesn't have to be the case.
Potential Problems with SPF
The main potential problem I see is that email forwarding services typically don't work with SPF. That is, if a domain publishes a restrictive SPF record, an individual receiving emails from that sender provides an email address that is actually a forwarding address, and the eventual destination of that forwarding address checks SPF records, the email will be rejected.
Since the sending server typically cannot control what kind of email addresses its customers provide, this seems like an unacceptable situation to me. Undoubtedly some end-users will provide email addresses which will be unable to receive email from a domain with strict SPF settings, and they'd never know they had done so. (Although the sending server should receive bounce emails indicating SPF failure in those cases.)
For those curious but not curious enough to work through the linked articles.
SPF is implemented by a domain adding a special kind of DNS record to its DNS server. (Apparently this can be either a TXT record or a SPF record, with the same content/format either way.) I won't go into the details documented elsewhere, but a simple example would be:
somedomain.com. IN TXT "v=spf1 a mx -all"
Meaning, for email with an envelope sender address in somedomain.com, only accept the email if the sending IP is either one of the domain's DNS "A" servers (the main DNS record for a domain) or one of its DNS "MX" (mail) servers. Consider "all" other IP addresses a "hard FAIL" (i.e. reject them if you care about such things).
I looked up ibm.com and saw that it actually has an SPF record that says no servers at all should be sending email for @ibm.com:
ibm.com. IN TXT "v=spf1 -all"
I had to ponder for a bit before I thought to check us.ibm.com. It has several valid senders listed, including some IP ranges:
us.ibm.com. IN TXT "v=spf1 ip4:126.96.36.199/24 ip4:188.8.131.52/24 a:d2
Hard and Soft Fail
Note the difference in the "all" clauses in the previous two examples. "-all" (hyphen) means to treat emails from all (other) senders as a "hard FAIL". "~all" (tilde) means to treat them as a "SOFTFAIL". Note that Google.com's SPF record and Microsoft.com's SPF record also use the SOFTFAIL default.
SOFTFAIL is theoretically intended as a transitional setting while you're testing out the implications of your SPF record/policy, with the recommendation that recipients accept the email but "mark" them in some way. But based on the noted use of that SOFTFAIL indicator by those large, savvy domains, I'd say that Hard FAILS probably reject too many real-world uses today. (I suspect the forwarding scenario described above as one of the main such problematic uses.)
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
Through just a little trial-and-error, these trace strings get me the basic URL and request/response message contents when running JAX-
internal.log is the request/response messages, ResourceImpl is the URL.
Also See Must
(Similar, but more detailed, post about trac