WLST : get runtime data iterating on instances

In the WebLogic console you may find that is difficult to do a fast check on a runtime property for all the configured managed instances of a domain.

Here you’ll find how to do it by using WLST interactively.

Note: this sample was tested with “WebLogic Server 10.3.5.0”.

After loading the environment (. ./setDomainEnv.sh) and running the WLST console (see Oracle WLS 10.3.5 Documentation – Using WLST) you’ll connect to the administrative instance by using the command

connect(username,password,'t3s://myhost:8001')

You’ll collect the managed servers into “serverNames” variable by going to the Domain Config MBean tree:

wls:/MYDOMAIN/serverConfig> domainConfig()
wls:/MYDOMAIN/domainConfig> serverNames = cmo.getServers()

After that you have to go to the Domain Runtime MBean tree, cycle through the servers and get the desired runtime property (in this sample the “Activation Time”):

wls:/MYDOMAIN/domainConfig> domainRuntime()
wls:/MYDOMAIN/domainRuntime/ServerRuntimes> for name in serverNames:
...     print name
...     cd("/ServerRuntimes/"+name.getName())
...     print java.util.Date(cmo.getActivationTime())
...

Tip: (python syntax) the white space before commands inside the “for” cycle are TAB characters. They are needed to tell the Jython interpreter that the commands must be executed inside the “for” cycle. To end the cycle in the last void line press enter without typing the tab…

Tip: Since WebLogic is implemented with Java, all the values are java-type values. To convert the date value into readable format you must use java.util.Date(<date-value>)

To retrieve other attributes of the ServerRuntime you can refer to the MBean documentation WLS 10.3.5 ServerRuntime Attributes and call “cmo.get<attribute>”.

Improvement: do not exit loop if some instance is not responding.

If one instance is down or not responding the loop will exit. To avoid this you can use the try-except python syntax.

for name in serverNames:
    print name
    try :
        cd("/ServerRuntimes/"+name.getName())
        print java.util.Date(cmo.getActivationTime())
    except WLSTException :
        print "ERROR Detected"

Please note that WLSTException is the exception object type returned when the instance is not up. If you want to catch more exception object types you can use the parenthesis syntax: except (WLSTException, NullPointerException) :

Unix shell: loop on a server list and execute interactive commands remotely with ssh

When managing several Unix servers it may be useful to execute some commands remotely looping on them. This can be done in several ways for the simplest case, but you may encounter some problems:

  • If the remote command or the ssh command requires input, the loop created with “cat list.txt | while read SERVER ; do ...” will be interrupted.
  • It may be not possible to execute interactive commands with manually entered input for each server.

The following sample is useful when you need to execute commands on a list of servers and you want to manually enter input data on each of them, but automating the connect-disconnect commands.

# Open file descriptor 3 (fd #3) for reading with list.txt
exec 3< list.txt

# Read from fd #3 until end of file
while read SERVER <&3 ; do
    echo Executing on $SERVER ...
    ssh -t $SERVER script_with_input.sh
    echo
done

# Close input for fd #3
exec 3>&-

The concept behind the script is to open a different file descriptor from the standard input(0) / output(1) / error(2) ones by using exec 3< list.txt. To read data from opened file I use the following syntax: read SERVER <&3. This command reads one value from each line of the file and puts it into "SERVER" variable. It can be expanded for reading multiple values (space delimited on each line of list.txt) by using read VAR1 VAR2 VAR3 <&3. The file descriptor must be closed by using exec 3>&-.

The last detail that gives "full power" to this script is the "-t" option in the ssh command: it asks ssh command to allocate pseudo-tty to allow input on the remote server (see ssh man page)

If you want to read only some lines from list.txt or you want to open the file descriptor against a pipe (i.e. input taken from other commands output), in ksh shell, you have to change the open-file syntax by appending &0 to the exec command. This will tell to open input from the pipe output. For example this will read from list.txt only servers with "ab" in the name:

cat list.txt | grep "ab" | exec 3<&0

This will not work in bash shell because the exec 3<&0 command is executed in a subshell. See Vidar’s Blog : Why Bash is like that: Subshells for an explanation.

In bash shell you can do it with a temporary file ($$ will use the PID of the current process to guarantee the file to be unique):

TMP_FILE=_tmp.$$
cat list.txt | grep "ab" > $TMP_FILE

# Open file descriptor 3 (fd #3) with TMP_FILE
exec 3< $TMP_FILE

Remember to remove the temporary file when finished to read from it.

