17
May
09

Accessing a HMC through a SSH tunnel

For sysadmins this might be a rather easy task, but as a HMC end-user I had to search a little bit.
If you never used an IBM server you might be wondering what is an HMC. At first it seems like a notebook in a blade format as you can see on the picture below:

HMC

HMC (source: http://www.fz-juelich.de/jsc/index.php?index=1979)


But apart from its similarity to a fancy notebook, its purpose is to allow administration of IBM LPARs (or DLPARs after Power6 arrival).
There you can boot, shutdown, change CPUs and memory for LPARs, etc.
Apart from allowing the administration in loco, it provides a Java based application that can be installed either through a Java Web Start launcher or using an MSI installer.
I’ll try to explain the steps involved in running it using the JNLP Java Web Start launcher.

Setup SSH tunnel and Download JNLP

Open the SSH connection between you and any host on the same network as your HMC (this can even be the HMC itself) and tunnel the following ports from your machine to HMC’s IP.

  • 30000 up to 30009
  • 9090
  • 9960
  • 8443
  • 443
  • 80

Sincerely, I did not check if, strictly speaking, all the ports are necessary but feel free to test them and leave  a comment. These ports were the result of a few searches over the internet.

After setting up the tunnel, point your preferred browser to http://localhost and download the JNLP file at the following link:

HMC html page

HMC html page

I had to edit the codebase property of the JNLP file, but I guess it wont be necessary as I still had to edit the hosts file and add an alias for the machine name (eg.: hmc.my-server.mylocalnetwork).  You’ll end up having codebase as follows:

codebase="http://127.0.0.1/wsmship/codebase"

Edit hosts file

The next step is to edit your hosts file so it will have an extra alias pointing to 127.0.0.1. Copy the host name from the original value of the codebase property.
Then launch the JNLP file with Java Web Start. If you have the mime type correctly associated at your operating system, double click the file and wait for its launch. Sometimes it may complain at the first connection attempt, retry it and it’ll connect successfully. I guess I might still be missing some ports from the 30000~30009 range, since my first attempt was using ports from 30001~30009 and it always complained at the first attempt.

03
May
09

WebSphere Concepts: Cell, Node, Cluster, Server…

Quick post… If you are not familiar with WebSphere at first you might get confused with its concepts: cell, deployment manager, node, node agent, cluster, server, …

First of all, lets start with the concept of a Cell:

A Cell is a virtual unit that is built of a Deployment Manager and one or more nodes. I guess a picture will help making things clearer:

WebSphere Cell

WebSphere Cell

But still there are a few concepts that need to be explained. The next obvious one is the Deployment Manager.

The Deployment Manager is a process (in fact it is an special WebSphere instance) responsible for managing the installation and maintenance of Applications, Connection Pools and other resources related to a J2EE environment. It is also responsible for centralizing user repositories for application and also for WebSphere authentication and authorization.

The Deployment Manager communicates with the Nodes through another special WebSphere process, the Node Agent.

The Node is another virtual unit that is built of a Node Agent and one or more Server instances.

The Node Agent it the process responsible for spawning and killing server processes and also responsible for configuration synchronization between the Deployment Manager and the Node. Extra care must be taken when changing security configurations for the cell, since communication between Deployment Manager and Node Agent is ciphered and secured when security is enabled, Node Agent needs to have configuration fully resynchronized when impacting changes are made to Cell security configuration.

Servers are regular Java process responsible for serving J2EE requests (eg.: serving JSP/JSF pages, serving EJB calls, consuming JMS queues, etc).

And to finish, Clusters are also virtual units that groups Servers so resources added to the Cluster are propagated to every Server that makes up the cluster, this will in fact affect usually more than a single Node instance.

Lets finish this post with another diagram to illustrate all those concepts.

WebSphere Concepts

WebSphere Concepts

10
Apr
09

First impressions of IBM WebSphere MQ Low Latency Messaging

IBM has a rather new platform for messaging. It is called WebSphere MQ Low Latency Messaging (aka WebSphere MQ LLM). It was released on the fourth quarter of 2007 and sincerely it hasn’t much similarities with the well known WebSphere MQ (former MQ Series).

First of all, after installing it you will probably notice that there isn’t a service for starting up. Soon you notice that it is rather a library that provides messaging services. Actually, it is a native library (currently [v2.1] only available for Linux x86, Windows x86 and Solaris Sparc) that comes already with JNI bindings.

To make things even harder, there isn’t much documentation available (and it seems like IBM is still organizing its docs online).

But, IBM claims that it has shown impressive numbers on its benchmarks:

WebSphere MQ Low Latency Messaging has demonstrated very high throughput, one-to-many multicast messaging, which can deliver approximately one million 120-byte messages per second on Ethernet, close to three million 120-byte messages per second on InfiniBand, and more than 8 million smaller messages per second, all on common x86 servers. Testing has also measured very low latency of 30 microseconds for 120 byte messages delivered at 10,000 messages per second on InfiniBand or 61 microseconds on Ethernet (1)

Source: IBM press release

In its Java version, the main classes that you’ll interact when using WMQ LLM are:

  • RUMInstance (available through RUMFactory)
  • RMMInstance

For instance, RUM stands for Reliable Unicast Messaging and RMM stands for Reliable Multicast Messaging. As you can guess, RUM is used for Queue styled messaging and RMM for Topic styled messaging.

One of its drawbacks is that it still lacks a JMS based Resource Adapter but nothing denies you from rolling your own if you can’t wait for an official adapter from IBM.

I am planning to do some benchmarking against a regular MQ integrated application. As soon as I have the results I’ll post them over here.

28
Mar
09

WebSphere custom user repository

If you already used JBoss you probably used (or at least knew there is) the DatabaseServerLoginModule. But, if you happen to be using WebSphere things are a little bit different. WebSphere (I guess version 6 onwards) comes with the powerful concept of the federated repository. This feature allows multiples sources for authentication and authorization. The final layout inside WebSphere ressembles an LDAP tree, every Repository is suffixed with an identifier.

But, unfortunately, through the Web Administration interface you are limited to LDAP and the builtin FileBased WIM authentication.

Another thing that makes it even harder is that there isn’t much documentation about these extended repositories.

There is one post from IBM that suggests that there are alternatives:

The information used for the registry lookup is customizable and can be made totally flexible if a custom registry is developed using the WebSphere Application Server custom registry interface.

But still there isn’t a single link from this article that points out how to achieve this. If you get the key words in this phrase and risk a Google search you’d end up finding how to do this on WebSphere 4, that, by the way, was much limitted when compared to what is available on WebSphere 6.

Refining this search a little bit you’ll find what you are looking for, how to do this on WebSphere 6. But you’ll only take this approach if you are willing to roll your own adapter, but be advised that this tutorial won’t cover every steps you need and this is the content of another post. There is a complex interface that needs to be implemented in order to fulfill the requirements of an WebSphere Repository. The complexity is derived from the fact that all method in this interface is based on commonj.sdo.DataObject class and this class maps an XML to a Java Object hierarchy making for now this implementation almost a guessing game since there isn't much public information regarding this interface contract.

But, returning to the original objective of the post that was to guide on how to make WebSphere authenticate users against a database, setup the DBAdapter using the guide that is found on this page. If you want, check the list of WebSphere builtin adapters here.

The last step is to create the tables for the database as described on step 3 of this post. This post in fact describes various possibilities for user repositories available in WebSphere.

JBoss DatabaseServerLoginModule adantages over WebSphere approach are its simplicity and flexibility but on the other hand, WebSphere Federated Repositories present a much more robust approach for handling user databases.

I’ll try to post some tips on how to roll your own Repository in the next few days.

14
Mar
09

Avoiding method timeouts in EJB Containers using Command Pattern with a JMS Queue

If you ever needed to run a complex processing in EJB that would take for example two minutes you probably have already faced the container time limitation for SessionBean methods.

This timeout (in contrast to what most think) isn’t there only to developer’s life harder. Actually, it is exactly the opposite: it is there to avoid that someone inadvertly implement a code that takes the whole server down (including your beloved application).

But there are times when long running operations are really necessary, for example a cache warmup.

MDBs are an exception

As in our project a few operations would easily violate this limitation we had to research a smart way of circumventing this limitation. During our research we found out this post on /dev/websphere blog. So we already knew that we would end up using a JMS Queue but having one Queue, MDB and so ever for each task would be a mess (not to mention that it was way too much work and not ellegant). So, that was when we came to the conclusion that what we needed was an way of having multiple tasks on top of the same infra-structure.

Command Pattern to the Rescue

We realized that by using an ObjectMessage that carried our Command object we would end up having a single queue that would handle all of our long running tasks. If there is specific context for the task processing we can have it stored in the Command Object (eg.: id of a purchase transaction that needs to be processed, or even the purchase object itself).

Sequence Diagrams for the solution

Let’s have an example, suppose we have a long running cleanup of a database that needs to be run in a timely manner. We would end up having the following flow of method calls:

JOB Submission on Working Queue

JOB Submission on Working Queue

Having the Command object implement Runnable interface is a wise idea (to avoid having another interface that is almost a Runnable clone not to mention that future JavaEE Asynch beans will probably be implemented on top of Runnable interface).

The next important part is the JOB execution, which is depicted below:

JOB execution Working MDB

JOB execution Working MDB

As mentioned on the notes, you need to be aware that the Transactional Context for the MDB MUST be Never, otherwise you’d avoid method timeouts but would still have transaction timeouts.

Another tricky part is splitting the long running task in smaller chunks that can execute under the method timeout.

As stated in the diagram, the LongRunningJOB code inside the run method is called inside the execution context of the MDB which is free from the method timeout limitation.

Signalling JOB return code

If you need to be notified that the JOB has finished its execution you’d need to have either another JOB passed as parameter to this JOB and it’ll be responsible of executing the code that would inform its return status OR have a message sent on a Temporary Queue OR the last option would be to submit a reply in another queue and have a CorrelationID link the request and the response message.

03
Mar
09

Architecture Evaluation using ATAM

Those who work as a Software Architect have already been tasked with something like:

“We need to develop an Web application with a huge aptitude to scale horizontally and also able to conform with tight response times”

If you are really an architect, you’ll start to make up the architecture either in your mind, on an UML tool or even on a simple paper. It is as easy as it was coded on you, by heart you start to scratch how the solution would look like and in the end it’ll probably meet all the functional and non-functional requirements you had been told.
This works in this scenario but imagine if now, instead of coming up with a proposal of an architecture you are tasked to evaluate someone else architecture.
This is the scenario where ATAM is the way to go. It was designed as a sucessor of Software Architecture Analysis Method (SAAM). ATAM is also already a very accepted methodology.

ATAM authors define it as:

“The purpose of the ATAM is to assess the on sequences of architectural decisions in light of quality attribute requirements.”

ATAM is based on meetings with key stakeholders from diferent areas. During these meetings key quality attributes (QA) are formalized for the architecture and are later detailed, they are also further prioritized in relation to the importance of each QA and also the risk of not having this QA complete.

The last step is the generation of a report containing (mainly):

  • Risks and Non-risks
  • Sensitivity and Tradeoff Points

If you have alredy this need, give a look on ATAM. I’ll try to post some insights on how to apply it on the next few weeks.

07
Feb
09

Enabling CORBA support on Oracle BPM Studio (former BEA Aqualogic BPM Studio)

If you ever tried to add a CORBA component to a project inside Oracle BPM Studio (former BEA Aqualogic BPM Studio) you probably got this error message:

An ORB Library must be installed in the ORB introspector plugin

ORB error message on Oracle BPM Studio

To make things even worse, BPM Studio docs state that you need to install the jCorb library (yes, you read it right. It is mispelled in the docs); not to mention it does not even say how or where to install it.
So first step: download jacORB.
Unzip it and get the following files from the lib directory.

  • antlr-2.7.2.jar
  • avalon-framework-4.1.5.jar
  • backport-util-concurrent.jar
  • idl.jar
  • jacorb.jar
  • logkit-1.2.jar
  • picocontainer-1.2.jar
  • wrapper-3.1.0.jar
  • wrapper.dll

place them under the following folder:
${aqualogicDirectory}/studio/studio/eclipse/plugins/fuego.ncorba_6.0.0/lib
After that you can start BPM Studio and support for CORBA components will be working fine.
Provide or point the URL of your IOR. If you have any EJBs deployed inside an WebSphere installation, get his IOR and give a try.

01
Feb
09

Future updates to the JCA tutorial

This week I had a conf-call with a developer from a JavaEE server vendor to figure out what was happening with one of our JCA adaptors when a failure was reported in the underlying system and to my surprise “connectionErrorOccurred” method may not be called as I felt when I read the specs. One of the points that came up in the conf-call were the missing parts of the spec. This became clear when we discussed that on two other containers the adapter that caused the discussion worked fine and was giving problems only on this particular container. The developer argued (and he is right, spec does not cover this) that this vendor chose to disallow “connectionErrorOccurred” calls while connection is not in use (as the developer referred “our connections”, or, connections that are being held by the container in the connection pool). He also argued that this assumption (the one made by the container) was motivated to increase performance as it could reduce synchronization code. So, after these discoveries I’ll be updating the posts related to JCA and in the further weeks, after I have some time to do some updates to my FooJCA connector (this connector was useful to reproduce the bug inside the vendor lab) I’ll release it here for download so anyone willing to see a working example of a JCA connector will have a quick start code.

01
Feb
09

Monitoring a secured WebSphere installation through JOPR/RHQ

Monitoring an WebSphere installation with security enabled using JOPR/RHQ may seem at first simple and indeed it is if it weren’t for a few missing parts on the JOPR agent and MC4J library.
For those in a hurry that don’t want to wait till it gets incorporated into JOPR and MC4J I’ll try to summarize the changes and also provide the JMX Agent jar to be replaced. Apart from this, there is a need to import the server certificate for WAS SOAP Admin port into the JVM that JOPR is running (I hope there’ll be a certificate management feature in JOPR in the future to make this even simpler).
Let’s get to the changes.
First of all download RHQ code from SVN.


svn co http://svn.rhq-project.org/repos/rhq/tags/RHQ_1_1_0_GA/

Use tag 1.1.0 since I made the changes on top of that version.
Replace the following file on JMX plugin:
JMXServerComponent


/*
* RHQ Management Platform
* Copyright (C) 2005-2008 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.rhq.plugins.jmx;

import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mc4j.ems.connection.ConnectionFactory;
import org.mc4j.ems.connection.EmsConnection;
import org.mc4j.ems.connection.local.LocalVMFinder;
import org.mc4j.ems.connection.local.LocalVirtualMachine;
import org.mc4j.ems.connection.settings.ConnectionSettings;
import org.mc4j.ems.connection.support.ConnectionProvider;
import org.mc4j.ems.connection.support.metadata.ConnectionTypeDescriptor;
import org.mc4j.ems.connection.support.metadata.J2SE5ConnectionTypeDescriptor;
import org.mc4j.ems.connection.support.metadata.LocalVMTypeDescriptor;

import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.domain.measurement.AvailabilityType;
import org.rhq.core.domain.resource.Resource;
import org.rhq.core.domain.resource.ResourceType;
import org.rhq.core.pluginapi.inventory.ResourceContext;

/**
* The generic JMX server component used to create and cache a connection to a local or
* remote JMX MBeanServer. This component is responsible for building an isolated connection/classloader
* to the managed resource's JMX MBeanServer. Each connection is isolated from other connections
* created by other instances of this component. This allows for it to do things like manage
* multiple JBossAS servers that are running on the same box, even if they are of different JBossAS
* versions. The same holds true for Hibernate applications - multiple connections can be created
* to different versions of the Hibernate MBean and due to the isolation of each connection, there
* are no version incompatibility errors that will occur.
*
* @author Greg Hinkle
* @author John Mazzitelli
*/
public class JMXServerComponent implements JMXComponent {
private static Log log = LogFactory.getLog(JMXServerComponent.class);

private EmsConnection connection;
private ConnectionProvider connectionProvider;

ResourceContext context;

public void start(ResourceContext context) throws Exception {
this.context = context;
log.info("Starting connection to JMX Server " + context.getResourceKey());

try {
internalStart();
} catch (Exception e) {
log.warn("JMX Plugin connection failure", e);
// The new model is to always succeed in starting, but warn about the errors (we only do this the first request)
/*throw new Exception("Unable to connect to Java VM ["
+ configuration.getSimple(JMXDiscoveryComponent.CONNECTOR_ADDRESS_CONFIG_PROPERTY).getStringValue()
+ "]", e);*/
}

if (connection == null) {
log.warn("Unable to connect to JMX Server " + context.getResourceKey());
}
}

protected void internalStart() throws Exception {
Configuration configuration = context.getPluginConfiguration();

String connectionTypeDescriptorClass = configuration.getSimple(JMXDiscoveryComponent.CONNECTION_TYPE)
.getStringValue();

if (LocalVMTypeDescriptor.class.getName().equals(connectionTypeDescriptorClass)) {
String commandLine = configuration.getSimple(JMXDiscoveryComponent.COMMAND_LINE_CONFIG_PROPERTY)
.getStringValue();

Map vms = LocalVMFinder.getManageableVirtualMachines();
if (vms != null) {
for (LocalVirtualMachine vm : vms.values()) {
if (vm.getCommandLine().equals(commandLine)) {
connectLocal(vm.getVmid());
}
}
}
} else if (JMXDiscoveryComponent.PARENT_TYPE.equals(connectionTypeDescriptorClass)) {
// We're embedded in another jmx server component without jmxremoting set so just use the parent's connection
this.connection = ((JMXComponent) context.getParentResourceComponent()).getEmsConnection();
this.connectionProvider = this.connection.getConnectionProvider();
} else if (J2SE5ConnectionTypeDescriptor.class.getName().equals(connectionTypeDescriptorClass)) {
// We're embedded in a J2SE VM with jmxremote defined (e.g. for jconsole usage)
String principal = null;
String credentials = null;
PropertySimple o = configuration.getSimple(JMXComponent.PRINCIPAL_CONFIG_PROP);
if (o != null) {
principal = o.getStringValue();
}
o = configuration.getSimple(JMXComponent.CREDENTIALS_CONFIG_PROP);
if (o != null) {
credentials = o.getStringValue();
}

ConnectionSettings settings = new ConnectionSettings();
J2SE5ConnectionTypeDescriptor desc = new J2SE5ConnectionTypeDescriptor();
settings.setConnectionType(desc);
settings.setServerUrl(configuration.getSimple(JMXDiscoveryComponent.CONNECTOR_ADDRESS_CONFIG_PROPERTY)
.getStringValue());
if (principal != null) {
settings.setPrincipal(principal);
}
if (credentials != null) {
settings.setCredentials(credentials);
}

prepareConnection(settings);

} else {
// This can handle internal connections (within the same vm as the plugin container) as well as
// any remote connections
ConnectionSettings settings = new ConnectionSettings();

String principal = null;
String credentials = null;
PropertySimple o = configuration.getSimple(JMXComponent.PRINCIPAL_CONFIG_PROP);
if (o != null) {
principal = o.getStringValue();
}
o = configuration.getSimple(JMXComponent.CREDENTIALS_CONFIG_PROP);
if (o != null) {
credentials = o.getStringValue();
}

settings.initializeConnectionType((ConnectionTypeDescriptor) Class.forName(connectionTypeDescriptorClass)
.newInstance());

settings.setConnectionType((ConnectionTypeDescriptor) Class.forName(connectionTypeDescriptorClass)
.newInstance());
settings.setServerUrl(configuration.getSimple(JMXDiscoveryComponent.CONNECTOR_ADDRESS_CONFIG_PROPERTY)
.getStringValue());

String installPath = configuration.getSimpleValue(JMXDiscoveryComponent.INSTALL_URI, null);
if (installPath != null) {
settings.setLibraryURI(configuration.getSimple(JMXDiscoveryComponent.INSTALL_URI).getStringValue());
}

if (principal != null) {
settings.setPrincipal(principal);
}
if (credentials != null) {
settings.setCredentials(credentials);
}
prepareConnection(settings);
}

this.connection.loadSynchronous(false);

}

public void stop() {
if (connection != null) {
connection.close();
connection = null;
}
}

protected void connectLocal(int vmid) {
// TODO GH: Refactor ems to also accept the vm itself
ConnectionSettings settings = new ConnectionSettings();
settings.setConnectionType(new LocalVMTypeDescriptor());
settings.setServerUrl(String.valueOf(vmid));
prepareConnection(settings);
}

protected void prepareConnection(ConnectionSettings settings) {
settings.getControlProperties().setProperty(ConnectionFactory.COPY_JARS_TO_TEMP, String.valueOf(Boolean.TRUE));
settings.getControlProperties().setProperty(ConnectionFactory.JAR_TEMP_DIR,
this.context.getTemporaryDirectory().getAbsolutePath());

addAdditionalJarsToConnectionSettings(settings);

ConnectionFactory cf = new ConnectionFactory();
cf.discoverServerClasses(settings);

this.connectionProvider = cf.getConnectionProvider(settings);
this.connection = this.connectionProvider.connect();
}

public EmsConnection getEmsConnection() {
return this.connection;
}

public AvailabilityType getAvailability() {
if (connectionProvider == null || !connectionProvider.isConnected()) {
try {
internalStart();
} catch (Exception e) {
log.debug("Still unable to reconnect resource: " + context.getResourceKey() + " due to error: "
+ e.getMessage());
}
}

return ((connectionProvider != null) && connectionProvider.isConnected()) ? AvailabilityType.UP
: AvailabilityType.DOWN;
}

public List discoverServices(ResourceType type, Configuration defaultPluginConfiguration) {
defaultPluginConfiguration.getSimple("objectName").getStringValue();

return null;
}

private void addAdditionalJarsToConnectionSettings(ConnectionSettings settings) {
// get the plugin config setting that contains comma-separated list of files/dirs to additional jars
// if no additional classpath entries are specified, we'll return immediately and not do anything to settings
Configuration pc = context.getPluginConfiguration();
PropertySimple prop = pc.getSimple(JMXDiscoveryComponent.ADDITIONAL_CLASSPATH_ENTRIES);
if (prop == null || prop.getStringValue() == null || prop.getStringValue().trim().length() == 0) {
return;
}
String[] paths = prop.getStringValue().trim().split(",");
if (paths == null || paths.length == 0) {
return;
}

// get the current set of class path entries - we are going to add to these
List entries = settings.getClassPathEntries();
if (entries == null) {
entries = new ArrayList();
}

// Get all additional classpath entries which can be listed as jar filenames or directories.
// If a directory has "/*.jar" at the end, all jar files found in that directory will be added
// as class path entries.
final class JarFilenameFilter implements FilenameFilter {
public boolean accept(File dir, String name) {
return name.endsWith(".jar");
}
}

for (String path : paths) {
path = path.trim();
if (path.length() > 0) {
if (path.endsWith("*.jar")) {
path = path.substring(0, path.length() - 5);
File dir = new File(path);
File[] jars = dir.listFiles(new JarFilenameFilter());
if (jars != null && jars.length > 0) {
entries.addAll(Arrays.asList(jars));
}
} else {
File pathFile = new File(path);
entries.add(pathFile);
}
}
}

// now that we've appended our additional jars, tell the connection settings about the new list
settings.setClassPathEntries(entries);

return;
}
}

Also, download MC4J libraries patch it with the changed class below and replace it inside JMX plugin after it is built (sincerely as I don’t use maven I don’t know a cleaner way of replacing it prior to build).
Below the changed code for WebsphereConnectionProvider:


/*
* Copyright 2002-2004 Greg Hinkle
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.mc4j.ems.impl.jmx.connection.support.providers;

import org.mc4j.ems.impl.jmx.connection.support.providers.proxy.GenericMBeanServerProxy;

import javax.management.MBeanServer;
import javax.management.j2ee.Management;
import javax.naming.Context;
import javax.naming.NamingException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URI;
import java.security.Security;
import java.util.Properties;

/**
* This Node acts as a connection to a WebSphere(tm) MBean Server (TMX4J based).
*
* @author Greg Hinkle (ghinkle@users.sourceforge.net), January 2004
* @version $Revision: 575 $($Author: ghinkl $ / $Date: 2006-05-21 23:38:53 -0300 (Dom, 21 Mai 2006) $)
*/
public class WebsphereConnectionProvider extends AbstractConnectionProvider {

protected GenericMBeanServerProxy statsProxy;
protected MBeanServer mbeanServer;
private Management mejb;

private static final String MEJB_JNDI = "ejb/mgmt/MEJB";

protected void doConnect() throws Exception {
Context ctx = null;

ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();

Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());

try {

//System.setProperty("jmx.serial.form", "1.0");

/* From a WS admin article
Properties clientProps = new Properties();
connectProps.setProperty(AdminClient.CONNECTOR_TYPE,
AdminClient.CONNECTOR_TYPE_SOAP);
connectProps.setProperty(AdminClient.CONNECTOR_HOST, "localhost");
connectProps.setProperty(AdminClient.CONNECTOR_PORT, "8879");

AdminClient adminClient = null;
try
{
adminClient = AdminClientFactory.createAdminClient(clientProps);
}
catch (ConnectorException e)
{
System.out.println("Exception creating admin client: " + e);
}
*/

Class adminClientClass =
Class.forName("com.ibm.websphere.management.AdminClient", true, this.getClass().getClassLoader());
Class adminClientFactoryClass =
Class.forName("com.ibm.websphere.management.AdminClientFactory");

// TODO GH: LATEST! This works from a SUN VM...
// Autodetect the vm and suggest the correct factory
// Hashtable env = new Hashtable();
// env.put(Context.INITIAL_CONTEXT_FACTORY,
// "com.sun.jndi.cosnaming.CNCtxFactory");
// env.put(Context.PROVIDER_URL, "corbaname:iiop:localhost:2809/NameServiceServerRoot");
//env.put(Context.PROVIDER_URL, "iiop://localhost:2809/NameServiceServerRoot");
// ctx = new InitialContext(env);
//this.mejb = retrieveMEJB(ctx);

/*
Properties orbprops = new Properties();
orbprops .put("org.omg.CORBA.ORBClass", "com.ibm.CORBA.iiop.ORB");
orbprops .put("com.ibm.CORBA.ORBInitRef.NameService",
"corbaloc:iiop:localhost:2809/NameService");
orbprops .put("com.ibm.CORBA.ORBInitRef.NameServiceServerRoot",
"corbaloc:iiop:localhost:2809/NameServiceServerRoot");
ORB _orb = ORB.init((String[])null, orbprops );

org.omg.CORBA.Object obj = _orb.resolve_initial_references("NameService");
NamingContextExt initCtx = NamingContextExtHelper.narrow(obj);
Object objref = initCtx.resolve_str("java:comp/env/ejb/mgmt/MEJB");
ManagementHome home =
(ManagementHome)PortableRemoteObject.narrow(objref,ManagementHome.class);
this.mejb = home.create();
*/

//props.put(Context.SECURITY_PRINCIPAL, connectionSettings.getPrincipal());
//props.put(Context.SECURITY_CREDENTIALS, connectionSettings.getCredentials());

Properties props = new Properties();
URI serverUrl = new URI(connectionSettings.getServerUrl());

if (serverUrl.getScheme().equalsIgnoreCase("http") || serverUrl.getScheme().equalsIgnoreCase("https")) {
System.setProperty("javax.net.debug", "ssl,handshake,data,trustmanager");
//Security.addProvider(new sun.security.provider.Sun());
System.setProperty("java.protocol.handler.pkgs","com.sun.net.ssl.internal.www.protocol");
//System.setProperty("ssl.SocketFactory.provider", "javax.net.ssl.SSLSocketFactory");
props.put(
getConstant(adminClientClass, "CONNECTOR_TYPE"),
getConstant(adminClientClass, "CONNECTOR_TYPE_SOAP"));
} else {
props.put(
getConstant(adminClientClass, "CONNECTOR_TYPE"),
getConstant(adminClientClass, "CONNECTOR_TYPE_RMI"));
}
String username = connectionSettings.getPrincipal();
String password = connectionSettings.getCredentials();
boolean security = ((username != null) && (!"".equals(username)));
if (security) {
props.setProperty(getConstant(adminClientClass, "CONNECTOR_SECURITY_ENABLED"), Boolean.toString(security));
props.setProperty(getConstant(adminClientClass, "USERNAME"), username);
props.setProperty(getConstant(adminClientClass, "PASSWORD"), password);
}

props.put(
getConstant(adminClientClass, "CONNECTOR_HOST"),
serverUrl.getHost());
props.put(
getConstant(adminClientClass, "CONNECTOR_PORT"),
String.valueOf(serverUrl.getPort()));

Method createMethod =
adminClientFactoryClass.getMethod("createAdminClient", Properties.class);

Object adminClient =
createMethod.invoke(null, props);

this.statsProxy = new GenericMBeanServerProxy(adminClient);
this.mbeanServer = statsProxy.buildServerProxy();

//this.mejb = retrieveMEJB(ctx);

// TODO GH: Customize exception and error messages to help
// with typical problems (jsse jars missing, passwords, etc.)
} finally {
Thread.currentThread().setContextClassLoader(contextClassLoader);
}
}

public String getConstant(Class clazz, String name) throws Exception {
Field field = clazz.getField(name);
return (String) field.get(null);
}

// public Management getMEJB() {
// return mejb;
// }

private Management retrieveMEJB(Context ic) {
try {
java.lang.Object objref = ic.lookup(MEJB_JNDI);
// ManagementHome home =
// (ManagementHome)PortableRemoteObject.narrow(objref,ManagementHome.class);
// Management mejb = home.create();
return mejb;
} catch(NamingException ne) {
// ErrorManager.getDefault().notify(ne);
// } catch(RemoteException re) {
// ErrorManager.getDefault().notify(re);
} catch(Exception ce) {
// ErrorManager.getDefault().notify(ce);
}
return null;
}
public MBeanServer getMBeanServer() {
return this.mbeanServer;
}

public long getRoundTrips() {
return statsProxy.getRoundTrips();
}

public long getFailures() {
return statsProxy.getFailures();
}

}

Now, since the changes I made to the JMX plugin still don’t cover adding WebSphere libs to classpath it still necessary to add it manually, so copy the following jars from WebSphere to the Agent lib directory:

  • AppServer/lib/bootstrap.jar
  • AppServer/deploytool/itp/plugins/com.ibm.websphere.v61_6.1.200/ws_runtime.jar
  • AppServer/runtimes/com.ibm.ws.admin.client_6.1.0.jar
  • AppServer/plugins/com.ibm.ws.security.crypto_6.1.0.jar

Now the last part, the JVM that is running your agent needs the server certificate for the SOAP Admin port of your WebSphere installation. If you are using Firefox browse to your server on Admin Port you can check it clicking on the server instance under “Application Servers” and then expanding the Ports element and looking for the “SOAP_CONNECTOR_ADDRESS” entry. It is usually 8880. Double click on the padlock icon located on the bottom right corner, click display certificate then export it using the default format (X.509 Certificate (PEM)). Remember where you saved it for the next step.
Now run the following command (pointing to the JVM that will run your agent):


%JAVA_HOME%\jre\bin\keytool -import -alias somealias -file c:/temp/yourcertificate.crt -keystore %JAVA_HOME%\jre\lib\security\cacerts

Replace the %JAVA_HOME% with your JVM directory (or use the command as is in case the environment variable is set).

Now you are ready to setup the component inside JOPR.
For those that don’t want to build it manually, I’m providing the patched rhq-jmx-plugin-1.1.0.GA.jar attached in this PDF.

Note that the steps cited above for the certificate also applies if you are using IBM Tivoli Monitoring 6.2 (fp1 and onwards) together with a custom agent built using Tivoli Agent Builder. If you miss those steps you’ll see security error messages on the JMX agent log.

30
Jan
09

Why improve development process?

Recently I began to work as a Quality Engineer and one of the first questions that I did was: “Why are you looking for process improvements?”.

The answer was to get the best practicies and spread the knowledge around the company. This answer, at least for me, sounds like: “now I’m working to get the best team performance and it don’t care if a process is CMMI like, PMBOK like, or SCRUM like”.

I understand that assessment in a maturity model like CMMI (you read right: ASSESSMENT, CMMI isn’t a certification program) can be good if the main goal of the appraisal is to do the things in a better way, not only to get a CMMI logo in your bussines card.

Think about it. Process improvment can’t only be a marketing strategy, it’s to get the things done better than we are doing now.