To debug the current file descriptors you can use the command in your scripts:

lsof -a -p $$ -d0,1,2,3

Note that -d0,1,2,3 is the sample list of descriptors to print out.

Here you'll find a good site with samples on the various types of Bash I/O Redirection.

Another article that explains how redirection works in bash is Bash One-Liners Explained, Part III: All about redirections.

Notes:

Script tested on Linux 2.6.18-274.el5 / RedHat 5.7, HP-UX B.11.11, with bash, ksh and nsh shells.

The script_with_input.sh is the remote interactive command that must be present on the remote server.

Get the device ID in iOS 7.0 and earlier

In my previous article Get the device ID in iOS 6.0 and earlier I used [[UIDevice currentDevice] uniqueIdentifier] to retrieve a unique identifier for the user device when the current iOS version is 5.x or older.

But uniqueIdentifier method cannot be used anymore on Apple App Store apps. As mentioned by other developers (see MKStoreKit discussion on uniqueIdentifier and Stackoverflow identifierforvendor discussion) Apple added an automatic check which rejects all apps using this method. Moreover in iOS7 Apple removed uniqueIdentifier method.

Unfortunately Apple forces applications to remove the ability to get the UDID for privacy reasons. A universal identifier able to identify the device without requiring authorization from the user may allow to collect usage information from different applications and relate them to build a user profile based on applications usage (for example a third party vendor may buy informations from different app vendors…).

The following implementation avoids using uniqueIdentifier method in iOS 5.x or below.

  • For iOS6.0 or later I use the identifierForVendor new method.
  • For iOS5.x or below I use CFUUIDCreate method in association with storage into NSUserDefaults.

The second method will not ensure to have a unique identifier if the application is deleted and reinstalled.

You have to replace the @"app identifier" with your app identifier. The code uses ARC for memory management.

// Get the device id on iOS7.0 and previous versions
- (NSString *) getDeviceId {
    NSString *deviceID;
    UIDevice *device = [UIDevice currentDevice];
    if ([UIDevice instancesRespondToSelector:@selector(identifierForVendor)]) {
        deviceID = [[device identifierForVendor] UUIDString];
    } else {
        // In iOS5.x or older 'identifierForVendor' is not available
        deviceID = [[NSUserDefaults standardUserDefaults] objectForKey:@"app identifier"];
        if (!deviceID) {
            CFUUIDRef uuidRef = CFUUIDCreate(NULL);
            CFStringRef uuidStringRef = CFUUIDCreateString(NULL, uuidRef);
            deviceID = [NSString stringWithString:(NSString *) CFBridgingRelease(uuidStringRef)];
            CFRelease(uuidRef);
            [[NSUserDefaults standardUserDefaults] setObject:deviceID forKey:@"app identifier"];
            [[NSUserDefaults standardUserDefaults] synchronize];
        }
    }
    return deviceID;
}

Tip: CFUUIDCreate and CFUUIDCreateString functions are Core Foundation functions that follows the Create Rule. So the uuidRef must be released with CFRelease whereas the uuidStringRef ownership is transferred to ARC with CFBridgingRelease and CFRelease is not needed.

List Oracle Service Bus EndPoints in WLST

If you administer or need to support an Oracle Service Bus installation, you may need to do a fast check on all the systems that are “connected” to the service bus.

In this post I show a simple WLST script that allows to extract all the EndPoints.

A very little theoretical introduction

In Oracle Service Bus (Formerly also known as “BEA AquaLogic Service Bus”) every remotely connected service is configured as “Business Service”. The Business Service configuration usually contains the information on where is the service in the “EndPoint URI” configuration field.

A good tutorial giving infos on Business Services, endpoints, and other basic concept of Oracle Service Bus is here: How to Provision a Service in Oracle Service Bus.

The script

The script was tested on “AquaLogic Service Bus 2.6” and on “Oracle Service Bus 11g (11.1.1.4)”. See below for other tips on the script.

from com.bea.wli.sb.management.configuration import SessionManagementMBean
from com.bea.wli.sb.management.configuration import ALSBConfigurationMBean
from com.bea.wli.sb.management.configuration import BusinessServiceConfigurationMBean
 
from com.bea.wli.sb.util import EnvValueTypes
from com.bea.wli.config import Ref
from com.bea.wli.sb.util import Refs
from xml.dom.minidom import parseString
 
connect(userConfigFile='<userConfigFile_location>', userKeyFile='<userKeyFile_location>', url='t3://<myserver_ip>:<myserver_port>')
domName=cmo.getName()
domainRuntime()
sessionMBean = findService(SessionManagementMBean.NAME,SessionManagementMBean.TYPE)
sessionName="WLSTSession"+ str(System.currentTimeMillis())
sessionMBean.createSession(sessionName)
alsbSession = findService(ALSBConfigurationMBean.NAME + "." + sessionName, ALSBConfigurationMBean.TYPE)
alsbCore = findService(ALSBConfigurationMBean.NAME, ALSBConfigurationMBean.TYPE)
allRefs=alsbCore.getRefs(Ref.DOMAIN)
for ref in allRefs.iterator():
    typeId = ref.getTypeId()
    if typeId == "BusinessService" :
        name=ref.getFullName()
        uris=alsbSession.getEnvValue(ref, EnvValueTypes.SERVICE_URI_TABLE, None)
        print name
        print uris
        print

The connection is performed by using user security files that must be created with the storeUserConfig WLST command. Change <userConfigFile_location>, <userKeyFile_location>, <myserver_ip>, <myserver_port> with the current values.

JSON WebServices from iOS in Objective-C

In this article I present an effective way to call a webservice method from an iOS device.

Input and output are encoded to and decoded from a widely used format: JSON. For this I use the NSJSONSerialization class included in iOS starting from version 5.0.

First of all prepare input arguments by using an NSDictionary. This is an initialization valid for a fixed number of input arguments. The sample has 3 input arguments that may be any of the allowed NSJSONSerialization types (see NSJSONSerialization documentation).

    NSDictionary *inputData = [NSDictionary dictionaryWithObjectsAndKeys:in1, @"Input1", in2, @"Input2", in3, @"Input3", nil];

The conversion to a JSON string is a two step process . First to a binary format (NSData) by using dataWithJSONObject:options:error:, then to the JSON NSString. The error handling is not performed in this sample.

    NSError *error = nil;
    NSData *jsonInputData = [NSJSONSerialization dataWithJSONObject:inputData options:NSJSONWritingPrettyPrinted error:&error];
    NSString *jsonInputString = [[NSString alloc] initWithData:jsonInputData encoding:NSUTF8StringEncoding];

the synchronous WebService call , is a HTTP POST call to the server.

    NSURL *url = [NSURL URLWithString:@"http://host:port/Service.asmx/WebService1"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setHTTPMethod:@"POST"];
    [request setValue:@"application/json; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
    [request setHTTPBody:[jsonInputString dataUsingEncoding:NSUTF8StringEncoding]];
    NSURLResponse *response;
    NSError *err;
    NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&err];

The execution will block on sendSynchronousRequest:returningResponse:error: until the full response is read from the server.

The JSON (binary) response data from http call can be converted into the corresponding Objective-C object by using:

    // Parse response
    id jsonResponseData = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:nil];

I use ‘id‘ reference because usually we do not know which is the object type returned from the server. Here the sample may be considered completed, but I want to add additional tips to interpret the output and detect error messages that may come from the server.

Even if we know the type returned bye the server it is a better choice to check it because the server may return an error in a JSON response which will be encapsulated in a different object type.

The .NET server on which I tested this sample code always returns a collection of name/value pairs, decoded by NSJSONSerialization into an NSDictionary Objective-C object. This collection always contains a value named “d”. So I check for it and extract the value of “d”:

    NSDictionary *jsonResponseDict;
    if ([jsonResponseData isKindOfClass:[NSDictionary class]]) {
        jsonResponseDict = jsonResponseData;
    } else {
        // Error-handling code
    }
    jsonResponseData = [jsonResponseDict objectForKey:@"d"];
    if (jsonResponseData == nil) {
        // Server may have returned a response containing an error
        // The "ExceptionType" value is returned from my .NET server used in sample
        id jsonExceptioTypeData = [jsonResponseDict objectForKey:@"ExceptionType"];
        if (jsonExceptioTypeData != nil) {
            NSLog(@"%s ERROR : Server returned an exception", __func__);
            NSLog(@"%s ERROR : Server error details = %@", __func__, jsonResponseDict);
        }
    }

If the server does not return expected values you can debug by logging jsonResponseDict value.

Tip: By using “__func__” in NSLog you can easily track the class/method where logged message was written.

From now on you can iterate by examining the jsonResponseData object type and extracting data from it. JSON definition declares only two collection types: “A collection of name/value pairs”, which is mapped to NSDictionary, and “An ordered list of values” which is mapped to NSArray. You can iterate on items of these collections and extract basic types (NSString, NSNumber).