Pub Websphere Application Server Administration Using Jython
Pub Websphere Application Server Administration Using Jython
Visit ibmpressbooks.com
for all product information
SOA Governance
Brown, Laird, Gee, Mitra
ISBN: 0-13-714746-5
Executing SOA
A Practical Guide for the
Service-Oriented Architect Dynamic SOA and BPM
by Norbert Bieberstein, Robert G. Laird, Fiammante
Dr. Keith Jones, and Tilak Mitra ISBN: 0-13-701891-6
ISBN: 0-13-235374-1
In Executing SOA, four experienced SOA
implementers share realistic, proven, “from-the-
The Greening of IT
trenches” guidance for successfully delivering the
Lamb
largest and most complex SOA initiative.
ISBN: 0-13-7155083-0
This book follows up where the authors’ bestsell-
ing Service-Oriented Architecture Compass left
off, showing how to overcome key obstacles to
successful SOA implementation and identifying Enterprise Master
best practices for all facets of execution— Data Management
technical, organizational, and human. Among Dreibelbis, Hechler, Milman,
the issues it addresses include introducing a Oberhofer, van Run, Wolfson
services discipline that supports collaboration and ISBN: 0-13-236625-8
information process sharing; integrating services
with preexisting technology assets and strategies; Enterprise Java Programming
choosing the right roles for new tools; shift- with IBM WebSphere,
ing culture, governance, and architecture; and Second Edition
bringing greater agility to the entire organizational Brown, Craig, Hester, Pitt, Stinehour,
lifecycle, not just isolated projects. Weitzel, Amsden, Jakab, Berg
ISBN: 0-321-18579-X
Listen to the author’s podcast at:
ibmpressbooks.com/podcasts
Deployment
Server and Advanced
Configuration
Administration
Using Jython
Roland Barcia, Bill Hines, Tom Alcott, and Keys Botzum
IBM Press
Pearson plc
Upper Saddle River, NJ • Boston • Indianapolis • San Francisco
New York • Toronto • Montreal • London • Munich • Paris • Madrid
Cape Town • Sydney • Tokyo • Singapore • Mexico City
Ibmpressbooks.com
IBM Press offers excellent discounts on this book when ordered in quantity for bulk purchases or special
sales, which may include electronic versions and/or custom covers and content particular to your business,
training goals, marketing focus, and branding interests. For more information, please contact:
International Sales
[email protected].
ISBN 978-0-13-700952-7
All rights reserved. This publication is protected by copyright, and permission must be obtained from the
publisher prior to any prohibited reproduction, storage in a retrieval system, or transmission in any form or
by any means, electronic, mechanical, photocopying, recording, or likewise. For information regarding
permissions, write to:
ISBN-13: 978-0137009526
ISBN-10: 0137009526
Text printed in the United States on recycled paper at R.R. Donnelley in Crawfordsville,
Indiana.
First printing October 2009
Acknowledgments xxi
About the Authors xxiii
Chapter 1 Introduction 1
Chapter 2 Jython Fundamentals 5
Chapter 3 Jython Statements 27
Chapter 4 Jython Classes 63
Chapter 5 Jython Modules 87
Chapter 6 wsadmin 113
Chapter 7 Introduction to Admin Objects 129
Chapter 8 The AdminConfig Object 149
Chapter 9 The AdminControl Object 167
Chapter 10 The AdminApp Object 185
Chapter 11 The AdminTask Object—Server Management 199
Chapter 12 Scripting and Security 241
Chapter 13 Databases and Authorization 277
Chapter 14 Messaging 301
Chapter 15 Administering Web Services 345
Chapter 16 Version 7.0 Scripting Libraries 393
Index 449
xi
Acknowledgments xxi
About the Authors xxiii
Chapter 1 Introduction 1
Why Is This Book Necessary? 1
About the Websphere Application Server Product 2
This Book and Its Organization 2
xiii
Security 310
Enabling Bus Security 311
Example: Enabling Bus Access Security 312
Example: Enabling Transport Security 314
Reference Section 317
Creating Message Buses 317
Deleting a Bus and Bus Components 326
Modifying a Bus and Bus Components 329
Displaying Buses and Bus Components 334
Bus Security 337
Summary 344
Index 449
Although it has been stated before, it bears repeating: Books do not come together without a great
deal of time and effort. It is probably a good thing that we don’t realize just how much time and
effort we are committing to when we first sign up for a task of this size. Nor does a book make it
through the process without help and support from an entire community. It is an enormous under-
taking, and we could not have done it without a great deal of assistance.
First, we would like to thank IBM for providing its amazing WebSphere Application Server
product. It is function-rich and contains so many features that it is difficult for any one person to
know all of its capabilities. If it were not an important and valuable product, there would be little
need for a book like this.
We would also like to thank our colleagues for their continued support during the time
required to pull all of this information together. We would especially like to thank our reviewers
who made time in their busy schedules to help make this a better book: Ty Shrake, Bill
Holtzhauser, Mike Shenhouse, Rich Montjoy, Peter Neergaard, Peter Jakab, Preston Law, and
Gale Botwick.
Bob would also like to thank the management at IBM, especially Wayne Sholtes, for pro-
viding the kind of environment that allows and encourages excellence and outstanding teamwork.
Thank you also for making this such a wonderful place to work.
And last, but not least, we want to be sure to thank the IBM Press team that helped us
through the challenge of driving this book to completion. Thank you to Katherine Bull, Pearson’s
acquisition editor, Steven Stansel, IBM’s program manager for IBM Press, and most of all,
Kendell Lumsden, our development editor. Your perseverance, dedication, professionalism,
encouragement, and gentle guidance helped us immensely.
xxi
Bob Gibson is an Advisory Software Engineer who has more than 30 years of experience in
numerous software-related roles at IBM, including Architect, Developer, Tester, Instructor, and
Technical Support. For the last 10+ years, he has been working with IBM’s WebSphere Applica-
tion Server and is currently a team leader for the technical support group responsible for this
amazing product. He holds both a Bachelor of Science degree in Engineering Science and a Mas-
ter of Science degree in Computer Science from the University of Virginia.
Arthur Kevin McGrath has worked for Contract Engineers in a variety of positions since 1983.
Kevin has lectured internationally on programming languages, management, and quality assur-
ance subjects. He has authored and co-authored courses on programming, management, and
quality topics and trained new instructors. Kevin received a BA in History in 1970 from Dowling
College.
Noel J. Bergman is a Consultant and Contact Instructor. He has over 25 years of experience, 20
of which are with enterprise class distributed computing systems. Noel’s areas of expertise
include Java, JavaEE, SOA, WebSphere Application Server, Enterprise Service Bus, Process
Server, and Portal, including both development and administration. Noel is a member of The
Apache Software Foundation and vice president of the Apache Incubator. In his spare time, Noel
enjoys hanging out on coral reefs with old friends.
xxiii
Introduction
1
Jython is an implementation of the Python programming language that executes on a Java Virtual
Machine.
If you will, think of WebSphere as a healthy, bio-diverse, coral reef, rich in wildlife. In this
book, we teach you to master the core concepts necessary to explore the reef and introduce you to
many of our favorite reef denizens. Afterward you will be prepared to explore more of the reef on
your own, discovering for yourself more of the richness that IBM has built into WebSphere. Once
you’ve mastered the core concepts, self-discovery becomes important; each new product layered
on WebSphere (for example, WebSphere Enterprise Service Bus and WebSphere Process Server)
and each new version adds more and more scripting capabilities. So in the way of the ancient
parable, we will not only give you some fish, but also teach you to fish.
We hope that you enjoy the book...and the journey.
—Bob, Kevin, and Noel
2
http://www.IBM.com/software/webservers/appserv/was/library/.
3
Python is a programming language, and Jython is an implementation of that language. We won’t worry about
this distinction and will continue to refer to it as the Jython programming language for simplicity’s sake.
4
Please note, however, that the version of Jython that is provided and supported by the wsadmin utility
does not include all of the features and facilities available in the “latest and greatest” version of Python. So,
keep this in mind as you are writing your wsadmin scripts.
5
http://www.IBMPressBooks.com/title/9780137009527.
Chapter 10, “The AdminApp Object,” covers the AdminApp scripting object in detail. This
object is used to list, view, install, uninstall, and modify AppServer applications. As such, this
chapter explains how to perform these operations using the AdminApp object methods.
Chapter 11, “The AdminTask Object—Server Management,” is where we begin the
description of some of the AdminTask scripting object methods. The AdminTask object is enor-
mous. Additionally, as is explained in this chapter, the methods included vary based upon a num-
ber of factors. The scope (as in breadth and depth) of this object is huge. It includes hundreds and
hundreds of methods. As such, there is no way for it to be adequately covered in a single chapter.
In fact, Chapters 12 through 15 largely deal with AdminTask object methods. That’s not all they
cover, but it is at the core of each of these chapters.
Chapter 12, “Scripting and Security,” deals with scripting and security. As such, it
addresses a number of security-related items. Anyone who needs to administer an enterprise
application server should be familiar with the topics described in this chapter.
Chapter 13, “Databases and Authorization,” covers databases and authorization. Even
though the configuration and administration of database-related resources can seem overwhelm-
ing, this chapter presents these topics in a simple fashion. You discover the easy way to configure
the database-related resources (“the plumbing,” if you will) required for interactions with a data-
base. These explanations include descriptions about the properties you can control and those that
are automatically configured for you. The chapter then moves into exploring and manipulating
the more complicated aspects and properties of database-related resources and then finishes with
a detailed explanation of commonly used database and authorization AdminTask methods.
Chapter 14, “Messaging,” is all about messaging. This complicated topic is explored in
detail but explained simply. The chapter starts by discussing messaging basics and then adds a
discussion of security. It ends by explaining the more commonly used messaging AdminTask
methods in great detail.
Chapter 15, “Administering Web Services,” is all about Web services. So what exactly are
Web services? The IBM online documentation has this to say about Web services:
Web services are self-contained, modular applications that can be described, published,
located, and invoked over a network. They implement a services-oriented architecture
(SOA), which supports the connecting or sharing of resources and data in a very flex-
ible and standardized manner. Services are described and organized to support their
dynamic, automated discovery and reuse.
This chapter describes Web services and explains how they should be managed. It also discusses
policies, policy sets, bindings and even the use of keystores for the security-related aspects of
Web services.
Lastly, Chapter 16, “Version 7.0 Scripting Libraries,” is about the scripting object libraries
that are included in version 7 of the AppServer product. These Jython libraries demonstrate some
techniques for the management and manipulation of AppServer entities. Some people find the
programming interface provided by some of the wsadmin scripting objects difficult to under-
stand and even harder to work with. These libraries present another approach and provide meth-
ods that use simpler parameter lists to some of these scripting object methods.
Jython
Fundamentals
Even though this book isn’t going to be a complete introduction to “Programming with Jython,”
we provide enough detail about the language that someone familiar with programming can learn
its syntax and semantics. What does this opening quote mean for WebSphere Application Server
administrators? It has a few implications. The fact that Jython is an implementation of Python
means that Jython is based on a solid and well-designed language. The fact that it is implemented
in Java means that it fits in seamlessly with the WebSphere product, which is also implemented
in Java.
What does this mean for us? Simply put, it means that we can quickly and easily write
scripts that allow us to access and manipulate our WebSphere Application Server environment.
One of the biggest implications of this fact is that while a script is being written, the developer
can interact with a WebSphere configuration or environment to validate their understanding of
the situation. This allows scripts and commands to be tested as they are developed and demon-
strates an important strength of interpreted scripting languages, sometimes called rapid software
prototyping.
This book includes numerous examples of interactive wsadmin sessions that demonstrate a
particular subject. We encourage you to have an interactive wsadmin session available as you are
reading this book. Our hope is that you will try things out and reinforce your understanding of the
topics being covered, as well as the various aspects of the scripting objects and the interface being
explained.
One thing to remember, though, is that there are lots of places where you can find Jython
and Python code examples (such as in books or on the Internet). It is important to note that the
“latest and greatest” version of Python has language features that are not part of Jython. Addi-
tionally the “latest and greatest” version of Jython might, in fact, have features that are not part of
the version of Jython provided with the WebSphere product you are using. That said, should you
find code in a book or on the Internet, be sure to test it, perhaps even using an interactive wsadmin
session, to ensure that it does what you expect.
Introduction
A scripting interface for the WebSphere Application Server environment has been available for
numerous versions of the product. For example, versions 3.5 and 4.0 of the application server
product included the WebSphere Control Program (WSCP), a command-line scripting interface
that could be used to administer the application server using the Jacl scripting language.
Version 5.0 introduced significant changes in the way product configuration was per-
formed. For this and other reasons, WSCP was replaced by wsadmin as the scripting tool for the
application server product. At this point, Jacl was the only supported scripting language.
Version 5.1 introduced Jython as an alternative scripting language. Support for both Jacl
and Jython continued and improved through version 6.0 of the product. Jython is now the pre-
ferred scripting language and as such is the topic of discussion for this book.
With the implementation of numerous alternative languages for the WebSphere Applica-
tion Server Java Virtual Machine (JVM), you may wonder what sets Jython apart. A scripting lan-
guage that is written in Java and that therefore can be executed on the JVM boasts many
advantages. For one, Jython allows for close interaction between the administrative scripts and
the application server environment. Additionally, Jython scripts can easily access Java (and there-
fore WebSphere Application Server) libraries, objects, properties, and resources. In the following
sections, we look at some of the elements that comprise Jython’s productivity advantage—
namely data types and statement types.
NOTE The examples in this book were written for and tested with the latest version of
the WebSphere Application Server product generally available at the time of this book’s
writing (versions 6.1.0.23, and 7.0.0.3). Some issues might be encountered using an earlier
version of wsadmin or the application server product. Should this occur, please check your
version and consider upgrading to the latest available version. Details about the recom-
mended versions of the product are available at http://IBM.com/support/docview.wss?
rs=180&uid=swg27004980.
Data Types
Computer programs are tools. Like any other tool, every program is designed for a specific job.
To build useful programs, we must be able to describe, in precise detail, what the computer needs
to do and how it is to be done. Jython is no exception. It was designed to have a simple syntax that
is easy to read, understand, and develop. After you’ve had a chance to work with some scripts,
you will certainly agree.
One of the first “programs” to be demonstrated in many introductory programming classes
displays a simple message (such as “Hello world”) and terminates. Unfortunately, this kind of
program isn’t very exciting given that it only does one thing. Programs don’t get interesting until
they are able to manipulate information. Let’s take a look at the kind of information, or data,
Jython programs or scripts are able to manipulate.
Numbers
Jython programs can work with integers, floating point values, and even complex numbers.1
Plain integers have values that range from -2147483648 to 2147483647. Long integers are indi-
cated with an “L” suffix,2 and are able to represent integer values in an almost unlimited range
(subject to the memory limitations of the computer being used). Floating point values are repre-
sented using the IEEE Standard for Binary Floating-Point Arithmetic (ANSI/IEEE Std 754-
1985), which allows at least eight significant digits and an exponent from approximately -300
through 300.
Jython represents complex numbers using two floating point numbers for the real and imag-
inary portions of the value. Complex numbers can be written using either a “j” or “J” suffix (note
that 1J is the same as 1j). Complex numbers with a non-zero real component are written as
(1.25+3.14j), where the first floating point value represents the real portion of the complex num-
ber and the second represents the imaginary portion. Using the complex (real, imaginary) func-
tion3 is another option for creating complex numbers. Listing 2.1 shows an example of how
complex numbers are written.
1
Why one might want to use complex numbers in the administration of a WebSphere Application Server is
beyond us.
2
Because it is all too easy for human readers to misinterpret a lowercase L suffix as a digit (1), you are
strongly encouraged to avoid the use of the lowercase L suffix for long integer values.
3
Functions are described and discussed in Chapter 3, “Jython Statements.”
Strings
One of the most frequently used data types in administrative scripts is the string, which is an
immutable4 sequence of zero or more characters. String literals are designated by enclosing the
characters in matching single or double quote characters. Short string literals generally have
the beginning and ending quote characters on the same line of text and are allowed to contain
the quote character that wasn’t used to start and end the string. Let’s take a look at some sample
string literals in Table 2.1.
’’ Yes Empty strings are valid, and either single or double quote charac-
ters may be used.
’0’ Yes Strings containing a single character are also valid. Note, however,
that a string containing digits is still a string and not a number.
’Oops!” No The starting and ending quote characters must be the same.
”Don’t” Yes Matching starting and ending (double) quote characters, with the
string containing an embedded single quote character.
’”Jython”’ Yes Matching starting and ending (single) quote characters, with the
string containing embedded double quote characters.
’He ‘ “won’t” Yes A nice feature of string literals in Jython is the fact that adjacent
‘ go’ string literals separated only by whitespace (space and/or tab char-
acters) are automatically concatenated. The delimiting whitespaces
are not included in the created string.
In addition to short strings, Jython has something called long strings. Long strings are
enclosed in matching pairs of three identical (single or double) quote characters and are generally
referred to as triple-quoted strings. These are called long strings because unlike short strings, the
starting and ending triple-quote sequences don’t have to be on the same line (at least in an input
file). This allows long strings to contain newline characters that will become part of the string.
For example, the long string shown in Listing 2.2 is possible in a Jython source file.
4
Immutable simply means that the values in question are not allowed to be changed; they must be replaced.
The usefulness of this type of string will become abundantly clear the first time you create a
multi-line message and want the message text to be aligned in a particular way. Triple-quoted (long)
strings are ideal for this. You will find them used throughout the scripts provided with this book.
Regardless of the type, sometimes strings must contain special characters. The syntax used
to identify these special characters is called an escape sequence. Escape sequences begin with the
backslash (\) character, and are followed by one or more characters (depending on the special
character to be represented). Table 2.2 identifies the character (or types of characters) that could
be represented using each escape sequence.
\\ Backslash
\’ Single quote
\” Double quote
5
Remember that even though these escape sequences require two or more characters, each represents an
individual character in the actual string. For example, \\ actually represents a single character.
\ddd Character with the specified octal value, where ddd are three octal digits (that
is, digits in the range 0–7 inclusive)
\xhh Character with the specified hexadecimal value, where hh are two hexadeci-
mal digits (that is, digits in the range 0–9 or the letters ‘A’..‘F’ or ‘a’..‘f’
where the letters are used to represent values from 10–15).
Additionally, if a string in an input file6 has a backslash newline sequence (that is, if the last
non-blank character on the line is a backslash \), the string is allowed to span multiple lines. The
newline character is ignored, and the string is created as though the backslash and the newline
were not present. Listing 2.3 demonstrates this more clearly.
The input file (string.py, as seen on lines 2–4) shows that the string spans multiple lines
and contains the backslash newline sequence. The generated output (on line 8) shows that the
string contains neither the backslashes nor the newline characters found in the input file. How-
ever, the leading spaces are present in the output.
6
The distinction is made that these strings may occur in an input file because this construct is not supported
in an interactive wsadmin session.
Additional details about strings, specifically the use of string methods, are discussed in
Chapter 4, “Jython Classes,” after we’ve had a chance to discover objects and methods.
Raw Strings
Is there an easy way to tell Jython not to interpret the backslash character as an escape sequence
indicator? Yes—you would simply add an ‘r’ prefix to the string literal. For example, r’\n’ is a
two-character literal string, with the first character being a backslash and the second being the let-
ter ‘n’. Without the raw string prefix (that is, where ‘r’ immediately precedes the string literal),
‘\n’ is recognized as a single character representing a “newline” (the ASCII character with the
ordinal value of 10).
Be careful, though—the presence of the ‘r’ prefix is not simply an indication to Jython to
leave the backslash alone. It just tells Jython to interpret the backslash and the character that fol-
lows differently. This means that r’\’ is NOT a valid sequence. If you really want a single charac-
ter backslash string, use ‘\\’ instead. Raw strings are particularly useful for regular expressions
and fully qualified file names where the backslash is used as a directory delimiter (for example,
on the Windows® operating system).
Tuples
In addition to strings, Jython provides for an immutable sequence of heterogeneous values called
a tuple (see Table 2.3). A tuple is an ordered sequence of values enclosed in parentheses and sep-
arated by commas.
() An empty tuple.
(1,) This is the proper syntax for a tuple containing a single element (note
the presence of the comma).
(,1) This is not a valid tuple and will cause a syntax error.
The only differences between strings and tuples are the following:
1. The syntax (string values start and end with matching quotation marks, and tuples start
and end with parentheses).
2. The values that may be present in the sequence (a string may only contain individual
characters, whereas a tuple can contain other values such as strings, tuples, and lists).
Lists
Lists, in Jython, are modifiable sequences of heterogeneous items. A list is identified by enclosing
items, or elements, in square brackets (’[‘ and ’]’). One of the biggest differences between lists
and other sequence types is the fact that a list may be dynamically modified. Table 2.4 shows
some valid and invalid lists.
[] An empty list.
[1] This list contains only 1 value. Note that unlike a tuple containing a
single value, a trailing comma is not required.7
[,1] This is not a valid list and will cause a syntax error exception.
We see more details and examples of lists and how they can be created, used, and modified
in Chapter 4.
7
Pease note, though, that how the value in brackets is interpreted is based on where it occurs.
8
It is also quite common to process all of the elements of a sequence in order. We see how this is done a bit
later.
sequence. The syntax used to reference an element of a sequence using an index is to surround the
index value in square brackets.9 The examples in Table 2.5 show how indexing can be used to
access an element of a sequence.
(“Testing”,1,2,3 Tuple ‘testing’ The tuple has five elements (the index
,’testing’)[4] values for which are 0 through 4 inclu-
sive). So the index for the last element
is one less than the number of elements
in the sequence.
Sometimes it is more convenient to access the elements at, near, or relative to the end of a
sequence. In Table 2.5, we saw how the last element of a sequence can be accessed using the
length of the sequence minus 1. Jython conveniently allows negative indices to be used to access
elements relative to the end of the sequence. So, the last element of a sequence can be accessed
using an index of -1, and the penultimate element can be accessed using an index of -2, and
so on.
Table 2.6 shows some valid and invalid negative index values. Make special note of line 4
(”[‘Bob’][0][1]”), where a list containing a single string has two indexes provided to directly
access an individual character of the string.
9
Unfortunately some people, especially those for whom this syntax is a bit new, find it a little confusing.
This is especially true when an index (in square brackets) is used to identify a particular element of a list,
which also uses square brackets to identify elements of a list. Try to remember that a single numeric value
in square brackets might be an index.
Dictionaries
Another powerful data type that exists within Jython is the dictionary, which is especially useful
when data is not best represented as a sequence. For situations where some unique key can be
used to identify a particular value, dictionaries are likely to be the data structure of choice. Each
item within a dictionary is defined as a key/value pair. A key may be of any immutable type
(which excludes lists as a key) and is used as an index to access or retrieve the associated value,
which can be of any data type supported by Jython.
Dictionary literals are enclosed in curly braces and have the key separated from the value
by a colon ’:’. Multiple dictionary elements (that is, key/value pairs) are separated by commas.
Listing 2.4 shows how to define a multi-valued dictionary literal, as well as how to access an indi-
vidual entry using the key ’spam’ to retrieve the associated value.
NOTE Just in case you’ve been wondering about the topics used in some of the
examples, the Python tutorial available at http://docs.python.org includes the following
admonition: “By the way, the language is named after the BBC show “Monty Python’s Fly-
ing Circus” and has nothing to do with nasty reptiles. Making references to Monty Python
skits in documentation is not only allowed, it is encouraged!”
Literals (Constants)
Whenever a fixed value is used, be it an integer, a floating point value, or a string, it is simply a
representation of the value of a particular data type. We have already seen examples of literals
(0, 3.14159, ’testing’, and []), and our scripts are likely to contain others. Up to this point,
almost all of the example Jython code we have seen could only make use of these literal or con-
stant values.
a1a Yes Begins with a letter and is composed of letters and digits.
_ Yes Valid, but not very descriptive. It is far too easily overlooked and
therefore is not recommended as a variable name.10
One of the ongoing challenges with programming is the choice of selecting reasonable, and
hopefully intuitive, names for variables. Though a particular variable name makes sense to you while
the program, or script, is being written, it might not resonate with someone else or even with you in
the months to come. It is also important to remember that a long variable name is not always best.
Keywords
There are some identifiers, however, that should not be used as variable names. These identifiers
have a specific meaning and are either reserved for use by Jython or have a special meaning to
wsadmin. Jython reserved words, or keywords, cause syntax errors if you try to use them inappro-
priately. Table 2.8 lists these special identifiers in alphabetical order.
In addition to these special identifiers, another exists that is used to indicate that a variable
has “no value.” This special identifier is None. Interestingly enough, only one None object exists.
Every reference to None within a script will be to the same object that has this special value. If the
result of an expression is None, this value is evaluated as false.
Variables
Up to this point, we’ve used literals in the examples. This is because we had yet to describe vari-
ables. Now that we know what a variable is and how it can be named, let’s learn how to define a
variable and give it a value.
Variables are declared, or defined, using an assignment statement. The syntax of an assign-
ment statement is that a variable name is followed by an equal sign ’=’, which is then followed
by the value to be given to the variable. Table 2.9 shows some example assignment statements.11
10
In fact, when wsadmin is being used in interpretive, or interactive, mode, this variable holds the value of
the last printed expression. It is unlikely that ‘_’ as a variable name would be a good choice.
11
Even though the whitespace around the equal sign and operators is not required, examples herein use
whitespace for readability.
and break def else exit** from import lambda pass raise while
as* class del except finally global in not print return with*
rhyme = ( 1, 2, ‘buckle my shoe’ ) rhyme A three element tuple containing two integers and a string.
result = None result The ”special” value, noted earlier, which is used to assign a
”nothing”, or non-value to a variable.
12
Keywords flagged with an asterisk are (or will eventually become) keywords in Python. However, because changes to Python eventually find their way into
Jython, it would be best to not use these identifiers in your Jython scripts. Those flagged with a double asterisk aren’t really keywords but are “special” commands
that are recognized by wsadmin when it is being used in interactive mode. Therefore, they are also poor choices for variable names in your scripts.
17
From the Library of Lee Bogdanoff
18 Chapter 2 Jython Fundamentals
Some programming languages require that when a variable is declared, its data type is also
identified. This means that for these programming languages, the data type of a variable is fixed,
and the variable can only be assigned values matching this data type. This is not the case with
Jython. Jython variables do not have a fixed type and may be assigned any value. In fact, you can
assign a variable an integer value and then later assign that same variable a string or even a dic-
tionary value. It just doesn’t matter (at least not to Jython).
Expressions
Everyone should be familiar with arithmetic expressions, the most common of which have a
value, followed by an operator followed by an expression. Table 2.10 shows some expressions,
most of which should be familiar to you.
Addition + 1 + 2 3
Subtraction - 2 - 3 -1
Multiplication * 3 * 4 12
Division / 20 / 4 5
Exponential ** 2 ** 3 8
Some of these operations may warrant additional explanation. First, it is important to note
that if operands do not share a common numeric data type, the values are converted to a common
type before the operation is performed. Table 2.11 shows some conversion examples.
1 + 2L 3L The plain integer (1) is converted to a long integer before the addition
is performed.
8.0 / 9 0.888. The denominator is converted to a float (that is, a floating point
.. value), and the result is also a float.
String Operators
In Table 2.1, we saw that adjacent string literals are automatically concatenated. (The useful-
ness of this string operation alone justifies its own operator.) An operator is provided to allow
any two strings, not just literals, to be concatenated. The conventional operator used by many
programming languages, Jython included, is the plus sign (+). So, when two string values
and/or variables are separated by a plus sign, the result of this expression will be the concate-
nation of the strings. Please note, however, that the items to be concatenated both need to be
strings. If you try to concatenate a string and a number, an exception is raised.
What a pain. Isn’t there something that we can do to minimize these exceptions and allow
us to concatenate a string with some other value? Yes, if you surround a value, or expression, or
variable name in backticks, the result will be represented as a string. Listing 2.5 includes a
demonstration of the backtick operator.
Another useful string operation is provided by the string repeat operator. It is sometimes
much easier to have Jython duplicate, or repeat, a string a specified number of times than it would
be for the programmer to specify a hard coded, literal string with a specified number of dupli-
cated characters. The syntax for this operation is string * number.
Listing 2.5 shows some sample uses of string operators. Line 1 demonstrates how to make
use of the string repeat operator using the asterisk ’*’ character, which is related to the multipli-
cation operator that uses the same symbol. As you can see, using the repeat operator in this fash-
ion makes it very obvious how many characters will exist in the generated string. Line 3 shows
that the string being repeated can contain more than one character. Line 5 contains an expression
composed of both the string repeat operations as well as string concatenation. It should also be
noted how parentheses can be used to group a portion of the expression. Lines 7–14 show what
happens when the wrong data type is provided for a string operator. And lines 15–16 show how
the backtick operator can convert the value of a variable to a string so that the string concatena-
tion operator may be used.
Operator Precedence
One aspect of expression evaluation that sometimes causes confusion is the order in which oper-
ations occur. Let’s take a look at a simple expression containing multiple operators, specifically
1 + 2 * 3. We have two possible ways to evaluate this expression:
Jython, like most programming languages, defines an order of precedence for expression evaluation.
For the operators we’ve already seen, this precedence order is shown in Table 2.12, where the opera-
tors at the top of the table have the highest precedence, and the ones toward the bottom of the table
have a lower precedence.
** Exponentiation
This means that if an expression has operators of different precedence, the operations with
the highest precedence level will be evaluated first. If an expression has multiple operators of the
same precedence level, then those sub-expressions will be evaluated from left to right. This is
demonstrated in Table 2.13, where the steps used to evaluate an expression are shown.
This is just the beginning as far as operators are concerned. The next ones described are
called the unary operators. Unlike the simple arithmetic operators shown so far, unary operators
deal with a single value. The four unary operators are shown in Table 2.14.
The next group of operators is used to manipulate integers and long integers as binary val-
ues. If necessary, values are converted to a common type as part of the expression evaluation.
Unfortunately, it would require too many pages to describe and explain binary arithmetic
for the little that it is likely to prove useful in the administration of a WebSphere Application
Server. Because of that, the operators are identified with a minimum of description. Should you
find this material interesting, you are encouraged to investigate bitwise manipulation further. The
bitwise operators Jython supports are shown in Table 2.15.
13
The value generated by this inversion process is also called the two’s complement.
<< 1 << 2 4 The left operand is left-shifted the number of bit posi-
tions specified by the right operand.
>> 256>>4 16 The left operand is right-shifted the number of bit posi-
tions specified by the right operand.
The last two operators in Table 2.15 are identified as Boolean. For these operators, the fol-
lowing values are considered “false”:
• Any numeric zero value (for example, 0, 0L, 0.0)
• Any empty sequence or dictionary (for example, [], (), ’’, {})
• None
All other values are considered ”true”.
The last kind of (numeric) operators to be described are used much more frequently than
the preceding bitwise operators. The following operators are used to determine the relationship
between two values. The result of using one of these operators on two values yields either a value
of 0 (also referred to as false), which is used to indicate that the specified relationship is not
correct (does not hold), or 1, which is used to indicate that the specified relationship holds (or
is correct). Table 2.16 shows these relationship, or comparison, operators and how they can
be used.
1 == 2 0 1 is “equal to” 2
Note: This is the obsolescent form of the “not equal to” test. The != operator
is preferred.
Next, we cover the remaining relationship or comparison operators. These are a little spe-
cific but are valuable nonetheless. Given a sequence, it is very useful to quickly and easily deter-
mine whether or not a specific value exists therein. It is also useful to be able to determine
whether or not two objects are the same, or different. Listing 2.7 and Table 2.17 further explain
these operators and demonstrate their use.
13–18 Show how the operators can be used to determine whether or not two items refer to the
same object.
Note: These operators do not compare the values of the operands, just their identities.
Table 2.18 is the revised operator precedence table and includes all of the operators that we
have seen. Again, the operators closer to the top of the table have a higher precedence than those
lower in the table. All operators on the same row have the same precedence and if they exist
together in an expression, are evaluated from left to right.
Operator(s) Description
| Bitwise “or”
or Boolean “or”
Statement Separator
Generally, it is considered a best practice to have one statement on a line. There are exceptional
circumstances, however, where it is convenient to be able to violate this practice and have mul-
tiple simple statements on one line. This means that compound, or loop, statements (to be cov-
ered shortly) are not allowed. To do so, use a semicolon to indicate where the first simple
statement ends and the next should begin. Listing 2.8 shows an example:14
14
All statements separated by a semi-colon are considered to be at the same indentation level.
Comments
Jython is meant to be a very readable language. However, there are times when the program state-
ments should be annotated with comments for the reader. This is especially true for scripts that
are to be used more than once or if they are meant to be used by more than one person. Comments
are provided in some of the examples and with all of the scripts made available with this book.
Comments can use the whole line, or they might be at the end of a line after another Jython
statement. Comments begin with an octothorpe (’#’) and continue to the end of line. An
octothorpe in a string is not considered a comment, but rather it is simply a character.
Coding Conventions
Even though it isn’t technically part of the Jython syntax, it is worth mentioning that adhering to
rules, guidelines, and conventions for how scripts are to be written greatly enhances script read-
ability. Therefore, you are encouraged to define and document the coding conventions you and
your team use. For example, you might want to review the coding conventions used for the
Python standard library, which are available from http://www.python.org/dev/peps/pep-0008/.
Summary
In this chapter, we started exploring the Jython programming language. We looked at the basic
data types and the structures that are available to all Jython scripts. We also covered expressions,
coding conventions, and the topic of operator precedence. In the next chapter, we see where
these are used in Jython statements.
Jython Statements
In the previous chapter, we looked at the basic building blocks of Jython scripts—that is, the data
types and structures used to represent information. In this chapter, we expand on these concepts
and explore the next programming construct: statements.
Expression Statements
Expression statements are used to compute values and to invoke functions. They are frequently
used in an interactive wsadmin session, where the result (if it is not None) is displayed. This can
be seen in Listing 3.1 (lines 12–13). When wsadmin is not used in an interactive mode, the results
of expression statements are discarded, as also shown in Listing 3.1 (line 8).
27
7|WASX7357I: ...
8|The result is: 7
9|
10|C:...\bin>wsadmin -conntype none -lang jython
11|WASX7357I: ...
12|wsadmin>1 + 2 * 3
13|7
14|wsadmin>print ‘The result is:’,
15|The result is:wsadmin>print 1 + 2 * 3
16| 7
17|wsadmin>quit
Lines 2–4 of Listing 3.1 show the contents of the example script file, print.py. Line 8 shows
the output generated by the print statements within the script file, and lines 12–16 show the result
of manually entering the same commands in an interactive wsadmin session.
While executing the script, the result of the expression statement in line 1 of the input file
(that is, 1 + 2 * 3) is discarded or, rather, not displayed. Interestingly enough, what you see are the
results of two different print statements displayed on a single line (line 8). This is because the first
print statement (line 2) ends with a comma. The comma tells the print statement not to add a new
line to the end of the information displayed. Note that the comma at the end of the interactive print
statement (line 15) causes the wsadmin prompt to be displayed on the same line as the text gener-
ated by the print statement.
Assignment Statements
In simple terms, assignment statements are used to associate, or bind, a name to a value. A more
complete and accurate definition would include that assignment statements can bind or rebind
names to values and modify mutable items. Throughout this chapter, there are many examples of
assignment statements that should make this point clearer. Now that you have some background,
let’s take a look at some of the forms assignment statements can take in Table 3.1.
name = ‘Bob’ This is another simple assignment statement showing how the
value to be assigned can be of any Jython data type. It could just
as easily be an instance of any of the sequence types (string, list,
tuple) or even a dictionary.
i = i + 1 The value to the right of the equal sign can be an expression. Just
in case you are unfamiliar with it, this statement takes the current
value of i and attempts1 to add one to (increment) this value and
assign the result of this expression to the variable on the left of
the equal sign.
a = b = c = 0 This assignment statement binds the value of the expression (in
this case 0) to each of the specified variable names.
a = 1, 2 Should the expression include commas and therefore provide
multiple values, the expression is considered a tuple. In this case,
if you were to follow this assignment statement with print a, then
the generated output would be: (1, 2).2
a, b = 1, 2 In this case, the number of identifiers on the left of the equal sign,
also called targets, equals the number of comma separated values
to the right of the equal sign. So, the values are assigned to the
targets based upon the order in which they occur. Thus, this
assignment statement is equivalent to “a = 1; b = 2.”
1
Remember that i could be an immutable value, so an attempt to “add one to it” could cause an exception.
2
See the “Packing and Unpacking” section.
a, b = ‘12’ Strings are sequences too. As long as the number of target vari-
ables is the same as the length of the string, then each variable
will be assigned the corresponding character from the source
string, thus making this assignment statement equivalent to:
a = ‘1’; b = ‘2’.
a, b = [(1,2),’Buckle This example is a little more complicated. The list (literal) has
my shoe’] two elements, the first being a tuple (1,2) and the second a
string. This statement will bind the tuple to a and the string to b.
Let’s take a deeper look at the term “bind” as it applies to the action performed by an
assignment statement. The term warrants further explanation, especially when we examine what
actually occurs in Listing 3.2. It should be fairly clear that each of the target variables is associ-
ated with a two-element list. What might not be clear is the fact that after this statement is exe-
cuted, a single list is created, and each variable refers to the same object.
Lines 1–3 show how the assignment statement in line 1 binds each of the target variables to
a two element list. Because a list is mutable, you can modify its value in place. This happens in
line 4, where the first element of the list bound to the variable is changed to “-5”. Lines 5 and 6
show that each variable refers to the same object. Lines 7–10 show how this same binding occurs
with simple assignment statements.
sign ’=’ and are separated by commas), a tuple is created. This process of combining comma sep-
arated values into a tuple is called tuple packing. When multiple target identifiers exist on the left
side of the assignment statement (that is, precede the equal sign) and multiple source values exist
to be assigned to these identifiers, the inverse operation occurs and is called unpacking. Because
unpacking can occur from any sequence, this operation is actually called sequence unpacking.
Listing 3.3 demonstrates this, and Table 3.2 explains these statements in more detail.
4 Tuple packing is used to create a tuple, and sequence unpacking is used to assign
(bind) the sequence values to the specified variables.
5–6 This shows that the values of a and b are individual integer values, and not a tuple as
was seen previously.
7 Again, tuple packing is used to create a tuple containing the current values of the speci-
fied variables, and then sequence unpacking is used to assign (bind) the values to the
alternate variables.
8–9 This shows that the values of a and b have been exchanged (swapped).
Augmented Assignment
One of the most common uses of the assignment statement is to modify an existing value of a par-
ticular variable. For example: i = i + 1 is an idiom used to increment the value of i. This kind
of thing (that is, having a variable as one of the operands in a binary operation and then assigning
the result of the operation to the variable) is common enough to warrant a shorthand notation,
which is called an “augmented assignment” statement. Table 3.3 shows these symbols and
defines the augmented operation for each operator.
-= Subtraction
/= Division
**= Exponentiation
|= Bitwise or
Slices
Now that you are aware of how assignment statements can bind multiple variable names to the
same object, you might be wondering how to bind a variable to a copy of a sequence. This
technique is called making a slice, or slicing. Square brackets with 0 to 3 numeric expres-
sions, separated by colons, are used to indicate a slice.
food[ 0:5 ] ’bacon’ The slice creates a copy of the specified string, copying only the
characters from index [0] up to but not including the character with
an index [5] (that is, the comma ’,’).
food[ :5] ’bacon’ If the starting index is unspecified, an index of [0] is used. So the
slice here is identical to the previous example.
food[ 17: ] ’spam’ If the ending index is unspecified, the sequence length is used as the
ending index. So, this is equivalent to food[ 17:21 ].
food[ -4: ] ’spam’ As noted earlier, a negative index can also be used. Any negative
index value is added to the sequence length to determine the actual
index to be used. Therefore, this is identical to the previous example.
six[ -1:-2 [] Should the starting index (that is, -1) be greater than the ending index
] (that is, -2), the result is an empty sequence of the same type.
lang[:] ’”Jython”’ If both the starting and ending indexes are missing, the result is a
complete copy of the source sequence and is equivalent to having
used lang[0:8].
lang[ 1:-1 ’Jython’ This idiom is used to create a copy of the specified sequence without
] the starting and ending elements. In this case, notice how it can be
used to remove the leading and trailing double quotes from the
specified string value. You will see this idiom later with code that
extracts information from strings.
six[ ::2 ] [0, 2, 4] The use of two colons indicates an extended slice. The expressions
default the starting and ending indices, while providing or specifying
the step, or stride, value. Use of an extended slice iterates over the
sequence by adding the step value to the current index on each
iteration.
six[ 1:4:2 ] [1, 3] This extended slice indicates that the result should be generated by
first selecting the element [1], then [1+2]. Because [1+2+2] is
beyond the specified ending index of [4], it is not included.
lang[ ::-1 ] ’”nohtyJ”’ If the stride value is negative, then the default starting element is
the last item in the sequence, and default ending index is logically
before the first element of the sequence. The resulting slice will be
generated by iterating over the specified range in reverse order.
This example is equivalent to lang[ 7::-1 ]. Note, however,
that you have to default the ending index if you want to include the
first element in the sequence (that is, [0]) because attempting to
reference [-1] is interpreted as the last element in the sequence.3
Slices can also identify a target portion of a mutable sequence (that is, a list) to be modified.
Listing 3.4 shows some examples of this use of slices. Line 3 identifies the target slice of the list
to be replaced. The interesting thing to note about this is how the result (line 5) might not be what
you expect. If what was intended was to replace elements 1 and 2 with a single string element,
then the syntax shown in line 6 should be used.4 Note how one slice is used for the target, and a
different slice can be used to specify a subset of the source. In this case, the source slice (that is,
the [ 1:-1 ]) is a commonly occurring slice that is used to copy everything from the source
sequence except the leading and trailing elements. If a complete copy of the source sequence
were to be used, then the slice syntax would have been [:]. Additionally, lines 9–14 show the dif-
ference between assigning using an index (where no colon occurs) versus using a slice (where 1 or
2 colons occur). Lines 12 and 15 show how sequence unpacking from a list and a tuple could have
been used to perform this particular assignment.
3
Unfortunately, version 2.1 of Jython, which is the version provided with WebSphere Application Server 6.1, has a
defect that doesn’t implement lang[ 7:-1:-1 ] correctly. It results in ’”nohtyJ”’ instead of the correct
empty string.
4 Technically, the right-hand side of the assignment statement could be any sequence. However, it was felt that using
the sequence unpacking from a list (i.e., the syntax shown) would be more easily understood than either of the
sequence unpacking from a tuple—that is, either this: six[ 1:-3 ] = lang[ 1:-1 ] or this: six[ 1:-3 ]
= ( lang[ 1:-1 ], ).
Simple Statements
Up to this point, we have seen expression and assignment statements. Now it’s time to start
exploring the next programming construct, simple statements.
The assert Statement
assert statements are used to validate that conditions or relationships hold before an important
calculation is performed. If you expect a specific variable to be non-zero, for example, you can
use an assert statement to enforce this condition. The two forms of the assert statement are
shown in Listing 3.5.
Listing 3.5 assert Statement Examples
1|wsadmin>x = 1 + 2 * 3
2|wsadmin>assert x
3|wsadmin>assert x == 0, ‘Assertion failed.’
4|WASX7015E: Exception running command: “assert x == 0, ‘Assertion
failed’”;
5| exception information: com.ibm.bsf.BSFException: exception from
Jython:
6|Traceback (innermost last):
7| File “<input>”, line 1, in ?
8|AssertionError: Assertion failed
Line 2 shows the first form of the assert statement, that is the assert keyword followed by a
single expression. Line 3 shows the second form, where the assert keyword is followed by two
comma separated expressions. Frequently the second expression is an “error” message or text
string to be displayed should the assertion fail. In either case, the first expression is evaluated. If
the result is non-zero, the assertion is considered to have succeeded, and execution continues.
Should the expression result be a value of 0, the assertion is considered to have failed, and an
exception is raised. Lines 4–8 show the results of an assertion failure. This should encourage you
to have clear, complete, and concise assertion messages.
15|[0, 2, 4]
16|wsadmin>six = [ 0, 1, 2, 3, 4, 5 ]
17|wsadmin>del six[ 1 ], six[ 3 ], six[ 5 ]
18|WASX7015E: Exception running command: “del six[ 1 ], six[ 3 ], six[
5 ]”; exception information:
19| com.ibm.bsf.BSFException: exception from Jython:
20|Traceback (innermost last):
21| File “<input>”, line 1, in ?
22|IndexError: index out of range: -1
23|
24|wsadmin>six
25|[0, 2, 3, 5]
26|wsadmin>six = [ 0, 1, 2, 3, 4, 5 ]
27|wsadmin>del six[ 1 ]
28|wsadmin>six
29|[0, 2, 3, 4, 5]
30|wsadmin>del six[ 3 ]
31|wsadmin>six
32|[0, 2, 3, 5]
Lines(s) Description
1–9 These show how to create, or bind, a value to a variable name and then to use the del
statement to remove, or unbind, that variable name. The exception seen in lines 4–8
should not be a surprise. Attempts to use an unassigned identifier generate a NameError
exception.
10–15 These show how to use a slice in a del statement to remove elements from a list.
Remember that the second expression in the slice syntax identifies the element past the
end of the slice. In this case, 1:3 identifies elements 1 and 2.
16–32 These lines might surprise you a bit, at least until you consider what happens to the list
as each of the specified elements is removed. This is why lines 24–32 are provided—so
that you can see, as each of the del statements (in lines 27 and 30) are executed, the
length of the list is reduced so that by the time the del six[ 5 ] is attempted, only four
elements exist in the list, which is why the items in the list were removed in reverse
order in line 15. So be careful when you are using the del statement to remove items
from a list.
1 Assigns a string to the cmd variable, the contents of which are a complete print
statement.
8 Actual use of the exec statement to execute the contents of the cmd variable.
10 Current value of the variable showing how the command executed in line 8 modified
the value of variable a.
Control Flow
So far, we’ve looked at only individual commands or statements that can be executed sequen-
tially. For more useful programs, you need some statements that allow decisions to be made about
what statements should and should not be executed and more importantly, in what order. Let’s
start with some simple statements and build upon them explaining as we go along.
Before discussing control structure, however, you first need to understand how Jython iden-
tifies groups of statements. Some programming languages use special symbols (for example,
curly braces ’{‘ and ’}’), or special identifiers (keywords) to indicate the start and end of a
group of statements.
Jython is different. It uses indentation to identify the grouping and association of state-
ments. For those unfamiliar with this technique, it can take a little getting used to. However, once
you make this adjustment, many you will likely find that structuring your programs in this way is
very intuitive. Many programming instructors feel that indentation makes programs more read-
able and therefore easier to understand. Jython takes this suggestion and enforces it by making
indentation significant, thus making Jython scripts significantly easier to read.
How does it work? As Jython looks at each line, leading tab characters are replaced by the
appropriate number of blanks (space characters) in order to have the “tab stop” position aligned
on a column number that is a multiple of 8.
Listings 3.8 and 3.9 show an absurd example of how this works. There are two, almost
identical, script files, absurd0.py and absurd1.py, the first of which is shown in Listing 3.8.
Each script file has a sequence of print statements. The statements on lines 2–9 are all consid-
ered (at least by Jython) to have identical indentation, which means that they are considered a
statement-suite and will be executed in the order that they occur. The only difference in each line is the
number of spaces ’ ’ that precede the tab character ’\t’ before the print keyword. In order to bet-
ter understand where the tab is located, in this example, we use the ’•’ character to represent a tab.
The quoted string after each print identifies the characters that precede the print on the given line.
Listing 3.9 shows what happens when the contents of the script files are displayed by the
operating system and then executed by wsadmin. First, the contents of absurd1.py are dis-
played, and you can see that Windows interprets the indentation as expected. This is evidenced by
the fact that the print statements (lines 3–10) are all aligned. With this indentation, these state-
ments are logically grouped together by the reader, the operating system, and by Jython.
What about the other statements in the file (that is, lines 2 and 11)? They both begin in col-
umn 1, meaning that Jython also understands them to be associated in a sequential manner. Line 2
shows the first of the compound, or control flow, statements. The first word on the line is if, a key-
word seen earlier. In its simplest form, the if keyword is followed by an expression to be evalu-
ated, and this expression is followed by a colon ’:’. Should the result of the expression be
evaluated as non-zero (that is, true), the indented statements immediately following the if are
executed. If the result is evaluated as zero, the indented statement group is skipped, and any sub-
sequent statement with the same indentation as the if is executed.
10| print ‘space space space space space space space tab’
11|print ‘no tab’
12|
13|C:...\bin>wsadmin -conntype none -lang jython -f absurd0.py
14|WASX7357I: ...
15|no tab
16|
17|C:...\bin>wsadmin -conntype none -lang jython -f absurd1.py
18|WASX7357I: ...
19|tab
20|space tab
21|space space tab
22|space space space tab
23|space space space space tab
24|space space space space space tab
25|space space space space space space tab
26|space space space space space space space tab
27|no tab
Looking closely, you can see that the only difference between the two script files occurs in
the first line, where absurd0.py contains “if 0 :” and absurd1.py contains “if 1 :”.
Using this information you have a better chance of understanding the output seen in Listing
3.9. When absurd0.py is executed (lines 13–15), the expression to be evaluated is 0, so the
indented statements are skipped, and execution continues with the subsequent statement. The next
statement that has the same indentation as the if statement is executed. This results in the no tab
output (line 15).
When absurd1.py is specified as the script file to be run (line 17), the expression is evalu-
ated as 1, so the indented statements are executed in the order seen (lines 19–26). After the last
indented print statement is executed, execution continues with the next (and last) statement in
the file, which is why we again see the no tab output on line 27.
This example clearly illustrates how difficult it can be to interpret the indentation when
space and tab characters are mixed. This is especially true if the text editor you are using allows
you to define your own tab stops and you are inconsistent with the characters used for indenta-
tion. Should this occur, you will see a SyntaxError when wsadmin tries to execute the script file.
Compound Statements
The next level of complexity involves compound statements that determine whether or not
associated statements should be executed and how many times.
The if Statement
As seen in the previous section, one of the compound statements available to us is the if statement,
the syntax of which is as follows:
if <expression> :
statement-suite
else :
statement-suite
This statement is used when a choice needs to be made between two different statement groups.
Should the expression evaluate to true (non-zero), the first statement-suite is executed. At the
end of the statement-suite, control skips over the second statement-suite and continues with the
next logical statement of the same indentation level as the if. Should the expression evaluate as
false (that is, zero), the first statement-suite is skipped, and the second statement-suite is exe-
cuted. Occasionally a choice needs to be made among more than two groups of statements. For
this kind of situation, one or more elif clauses can be added, as shown here:
if <expression> :
statement-suite
elif <expression> :
statement-suite
else :
statement-suite
In this case, the expressions are evaluated in the order they occur until a non-zero result is
encountered. The associated statement-suite is executed, and control continues after the last of the
statement-suites in this construct. Should none of the expressions evaluate as true, the statement-
suite following the else keyword is executed (that is, if the optional else clause is present).
loop Statements
The following compound statements can cause the statement-suite to be executed zero or more
times. Because of this, they are know a as loop, or looping statements. However, be sure these
loops include some way to exit the loop constructs. If there is no way for the loop to terminate, an
unfavorable condition known as an infinite loop occurs.
while <expression> :
statement-suite
else :
statement-suite
Listing 3.10 shows a sample while loop. Line 1 initializes the variable that will be used in the
while expression. The first time the expression is evaluated, count has a value of 10, so the
expression result is true (that is, 10 is greater than 0), and the indented statement-suite is exe-
cuted. Line 3 prints the current value but does not include a newline character because of the pres-
ence of the comma at the end of the print statement. Line 4 decrements the value of the count
variable (using an augmented assignment statement). Because the end of the statement-suite has
been reached at this point, control is returned back to the while statement so that the expression
can be re-evaluated. Lines 2–4 are executed in turn as long as count is greater than 0.
Eventually, the expression evaluates as false when the value of count equals 0, and control
passes to the statement-suite associated with the else portion of the while statement. Because
this example was used in an interactive wsadmin session, you can see the output that was gener-
ated by the while statement on line 8.
Listing 3.11 shows two more examples of the while statement. This time, including the
break statement mentioned earlier. For the first while loop, seen in lines 4–10, execution
includes the evaluation of the expression in line 4, which is used to determine if the loop execu-
tion has checked every element in the values list for an occurrence of 5. Eventually, the expres-
sion evaluation results as false, and control is passed to the else statement on line 10. The
result is the “5 was not found” message shown on line 12.
The while loop (lines 15–21) of Listing 3.11 is nearly identical; however, this time the value to
be checked is present and is eventually located. When it is, the print statement (line 17) is executed,
followed by the break statement (line 18). When a break statement is executed, as noted earlier, the
nearest enclosing loop is terminated. When it is, any associated else clause is skipped. That is why
we only see the 4 is present message printed (line 17) and not the one from the else suite (line 21).
Listing 3.12 has some for statement examples to study. The first for loop (lines 3–6) sum up the val-
ues in the specified sequence. When the loop has processed each element in the list, control transi-
tions to the else statement-suite (lines 6–7). The output (line 8) should not be too much of a surprise.
The second for statement (lines 10–15) includes another of the previously mentioned
continue statements. When a continue statement is executed, control is transferred to the end
of the nearest enclosing loop, in this case the for loop, and the next iteration value is
assigned, should one exist. If the sequence values are exhausted, control transitions to the else
statement-suite. In this particular example, the if statement (line 11) is executed to look for any
values of 10. If any are encountered, the continue statement is executed to skip over any remaining
statements within the loop (that is, the augmented assignment statement to add the current value
to the sum). Because only one instance of the value of 10 exists in the list of values, the result of
this test and the continue statement should be straightforward and easily understood. Notice
how the else statement-suite still gets executed, even though the continue was executed while
processing the last value in the sequence.
24|wsadmin>else :
25|wsadmin> print ‘sum =’, sum
26|wsadmin>
27|even number encountered
28|wsadmin>
The last for statement example in this listing can be found in lines 19–25. In this case, the
test is for even numbers. This check is made using the modulo operator ’%’, which divides the
quotient (that is, the left operand) by the dividend (the right operand). The value returned by this
operator is the remainder after performing integer division. The purpose of this example is to
show that when a break statement is executed, the nearest enclosing loop is terminated,
and any associated else statement is skipped.
WARNING Don’t directly modify the list over which the for statement is iterating. To
demonstrate this, we need to reference something that the book has not yet discussed,
and that is the list method named “remove(),” the purpose of which is to delete the
specified value from the list. An example of this is shown on lines 4 and 11 of Listing 3.13.
The problem is demonstrated by the first for loop seen in lines 2–4. The expectation is that
the if statement within the loop would remove all of the even values in the list. Unfortunately, this
does not happen when the for loop iterates over the list being modified. Remember to make a
complete copy of the list using the slice construct (that is, [:]), as shown on line 9. By making
this simple change, every element of the list is processed correctly.
The except and associated statement-suite can occur zero or more times, but each time it occurs,
a unique exception expression identifying an exception handler must be specified. When an
exception occurs in the try statement-suite, the exception handlers are checked, in the order
specified, until a match is found or the list of handlers is exhausted. It is also valid to specify an
expressionless except clause. However, if so, it must occur last in the list, and it will be a match
for any exception.
The optional else clause can only occur if at least one except clause exists and is invoked
if none of the exception handlers has been executed. Additionally, the optional finally clause is
supposed to be invoked as a cleanup handler. If an unhandled exception is encountered in any of
the statement-suites, the exception information is saved, and the finally suite is supposed to be
executed. At the end of the finally statement-suite, the exception is reraised unless the
finally suite executes a return or break statement, in which case the saved exception is lost.
Listing 3.14 shows a little more complex example that has a try statement within a for
loop construct. Essentially, the for statement has a statement-suite that consists of a single try
statement (lines 2–16). The for loop iterates over the values in the list, assigning each value, in
turn, to the loop control variable “i” (line 1).
8|wsadmin> x = unassigned
9|wsadmin> else :
10|wsadmin> print ‘No error’
11|wsadmin> except NameError :
12|wsadmin> print ‘NameError exception caught’
13|wsadmin> except :
14|wsadmin> print ‘unknown exception caught’
15|wsadmin> else :
16|wsadmin> print ‘success - no exception raised’
17|wsadmin>
18|Divide by zero test
19|unknown exception caught
20|NameError exception test
21|NameError exception caught
22|No error
23|success - no exception raised
24|wsadmin>
The first time through the loop, the value of “i” is 0. When control gets to line 3, the
expression evaluation is successful, and the statement-suite on lines 4–5 are executed. The print
statement on line 4 generates the first line of output seen on line 18. Then the division by 0 on line
5 causes the try statement to search for a matching exception handler. First, a test is made (line
11) for a NameError. Then the expression-less except is checked (line 13), and a match is found
(given that this kind of except matches any exception).5 This causes the suite in line 14 to be exe-
cuted, and the output is generated, seen on line 19.
Control then completes the execution of the try statement, and the for loop iterates to the
next value (that is, 1), and the try statement is again executed. The if expression in line 3 fails,
so control transfers to line 6 where the elif expression succeeds, and the statement-suite in lines
7–8 are executed. The print statement in line 7 generates the output seen on line 20. The attempt to
access the variable unassigned in line 8 causes the NameError exception to be raised. The try
begins looking for a matching exception handler in line 11 and finds a match. Thus, control is
transferred to line 12, and the generated output is seen on line 21.
Control then completes the execution of the try statement, and the for loop iterates to the
next value (that is, 2), and the try statement is again executed. This time, the if and elif
expressions fail, and control transfers to the else statement-suite found on line 10, which gener-
ates the output seen on line 22. Because no exception was raised in the try suite, control is trans-
ferred to the else found in line 16, which generates the output seen on line 23. Control attempts
5
Just in case you are wondering, there is a way in an except statement-suite to find out about the exception that was
raised. Unfortunately it will make a bit more sense if we wait until Chapter 5, where we discuss the sys module.
to iterate to the next for value and finds that the sequence values have been exhausted. Control
transfers to the statement following the for, which does not exist, so you can see the wsadmin
command prompt on line 24 that indicates that the for loop has completed successfully.
If you were reading the paragraphs ahead of Listing 3.14 carefully, you would have noticed
references to the phrase “...is supposed to...” with regard to the optional finally clause. This is
because of the fact that the finally clause has a problem and doesn’t work properly. This defect
should be fixed in a future version of Jython. In the meantime, you must use a different technique
to make use of a finally cleanup handler.
To work around this problem, have an outer try/finally as a wrapper for an inner try
statement without a finally clause. An example of this nesting is shown in the following code
sample, with extra indentation used to emphasize the inner try statement.
try :
try :
statement-suite
except <expression>, <target> :
statement-suite
else :
statement-suite
finally :
statement-suite
Functions
Most programming languages have a method of gathering statements together for easy reuse. In
Jython, this is done by defining a function using the syntax shown here:
def <function_name>( <parameter-list> ) :
statement-suite
A function definition, like an assignment statement, binds the function name to the specified
statement-suite. Because the intent of a function is to allow it to be easily reused, Jython allows a
way to easily document the role of the function and how it should be used. This technique allows
using the definition of a documentation string as part of the function definition.
Function Definitions
Listing 3.15 shows how to define and use some simple functions. Three function definitions
appear on lines 1–16. Once a function has been defined, it can be executed (invoked or called)
using the function name followed by parentheses (on lines 19, 21, 22, 24, and 25).
When a function is executed (for example, test1(), on line 19), Jython “remembers”
where the call originated6 and begins the execution of the specified function statement-suite.
The statements in this particular function try to reference a variable named x. The question
though is to which identifier does this refer?
NOTE If you don’t include the parentheses, you are simply referencing the function, not
calling it (see line 17). In interactive mode, this expression statement causes information
about the function to be displayed.
6
Jython needs to know where the call originated so that when the function is complete, control can go back to any
statement that follows.
Namespaces
A namespace is a mapping used to determine to which object a name refers. For each context,
Jython has both a global and a local mapping.7 This allows a distinction to be made between local
and global variables. It’s not until we discuss functions that this makes sense though. When a
function is defined, a local namespace is created and populated with name and object references
based on what identifiers are assigned within the function. If no assignments are made to an iden-
tifier within the function, then this identifier is not added to the local namespace. References to it
use the global namespace mapping.
Because no assignments to x occur in the test1() function, all references to this identifier are
to the global namespace. The first time test1() is called, x does not exist in the global namespace, so
the except statement-suite (line 8) is executed. This causes the x is undefined message to be
displayed. The function then completes, and control returns to the place from where the function was
called. In this case, control returns to the statement after the function call (line 19). Because no state-
ment exists to be executed, a wsadmin prompt is displayed (line 21), indicating that user input is
expected.
The next function call (line 21) is to the function named test2(). The only action per-
formed by this function is to assign the value 1 to the variable named x. Because an assignment
occurs to this identifier within the function, it is added to the local namespace, and references to it
within this function will be to a local variable. This explains why the output on line 23 is seen. It
shows that no global variable was created by the assignment statement.
Listing 3.15 shows that the identifier-list is simply a comma separated list. Line 14 shows that
when a single identifier is used, no comma should be present.
By having this global statement, the assignment to x (line 15) binds the specified value to
a global variable with this name. It is important to note that before this function was executed, the
global variable x did not exist, so the result of the assignment causes the global variable to be cre-
ated in the global namespace so that when test1() is again executed, it is able to access the
global identifier x. This, in turn, causes the output generated (line 26).
7
There is also a “built-in” namespace that contains the names and references to all of the objects known to Jython (for
example, None).
Listing 3.16 shows how an assignment to an identifier within a function makes all refer-
ences to that identifier local to the function. Without the assignment statement within the func-
tion, on line 6, all references to the identifier x would be to a global variable. However, because an
assignment to this identifier occurs within the function (even though the assignment occurs at the
end of the function), all other reference to this identifier within the same function are considered
to be to local variables. This is shown by the output generated on lines 9 and 12.
The output on line 9 might be a little confusing at first, but it does make sense once you
understand what is happening. As the function is executing, the print statement in line 3 begins to
execute. The first part of this statement generates the literal string “x =” before any attempt is
made to access the value of the local variable x. At this point, an exception occurs because the
local variable has not yet been assigned a value. Control transfers to the exception statement-suite
on line 5, and the remainder of the message is generated (that is, the oops).
Line 10 defines a global variable named x, which has no effect on the execution of the func-
tion because all references to this identifier within the function are considered to be to a local
variable having this name. Hence, we see the same output generated on line 12 as we saw on line
9. If the reference to x in line 3 were to a global variable, then the output in line 12 would display
the value of the global variable instead of the oops message.
Function Parameters
The syntax of a function definition, seen earlier, showed that parameters can be passed to func-
tions. The simplest form of a function parameter list is a group of comma-separated identifiers
within the parentheses. It is important to understand how function parameters work, so take a
look at the following simple example.
Listing 3.17 shows how to define a function, f(), and specify one formal parameter, a. As
far as the function is concerned, this formal parameter is an identifier that is local to the function.8
When the function is called (line 7) an actual parameter is provided for each formal parameter
listed. For this particular example, the current value of the actual parameter (that is, variable x) is
used as the initial value for the “formal parameter” (that is, variable a). This can be verified by
observing the output generated by the print statement (line 8).
Listing 3.17 Simple Function Parameters
1|wsadmin>def f( a ) :
2|wsadmin> print ‘f(), a =’, a
3|wsadmin> a += 1
4|wsadmin> print ‘a =’, a
5|wsadmin>
6|wsadmin>x = 0
7|wsadmin>f( x )
8|f(), a = 0
9|a = 1
10|wsadmin>x
11|0
You can also see that although the value of this formal parameter (local variable) is modi-
fied, when control returns to the place where the function was called, the value of the actual
parameter is unchanged (as evidenced by the output shown on line 11). This kind of parameter
passing is sometimes referred to as “pass by value.”9 Because only a value is needed as an actual
parameter, you could have just as easily called the function using a literal (such as, f(0)).
Optional Function Parameters
There are times when it is convenient to define functions that allow a variable number of parame-
ters. Jython supports the following types of optional parameters.
Default Function Parameters Frequently, it is useful to define an initial value of a formal
parameter. The syntax for this is to have an equal sign followed by an expression representing
the initial value for the parameter. Listing 3.18 shows how to define a default value (on line 1)
and how the default value is used should an actual parameter not be specified where the func-
tion call occurs (on line 7). You can also see (on lines 9–10) that when an actual parameter is
specified, its value is used instead of the default.
8
Should a global identifier exist with this name, it is inaccessible within the function.
9
The way in which parameters are passed to functions is not, technically, “pass by value.” A more accurate description
would be “pass by object reference.” However, because we have yet to describe or discuss objects, it is much easier at
this point to simply say that parameters are “pass by value.”
What happens if we have multiple parameters (sometimes called arguments)? Can default
values be used? Yes, but all parameters without default values must precede any and all parame-
ters with default values. This can be seen in Listing 3.19 (lines 1–2) where the proper way to
define a function having parameters with and without default values is shown.
Next (lines 4–10) you can what happens if you try to define a formal parameter list having a
parameter with a default value before one without a default value. Jython is nice enough to tell us
how silly this would be (lines 7–10). The reason this is unacceptable is that because it would be
ambiguous. If it were allowed, and the user specified a single actual parameter value, to which
formal parameter should this single actual parameter value be applied?
Additionally (lines 11–16) you see what happens should a required parameter value not be
specified. Again, Jython is nice enough to point out the problem with an easily understood error
message. And lines 18–36 show some valid and invalid function calls, with the examples in lines
18–25 being valid, and those on lines 26 and 31 being invalid and causing (easily understood)
error messages.
Named Parameters An interesting feature of function parameters is that they may be specified
using their keyword or formal parameter names. This is demonstrated on lines 20–25 of Listing
3.19. These lines demonstrate that when the formal parameter names are not specified, then the
actual parameter values are associated with the corresponding formal parameter in the order in
which they occur. This is sometimes called positional parameter passing.
However, should a formal parameter name exist in the actual parameter list, then all subse-
quent parameters in the actual parameter list must have the appropriate formal parameter name
specified. Lines 27–30 show the error message generated should this requirement not be met.
Listing 3.19 Optional Versus Required Parameters
1|wsadmin>def ok( a, b=1 ) :
2|wsadmin> print ‘a =’,a,’b =’,b
3|wsadmin>
Additionally, lines 31–36 show another type of error message that is displayed, also related to
the use of formal parameter names. The message is pretty straightforward and should require no
additional explanation.
Arbitrary Parameters Jython also allows for functions with a variable number of arguments.
These are referred to as arbitrary parameters, and the syntax for this type of parameter is shown in
Listing 3.20 (line 1). Subsequent lines show how you can use this type of argument. Note that
when arbitrary parameters are used, the “formal parameter” (that is, local variable) value will be
a tuple containing the actual values specified.
NOTE An arbitrary parameter entry (there can only be one) must occur after positional
and/or default formal parameters.
The last few examples in Listing 3.20 might leave you asking, “Given a list, or a tuple, is
there a way to specify its contents as the actual parameter list?” The reason for this question can
be explained by revisiting lines 11 and 12 in Listing 3.20, where you can see a list variable as the
actual parameter, and the result of this call being a single element tuple with the list as args[ 0 ].
If the desired outcome were to have the contents of the list passed to the formal parameter, a way
to unpack the sequence as part of the function call is needed. To do this, precede the actual param-
eter with an asterisk ’*’, as seen in Listing 3.21. Look closely and you will see how this unpack-
ing can be used on any sequence (lines 12–17). Note, however, what happens when it is used on a
string (lines 16–17), which might not be what you intended.
8|wsadmin>fun( a )
9|args = ([1, 2, 3],)
10|wsadmin>fun( b )
11|args = ((9, 8, 7),)
12|wsadmin>fun( *a )
13|args = (1, 2, 3)
14|wsadmin>fun( *b )
15|args = (9, 8, 7)
16|wsadmin>fun( *’spam’ )
17|args = (‘s’, ‘p’, ‘a’, ‘m’)
18|wsadmin>
Keyword Arguments Using a Dictionary As with arbitrary parameters, there are times when it
is convenient to use the contents of a dictionary to satisfy or provide the actual function parame-
ter values. To do this, the dictionary identifier is prefixed by ’**’ to indicate that it should be
unpacked, much like the sequence unpacking prefix discussed previously. Listing 3.22 demon-
strates this situation.
Unfortunately, lines 9–13 display one of the potential problems of using the dictionary
unpack prefix. The question is, what can and should be done about possible “extra” name/value
pairs within the unpacked dictionary? Is there a way to allow these extra, or arbitrary, name/value
parameter pairs?
Yes, Jython includes a notation similar to arbitrary parameters for arbitrary keyword
parameters. To identify a parameter for arbitrary keyword parameters, the last formal parameter
may have a double asterisk (“**”) prefix specified. Listing 3.23 demonstrates both kinds of arbi-
trary parameters, as well as how to use the unpack prefix on the actual parameters.
A return statement may include an optional expression list (that is, a collection of expres-
sions separated by commas). When this is done, the function call, with any actual parameters,
should occur where an expression is allowed by the Jython syntax.
Listing 3.24 shows how return statements can include various optional expressions and some
ways in which these functions can be called. Notice that when an implicit return is used (line 1), the
returned value is None (line 14). Because functions return values (remember, None is a value), they
can be used anywhere that allows the data type returned by the function. This is why we see each of
these function calls as the expression on print statements on lines 13–23. In each instance, the
specified function is called, and the returned result is displayed on the subsequent line.
What does this mean? It means that you may not get the intended result if you aren’t care-
ful. Notice how lines 5–10 display an ever lengthening list of values. You might have expected the
formal parameter L to be assigned an empty list each time the function was called. In fact, when
the def statement is executed, the default expression is evaluated, and a list object is created.
Each time the function is called, the formal parameter, L, is assigned to the current value of this
list object. Because lists are mutable objects, every change to the list that occurs within the func-
tion will persist across function invocations. This is shown on lines 5–10, where you see the num-
ber of elements increasing every time the function is invoked.
There are times when this is exactly how you want your function to work. If you want the
default value for your parameter to be an empty list object, you need to use a technique similar to
what is shown on lines 11–13. Here, the expression that is evaluated during the execution of the
def statement is the value None. When the def statement is executed, the default value for the L
parameter is None. When the function is called, the if statement (line 12) checks to see if the
value for L is the special None (that is, the default) value. If this is the case, then L can be initial-
ized as an empty list (on line 13).
NOTE Remember that the interactive mode of wsadmin does not support multi-line
triple-quoted strings. So multi-line docstrings should to be defined, or specified, in an input
(text) file containing the complete function definition. Another alternative is to include
newline characters in the docstring using an escape sequence for each newline character
(that is, ’\n’).
In his book An Introduction to Python, Guido van Rossum, the author of the Python pro-
gramming language, recommends the following conventions for documentation strings:
• The first line should be a short and concise summary of the function purpose.
• Strings need not restate the function or object name unless the name happens to be a
verb describing the function’s operation.
• The first word of a string should be capitalized, and the line should end with a period.
• If additional lines are appropriate, include a blank line between the summary and the
remainder of the text to separate the summary from the description.
• The remainder of the string text should describe how the function or object is to be used,
any results and/or side effects, and so on.
When multiple lines of text exist, a triple-quoted string is generally used for the docstring.
Summary
In this chapter, we saw the various Jython statement types. We started with something simple,
that is, expression statements, progressed into assignment statements, with a little side excursion
to discuss slices, and then resumed our discussion by talking about simple statements. These
then led to compound statements, and finally we saw how these different types of statements
could be put together as function definitions.
Jython Classes
Object-oriented programming (OOP) is an enormous concept and unfortunately not the topic of
this book. A wealth of information about OOP is available from a variety of other resources.
Therefore, this chapter is limited to the syntax and semantics of Jython OOP constructs. How-
ever, consider the fact that in Jython we use scripting objects to interact with the WebSphere
Application Server environment, and objects are created using classes.
Class Statement
To create an object, you must be able to define the data type for the object. To do so, use the class
statement, the simplified syntax for which is shown here:
class ClassName :
<statement>
<statement>
...
Like function definitions, class definitions are executable statements. When one is executed,
information about the specified class is collected by Jython. Generally, the statements within a
class definition are function definitions. In addition to function definitions, a class documen-
tation string (docstring) is also allowed. As with function definitions, if the first non-blank
expression statement in a class definition is a string literal, it is considered the class docstring
and can be accessed using either ClassName.__doc__ or objectName.__doc__.
This use of a period (’.’) after a class or object name is significant. It identifies that the
name/identifier that follows is an attribute, or method, of the specified class or object. The “Mod-
ules” section in this chapter notes that this “dot qualifier” is also used to indicate that the identifier
63
after the dot (period) is qualified by the identifier preceding the dot. So ClassName.__doc__
identifies that the __doc__ (docstring) attribute for the specified class is being referenced.
Also note that the name of the first parameter defined in class methods is not required to be
self. This is merely a convention, not a requirement. However, using something other than self
is probably a bad idea because of the potential confusion that it could cause to the human reader.
Jython (and Python) programmers are comfortable with the convention of using self to indicate
when the first parameter of a function (method) is used to identify the object with which the func-
tion is associated.
Listing 4.2 demonstrates how to instantiate (create) two objects of this new data type using the
same notation used to execute a function—that is, to use the class name followed by parentheses.
Table 4.1 explains each line in Listing 4.2 in more detail.
Line Description
2 Execute the setName() method for the object passing it a literal string.
4 Call the getName() method for thing2 to obtain, the object name value.
5 The displayed attribute value for this object instance has not been defined, so the default
value is displayed.
6 Call the getName() method for thing1 to obtain the object name value.
7 The displayed value for this object instance attribute is the value that was provided using
the setName() method call (line 2 in Listing 4.2).
8 Statement used to display the method docstring for the class setName() method.
Unlike some object-oriented languages, Jython does not rigidly restrict or even limit access to
attributes and methods within an object. It is the responsibility of the programmer to use good sense
and not abuse the openness of the language. Use the object methods to access the instance data. If
your code ignores this convention, it will be more difficult to maintain. Imagine what happens to
your scripts if the underlying class definition changes in some way (that is, the attributes or their
types are modified). Things that were previously working now either cause exceptions or (even
worse) invalid results. Exceptions are easy to see, whereas a incorrect value somewhere in the
middle of your script is much more difficult to understand and locate. Therefore, it is a best practice
to use the interface provided by the object methods to access and update the underlying information.
What does this mean? Generally, it means that you should not write code that “looks into”
an object to access or manipulate its attributes. Use the provided methods to “get” or “set” values
within the object. If the class is almost but not quite what you need, consider creating and defin-
ing a descendent class that extends the existing class to do what you need it to do.
Object Instantiation
One of the things we have yet to discuss is object customization during the creation process. In
some programming languages, the terminology for a method to be executed during the object cre-
ation process is a constructor. In Jython, if a method named __init__ exists within the class, it
will be called as part of the instantiation process. The syntax for this method is shown here:
NOTE There are no special methods that are automatically executed when an object
instance is no longer needed (that is, there are no destructor methods).
Built-in Constants
You should be aware that the only “constants” in Jython are the numeric (and string) literal val-
ues. Even the “special” identifier, None, is not a constant.1 Hopefully it won’t be too difficult for
you to restrain from assigning a different value to it. Listing 4.3 shows an example of how dan-
gerous this can be.
If you were to do something silly like this (that is, assigning a value to None), someone
(either you or someone who tries to make use of your script) is likely to lose time trying to figure
out why scripts are not working as expected or even worse, debugging scripts that apparently
worked fine previously. So be careful not to do this kind of thing.
1
None became a constant in version 2.4 of Python. It is not clear when the version of Jython that is used by wsadmin
will do the same.
List Methods
The following methods are available for all list objects. It is very doubtful that you will be reading
this in order from start to finish, so you can use the following as a reference when you need to
check what methods exist for list objects.
append( item )
Lengthen the list by adding the specified item. Logically, equivalent to:
List[ len( List ) : len( List ) ] = [ item ]
count( item )
Return the number of times that item occurs in the list.
extend( item )
Lengthen the list by adding the specified item. This differs from the append() method
when the item to be added is a sequence. When a sequence is added using append(), it
is added to the end of the list as an individual item. The extend() method appends each
sequence element individually, as can be seen in Listing 4.4.
index( item )
Return the index of the first occurrence of item in the list, if it exists. If it doesn’t exist in
the list, a ValueError exception is raised.
insert( index, item )
Inserts the specified item at the indicated index position. Logically, equivalent to:
List[ index : index ] = [ item ]
pop( [ index ] )
If the optional index is specified, remove and return that item from the list; otherwise,
remove and return the last item in the list. Should the list be empty or should the speci-
fied index element not exist, an IndexError exception is raised.
remove( item )
Remove the first occurence of the specified item from the list, should it exist. If the item
does not exist in the list, a ValueError exception is raised.
reverse()
Reverse the list contents “in place.” Listing 4.5 provides an example of how you would
use the reverse() method.
NOTE This method returns None, not another (reversed) list instance.2
sort( [ compareFunction ] )
Sort the list contents “in place.” The compareFunction, if specified, is used to deter-
mine the ordering of the list elements. This is especially useful when the list elements
are not simple types. If the compareFunction is provided, it is called and passed two
items from the list. It should return the following:
2
As shown in Listing 4.5 (lines 4–5).
• -1—To indicate that the first item is less than the second.
• 0—To indicate that the first item is equal to the second.
• 1—To indicate that the first item is greater than the second.
NOTE This method returns None, not another (sorted) list instance.
Dictionary Methods
Dictionaries are also objects. Each dictionary has the following methods available to it. Again, it
is unreasonable to expect you to read and remember all the methods described in this section. It is
more likely that it will be used as a reference while using dictionary objects.
clear()
Remove all items from the dictionary.
copy()
Return a “shallow” copy of the dictionary, which means that the copy will have the same
keys, but each value will refer to the same value object, should one exist. Listing 4.6
provides a copy() method example, and Table 4.2 explains this listing in detail.
1 Create a dictionary D.
11–12 Display the complete dictionary contents, including the modified element of
key 1.
has_key( key )
Return 1 if the specified key exists in the dictionary; otherwise, a 0 is returned.
items()
Return a list of the dictionary key/value (tuple) pairs.
keys()
Return a list of the dictionary keys.
setdefault( key [, defaultValue ] )
If the specified key exists in the dictionary, return the associated value. Otherwise,
String Methods
Strings are also objects, and have their own set of methods. Since string use in scripts is so com-
mon, we expect that this will be a frequently referenced section of the book.
capitalize( )
Return a copy of the string with the first character capitalized.
center( width )
Return a space padded string of the specified width containing the given string centered
in the middle.
count( substring[, start[, end ] ] )
Return the number of occurrences of the given substring, where the optional start and
end parameters are used like slice values to indicate the portion of the string to be checked.
endswith( suffix[, start[, end ] ] )
Return 1 if the string ends with the specified suffix; otherwise, return 0. The optional start
and end parameters are used like slice values to indicate the starting and ending indices.
expandtabs( [tabsize] )
Return a copy of the string with all tab characters are expanded using spaces. If the
optional tabsize parameter is not specified, 8 is used.
find( substring[, start[, end ] ] )
Return the lowest index in the string where the substring is located. The optional start
and end parameters are used like slice notation values to indicate the portion of the
string to be checked. Return -1 if the substring is not found.
index( substring[, start [, end ] ] )
Like find(), but a ValueError exception is raised should substring not be present.
isalnum( )
Return 1 if at least one character exists and all characters in the string are alphanumeric (that
is, ’0’ through ’9’, ’a’ through ’z’, or ’A’ through ’Z’). Otherwise, a 0 is returned.
isalpha( )
Return 1 if at least one character exists and all characters in the string are alphabetic
(’a’ through ’z’, or ’A’ through ’Z’). Otherwise, a 0 is returned.
isdigit( )
Return 1 if at least one character exists and all characters in the string are numeric (’0’
through ’9’). Otherwise, a 0 is returned.
islower( )
Return 1 if at least one letter character exists and all letters in the string are lowercase.
Otherwise, a 0 is returned.
isspace( )
Return 1 if at least one character exists and all characters in the string are whitespace
characters (space, tab, newline, carriage return, vertical tab). Otherwise, a 0 is
returned.
istitle( )
Return 1 if at least one character exists and all characters in the title follow capitaliza-
tion rules (uppercase letters may only follow non-letters, and lowercase letters may only
follow letters). Otherwise, a 0 is returned.
isupper( )
Return 1 if at least one letter character exists and all letters in the string are uppercase.
Otherwise, a 0 is returned.
join( sequence )
Return a string that is the concatenation of the strings in the sequence. The separator
between elements is the string whose method is being used. Keep in mind that if an
empty delimiter string is specified, the sequence strings are simply concatenated.
Listing 4.8, on line 5, shows how the string for which the join() method is being called
is a single space.
ljust( width )
Return a string of the specified width, padded on the right with spaces. If width is less
than or equal to length of given string, return a copy of the given string.
lower( )
Return a copy of the string with all uppercase characters converted to lowercase.
lstrip( )
Return a copy of the string with all leading whitespace characters removed.
replace( old, new[, count ] )
Return a copy of the string after replacing a maximum of the count occurrences of old
replaced by new. If count is not specified, all occurrences are replaced.
rfind( substring[,start [,end ] ] )
Like find(), but the highest index is returned or -1 if the substring is not found in the
string. The optional start and end parameters are used like slice notation values to
indicate the portion of the string to be checked.
rindex( substring[, start[, end ] ] )
Like rfind(), but a ValueError exception is raised if the substring is not present.
rjust( width )
Return a string of the specified width, padded on the left with spaces. If width is less
than or equal to length of the original string, return a copy of the given string.
rstrip( )
Return a copy of the string with trailing whitespace characters removed.
split( [ separator [,maxsplit ] ] )
Return a list of substrings delimited by the given separator. If the optional maxsplit
parameter is specified, its value is used to limit the maximum number of split operations
performed. If maxsplit parameter is not specified, all possible split operations are per-
formed. If the optional separator parameter is not specified, whitespace characters are
used (after removing any leading and trailing whitespace characters). Listing 4.8 has a
simple example of using the split() method using a single blank as a parameter.
splitlines( [keepends] )
Return a list of the lines in the string, breaking at end-of-line boundaries. If the optional
keepends parameter is specified and is non-zero, then each list element will include the
end-of-line delimiter.
startswith( prefix[, start[, end ] ] )
Return 1 if the string begins with the specified suffix; otherwise, return 0. The optional
start and end parameters are used like slice values to indicate the portion of the string
to be checked.
strip( )
Return a copy of the string with leading and trailing whitespace characters removed.
swapcase( )
Return a copy of the string with lowercase characters converted to uppercase and vice
versa.
title( )
Return a copy of the string where words start with uppercase characters; all other char-
acters are lowercase.
upper( )
Return a copy of the string where all lowercase characters are converted to uppercase.
zfill( width )
If width is greater than the given input string, return a copy of the string left padded with
zeros to the specified width. Otherwise, return a copy of the input string.
String Formatting
It is difficult to precisely control the appearance of output generated using the print statement.
For example, to perform an action on a group of names that have “user” as a prefix and a numeric
suffix (from 0..5), you might be tempted to try something like what is shown in Listing 4.9.
Unfortunately, by using the comma between the “prefix” string and the number, a space is
inserted between the each value (as in line 3). What if you use a plus sign to concatenate the user
string with the loop control value? Let’s take a look at Listing 4.10.
3
Remember that when the statement-suite of a compound statement is a single simple statement, it can occur on the
same line as the statement keyword.
What does that mean? Oh, yeah, that’s right. String concatenation is only defined for two
strings, not a string and a number. Can you convert the number to a string and then concatenate?
Certainly, you can use the backtick operator described in Chapter 2, “Jython Fundamentals.”
Listing 4.11 shows how this might be done.
Is there a better way to perform string formatting? Yes, but it is much more involved than
the simple display output seen previously. A string format operator exists that allows you to com-
pletely control how data should be represented. The operator uses the percent sign (“%”), and
has a “format string” as the left operand and the value(s) to be displayed as the right operand.
The way to do this is to use the Jython string format operator (“%”) to identify the kind of
data to be displayed and how it should be displayed. When a string is followed by the percent sign,
Jython processes the string and the values that follow, the result of which is a formatted string.
formatString % values
The string format operation involves the processing of the formatString, looking for format
specification sequences, and using these sequences to format the associated data from the right
operand. For any other text in the format string, the data is copied “as is” to the result string.
Each format specification begins and ends with a required character. The character used to
indicate the start of a format specification is the percent sign (“%”), and the ending character iden-
tifies the type of data to be processed. A complete and detailed description of all the available string
format options is beyond the scope of this book; however, some of the scripts will make use of this
feature, so it is appropriate to provide the following information, examples, and explanations.
Section “3.6.2” of the Python Library Reference, “String Formatting Operations,” describes
this topic more completely, and is available at http://docs.python.org/lib/typesseq-strings.html.
String format examples are provided in Listing 4.12 and explained in Table 4.3.
2–3 This format string contains four format specifications, like this:
• %(str)s—Format the value named str as a string.
5–9 Shows how you can use the string format operator with a print statement to display
the values indicated in the specified ways. Note how the presence of the newline (i.e.,
’\n’) in the format string causes each value to be display on a separate line.
11–14 Because the format specifiers do not include a “name” in parentheses, the right
operand of the string format operator must be a tuple containing the exact number of
11–14 values for which format specifiers exist. The values in the tuple are displayed in the
order they occur:
• %e—Format the value as a floating point using the default exponential nota-
tion.
15–16 A trivial example where a three-digit octal value is displayed with leading zeroes
(%03o). Because only one format specification exists in the format string, a single
value can be used as the right operand for the string format operator.
Built-in Functions
A number of built-in functions exist in Jython. They can be used without having to do anything
special to make them available. One unfortunate difference between Python and Jython is that in
Python, there is a special module named __builtins__ that contains all of the built-in func-
tions identified in the following list. This is not the case with the version of Jython provided with
WebSphere Application Server version 6.1. This has been corrected in version 7.0, where you are
able to list these functions simply by using dir( __builtin__ ).
abs( x )
Return the absolute value of the specified numeric expression. For integers, long inte-
gers, or floating point values, the absolute value represents the positive value. If a value
is negative, the sign is dropped. For complex values, the result is the square root of the
sum of the squares of the values, which is sometimes referred to as the magnitude of the
value. A simplistic definition is provided in Listing 4.13.
callable( object )
Return 1 if the specified object appears to be callable; 0 otherwise. If this returns 1, it is
still possible that an attempt to call the object could fail. But if the returned value is 0,
calling the object cannot succeed.
chr( i )
Return a single character string whose ASCII value is the specified integer, which must
be in the range [0..255] inclusive. For example, uppercase letters have values from
[65..90], and lowercase letters have values from [91..122]. This is the inverse of ord()
(defined in this section).
compile( string, filename, kind )
Compile the string into a code object. Code objects can be executed by an exec state-
ment or evaluated by a call to eval(). If the string was read from a file, the filename
parameter should specify the name of the file. Otherwise, pass some recognizable value
(for example, ’<string>’). The kind parameter indicates how the code contained
within the string is to be compiled. The value should be one of the following:
’exec’
If the string contains a sequence of statements.
’eval’
If the string contains of a single expression.
’single’
If the string contains of a single interactive statement.
complex( real[, imag ] )
Create a complex number with the specified real and imaginary components. If the
imaginary parameter is omitted, it defaults to zero. The function serves as a numeric
conversion function like int(), long(), and float().
delattr( object, name )
The name parameter is a string and must be an attribute name of the specified object.
The role of this function is to delete the specified object attribute. For example:
delattr(obj,’spam’) is equivalent to del obj.spam
dir( [object] )
The dir function returns a sorted list of names. If no object parameter is specified, the
returned list contains the names of the local objects. If an object parameter is specified,
the returned list contains the attribute names of the specified object.
divmod( a, b )
The parameters must be non-complex numbers, and the result is a tuple of two numbers
representing of the quotient and remainder of the expression a / b.
float( x )
Convert a noncomplex number or a string to floating point. If the parameter is numeric,
Jython returns the closest approximation of this value using the available floating point
precision. Otherwise, the string must contain a “well-formed” numeric value with
4
Unfortunately, versions of the Application Server earlier than 6.1.0.15 appear to have a defect requiring that the file-
name to be executed should be specified as a literal string that does not have blanks between the parentheses and the
quotation marks.
optional leading and/or trailing whitespace characters, and Jython again returns the
closest approximation of this value.
getattr( object, name[, default ] )
The name parameter must be a string and should contain the name of an attribute of the
specified object. If the name is of an existing attribute of the specified object, the current
value of that attribute is returned. If the specified attribute does not exist, and the default
parameter is provided, its value is returned. Otherwise, an AttributeError exception
is raised.
globals( )
Return a dictionary representing the current global namespace.
WARNING This function is unsafe because no checks are used to validate the user
input before it is evaluated.
Using the raw_input() function allows your script to verify and validate the user
specified input.
int( x[, radix ] )
Return the specified value converted to integer form. If the value parameter is a string, it
must be a well-formed number and is allowed to have leading and trailing whitespace char-
acters. The optional radix parameter specifies the conversion base to be used (and defaults
to 10). The radix value can be 0 or 2 to 36 inclusive and can only be specified when the first
parameter is a string. A radix value of 0 indicates that Jython should interpret the value as it
does integer literals. Conversion failures cause exceptions to be raised.
isinstance( object, classinfo )
Return 1 if the object parameter is an instance of or a subclass of the specified
classinfo parameter; otherwise, return 0.
issubclass( class, classinfo )
Return 1 if the class parameter is a subclass of the specified classinfo parameter;
otherwise, return 0.
len( s )
Return the number of items (for example, length) of the specified object. The object
could be a string, a tuple, a list, or a dictionary.
list( sequence )
Return a list built from the items in the specified sequence. Note that if the specified
sequence is a list, the list and not a copy is returned.
locals( )
Return a dictionary representing the current local namespace.
NOTE Append ’b’ to one of the mode letters shown here to indicate that the file is to
be opened in “binary” mode (end-of-line characters are not respected as such).The
optional bufsize parameter identifies a requested buffer size. A detailed description of
this function is beyond the scope of this book. Please review the Python documentation
for this information.
ord( c )
Return the ordinal value of the specified single character (which may be a Unicode
character).
pow( x, y[, z ] )
Return x ** y, or ( x ** y ) % z if the optional third parameter is specified.
range( [start,] stop[, step ] )
Return a list containing a range of plain integer values generated using the specified
(plain integer) parameters.5
5
It is very easy to generate a very large list using range, consider how many values are generated should you use
something silly like range(2147483647). Attempts to do so, however, require a large amount of memory and
could cause heap exhaustion. You might want to consider using xrange() (described and explained later in this
section).
NOTE If a single parameter is specified, start defaults to 0, step defaults to 1, and the
value is used as stop. If two values are specified, step defaults to a value of 1. The value of
step must not be zero, or a ValueError exception is raised.
raw_input( [prompt] )
Display the optional prompt string, if one exists, then read a single line of text from
“standard” input, remove the tailing newline character, and return this string as the func-
tion result. An example is shown in Listing 4.17.
15|wsadmin>reduce( cat, ( 0, ) )
16|0
17|wsadmin>reduce( cat, ( 0, 1 ) )
18|’01’
Line(s) Explanation
7–8 Note how function calls can be nested. In the first case, the result of range( 101 ) is a
list containing the integers from 0 through 100 inclusive, and the result of the
reduce() function is the sum of these values.
11–12 Don’t be confused. The string ’abc’ is the sequence to be reduced, and the ’->’ is the
initialValue parameter. The reduce concatenates all of the elements of the string
sequence to the initialValue. This also shows that reduce() can process other than
integer values.
15–18 The last two examples show how reduce() can be used to process elements of a tuple.
The interesting thing to note about the former is that the input sequence contains a
single element tuple containing the integer 0 and that the result of using reduce() on
this sequence is an integer and not the string that is returned by the specified cat()
function. This is more evident when the input sequence has at least two elements, as
seen on lines 17–18.
reload( module )
Reload a previously imported module. Unfortunately, the restrictions, limitations, and
caveats related to this function are a bit beyond the scope of this book. For specific
details about this function and how it should be used, look at some Python documenta-
tion, one example of which is available at http://docs.python.org/lib/built-in-funcs.html.
repr( object )
Return a string containing a displayable, or printable, representation of the specified
object.
round( x[, digits ] )
Return the specified value as a floating point after rounding to the specified number of
digits after the decimal point. If the digits parameter is unspecified, it defaults to 0,
thus truncating any existing decimal points from the specified value. That rounding is
“away from” the value 0, as seen here in Listing 4.19.
’replace’ Use the official Unicode replacement character (i.e., U+FFFD), as a replacement for
any characters that can’t be converted.
vars( [object] )
Return a dictionary containing details about the local variables, or those of the specified
object, if one is provided.
Summary
This chapter continued our discussion of Jython, specifically related to object-oriented program-
ming constructs (such as classes, attributes, and methods). In addition, references are provided
for the built-in list, dictionary, and string methods, as well as functions that exist as part of the
language. We also took a short side trip to explore the topic of string formatting.
Jython Modules
Classes, functions, and variable definitions can be collected into files for easy reuse and mainte-
nance. A file containing these kinds of definitions is referred to as a module and has a suffix of
.py. In this chapter, we take a closer look at Jython modules.
87
Line 1 shows, by specifying the name of the module file, Jython can execute the contents of
that file. Notice that the generated output (lines 2–3) show that the statements contained within
the file were, in fact, executed. It is also important to note that the output on line 3 lists the names
of the identifiers that are defined and available within the module. If you remember, one of the
actions performed by the execution of a function definition is to bind the function statement-suite
to the function identifier. That is why the local function (countdown) is listed in the namespace.
Line 4 shows how to execute a function defined within a module. The general form for this
is moduleName.functionName(). This also points out one of the challenges related to naming
and using modules, which is when an import statement is executed, the module (file) name is
bound to the module (file) contents. Another form of the import statement is available that helps
with this issue, namely import FileName as name. This means that instead of simply using
import countdown, as shown in Listing 5.2, you could identify the name (or alias) by which
we want this module known. An example of this is shown in Listing 5.3.
Both of forms of the import statement bind all of the module contents to a name in the
given namespace. However, doing so means that to access any of the objects within the module,
the object must be qualified using either the module name or an alias (if the second form of the
import statement was used). There are a few different ways around this, all of which are related
to binding individual identifiers in the local namespace to module objects.
1. Assign a local identifier to a module object. Listing 5.4 shows how a module object
(function) can be bound to a local identifier. Note that in order to bind a module function
to a name does not involve the function being called, so the parentheses after the func-
tion name are not included in this assignment.
2. Another alternative is to use the last form of the import statement, which is from
ModuleName import objectName, which only adds the specified object to the name-
space, as shown in Listing 5.5.
3. Another alternative is to use a variation of the from form of the import statement,
which allows the identification of an alias for the given module object, as shown in
Listing 5.6.
4. The last form of the “from” variant of the import statement is to use an asterisk ’*’ as
the list of module objects to be bound to the current namespace—for example, from
FileName import *. This form is not recommended because it not only clutters the
namespace with module objects, but can also override existing object definitions with
ones from the specified module.
nested_scopes
Previously mentioned was the fact that three namespaces exist for identifiers:
1. Local—These names (identifiers) are defined and assigned within a function, class, or
module.
2. Global—These names are defined outside of a function, class, or module.
3. Built-in—These names exist as part of the environment and are available without any
special action on the part of the script writer.
As shown previously, when a reference is made to an identifier within a function, the order in
which the namespaces are checked for this identifier becomes an issue. The nested scope issue
was discovered and was fixed in Python 2.2. This problem is demonstrated by the code shown in
Listing 5.7.
The issue arises when a function is defined local to another function. In this case, note how
the reference to the variable x in function g() can only access a local or global value. The origi-
nal definition of scoping rules meant that there was no way for the code in a nested function (for
example, g()) could access items local to the enclosing, or outer, function (for example, f())
without them being passed as parameters. The desired effect is to allow intermediate scopes to be
checked instead of being ignored.
This is why the SyntaxWarning is generated. This shortcoming was corrected in version 2.2
of Python. The Jython used by wsadmin is based on Python version 2.1 and therefore includes
this shortcoming. Because this “correction” to the language involves a change to the way in
which scripts function, the developers of the language provided a way that script writers would be
warned about the potential impact to existing scripts. Additionally, it allows script writers to com-
municate to Jython that it should make use of this “future language feature.” This involves using
the from variant of the import statement, and shown in Listing 5.8.
10|wsadmin>x = ‘global’
11|wsadmin>f()
12|f(): x = local to f()
13|g(): x = local to f()
14|wsadmin>
By adding the statement shown (line 1), the script writer is telling Jython to change the
way in which Jython processes the script. Without it, Jython will “generate a SyntaxWarning”
message for each script that will be affected by this language change when the feature is fully
implemented.
NOTE The profile script that we provide and recommend using (that is, WAuJ.py)
includes this import in order for you to simplify your scripts.
Packages
A package is a collection of modules (files) collected into a directory or directory tree. Each
directory in the tree is required to have a file named __init__.py (which may, in fact, be
empty). Unfortunately, Jython packages are outside the scope of this book. To learn more
about them, consider reviewing the Python documentation about packages that is available
from http://docs.python.org/tut.
Listing 5.10 shows an example of how this user-defined exception can be used. This allows
exception conditions to be specifically designed for the scripts being written. Line 2 shows the
creation of an exception object, and line 3 shows how the exception object instance is associated
with a particular identifier (that is, e). Line 4 shows how, by simply referencing the object identi-
fier, that the class __str__() method is invoked to return the string representation of the
instance attribute value.
Built-in Exceptions
Jython uses the same kind of exception class hierarchy as Python. However, some differences do
exist due to recent changes in Python. You may encounter exceptions in some Python code that do
not exist in Jython.
Listing 5.11 shows the names of the exceptions that can be generated by Jython, as well as
their relationship to the base Exception class. Should you decide to create an exception class for
your application, this information may help you decide on how to do that.
- ZeroDivisionError
- FloatingPointError
- AssertionError
- AttributeError
- EnvironmentError
- IOError
- OSError
- EOFError
- ImportError
- KeyboardInterrupt
- LookupError
- IndexError
- KeyError
- MemoryError
- NameError
- UnboundLocalError
- RuntimeError
- NotImplementedError
- SyntaxError
- IndentationError
- TabError
- SystemError
- TypeError
- ValueError
- UnicodeError
- SystemExit
- Warning
- DeprecationWarning
- SyntaxWarning
- RuntimeWarning
- UserWarning
Functional Programming
Jython also includes facilities that allow scripts to be written more concisely. These facilities are
related to a subject called functional programming and include the following:
• Lambda expressions
• The filter(), map(), and reduce() built-in functions
• List comprehension
This topic is somewhat involved and requires quite a bit of explanation. Fortunately, this explanation
is readily available elsewhere. Specifically, there are some very nice and readable articles related to
this subject available on the developerWorks® website (http://www.IBM.com/developerworks/).
Take a look at these developerWorks articles on Functional Programming:1
• Charming Python: Functional Programming in Python
Part 1: http://www.IBM.com/developerworks/linux/library/l-prog.html
Part 2: http://www.IBM.com/developerworks/linux/library/l-prog2.html
Part 3: http://www.IBM.com/developerworks/linux/library/l-prog3.html
• Using the full potential of Jython to build compact and maintainable wsadmin scripts
http://www.IBM.com/developerworks/websphere/library/techarticles/0801_simms/
0801_simms.html
1
It is necessary to mention, however, that the “listings” in Parts 1 and 2 of the Charming Python articles are a little
hard to read because of the way they are represented. For some reason, the significance of the end-of-line markers for
these listings was lost, so they require a little bit more study to understand. It helps if you remember that ’#’ is used
to indicate the beginning of a comment, and the ’>>>’ is the Python interpreter command prompt.
12| try :
13| istream = java.io.FileInputStream( fileName )
14| props = java.util.Properties()
15| props.load( istream )
16| istream.close()
17| result = {}
18| e = props.keys()
19| while e.hasMoreElements() :
20| key = e.nextElement()
21| result[ key ] = props.getProperty( key )
22| return result
23| except java.io.FileNotFoundException :
24| raise IOError, ‘FileNotFound: ‘ + fileName
4 A documentation string (docstring) used to identify the role of the file contents.
9–10 Import statements used to load the Java resources needed to perform the desired action.
14 Creation of a Java Properties object for accessing the specified properties file.
15 Calling of the properties method for processing the specified file as a properties file.
19 while loop used to process all property key values in the enumeration.
21 Assignment to the dictionary using the given key and the associated value.
22 After the loop completes successfully, the generated dictionary is returned to the caller.
23 Exception handler for a specific error (for example, the Java FileNotFoundException
thrown by the FileInputStream constructor).
available for the programmer to use and build upon. This collection is much too large to describe
here and includes code for all sorts of things, such as the following:
• Date and time manipulation
• Calendar-related functions
• Containers (for example, heaps, trees, lists, vectors, and so on)
Provided with this book are a few very useful and powerful modules used often by the scripts, as
discussed in the following sections.
sys Module
Rather than being a simple regurgitation of the Python documentation on this built-in and
(almost) always available module, let’s take a look at techniques for finding out what is in a mod-
ule like this. These same techniques prove useful later as you start learning about the WebSphere
Application Server scripting objects.
Listing 5.14 shows a trivial script that can be used to display information about the items in
the sys module. Lines 5–6 gets and sorts the list of items names in the sys module. Line 8 uses
list comprehension to determine the longest name for later use in the alignment of the output. The
most likely areas of confusion are lines 11–14 and line 16. Lines 11–14 are used to obtain the
type() of each named object as a string. Unfortunately, trying to use the type() on some
items causes an exception to be raised, which is why the try/except statement is needed.
This leaves line 16 to explain. It uses formatted string output to display the pertinent informa-
tion in a nicely aligned fashion. The ’%2d:’ formation string is used to format the item number,
right-justified in a two-digit field, followed by a colon. The ’%*s’ format string uses two values:
the width to define the width of the output field and specify the fact that the value should be left
justified in this field and the ’s’ to indicate that the value of name should be output as a string. This
is then followed by ’%s’ to have the value of kind output as a string. See Listings 5.14 and 5.15 for
examples.
We will only look at a few of the results in order to demonstrate how to use this kind of
information. Let’s start with lines 34 and 35, which show that the sys module has two integer
values to define the smallest and largest integer values. The value of sys.version for both
version 6.1 and 7.0 of the AppServer is 2.1. Line 26 shows that a function called sys.exit()
exists, and investigation shows that this routine can be called to terminate the script being exe-
cuted. Other values of interest include sys.argv, which contains the list of parameters speci-
fied when the script was executed. You will see how it can be processed shortly.
Some of the most important items in the sys module have been left for last. Sys.path is a
list of directories that is used by Jython to locate modules (for example, when an import
<moduleName> (of any form) is executed, Jython looks in the directories specified in this list.
Chapter 7, “Introduction to Admin Objects,” describes how this can be used.
One of the most important entries in the sys module is the sys.modules directory object.
It contains the names of the modules and reference information about modules that have been
loaded. Chapter 7 discusses how it can be used to get around one of the challenges that exist for
WebSphere Application Server Administration script authors.
And finally, sys.exc_info() is a method that is used within an except clause. The
result of calling this function is a tuple containing the following information about the exception
that is currently being handled:
• Type
• Value
• Traceback
Listing 5.16 shows one way in which this function might be used. You will see this function used
elsewhere in some of the scripts provided with this book.
getopt() Module
One reason for using scripts is that they can be tailored to process user input specified when
the script is invoked. Many of the scripts provided with this book are written to do just this.
Command-line process has been around for quite some time. To make things easier for C pro-
grammers, the getopt() library routine was provided and has been used extensively. For this
reason, the same kind of facility for processing Python command-line values has been developed
and made available as a module. The documentation for the getopt module is available on the
web at http://docs.python.org/lib/module-getopt.html.
The code shown in Listing 5.17 represents the main structure of many of the scripts provided
with this book.
Usage()
This routine, the skeleton for which is shown in Listing 5.18, is quite straightforward. Things to
note include the following:
1. cmdName parameter used to simplify the use of the script name in the output.
2. Jython triple quotes (long) string used to format usage information in a readable manner.
3. Use of named format specification (for example, %(cmdName)s) and the formatted
string operator ( ... % locals()) greatly simplifying the use of the script/routine
name in the usage information.
4. Use of sys.exit() to terminate the script when usage information is displayed.
13|\nOptional switches:
14|...
15|\nNotes:
16|...
17|Examples:
18|...
19|‘’’ % locals()
20| sys.exit( 1 )
parmTest()
This is the “named” routine, the one that is executed by the main test at the bottom of the script
to initiate the action work to be performed. As shown in Listing 5.19, in this case, the routine is
used to check how many user-specified parameters were provided and if enough are present,
“parse” (process) them, looking for the required and optional parameters.
8–13 Test for number of user parameters specified. Remember, if Usage() is called, it never
returns; sys.exit() is invoked to terminate the script.
24–26 The result of calling parseOpts() will be to populate the global Opts dictionary with
the user-specified values. The purpose of this code is to use the information in this dic-
tionary to assign variable names to make access to the values simpler.
parseOpt() Function
This is the routine that is only called by parmTest() to parse (process) the user-specified
parameters. Table 5.3 provides important items to note about the parseOpt() function shown
in Listing 5.20.
Listing 5.20 parseOpts() function
1|#-------------------------------------------------------------
2|# Name: parseOpts()
5 Use of default cmdName parameter, which is passed to Usage() should that routine be
called (see lines 16 and 43).
6 String identifying “short form” options; that is, a single letter with an optional colon to
indicate that this option switch requires an associated value.
7 List of long form options. Note the use of string split() method to create the list and
the use of an equal sign at the end of an option to indicate a required value.
11–16 Use of getopt() routine to use the short and long option lists to parse/process the user-
specified parameters and the use of an exception handler to deal with an error in the user-
supplied information (for example, missing or unrecognized option or missing value).
One of the powerful things about using getopt() to process the command-line parameters
is how it allows you to focus on making your script useful without having to spend all sorts of time
testing the command-line processing code. That has all been done for you by the people who
wrote and provide the getopt module. Take a look at the notes and examples provided with the
parmTest usage statement to understand this further. Listing 5.21 demonstrates this. First we see
the very end of the Usage() output (for example, the Examples: section) when the script is
invoked and no parameters are specified. Then, the long forms of the parameters names are
shown, and finally, the short forms of the same parameters are also shown. The use of getopt()
to process the command-line parameters allows the remainder of the script to focus on the actual
role of the script and minimize the amount of effort required to validate and make the user com-
mand-line input easily accessible to the script. The scripts provided with this book with make use
of getopt()for just this purpose.
A regular expression could be used to verify that the string “matched” this pattern and extract the
various name values from this string. The way that regular expressions work is that “normal”
characters, by definition, match identical characters in strings. Additionally, there are special, or
meta-characters, that have special meanings. A subset of the total list of meta-characters and their
roles are listed in Table 5.4.
’^’ Matches the start of the string (or after a newline in MULTILINE mode).
’$’ Matches the end of the string (or before a newline in MULTILINE mode).
[] Identifies a set of characters to be matched. Any character within the square brackets will
match.
\D Matches a non-digit.
\s Matches a whitespace character (for example, space, tab, newline, form-feed, vertical tab).
\ Escape prefix, which can be used to allow a meta-character (for example, ’.’) to occur in
the string and be matched.
These represent some of the most frequently used “special” characters and allow scripts to be
written that match a large variety of patterns. In addition, there are some modifiers that allow these
characters to occur a specific number of times. These modifiers are listed in Table 5.5. The reason
they are called “greedy” is that they indicate that “as many as possible” matches will be used.
{m,n} Preceding char/meta-char must exist at least ’m’ times and at most ’n’
times.
For those instances where a “greedy” match is not desirable, the modifiers shown in Table
5.6 can be used instead. For these, the shortest matching sequence is preferred.
{m,n}? Preceding char/meta-char must exist at least ’m’ times and at most ’n’
times.
Searching for and matching of regular expressions are the most common operations that
can be done with RegExp patterns. However, they are not the only things that can be done. The
methods that exist for RegExp objects are listed here.
span( [group] )
Return a tuple containing the starting and ending position for the specified group. If no
group number is specified, group defaults to 0.
pos
The starting position specified on the match or search or 0 if none was specified.
endpos
The ending position passed to the match or search method used to create the match
object. If no value was specified, it represents the length of the specified string.
lastindex
The integer value representing the number of captured groups.
lastgroup
The name of the last captured group, or None.
re
The regular expression object used to perform the match or search.
string
The string on which the match or search was performed.
Listing 5.22 shows an example interactive wsadmin session in which Regular Expressions are used.
1 This statement is better understood after reading Chapter 8, “The Admin Config Object,”
which describes the AdminConfig administration object. In the single application server
environment on which it was executed, it returns a configuration id string for the applica-
tion server.
2 This statement is used to load the regular expression (re) library code and creates a name-
space for this module.
3–4 These statements build a regular expression pattern string to be used to identify and extract
portions of a configuration id.
5 This statement invokes the compile function in the re namespace to create a regular
expression object, a reference to which is saved in the variable named reo.
6 The match method of the previously created regular expression object is used to process
the string variable named server that contains the configuration id. Note: Alternative tech-
niques for performing this same action and that don’t save the regular expression object
are:
7 The lastindex attribute of the match object can be used to access the match object cap-
tured groups. Note: group( 0 ) contains a copy of the entire string that matched specified
pattern.
8–11 This demonstrates a string formatting technique to display the index value, the starting and
ending positions for the group, and the value of the group.
12 This is the empty line that indicates the end of the for statement to wsadmin.
13–16 These are the four lines output by the print statement within the for loop.
Summary
In this chapter, we brought together a number of the concepts from the preceding chapters on
Jython (Chapters 2–4, specifically). We made use of this information in order to present the
enormously valuable concept of Jython modules. In subsequent chapters where we discuss Web-
Sphere scripting objects, you will better understand these objects because of the information
found herein.
wsadmin
“Make it so!”
—Jean-Luc Picard, USS Enterprise-E commanding
The wsadmin program can and should be considered a scripting engine for performing adminis-
trative tasks on an application server or its configuration. It can be used to execute individual
commands or multiple commands in an interactive/interpretive fashion, or it can be used to exe-
cute script files. Just as Jean-Luc Picard commands the astronauts who control the starship Enter-
prise, wsadmin commands and controls how WebSphere Application Server behaves and
configures the way WebSphere Application Server starts.
The operating system being used defines how the wsadmin program should be exe-
cuted. The examples included in this chapter show how the command to start the wsadmin
program looks in a Unix® and a Windows type of environment. The ./ before the name of the
file to be executed on a Unix environment is an indication that the specified file is located in
the current directory. The options in square brackets is simply a notation used to indicate
that user-specified options are, in fact, optional.
• AIX®—wsadmin.sh [options]
• Linux®—wsadmin.sh [options]
• z/OS®—wsadmin.sh [options]
• Windows—wsadmin1 [options]
Let’s begin by looking at the wsadmin “help” (usage) information. Specifying -?, -h, or -help
after wsadmin on the command line will cause wsadmin to display its help details, and terminate.
1
Windows executable files extensions (e.g., .bat) are optional.
113
Listing 6.1 shows a significant portion of the wsadmin help, and Table 6.1 describes values
that are allowed for individual options. From the number and variety of these options, it should be
clear that an assortment of things can be specified on the wsadmin command line to identify and
indicate what wsadmin should do for a particular invocation. Unfortunately, what may not be as
easily understood are the implications of the selections that can be made or the default settings
that exist and how these defaults can be changed to suit your particular needs. The purpose of this
chapter is to explain these aspects of the wsadmin program.
wsadmin
[ -h(elp) ]
[ -? ]
[ -c <command> ]
[ -p <properties_file_name>]
[ -profile <profile_script_name>]
[ -f <script_file_name>]
[ -javaoption java_option]
[ -lang language]
[ -wsadmin_classpath classpath]
[ -profileName profile]
[ -conntype
SOAP
[-host host_name]
[-port port_number]
[-user userid]
[-password password] |
RMI
[-host host_name]
[-port port_number]
[-user userid]
[-password password] |
NONE
]
[ -jobid <jobid_string>]
[ -tracefile <trace_file>]
[ -appendtrace <true/false>]
[ script parameters ]
...
script parameters Anything else on the command line. These string values are passed to the
script in the sys.argv variable.
trace_file Is the log file name and location where wsadmin trace output is directed.
To better understand these things, it is best to begin by describing what happens when
wsadmin starts executing. Looking at the wsadmin help output, you find a number of available
options. Unfortunately, the way that they are presented might make them a bit difficult to under-
stand, but grouping the options into categories might make things a little clearer.
wsadmin Options
It’s probably a good idea to familiarize yourself with the wsadmin command-line options. Even
though you may eventually get into a habit of using only a subset of these options, it is good to
realize which ones exist, just in case you need to do something different.
Usage Information
The first category of options might best be called usage information or documentation. The
options that fit this category are used to display the wsadmin usage details and were shown earlier.
If no command or script is specified, an interpreter shell is created for interactive use. To
leave an interactive scripting session, use either the quit or exit commands.
Several commands, properties files, and profiles may be specified on a single command
line. They are processed and executed in the order they are specified.
This option allows values to be provided that define how the JVM should be initialized. Any valid
JVM option may be included. For example, to define the maximum size to be used by the Java
heap, one can use something like -javaoption -Xmx1024m.
-wsadmin_classpath <classpath>
This option should be used to add Java class files to the classpath. Multiple entries should be sep-
arated using a semicolon. Should a space exist in any of the directory names, surround the entire
value in double quotes. The example option, shown next, demonstrates how to add the specified
archive (.jar) file to the wsadmin classpath. If you have Java libraries that you would like to add
to the wsadmin code base, this is how you would do that. If you have some Java code that uses
the Java Management Extensions (JMX) to monitor and control the behavior of WebSphere, this
is how you would load that code into wsadmin:
-wsadmin_classpath “C:/Program Files/classes/myClasses.jar”
Directive statements are of the form key=value and frequently correspond to command-
line options. The keys and values found in the default property files are created either during the
installation of the WebSphere Application Server product or during the creation of a profile and
have a prefix of com.ibm.ws.scripting. Table 6.2 shows the property key suffix, its default
value, and the corresponding command-line option (should one exist).2
It should be easy to understand that wsadmin performs its job depending on the options
that are provided on the command-line. What may not be clear is that the property files exist to
define “default” values should command-line options not be provided. It should be no surprise
that the primary property file that is processed during the initialization of wsadmin is named
wsadmin.properties. So should you decide that particular properties are appropriate for your
environment, you can either modify the existing property files or create your own to reflect your
individual or group needs.
echoparams true
validationOutput .../wsadmin.valout
traceString *=info
emitWarningForCustom true
SecurityPolicy3
2
Remember that each property key begins with com.ibm.ws.scripting.
3
This property suffix is all one camelcase word.
tempdir java.io.tmpdir
validationLevel HIGHEST
crossDocumentValidation true
Enabled
classpath -wsadmin_classpath
Another thing that you should realize is that multiple instances of the property files exist
(especially when multiple profiles exist), which brings up a major “pet peeve” with this and,
unfortunately, many other products—the use of very similar terminology for different things.
Specifically, the use of profile here actually refers to the profileName command-line option.
If you take a moment to search the online documentation for the term “profile” or “profiles,” the
vast majority of references are related to the topic of profileNames. In fact, choosing one of the
first pages4 that is located, you find that it contains the following statement:
“A profile defines the runtime environment. The profile includes all of the files that the
server processes in the runtime environment and that you can change.”
It is not until you reach a topic entitled “Setting up profile scripts to make tracing easier using script-
ing” that you encounter the first reference to the command-line option identified by the -profile
option. The topic of profile scripts is discussed shortly; however, first we need to finish the discus-
sion about the profileName option, which has the misfortune of being referred to as profile in
many places in the documentation. In this book, every effort is made to distinguish between the
concept of profile as in profileName and profile as in profile script file.
Anyway, it may not be immediately obvious which of the property files will be used when
wsadmin is executed and that values from multiple property files might be read and used during
one execution of wsadmin. What determines which files are used? Determining factors can
include the following:
1. Which wsadmin command script (for example, .bat or .sh) file was executed?
The answer to this question identifies that the wsadmin program, as is the case with any
of the command script files provided with the WebSphere Application Server product,
4
http://publib.boulder.ibm.com/infocenter/wasinfo/v6r1/index.jsp?topic=/com.ibm.websphere.base.doc/info/aes/
ae/cpro_overview.html.
can, by its location, imply a “default” profileName to be used should one not be spec-
ified on the command line. For example, should the “wsadmin” command script from a
particular profile bin directory (that is, ”...\WebSphere\AppServer\profiles\
AppSrv01\bin”) be executed, then this is exactly the same as having executed the
“wsadmin” command script from the <WAS_HOME>\bin (for example,
”...\WebSphere\AppServer\bin”) directory and having specified ”-profileName
AppSrv01” as a command-line option.
2. Which profileName has been identified as the “default?”
This question is important should the “wsadmin” command script from the
<WAS_HOME>\bin directory be executed without providing the profileName option,
in which case this identifies the profileName to be used should one not be provided.
3. What wsadmin command-line options were specified?
The answer to this question is especially important because it can change the “default” behavior
of wsadmin command. So regardless of the answers to the previous questions, if the
profileName command-line option is specified, it takes precedence over the default
profileName value. Furthermore, there is an option that allows you to specify additional prop-
erty files (for example, the ”-p” option, as described later).
If you don’t know or can’t remember which profileName has been defined as the default,
there is an easy way to find out which will be used by the wsadmin command script. From a com-
mand prompt, execute the manageprofiles command script and specify the -getDefaultName
option, as shown in the example:
...\bin>manageprofiles -getDefaultName
AppSrv00
Should you decide that a different profileName be used as the default for your environment,
the manageprofiles command may be used to change the default, as shown in this example:
...\bin>manageprofiles -setDefaultName -profileName AppSrv00
INSTCONFSUCCESS: Success: The default profile has been set.
Once you have determined the profileName being used when the wsadmin starts executing, the
next question to be answered is, “Which properties file(s) will be used during the initialization of
wsadmin?” During its initialization, wsadmin looks for a file named wsadmin.properties in
each of the following locations:
1. Below the installation root directory—For example, <WAS_HOME>\profiles
\<profileName>\properties\wsadmin.properties.
2. The user default, or home directory—For example, <USERPROFILE> \wsadmin.
properties.
3. The file specified by the WSADMIN_PROPERTIES environment variable (should one
exist)—For example, %WSADMIN_PROPERTIES%.
What does it mean that wsadmin “looks” for a file in each of these places? If the specified file
exists, any properties (for example, key=value statements) contained therein are read and
saved—meaning that a key=value statement occurring in the first file found may be overridden
by another occurrence of the same key in a subsequent property file. So be careful. You might
need to override a property file setting with a command-line option (for example, -tracefile)
and review the messages contained therein to understand exactly which properties files are
loaded and in which order to understand how the initialization of the wsadmin environment
occurs.
In addition to the properties files listed here, the -p command-line option can be used to
specify one or more additional properties files to be loaded and processed during the initialization
of wsadmin. Again, any of these files may be used to override existing key values set by any of
the previously identified property files.5 The syntax of this command-line option is seen here:6
-p <properties_file_name>
The wsadmin tool uses information from the property files to determine things such as:
• The default communication protocol to be used, if any
• The hostname of the default application server
• The default port number to which the connection request should be sent
• The user and password to be used for authentication.
Fortunately, the information in the property files is very well documented and easily under-
stood. However, not all option values are identified in the comments (for example, even though
NONE is a valid communication protocol, its availability is not documented in the wsadmin
.properties file).
5
Because of the potential confusion that can occur, a best practice would probably include a limitation of the number
of properties files to be specified and processed as part of the initialization of wsadmin.
6
Remember to enclose the properties_file_name in double quotes if a space exists anywhere in the value. For
example: -p “C:\Program Files\properties\my.properties”.
7
The IBM InfoCenter shows the word ”NONE” in uppercase. In fact, you can use either upper- or lowercase.
WARNING Changes made to the configuration in local mode should be made with
extreme caution because they can make the configuration invalid.
If the connection type identifies that either a SOAP or RMI/IIOP connection should be
established, then additional property settings are used to determine the host and port number to
which the connection request should be sent. Additionally, when security is enabled on the target
application server, the user and password information need to be communicated to the applica-
tion server so that permission to communicate with the server can be authenticated.
The properties and/or command-line options that are used during this connection phase are
as follows:
• conntype
• host
• port
• user
• password
You can choose to save the user and password authentication values in communication protocol-
specific files (for example, soap.client.props or sas.client.props). However, you
should be aware of the security implications of saving user and password information on your file
system. Additionally, you should also be aware of the implications of providing the user and
password information as wsadmin command-line options, given that it is possible to display the
command-line options of any executing program on all of the operating systems on which the
application server product is supported.
If security is enabled on your application server and the user and password information is
not available in the property files, or as command-line options, wsadmin attempts to open a dia-
log box and prompt you for the user and password information.
One of the useful characteristics about the wsadmin program is the fact that it explains
what it is doing, as well as what it is trying to do. For example, when wsadmin is started and is
able to connect to an application server, the first line of output generated indicates the name of the
server with which the connection was made (or attempted), the communication protocol that was
used, and the kind of application server to which the connection was made (if the connection was
successful). Listing 6.2 contains two examples of this connection message.
Listing 6.2 WASX7209I Connection Message
C:\IBM\WebSphere\AppServer\bin>wsadmin
WASX7209I: Connected to process “server1” on node ragibsonNode00 using
SOAP connector; The type of process is: UnManagedProcess
...
C:\IBM\WebSphere\AppServer\bin>wsadmin -profileName Dmgr01
NOTE For the remainder of this book, it is presumed that this change has been made to
the wsadmin.properties file. Therefore the use of the ”-lang jython” command-
line parameters will no longer be included in any of the examples.
If you change language, you should also change the names of the security profile scripts in
wsadmin.properties from something.jacl to something.py or remove them if no
corresponding something.py file is available. Otherwise, wsadmin will attempt to find
Jython versions of the Jacl scripts by looking for the .py file in the same directory and
complain if none exists.
Trace-Related Options
Another of the things that can be controlled about the environment initialization is related to trac-
ing. Three command-line options exist that relate to tracing of wsadmin:
• tracefile
• appendtrace
• jobid
The first two of these have corresponding settings in wsadmin.properties (for example,
traceFile and appendTrace). The other (-jobid) is only available as a command-line option
and is used to add a text string to the wsadmin trace file. This entry can be used to correlate the
contents of the trace file with a specific invocation of wsadmin. If the jobid text string contains
spaces, then the string should be enclosed in quotation marks:
wsadmin -jobid “Ports used” -f ListPorts.py
8
If you change the language setting, it is very important to also change the names of the default profiles. See the sec-
tion “wsadmin Profile Script Files” for very important details.
Remember to change the file extension for these profile files from .jacl to .py, and verify that
the specified files exist in the indicated locations. During the initialization of wsadmin, any files
specified here will be used to configure the wsadmin scripting environment before any command
or script is executed.
After you’ve made that change and started an interactive wsadmin session, you can use the
dir() command to find out what objects exist in the default namespace. Listing 6.3 shows an
example of this. When we first encountered this information, our initial reaction was, “Wow, from
where did all of these objects come?”
Listing 6.3 Default wsadmin Namespace
1|C:\IBM\WebSphere\AppServer\bin>wsadmin
2|WASX7209I: Connected to process “server1” on node ragibsonNode00
3| using SOAP connector; The type of process is: UnManagedProcess
4|
5|WASX7031I: For help, enter: “print Help.help()”
6|wsadmin>dir()
7|[‘AdminApp’, ‘AdminConfig’, ‘AdminControl’, ‘AdminTask’, ‘Help’,
8|’LTPA_LDAPSecurityOff’, ‘LTPA_LDAPSecurityOn’, ‘TypedProxy’,
9|’__doc__’, ‘__name__’, ‘bsf’, ‘cellName’, ‘checkuserpw’,
10|’doAuthenticationMechanism’, ‘doGlobalSecurity’,
11|’doGlobalSecurityDisable’, ‘doLDAPUserRegistry’, ‘domainHostname’,
12|’exportLTPAKey’, ‘flag’, ‘forceSync’, ‘generateLTPAKeys’,
13|’getLDAPUserRegistryId’, ‘getLTPAId’, ‘getSecId’,
14|’getSecurityAdminMbean’, ‘java’, ‘ldapPassword’, ‘ldapPort’,
15|’ldapServer’, ‘ldapServerId’, ‘ldapUserRegistryId’, ‘lineSeparator’,
16|’ltpaId’, ‘nodeName’, ‘secMbean’, ‘securityId’, ‘securityoff’,
17|’securityon’, ‘sleep’, ‘sys’, ‘whatEnv’]
18|wsadmin>
You might not like to have the namespace cluttered with things that you’re not planning on
using. So let’s remove the default profile script files that were used by commenting out the
com.ibm.ws.scripting.profiles directive in the wsadmin.properties file. After doing
this, you can see that the number of items made available in the default namespace is greatly
reduced. Listing 6.4 demonstrates the contents of the default Jython namespace when no profile
script files are specified.
Listing 6.4 Minimum wsadmin Namespace
1|C:\IBM\WebSphere\AppServer\bin>wsadmin
2|WASX7209I: ...
3|WASX7031I: For help, enter: “print Help.help()”
4|wsadmin>dir()
5|[‘AdminApp’, ‘AdminConfig’, ‘AdminControl’, ‘AdminTask’, ‘Help’,
6|’TypedProxy’, ‘__doc__’, ‘__name__’, ‘bsf’, ‘sys’]
7|wsadmin>
Because these specified files are Jython script files, you can use a text editor to find out
what they are doing and how it is being done.
securityProcs.py contains definitions for these functions:
but you get the idea. If you take the time to open the script file in a text editor, you will see that
half of the items are functions, and the remainder are variables.9
13–14 Nest the dir() function within the len() function to determine the number of items
added to the namespace.
Based on this information, you can decide whether to include the securityProcs.py or
LTPA_LDAPSecurityProcs.py as profile script files or not. For simplicity sake, remove these
default script files from the directive. If there are circumstances when you would like to occasionally
use one of these files, then you might want to consider using the -profile command-line option to
do so. It allows you to add one or more profile script files without modifying your properties files.
9
Please be careful, though. When we viewed LTPA_LDAPSecurityProcs.py in a text editor, we were very
surprised to find that indentation was done using a mixture of spaces and tab characters. This is an extremely bad
practice and should be avoided.
Another use for the -profile command-line option is that it allows you to test profile script
files and their contents before you decide that they are stable enough to be added to one of the
wsadmin.properties files. It is easy to create a profile script file containing a function to be
tested. Then this script file can be defined and loaded using the -profile command-line option
and thoroughly tested using an interactive wsadmin session. When you’re confident that the func-
tion works as you want it to, you can either move the function to an existing profile script file or
simply add this file to the list of profile script files in the profiles directive in the appropriate
wsadmin.properties file.
After all of the commands that have been specified using this option have been executed,
the wsadmin program exits gracefully and automatically commits any configuration changes you
have made. This is exactly the same effect as adding AdminConfig.save() immediately after
your command.
Thinking quickly about this might make you wonder whether this has any value at all. The rea-
son for this concern is the fact that there is a non-trivial amount of overhead related to starting up a
wsadmin session, and if all you are going to do is have a single command executed, why bother?
Well, the answer to that question is yes; there is some overhead associated with using the -c
command-line option to execute a single, or even a few, wsadmin command(s). However, there are
times when this technique can do exactly what you need it to do. Additionally, there are times when
the output of a single command can be voluminous, in which case, using the -c command-line option
to execute this command allows you to redirect the output of a command to a file for later review.
Because we have yet to discuss any of the administrative objects, it is a little difficult to
provide a good example for this option. However, Listing 6.7 shows an example that should be
The final command-line option to be discussed is -f, and is used to specify a Jython script
file to be executed. If you execute the wsadmin command from the directory containing the script
file, then you don’t have to include any path or directory references as part of the -f option. For
example, let’s look at this code:
C:\temp>set WAS_HOME=C:\IBM\WebSphere\AppServer
C:\temp>%WAS_HOME%\bin\wsadmin -conntype none -f ListPorts.py
If the fully-qualified path to the script file contains spaces, then this parameter should be enclosed
in double quotes, as shown:
wsadmin -f “C:\Program Files\scripts\ListPorts.py”
Another thing shown in the wsadmin usage information is something like [script
parameters]. This simply means that anything specified on the wsadmin command line that is
not recognized as a wsadmin command-line option is made available to the script. For Jython
scripts, parameters are made available via the sys.argv list. Listing 6.8 shows how to specify
script parameters and how they can be accessed using sys.argv data structure. It also shows
how the parameters are identified as unrecognized wsadmin options and are therefore being
passed on to the scripting environment. This topic was discussed in the section “getopt() Module”
in Chapter 5, “Jython Modules.”
Summary
wsadmin is a command shell. This chapter showed some different ways in which the wsadmin
environment can be configured, including the Java Virtual Machine used by wsadmin. We also
saw some configuration information that may be used to control wsadmin and its access to an
enterprise security service. Finally, we showed you the mechanics of using the wsadmin com-
mand shell. In the chapters that follow, we see how to use the scripting objects that exist within
the wsadmin environment.
Introduction to Admin
Objects
We all need help at one time or another, and trying to use or learn how to administer the Web-
Sphere Application Server product is no exception. It should be no surprise that the administra-
tive scripting objects and the scripting environment are complicated and complex. So complex, in
fact, that a Help scripting object is included, and each of the other scripting objects have help
methods to assist with the understanding of the object and how it can be used. This chapter dis-
cusses and describes the kind of help that is available from the Help object, the scripting object
methods, and active MBeans.
1
See Chapter 6, “wsadmin,” in the section “wsadmin Profile script files.”
129
AdminConfig2 Object used to view and manipulate configuration elements (xml files).
AdminControl3 Object used to view and manipulate active application server objects
(MBeans).
Help Object used to provide usage information about the administrative objects.
If you look at the namespace displayed for the imported module (line 8), you see that the
WebSphere administrative objects (that is, AdminApp, AdminConfig, AdminControl,
AdminTask, and Help) are not listed.
Although there are several ways for an imported module to gain access to the administrative
objects, the best way appears to be to make use of the fact that the administrative objects are
present and available for scripts processed as profile files, as shown in Listing 7.2 (lines 11–15).
2
See Chapter 8, “The AdminConfig Object,” for detailed information about this object.
3
See Chapter 9, “The AdminControl Object,” for detailed information about this object.
4
See Chapter 10, “The AdminApp Object,” for detailed information about this object.
5
See Chapters 11 through 15 for detailed information about this object.
6
Exactly what you see when you type dir() within wsadmin will vary depending on your version of WAS and
depending on what you have written in profile scripts for wsadmin. See Chapter 6, in the section “wsadmin Profile
script files,” for more details.
You can use a simple technique that works well, has a minimum chance of making a mis-
take, and is also very easy to add to your environment.
The technique involves using a property of the sys.modules dictionary. By adding
entries for each of the administrative objects to sys.modules, imported modules can access
these objects. The first attempt is a simple profile file (WSASobjects.py), shown in Listing
7.3.
What happens when you add WSASobjects.py to the list of files processed as profiles?
Take a look at Listing 7.5 to see if the issue has been resolved.
the AdminControl object will not be available. In either case, you will get a NameError excep-
tion any time you try to use an administrative object that is not available.
8|
9|WASX7031I: For help, enter: “print Help.help()”
10|wsadmin>
To eliminate this exception, you can create a useful profile, which here is called
WAuJ.py,7 that we will add to the wsadmin.properties file as the only profile file to be
loaded. Once this is done, the start up of wsadmin looks a little different, as shown in Listing
7.7. This example also demonstrates that a module can access the available administrative
objects.
The modifications made to the example module that allow it to check for and import avail-
able modules are shown in Listing 7.8. A module can check for each of the administrative objects
that is needed using a simple try/except statement and determine if execution should continue
should an object be unavailable.
7
WSAS Administration using Jython (WAuJ)—where WSAS is an acronym for WebSphere Application Server.
Based on the usefulness of this profile, the remainder of the book makes use of this mod-
ule, and it’s automatically loading by the following line in the wsadmin.properties file:
com.ibm.ws.scripting.profiles=C:/IBM/WebSphere/scripts/WAuJ.py
NOTE If you do use the WAuJ.py profile and dislike the banner, seen in Listing 7.7 (lines
3–10), that gets displayed when wsadmin starts, there is a way to tell the profile not to dis-
play the banner. Just add ’-WAuJ’ as a command-line parameter when you start
wsadmin. If found, this command-line parameter is removed (so your scripts don’t need to
check for or deal with it), and the banner isn’t displayed.
If you simply execute this help method, the result is shown to be a text string. Listing 7.9 shows
part of the result and how it looks using the recommended print statement.
8
See Chapter 9, “The AdminControl Object,” for information about MBeans and how to use them.
9
See Chapter 5, “Jython Modules,” in the “Regular Expressions (RegExps)” section for more information.
Table 7.2 explains the regular expression in this example in more detail. Unfortunately, as
you can see, regular expressions can be both powerful and hard to understand all at the same time.
You can write a very terse and somewhat cryptic pattern that allows you to extract exactly the
information you want from a text string.
re.MULTILINE Multiline flag identifies that newline characters indicate the “end of
line.”
10
See Chapter 9, “The AdminControl Object,” for information about MBeans and how to use them.
You can make use of the list of method names, looping over each, and generate the help for
the method using a really simple group of statements. A first attempt of this is shown in Listing
7.12. It’s not perfect, but it’s a reasonable start.
With minor revisions, the output looks quite reasonable. The modified version of this script
is called Helphelp2.py and is available from the book’s website. A small portion of this modi-
fied output is shown in Listing 7.13.
Arguments: MBean
Method: attributes
Notice how each attribute has an attribute name, a type, and an access indicator showing
whether the attribute value is Read-Only (RO) or Read-Write (RW). Wouldn’t it be nice to have a
11
Techniques for obtaining MBeans are discussed in Chapter 9, where we discuss the AdminControl object.
routine that could be used to retrieve all of the attributes for a given MBean and store them in a
nice Jython data structure? We’ve written such a routine, and called it MBattrAsDict(), which
is available in a utility module called WAuJ_utilities.12 Listing 7.15 demonstrates how this
routine can be used.
Table 7.3 explains this example in more detail. Next, you’ll see how the technique used to
understand the Help.attributes() method can be used with other methods of this and all of
the WebSphere administrative objects. In fact, the next Help method used is
Help.operations(). Passing this method the same MBean value (svr) results in the list of
operations available for this same MBean.
It should be no surprise when the output contains a number of routines, most of which
relate to the attributes listed earlier. In fact, you should find a correlation between the attribute
values and operations that can be used to get the named attribute value. These types of operations
are frequently called getters. For those attributes identified as having Read/Write (RW) access,
12
For the import in line 1 to succeed, the WAuJ_utilities module must be available in one of the sys.path
directories.
Line(s) Description
2 Obtain an MBean identified. Note: This could return multiple results, so you
may have to use something like:
svr=AdminControl.queryNames( ‘type=Server,*’
).splitlines()[ 0 ]
4–11 Get the attribute names and display some of them in alphabetical order.
13–14 For each of the specified attribute names, display the name and associated
value.
15 In interpretive mode, a blank line is used to identify the end of the for
statement.
you should also find an operation that allows you to modify (set) a new value for the attribute.
These types of operations are also called setters.
Line 15 shows how to use the AdminControl.invoke() method to call this operation.13
This use of the invoke method shows how to call an operation associated with a specific MBean
when no parameters need to be provided. The output of this call (specifically, line 19) includes an
example productID value. Given this information, line 26 shows how to invoke an MBean oper-
ation and pass it a parameter. In this case, the output from this call happens to be identical to what
is seen on lines 16–24, so are not displayed. So, you’re all set.
13
Additional details about the invoke method are covered in Chapter 9, where we discuss the AdminControl
object.
Making this interactive wsadmin session into a script file is quite easy. Some of the things
that should be done as part of this process include the following:
• Add comments and usage information to clarify what is being done and why.
• Decide whether the file should be executable as a script or imported as a module.
• Add error handling code for commonly occurring and unexpected situations.
This has been done, and the script file that was created is named beanConstructorys.py.
13–19 Formatted output of the only MBean name that has a non-empty constructor response.
In a similar fashion, you can write a script to display the Help.description() infor-
mation for each available MBean. The script that does this is beanDescriptions.py.
Example output from the execution of this script file is shown in Listing 7.18.
It should be noted at this point that this particular script does not process the
Help.descriptions() text much at all. Some of the descriptions are quite long and as such may
14
The AdminControl object and associated methods are discussed in Chapter 9.
benefit from some additional code to rearrange the text. This enhancement code is also left as an
exercise to the reader.
Similarly, another script has been written, named beanNotifications.py, to display
the notifications that are available for the active MBeans. Unfortunately, because of space limita-
tions, additional information about notifications is beyond the scope of this book.
The output from the Help.classname() method is, for almost all of the active MBeans in
an unmanaged application server, javax.management.modelmbean.RequiredModelMBean.
So although a script named beanClassnames.py is provided, no additional discussion should be
needed.
The last of the MBean-related help methods can be used to obtain all of the preceding help-
related information in one place, meaning that the result of calling Help.all() for a particular
active MBean is very similar to calling all of the following for the same MBean and merging the
resulting text:
Help.attributes()
Help.operations()
Help.constructors()
Help.description()
Help.notifications()
Help.classname()
A script named beanInformation.py is provided that shows a simple way to display this
information. Unfortunately, as was mentioned earlier, very little effort has been put into making
this output “pretty.”
Windows:
wsadmin[.bat] -conntype none –WAuJ -f ObjHelp.py >ObjHelp.out
Used like this, an output file approximately 1,800 lines long is generated that has the help
text for four of the five administrative objects all in one place. This gathering of information can
be much easier to use and search with a text editor.
The last administrative object, AdminTask, is a different beast, as can be seen by looking at
its help. Instead of having a collection of methods, the AdminTask has commands and
commandGroups. Looking at the output of print AdminTask.help(‘-commands’), you
can see that the “command names” look very much like the “method names” that exist for the
other Help objects. In fact, we can reuse the same RegExp to extract the command names from
this text as you used for extracting the method names for the other Help object.
If you take a close look at the AdminTask.help() output, you will see that in addition to
being able to execute AdminTask.help( commandName ), you can also specify an optional
stepName parameter for extra information.
Looking at the output of the script as it exists, you have to go a long way before finding a
command that includes a step. So enhancing this script to add checks for stepName checks and
displaying the associated help text is left as an exercise for you.
Useful Information
One of the things that we have done to it a little bit easier for ourselves is to bookmark some fre-
quently used pages in the online documentation.
Following pages can be particularly useful:
• Commands for the AdminApp object
selected “This Frame, Show Only this Frame.” This forced the address as well as the table of con-
tents pane on the left to be updated. This is the point that we suggest you bookmark.
Scrolling to the bottom of this page we found a link for the “Options for the AdminApp
object...” page referenced earlier. We suggest that you use this link to view the page and then
“Show Only this Frame” and bookmark this page as well. Scrolling to the bottom of this page,
you find the link for the “Usage table...” page mentioned earlier. Then, you can search for the
other administrative objects and use this same technique to bookmark these pages as well. This
will provide you with a useful set of bookmarks for the wsadmin administrative objects.
Summary
In this chapter, we discussed the wsadmin Help object, as well as the help method that exists in
each of the other administrative scripting objects. Hopefully, the discussion and examples pro-
vided leave you with a more thorough understanding of what is available from the Help object.
The AdminConfig
Object
One of the most valuable things that wsadmin allows us to do is manipulate the AppServer
configuration. In fact, what is really important about this is the fact that wsadmin can perform
this configuration manipulation when the AppServer is stopped. To perform this manipulation,
you must know how to use the AdminConfig scripting object, which this chapter covers in great
detail.
AdminConfig Overview
Looking at the AdminConfig.help() text,1 you see that this object can be used to perform sev-
eral operations on WebSphere Application Server configuration objects. These operations include
the following:
• List
• Create
• Remove
• Display
• Modify
1
This is explained further in Chapter 7, “Introduction to Admin Objects.”
149
Figure 8.1 shows a slightly different perspective of the information specified in this config
ID. This listing shows the directory structure under the WebSphere Application Server installation
directory for which this config ID applies (that is, .../profiles/AppSrv00/config). Notice
how we can use each portion of the config ID, in Listing 8.1, to traverse the directory structure
shown in Figure 8.1 to the exact location of the applicable configuration file (server.xml). Each
portion of the config ID from Listing 8.1 is underlined in Figure 8.1 to more easily locate and
identify each element.
What about that “stuff” after the filename, specifically the Server_1219933843508? If
you look at the contents of the specified file, you find that this information is contained within the
file as an attribute of the process:Server tag (that is, xmi:id=”Server_1219933843508”).
So not only does the config ID point directly to a specific file, but it also identifies a unique element
within that XML configuration file.
The fact that you can use a config ID to locate a specific file and XML tag within the file should
not be taken as encouragement to do so. Please let wsadmin and the scripting objects do this for you.
Manual manipulation of an XML configuration file could easily invalidate the configuration.
2
Starting wsadmin with –conntype none as one of the command-line options forces it to be in local mode.
3
Unfortunately, config IDs can be so long that they won’t fit on a single line unless you use a very small font. The con-
fig ID shown should, in fact, be a contiguous string containing no end-of-line characters.
Containment Path
Another frequently asked question is, “How do I get the config ID for a particular configuration
object?” Well, there a few different ways to do it. Choose one technique over the other based on
your personal preferences and the information you have available.
In the documentation, the most common technique uses the AdminConfig.getid()
method to obtain a config ID. However, this call requires that a containment path be provided. A
containment path is a collection of one or more name/value pairs in a specific order. The name
portion is required and is a configuration object type and is followed by a colon and an optional
value. The name/value pairs are delimited using the slash character ’/’. Some example contain-
ment paths would be ’/Cell:/’, or ’/Cell:myCellName/’. Each containment path, when
passed to the AdminConfig.getid() method, result in zero or more config IDs. Listing 8.2
shows some example calls to AdminConfig.getid() using a containment path (lines 3 and 5).
Should multiple name/value pairs exist within the containment path, the sequence of the
name/value pairs must match the hierarchy of the types in the WebSphere environment. This
means that the first type specified should contain objects of the second type specified, and so on.
For example, a containment path in which the first type specified was Cell and the second type
specified was Node would be valid because a cell is composed of node objects. However, a con-
tainment path where the first type is Node and the second type is Cell would not be valid
because the hierarchical relationship does not match that of the WebSphere objects. Listing 8.2
(lines 7–8) shows that using an invalid containment path results in no match being found in the
configuration. Additional information about this configuration object relationship is covered in
the “Create and Modify Methods” section later in the chapter.
Configuration Types
What configuration object types exist? A call to AdminConfig.types() can be used to get a list
of all valid types. A small, stand-alone script (AdminConfigTypes.py) is provided that displays
these types, identifies the number of types, and gives the length of the shortest and longest.
When you execute the script on a version 6.1 installation, almost 600 supported types exist.
For a version 7.0 installation, it was closer to 800. This means you can’t possibly cover these types in
any amount of detail. What you can try to do is to present some techniques for investigating types
and the object methods that use them. Hopefully these techniques will assist you in your investiga-
tions about those types in which you are interested that are not discussed within this book.
In addition to the getid() method, the AdminConfig.list() method can also be used
to find one or more config IDs. For example, the config ID shown in Listing 8.1 happens to be for
an unmanaged application server. The technique used to obtain this server config ID depends
upon your environment. For an unmanaged application server, it can be as simple as using some-
thing like print AdminConfig.list(‘Server’)).
What’s the difference between using the getid() and list() methods to obtain a config
ID, and why might you prefer one method over the other? The primary difference is that when the
AdminConfig.list() method is used, a type is specified (for example, ’Server’) instead of a
containment path. The result of this call can therefore include multiple objects.4 By using the
getid() method and providing qualified name/value pairs, the result might already be “fil-
tered.”5 In this case, additional processing to identify or select one of the results might not be nec-
essary. For example, Listing 8.3 shows how an unqualified containment path (lines 5–8) is the
same as using the call to AdminConfig.list() and specifying the same type (lines 1–4). How-
ever, by qualifying the containment path (lines 9–10), no additional code is needed to get to the
specific config ID in question (that is, server1).
4
For example, the result of calling AdminConfig.list(‘Server’).splitline() in a clustered environ-
ment should result in a list containing all of the config IDs of all of the application server in the cell.
5
The result of calling AdminConfig.getid(‘/Cell:cellName/Node:nodeName/’).splitlines()
contains only config IDs of items within the specified containment path, not the entire cell.
Because both the list() and the getid() method can result in multiple values, it is best
to have your scripts takes this into account. To do so, use the string splitlines() method to
convert the string into a list of strings, with each element being the config ID of an application
server. The splitlines() routine uses end-of-line markers as line delimiters.6 Should the result
of the AdminConfig.list() call be a single entry (for example, a single application server),
the result of the splitlines() call will be a single element list.
Using a config ID
What can be done once you have a config ID? One of the most useful AdminConfig methods is
AdminConfig.show(), which can be use used to provide information about the specific attrib-
utes and values that exist for the resource identified by the specified config ID. As seen in Listing
8.4 (lines 3–14), you can see that the result is many lines of text, with each line containing some-
thing that looks like a name/value pair. Interestingly enough, each line starts and ends with square
brackets (’[]’). One way to use this information would be to process, or parse, each line, search-
ing for entries of interest. However, there is an easier and better way.
6
Please note that the string splitlines() method that exists in the version of Jython in WebSphere Application
Server 6.0 doesn’t work as expected, so you should use split(‘\n’) instead.
8|[outputStreamRedirect (...)]
9|[parallelStartEnabled true]
10|[processDefinitions [...]]
11|[serverType APPLICATION_SERVER]
12|[services “[...]”]
13|[stateManagement (...)]
14|[statisticsProvider (...)]
Using the understanding of how the text result of the show() method is formatted, it is a simple
matter to create a routine to call the show() method for a given config ID and convert the result into a
dictionary, which can then be returned. A routine to do just this was created and is part of a collection of
utility routines provided in a module name WAuJ_utilities. Listing 8.5 shows an example use of
this routine to demonstrate its usefulness, and Table 8.1 explains this example in detail.
Line(s) Description
2 Assignment statement used to obtain the config ID of the first Application Server.
4–9 The dictionary keys, or indexes, can be used to display individual dictionary entries
that correspond to the names seen in Listing 8.4. For this example, only the name and
serverType name/value pairs are displayed.
by an AdminConfig or any of the other object methods. Being able to write something simple like
dict[‘name’] to access the name attribute of a given object is very powerful (and intuitive).
4 Use showAsDict() to get a dictionary of the available attributes for the specified server.
5 Create a RegExp pattern object to extract attribute names from multi-line text string.
6 Use the RegExp object to extract the attribute names from the attributes() text.
7 Use list comprehension to build a list of attribute names that don’t exist in the show()
result for the given application server configuration object.
8–13 Try to use AdminConfig.showAttribute() to obtain the value of the missing attrib-
ute in the given server and format the showAttribute() result.
14 Blank line used in interactive mode to designate the end of the preceding for loop.
15–21 Formatted output generated by the for loop, showing that showAttributes() returns
None for almost all of the undefined attributes.
Note the use of a try/except clause to define an exception handler for special cases.
Interestingly enough, some of the entries listed from the attributes() method call don’t
appear from the earlier call to the show() method. If you look again at the methods listed in the
help text, you see that another method called defaults() exists. Printing the help for this
method shows what appears to be an overlap of function between the two methods (attributes
and defaults). However, if you print the output from each method in which you specify the
type parameter as ’Server’, the descriptions are significantly different. The output of the two
routines might also raise some questions.
If an attribute doesn’t have a configured value, then you would expect that attribute to have a
default value. Why do we find attributes for which no default value is provided? And there is yet
another AdminConfig method called required(). If you display the required attributes for type
’Server’, using a statement like print AdminConfig.required(‘Server’), you see that only
the name attribute is required. How is it that so few are required as well as so few default attributes?
Does the AdminConfig.showAttribute() method return a value for the undefined attributes that
don’t have a default value? Unfortunately, these are questions only the developers could answer.
The last of the “show and tell” methods, as we like to think of them, is the
AdminConfig.showall() method. The difference between the show() and showall() methods
is that the show() method returns the attributes of the specified configuration object, and the
showall() method does that as well as recursively including all of attributes of the referenced con-
figuration objects. For example, given a configuration object for an unmanaged application server
(e.g., as seen in Listing 8.4) using AdminConfig.show() results in 12 attributes. On the other
hand, using AdminConfig.showall() results in almost than 650 attributes and nested attributes.
The unfortunate thing about the results of using the showall() method is that the result is
difficult to analyze at least programmatically. Is there anything that we can do to traverse a con-
figuration object hierarchy searching for a specific attribute? Well, nothing is provided, so you
have to develop your own.
How might you go about doing this? Let’s begin by taking a look at the information that
exists in the output from calling the AdminConfig.show() method using some config ID.
Because the showAsDict() routine does this and returns a dictionary, it should be easy to real-
ize that each line of the result should contain a name/value pair. What kind values are returned? It
depends on the kind of configuration object that was passed to the show() method.
Listing 8.4, shown earlier, details possible values such as the following:
• Empty lists (that is, open and closed square brackets [])
• Names, or identifiers (for example, true, false, server1, APPLICATION_SERVER)
• Numeric values (such as port numbers, threshold values, and timeouts)
• Single config ID (with or without the leading name)
• Config ID lists (contained within [...])
The ones of special interest at this time are the ones containing either a single config ID or a con-
fig ID list. What you need to be able to do in order to traverse the configuration object hierarchy is
to be able to recognize, extract, and use these config IDs in order to process the referenced con-
figuration object.
The best way to identify a single config ID is by using a regular expression (RegExp). How
do you build a RegExp to identify a config ID? Very, very carefully. The important part is to real-
ize that they begin and end with parentheses (with an optional identifier prefix). What would this
kind of RegExp look like? Simply stated, the expression is ’^(\w*\([^)]+\))$’. Table 8.3
explains this RegExp in detail.
Metachars Meaning
Metachars Meaning
[^)]+ Match one or more characters that are not a closing parenthesis
A similar RegExp for config ID lists is ’^”?\[([^\]]+)]”?$’. It differs from the previ-
ous RegExp in the following aspects:
• Optional surrounding double quotation marks
• Surrounding square brackets ([])
• Space between each config ID
The good news is that these work great for the vast majority of config identifiers. The bad news
is that in testing, we found something that we did not expect. It is valid to have a config ID that
has a name (the portion before the opening parenthesis) containing blanks. If a blank exists in
the name, the whole config ID is surrounded by double quotes. This means that the simple Reg-
Exp pattern (for example, the ’\w*’) isn’t valid for all config IDs. So the new and improved
RegExp to match this more complete understanding of config IDs would be
’(\w*\([^)]+\)|”[ \w]+\([^)]+\)”)’. The first part of this RegExp pattern (the portion
before the ’|’) is the same. The second part allows double quotes as well as spaces within the
name. The revised code is available in findAllAttributes.py, and includes code that
demonstrates how the function can be used.
The “test” code that is included within findAllAttributes.py script (that is, the code
executed when the file is executed instead of being imported) tries to find attributes having the
name “port.” Interestingly enough, this code doesn’t provide information about all of the ports
that are used by an application server. Unfortunately, this code is quite a bit harder to understand
and follow. Additionally, it is not clear how useful or applicable that it might be without addi-
tional experimentation and testing.
A better and more useful example would be a script that could be used to find and display
the port numbers configured for an application server. Interestingly enough, this script is very
easy to create and, in fact, has been provided in the script named ListPorts.py.7 The sample
output of this script is shown in Listing 8.7. To perform this task, the script only needs to:
7
It is not as easy as using an existing method like AdminTask.reportConfiguredPorts(), but we haven’t
gotten to the AdminTask scripting object yet. Additionally, the output of ListPorts.py looks better.
2. For each ServerEntry config ID, get the NamedEndPoint config IDs using:
NEPs = AdminConfig.list( ‘NamedEndPoint’, SE ).splitlines()
3. For each NamedEndPoint, use the endPoint attribute to get the port number:
This shows how challenging it can be to access a particular kind of information from the configura-
tion. It requires quite a bit of knowledge (such as the configuration type names of the objects), as
well as some perseverance to get the information you want displayed in a specific format. However,
it also shows how easy and intuitive it can be to use a utility routine like showAsDict() to sim-
plify your programs at the same time they are being made easier to read and understand.
Port#|EndPoint Name
——-+——————-
2809|BOOTSTRAP_ADDRESS
8880|SOAP_CONNECTOR_ADDRESS
9401|SAS_SSL_SERVERAUTH_LISTENER_ADDRESS
9403|CSIV2_SSL_SERVERAUTH_LISTENER_ADDRESS
9402|CSIV2_SSL_MUTUALAUTH_LISTENER_ADDRESS
9060|WC_adminhost
9080|WC_defaulthost
9353|DCS_UNICAST_ADDRESS
9043|WC_adminhost_secure
9443|WC_defaulthost_secure
5060|SIP_DEFAULTHOST
5061|SIP_DEFAULTHOST_SECURE
7276|SIB_ENDPOINT_ADDRESS
7286|SIB_ENDPOINT_SECURE_ADDRESS
5558|SIB_MQ_ENDPOINT_ADDRESS
5578|SIB_MQ_ENDPOINT_SECURE_ADDRESS
9100|ORB_LISTENER_ADDRESS
8
That is, print AdminConfig.help(‘create’).
Now that you understand what the Parent parameter represents, you can use the following
steps to create a new configuration object:
1. Decide the type of object to be created.
2. Locate the type name using the AdminConfig.types() method.
3. Verify that an object of this type can be created using AdminConfig.parents().
4. Identify the required, default, and allowed attributes for this type using the
AdminConfig.required(), AdminConfig.defaults(), and AdminConfig.
attributes() methods.
5. Identify the appropriate Parent type of the new object.
6. Locate the config ID of the object under which the new object is to be created.
7. Determine the necessary attribute values that need to be provided to the create call.
8. Call the AdminConfig.create() method to create the desired object using the appro-
priate parameters.
For something like a Server (which only requires that the name attribute be specified), this
could be as simple as the following:
node = AdminConfig.getid(‘/Node:/’).splitlines()[-1]
attr = [[‘name’,’serverName’]]
server = AdminConfig.create( ‘Server’, node, attr )
Wow, that’s pretty simple. Is that all there is? Almost, but not quite. One of the things that
wsadmin does is to provides a level of protection. When any configuration change is made, this
change is not actually made to the existing configuration. These changes are kept in a workspace
separate from the permanent configuration. All changes to the configuration are stored in this
workspace until the changes are committed (using the AdminConfig.save() method) or dis-
carded, either by terminating wsadmin (using either the quit, or exit command9) or by calling the
AdminConfig.reset() method.
What if you change your mind about the object you created? If that was the only change
made, you could simply discard all of the changes. However, if you are uncertain about all of
the changes, you can first display the list of modified files (using the print AdminConfig
.queryChanges() statement), or you can obtain the config ID of the created object and then use
the AdminConfig.remove() method to remove this object from the configuration. Remember,
though, that should you invoke the remove() method, the specified object is not actually
removed from a saved configuration until the AdminConfig.save() method is called.
A call to the AdminConfig.hasChanges() method can be used to determine whether or
not changes have been made to the configuration. The result of this call is either 0, which indicates
that no changes have been made, or 1, which indicates that unsaved changes exist in the workspace.
The last method in this category is the AdminConfig.modify() method. As you might
expect, it can be used to make changes to the attributes of a particular configuration object. To do
so, a config ID is required, as well as the list of attributes to be modified. A trivial example to
demonstrate this would be the following:
node = AdminConfig.list( ‘Node’ ).splitlines()[-1]
server = AdminConfig.create( ‘Server’, node, [[‘name’,’A’]] )
AdminConfig.modify( server, [[‘name’,’B’]] )
print AdminConfig.show( server )
AdminConfig.reset()
From this, you would see that the name attribute of the created server object was modified by the
call to the AdminConfig.modify() method.
Configuration Verification/Validation
This chapter started with a warning about the possibility of corrupting a configuration using
scripting. A number of questions come to mind related to what you can do to protect your Web-
Sphere configuration from corruption. Is there a way to check for a corrupt or invalid configura-
tion? What can be done to minimize the possibility of configuration corruption? What happens if
conflicts exist in the configuration?
The wsadmin utility is configured, by default, to use the highest level of protection and verifi-
cation available. As was discussed in Chapter 6, in the section “The wsadmin Environment Initial-
ization Phase,” many of these default settings are configurable in the wsadmin.properties file
9
Should modification be made when either the quit or exit command are issued, a warning message will be displayed
to remind you to save your changes should you desire to do so.
that is loaded when wsadmin starts. The settings provided in the properties file that are related to
validation/verification are as follows:
• validationOutput
• validationLevel
• crossDocumentValidationEnabled
Each of these attributes has a prefix of com.ibm.ws.scripting, and each has a comment block
in the properties file identifying the role provided by each attribute, as well as the default value,
should one exist.
If your script needs to query or change either of the last two attribute values, the
AdminConfig object has getter and setter methods to do so. Specifically, you would use
getValidationLevel(), setValidationLevel(), getCrossDocumentValidation
Enabled(), and the setCrossDocumentValidationEnabled() methods.
Interestingly enough, both the getter and setter for each of these values returns a string con-
taining the requested setting. In each case, the last blank delimited word in the result is either the
current value (in the case of the getter method) or the value after making the requested change (in
the case of the setter method). So, in order to save, or access this value, you can use something
like val=AdminConfig.setValidationlevel(‘high’).split(‘ ‘)[-1].
Another related setting exists for which only getter and setter methods are available (i.e.,
no corresponding attribute is available within the wsadmin.properties file). The possible
saveMode values are ’rollbackOnConflict’ (the default) and ’overwriteOnConflict’.
This value defines the action to be performed should a configuration conflict occur during a
request to save the configuration.
So some amount of checking is performed during a configuration save request. Addition-
ally, a call to the AdminConfig.validate() method can be used to perform a configuration
validation. The result of this call will be a string identifying the number of validation messages
generated (and written to the specified file) based on the current workspace contents, the value of
the cross-document validation-enabled flag, and the validation level setting.
Please note that with the highest level of validation enabled (which is the default setting),
calling the AdminConfig.validate() method can result in messages being written to the val-
idation output file even before any change to the configuration has been made.
The result of calling the AdminConfig.validate() method is a string that includes the
name of the validation output file and the number of each severity message written to the output file.
Should you be interested in determining the number of messages of each severity that
were written to the output file without parsing the validate() result string, another method
exists. Calling AdminConfig.getValidationSeverityResult() and passing a numeric
(severity) value returns a number representing the number of messages of the specified sever-
ity that were written to the validation output file.
WARNING Just because you can use these methods to copy WebSphere Application
Server configuration (i.e., XML) files out of the directory structure and then edit and replace
them, this should not be taken as encouragement to do so. It is extremely important that
WebSphere configuration files be managed by the administrative objects.
Miscellaneous Methods
The remainder of the AdminConfig methods are grouped together simply as a matter of conven-
ience. The first of these methods are related to clusters:
• convertToCluster()—Used to convert an existing server configuration object to
ServerCluster configuration object.
• createClusterMember()—Used to create a new ServerCluster configuration object
in an existing cluster and on an existing node.
The former is used in a script of the same name (convertToCluster.py) that is available with
the other scripts. Interestingly enough, in order to create a fairly complete script that performs a
reasonable amount of error checking and verification doesn’t require that many lines of code. At
first glance, convertToCluster.py appears to have a little over 300 lines of code, but this is
slightly misleading. There are lots of comment and empty (or blank) lines. When these are
removed, it seems that approximately 75–80 lines of code were needed in order to provide a com-
plete script that makes use of this AdminConfig method for converting an existing application
server into a cluster member. We’ve found that quite powerful.
The latter is also demonstrated in a script of the same name as the AdminConfig method.
It is a bit more complicated than the previous example. It also requires less than 200 lines of
executable code and less than 350 total lines to have a reasonable script that includes command
line parameter processing, script usage (documentation) information, error checking, exception
handling, and numerous comments to explain how the script functions.
Two of the AdminConfig miscellaneous methods are related to Templates. The first of
these, listTemplates(), is used in the createClusterMember.py example script to obtain
a list of config IDs for templates of a given type. As it is used in that script, an optional parameter
string is provided to identify text that must exist in each returned config ID
(’APPLICATION_SERVER’). The other Template-related method is createUsingTemplate(),
which can be used to create an object of a specified type in the configuration hierarchy. Another
script is provided, CreateServer.py, that shows one way to use the createUsingTemplate()
method.
The last of the paired miscellaneous AdminConfig methods are related to
ResourceAdapters:
• installResourceAdapter()—Used to install a J2C resource adapter with the given
.rar filename and an option string in the node.
• uninstallResourceAdapter()—Used to uninstall a J2C resource adapter with the
given resource adapter config ID.
These methods are fairly well-documented in the online documentation. Unfortunately, we
haven’t had an opportunity to create scripts that use these methods. If you have need of scripts
that make use of these methods, you might want to try modifying one of the available scripts to
make use of these methods.
The final miscellaneous method is getObjectName(). It can be used to lookup and return
the available MBean identifier for the specified object. For example, given the config ID of an
application server, this method can be used to obtain the MBean identifier for an active instance
of this application server. Remember, though, if the corresponding configuration object is not
active, or if wsadmin is in local mode (that is, if wsadmin was started with the -conntype
none command-line parameter), then either an exception will occur, or the result of the method
call will be an empty string.
Summary
This chapter described the AdminConfig administrative scripting object, which deals with
viewing and manipulating items in an application server configuration. We saw how objects can
only be created when the config ID of an existing object of the appropriate type is specified. We
also saw how some of the utility routines provided with this book can be used to make configu-
ration viewing and manipulation easier.
The AdminControl
Object
The AdminControl object is similar in many ways to the AdminConfig object. The primary differ-
ence between the two is that the AdminConfig object is used to manipulate configuration objects
(represented using XML), and the AdminControl object is used to manipulate active application
server objects (by interacting with managed beans—MBeans). One implication of this is that in
order for this object to function, wsadmin must be connected to an active application server (the
AdminControl object is not available when wsadmin is used in local mode).
167
A script that demonstrates the use of these AdminControl methods, named envInfo.py is
available from the IBM Press® website for this book at http://www.ibmpressbooks.com/
bookstore/product.asp?isbn=9780137009527.
The other methods in this group are as follows:
• reconnect()—Attempts to reconnect to the server.
• startServer()—Starts the specified server.
• stopServer()—Stops the specified server.
The last two methods in this group can only be used in a federated, or clustered, cell. Why is that?
Well, unlike the startServer command script (for example, *.bat or *.sh), the
AdminControl.startServer() method can only start a managed AppServer when wsadmin
is connected to the Deployment Manager, and the managing node agent is also active. The
AdminControl.stopServer() method, on the other hand is available, and can be used
when wsadmin is connected to an unmanaged server. However, calling the
AdminControl.stopServer() method when connected to an unmanaged node does not stop
wsadmin, just the server. What happens about subsequent wsadmin requests? As shown in Listing
9.1, an exception is raised (lines 8–10).
When and why might you need to reconnect to the server? Consider the situation where
you have a long running administrative script, and the server being administered becomes
unavailable for one reason or another. AdminControl.reconnect() could be used to reestablish
a connection to the server after it becomes available. Listing 9.1 shows how the unmanaged
server is stopped using the AdminControl.stopServer() method. What you don’t see is how,
in a different command prompt, the startServer command script was used to restart the server
before we were able to successfully reconnect to it (lines 11–13).
Anyway, let’s get back to the stopServer() and startServer() methods. What can we
do with these? One thing that came to mind while working with these methods was the usefulness
of creating the following scripts, which are also available from the book’s website:
• StartServers.py—Starts all managed application servers.
• StopServer.py—Stops all managed application servers.
The logic of each of these scripts is really straightforward. Each of them performs the following
steps to start or stop all managed application servers:
1. Verify that the script was executed and not imported.
2. Verify that no user specified parameters were provided on the command line.
3. Verify that wsadmin has a connection to an active Deployment Manager (such as Net-
work Deployment (ND) server).
4. Get the list of config IDs for all of the defined nodes.
5. For each non-ND node, obtain the list of application servers.
6. For each non-node agent, use the appropriate AdminControl method to either start or
stop the server.
While writing and testing these scripts, we found that a little additional effort would allow these
capabilities to be combined into a single script. This combined version, StartOrStop.py, which
is also available from the book’s website, can be used to start of stop all managed servers in a cell.
With a little more testing, we figured out that by adding some trivial checks we could look
for an MBean for a particular application server before trying to start or stop it. If an MBean for a
server exists, it doesn’t make sense to try starting the server. Conversely, if an MBean for a server
doesn’t exist, it doesn’t make sense to try stopping the server. The modified script that includes
these checks is SmartStartStop.py. In addition to looking for an MBean before starting or
stopping a server, this code also:
• Checks for the existence of extra application servers on the Deployment Manager node.
• Locates the node agent for each node and verifies that it is active before trying to start or
stop the application servers on the node.
During the testing of this script, we found that we were frequently stopping every node in the cell,
including all node agents and the Deployment Manager. It didn’t take us long to realize that it
would be fairly simple and more efficient to create a single script to do this for us. So the
StopCell.py script was created.
One advantage of using a single wsadmin script to do this became clear once we realized
how much overhead is associated with starting and initializing the Java Virtual Machine (JVM) to
execute a wsadmin script. Consider for a moment an environment having a cell that has one
Deployment Manager, two node agents, and two application servers. To use the command scripts
provided with the product (for example, the stopServer, stopNode, and stopManager batch
or script files) to stop the entire cell would require a JVM be started and initialized for each server
instance. So this environment would require five JVM initializations to stop all of the servers.
Using a single wsadmin script to do this means that only one JVM initialization occurs.
Are there any other advantages to having a script stop all of the servers in a cell? Sure. In
fact, the one that leaps to mind is the fact that the servers are terminated gracefully in the proper
order. You might not remember the appropriate order to terminate the servers in the cell. The
script can do this for you, and you don’t have to worry because the servers will always be termi-
nated in the appropriate order.
What steps are used for StopCell.py to stop all of the servers in a cell?
1. Verify that the script was executed and not imported.
2. Verify that no user-specified parameters were provided on the command line.
3. Verify that wsadmin has a connection to an active Deployment Manager.
4. For each of the configured nodes, perform this for each server in the node:
If the server is a node agent, save the server name; otherwise, stop the server
Stop the node agent.
5. Stop the Deployment Manager.
After writing and testing this script did we learn anything? And as important a question, did we
figure out any improvements? Certainly. One improvement would be to have the script check the
status of the node agent before trying to stop its managed servers. Did we write this script and
make it available on the book’s website? Yes, it is named SmartCellStop.py.
After writing these scripts, it was pleasing to see how few wsadmin administrative objects
and method calls were actually required to produce them. Each script needed at most the follow-
ing objects and methods:
AdminConfig methods:
list()
getid()
getObjectName()
showAttribute()
AdminControl methods:
getAttribute()
getCell()
getNode()
completeObjectName()
startServer()
stopServer()
So using four AdminConfig and six AdminControl methods, some useful scripts can be devel-
oped. This is pretty neat!
Because many of these scripts are checking server status during the course of events, what
is required to write a script to display the status of all application servers in the cell? The result
can be found in CellStatus.py.
Before this script was available, in order to determine the status of the application servers
on the machine, a batch file such as Listing 9.2 is necessary. Unfortunately, it is a very simple
command script that generates multiple lines of output for each application server.
Of course, this script does have some limitations. Specifically, if the Deployment Manager
is inactive, the script can’t be used to gain any useful information. Additionally, if any node
agents are inactive, the state of their managed servers are indeterminate. All the servers in the cell
had to be on the same physical computer for this script to work. All the profiles had to be located
in the <WAS_INSTALL_ROOT>/profiles directory. All the profiles are required to have the same
name as the directory in which they are stored. Finally, the script in Listing 9.2 will only work if
WebSphere Application Server is installed on a Windows computer. All of these restrictions are
lifted if we write a wsadmin script. In addition, as described earlier, the performance gains
obtained by using a single wsadmin script, and therefore a single JVM initialization, are signifi-
cant especially for multiple node configurations.
Besides generating lots of output, it can take a significant amount of time to complete,
especially as the number of inactive servers increases. It appears that the serverStatus com-
mand1 that is issued by this script has some kind of maximum time that is given for a server to
respond to the “status” request. When a server is not active, the serverStatus command waits
the entire time before deciding that an application server “appears to be stopped.”
1
The serverStatus command is provided with WebSphere Application Server product and is documented in the
online documentation (e.g., http://publib.boulder.ibm.com/infocenter/wasinfo/v6r1/index.jsp).
So you have a trade-off. If your Deployment Manager and node agents are (mostly) active,
the CellStatus.py script can be used. However, if you have unmanaged application servers, or
if your node agents might be inactive, you may want to use something like the script shown in
Listing 9.2.
Because some people don’t like voluminous output like that generated by the
Status.bat in Listing 9.2, we wrote a Python script that essentially performs the same action,
filters the output of the serverStatus command to condense the information into something
more usable. This script is called wasStatus.py and is available with the wsadmin script files
for this chapter. Please note, however, that this Python script can’t be run using wsadmin; it
requires a Python interpreter to be executed. Listing 9.3 shows the output of a sample execution
of this script.
result, it must be converted into something that the scripts can use. You can do this by invok-
ing the toArray() method that exists for Java list objects. So instead of using
AdminControl.queryMBeans(‘type=Server,*‘) to obtain the list of server MBeans to
be used or processed by our script, remember to use something like
AdminControl.queryMBeans( ‘type=Server,*’ ).toArray().
Unfortunately, the discussion of working with Java objects within wsadmin Jython scripts
is more aligned to the topic of a WebSphere Application Server Administration using JMX than it
is to Jython. Therefore, the amount of discussion concerned with the use of Java-related objects is
somewhat terse and abbreviated. There will be some discussion when other methods are encoun-
tered that return or require Java objects, but not much.
Should wsadmin be connected to a Deployment Manager with active node agents and pos-
sibly active managed application servers, the call to the completeObjectName() method will
display a warning message (with message id of WASX7026W) indicating that only one of the
matching MBean object name strings is being returned. Unfortunately, there is no way to tell
from the result that the specified information matches multiple beans.
However, another option (method) exists that can resolve this situation. It is the
queryNames() method. Passing this same search string to the queryNames() method returns
all of the matching MBean string names. Again, it is best to use the splitlines() string
method on this result in order to separate the lines of text into list elements. For example, this
statement would look something like this:
serverBeans = AdminControl.queryNames( kind ).splitlines()
Here’s a word of caution, though. Be sure that the search string used to find MBeans ends with a
“wildcard” pattern (such as ’type=Server,*’). Otherwise, the search string is interpreted as a
complete MBean name string. It is much more likely that you will be supplying an incomplete
MBean query and providing the wildcard asterisk to match the unspecified fields.
What other methods exist in this category, and what can they do for us? The
AdminControl.getConfigId() method, for example, can be used to obtain the configu-
ration ID for the specified MBean name string. This is the reciprocal of the
AdminConfig.getObjectName() method discussed previously in Chapter 8, “The
AdminConfig Object.”
This leaves us with the isRegistered() method, which returns a 1 to indicate that the
specified parameter identifies a registered object. Because the parameter is supposed to be an
MBean name, it is hard for me to imagine how you might have an MBean name that wouldn’t
be registered.
Attribute-Related Methods
The next group or category of methods are related to retrieving (getting) and assigning (set-
ting) the attribute values associated with MBeans. Here is the complete list of the regular
methods:
• getAttribute()
• setAttribute()
• getAttributes()
• setAttributes()
Looking closely at this list of methods, you can see that there are singular and plural versions of
getter and setter methods. What’s the difference? Well, the singular version will either get or set a
specific (singular) attribute value, whereas the plural may be used to get or set one or more attrib-
ute values all at the same time.
Is there any particular reason for using one form over the other? The singular methods tend
to be a bit simpler, for example to get a single value, such as the processType, you could really use
either form. All you would have to deal with would be the syntax of specifying the attribute to be
retrieved and the value being returned. Listing 9.5 demonstrates this difference as well as shows
another useful utility routine, MBattrAsDict().
Table 9.1 explains this example in detail. From this, you might be able to decide whether
(or if) you prefer the singular, getAttribute(), or plural, getAttributes(), version or if
you might prefer the MBattrAsDict() utility routine.
Line Explanation
1 AdminControl.queryNames() obtains the names of all MBeans for all the active
servers in the cell.
2 Convert the string into a list—one element for each Server MBean.
3 Select the first element of the list for use in this example.
7 The returned value is a list of strings. Note how the values are not quoted.
8 The WAuJ_utilities module is imported using an alias (WAuJ).
10 This demonstrates how easy it is to access a retrieved value from the returned dictionary.
11 The indexed value is a simple string.
Even though the help for the getAttributes() method doesn’t show it, the list of attrib-
utes to be returned is optional. Be careful though. Should you try something as simple as print
AdminControl.getAttributes(server), you might be surprised by the amount of informa-
tion that is returned (as a single string). When this was tested while connected to an unmanaged
server, more than 20,000 characters of data were returned. If you are going to be dealing with
multiple attributes, you are likely to prefer the MBattrAsDict() utility routine.
Given that the singular getAttribute() method can be used to retrieve a specific MBean
attribute value, what steps are required to use this method? Fortunately, these steps are easy to
describe:
1. Get the MBean for the object of interest (for example, a server).
2. Get the attribute name for this kind of object.
3. Use AdminControl.getAttribute(mbean, attributeName).
The real question at this point is, “How do you know the names of the attributes that exist for a
particular MBean?” In the “Help for MBeans” section of Chapter 7 you saw how the
Help.attributes() method can be used obtain this information. In addition to providing the
names and data types for each attribute, the returned string shows you whether or not each attrib-
ute can be modified. Is there an easy way to get the names of modifiable attributes? Well, as often
is the case, there are a number of different ways to do this—some easier to understand than oth-
ers. Let’s take a look at some different approaches to the same problem.
Each of the following examples use the output of the Help.attributes() method to identify
the modifiable attributes for a server MBean. The first, in Listing 9.6, uses a regular expression and list
comprehension to perform this job. It could be written in fewer lines, but this would make the line too
long to fit on one line in this book, and the explanation of this line would be harder to understand.
The explanation of this example can be found in Table 9.2. You might consider writing lines
4–6 in one statement. Before you do, think about how much harder a single line might be to under-
stand (and maintain). And remember how hard a single statement might be for someone to read.
Who knows, you could be the person who has trouble understanding it in six months or a year.
6 All occurrences of multiple adjacent blanks are replaced by a single blank, and the result
is converted to a list using splitlines().
The first line of the output of Help.attributes() has column headers, so this line is
discarded.
7 This expression uses list comprehension to only keep those lines that end with “RW,”,
which indicates that the values are read-write.
8–11 The list of modifiable attributes is output with a newline character (’\n’) between each
attribute.
If you had any trouble understanding the example in Listing 9.6, you might prefer the
example found in Listing 9.7. Granted, it might not be as efficient as the previous example, but
whoever’s responsible for the administrative scripts might understand this more easily.
The differences between the two listings are this: Lines 3–7 are used to obtain the text asso-
ciated with the attributes for the specified MBean and replace all occurrences of multiple blanks
with a single blank. Lines 9–13 are used to build the list of “read-write” attribute entries without
using list comprehension. The two figures are extremes, though. You get to choose one technique
over the other or something in the middle. In either case, remember to provide appropriate com-
ments that explain the statements that you use and why.
Now that you’ve seen these two extremes, take another look at Listing 9.5. You might have
missed it the first time through. Look how easy it was there to use the MBattrAsDict() utility
routine to put all of the MBean attributes into a dictionary. Now think how easy it would be to
combine this dictionary of server attributes with the list of modifiable attribute names generated
to change their values. This is what setter methods are all about.
Having discussed the singular and plural getter methods for attributes, it’s easy for us to
understand that only some MBean attributes are (dynamically) modifiable. What does this mean?
Can’t we change everything? Well, sort of. The modifiable attributes are allowed to be changed
on an active MBean. To change other attributes, you need to look at the configuration attributes
that exist for this object. To change these attribute values requires a configuration change and a
stop and restart of the appropriate resources (such as the application server):
att = ‘threadMonitorInterval’
stringResult = AdminControl.getAttribute( bean, att )
val = int( stringResult )
AdminControl.setAttribute( bean, att, str( val / 2 ) )
For the example shown in Listings 9.6 and 9.7, you can see that the modifiable attributes (for an
application server) are those that have threadMonitor as a prefix. The singular form of the
attribute setter method is pretty straightforward. For example, say you wanted to half the
threadMonitorInterval attribute for the given application server. The first thing you must
realize is that the data type returned by the getAttribute() method is a string and needs to be
converted to a numeric type in order to perform the desired mathematical operation.
Note that by putting the name of the attribute to be modified into a variable makes the get-
ting and setting a bit easier to read, as well as guaranteeing that the value being modified is the
same one that was retrieved. You should also note that not only is the value returned by the getter
a string, but the value to be modified needs to be a string as well.
What about the plural setter method (AdminControl.setAttributes())? What does it
look like?
result = AdminControl.setAttributes( bean, attributes )
What does attributes represent? Well, it can be either a string or a list of strings. If the string form
is used, it should be a string representation of a list. For example, something like the following:
attributes = ‘[ [ name1 value1 ] [ name2 value2 ] ]’
Does it have to be used to modify a multiple values? No, you could use the singular form of the
method for each attribute. Can it be used to modify a single value? Yes, it really doesn’t matter
how many attributes are specified, as long as each specified attribute is modifiable. You can even
specify an empty string or list of attributes to be modified that changes the same value multiple
times.3 What is returned by the method? The result is a string list containing the attributes that
were successfully modified by the call. Listing 9.8 shows a complete (interactive) example use of
the setAttributes() method call that makes use of the MBattrAsDict() utility function
described earlier. Some things to note from this example include the following:
1. The assignment of “ts” (the variable used to hold the TraceService configuration
ID) and “attr” (the variable used to hold the attribute values to be modified) each uses
two lines (lines 2–3 and 13–14, respectively) so that a long statement would not be
wrapped across multiple lines.
2. The fact that the MBattrAsDict() utility function adds a ’Modifiable’ entry to the
returned dictionary is very convenient (lines 5–8).4
2
Note how the list form requires a comma delimiter between the list elements.
3
If the same attribute name occurs multiple times, the last occurring value will be the one used.
4
This attribute was specifically added because of the testing that was done related to the examples shown in Listings
9.6 and 9.7.
3. Even though the ’ringBufferSize’ attribute is “modifiable” (as seen by the list of
modifiable attributes on line 10), and the modification was successfully made (as seen
on line 16), the modification didn’t really occur (as seen on line 18). Why? Because the
current configuration of this TraceService is configured as tracingToFile and not
to memory. So the request to modify the ’ringBufferSize’ was ignored.
4. Note that sometimes the value passed to the setter method may be “changed” when the
actual attribute modification occurs. For example, when the application server
traceSpecification value was set to ’com.ibm.*=all=disabled’, the actual
value saved was ‘*=info’.5 Listing 9.8 not only demonstrates how to use the
setAttributes() method call, it also shows that you might not actually be making
the modifications that you think you are. Just be careful and test your scripts thoroughly.
You may even consider having your script get the attribute that was just set and compare
the two values.
5
Why? Because the assigned trace string didn’t match the expected and currently supported format.
What would a script look like that allowed all of the TraceService configuration settings
to be viewed and optionally modified? The TraceService.py script does just this and is also
available with from the book’s website that appears to do the trick. One of the interesting things
demonstrated by this script is the fact that configuration values that exist on multiple screens on the
administrative console can, in fact, be modified by single execution of an administrative script.
Miscellaneous Methods
The penultimate group of methods cover some unrelated topics. This group of methods consists of
the following:
• invoke()—Calls an MBean method.
• testConnection()—Tests the connection to a DataSource object.
• trace()—Sets the wsadmin trace specification.
Let’s discuss these in reverse order, taking AdminControl.trace() first. The first time that we
encountered this, we hoped that it would allow us to easily change the traceSpecification of an active
application server. Unfortunately, that was not the case. For that, you need to use one of the
setAttribute methods shown earlier. This method is used to change the trace settings for the wsadmin
process. So a command like the following would be used to enable verbose tracing of wsadmin.6
AdminControl.trace( ‘com.ibm.ws.scripting.*=all=enabled’ )
This trace setting corresponds to the com.ibm.ws.scripting.traceString property found
in the wsadmin.properties file.
Next, you can take a look at the testConnection() method. To use this method, you
need to pass it the config ID of a dataSource object, for example, something trivial such as:
ds = AdminConfig.list( ‘DataSource’ ).splitlines()[ 0 ]
print AdminControl.testConnection( ds )
It is important to remember, however, that should the connection attempt fail, an exception is
raised. So it is a good idea to remember to use a try/except error handler around this call.
The invoke() method can be used to execute MBean object methods. Chapter 7’s “Help
for MBean Operations” provided an example use of the invoke() method to obtain product ver-
sion information. Let’s take another look at this method in a bit more detail. When we say that the
invoke() method can be used to execute MBean object methods, what does this really mean,
and more importantly, how do you find out what kind of methods exist that can be called?
Let’s start by looking at the online documentation:
1. Point your browser to the WebSphere Application Server Library page, http://www.
IBM.com/software/webservers/appserv/was/library/.
6 Most likely you would do this if requested to do so by IBM WebSphere Application Server technical support.
2. Select the tab for the version of the product being used (such as V 6.1).
3. Select the “View page” link for the product edition being used (“Network Deploy-
ment—distributed platforms”).
4. Select the “View page” link for the product edition7 (“WebSphere Application Server
Network Deployment, Version 6.1”).
5. In the left frame, expand the document of interest (“Network Deployment (Distributed
platforms and Windows), Version 6.1”).
6. Expand the “Reference” section.
7. Select the “MBean interfaces” section.
8. Scroll the “MBean Type List” selector to the MBean of interest and click a link (such as
“Server”).
9. Scroll the MBean details selector (the far right panel) to the “Operation Summary” to
review the list of available methods for MBeans of this type.
We were surprised to find that one of the available methods for Server type MBeans is the
restart() method. What is required to actually use this method?
You must obtain a MBname string for an object of the appropriate type and then use the
AdminControl.invoke() method to call the method and pass it the necessary parameters.
Is that it? In a word, yes. So to execute the restart() method for an active application
server, all you have to do is something like the following:
svr = AdminControl.queryNames(‘type=Server,* ‘ ).splitlines()[ -1 ]
AdminControl.invoke( svr, ‘restart’ )
# Give the new JVM time to initialize...
AdminControl.reconnect()
This even worked when wsadmin was connected to an unmanaged application server, which is
pretty neat. So once you know how to find the MBean methods, it’s pretty simple to have your
scripts call them using AdminControl.invoke().
What? You want another example? Oh, alright. Let’s take another look at the TraceService
mentioned earlier. In fact, in Listing 9.8 you saw how you could modify some attributes of a
TraceService. What kinds of methods exist on the TraceService MBean that you can invoke?
Well, from the online documentation, if you search for TraceService, one of the entries that is
found is called the “TraceService MBean Definition Table.” The list of methods that can be called
can be found in the table labeled “Operation Summary.” So to call or execute one of these meth-
ods you only need to:
7
Why there are multiple layers of this variation, we do not know.
*_jmx Methods
We have seen and discussed singular and plural forms of attribute getter and setter methods. If
you happened to look closely at the AdminControl.help() output, you would have seen some
other methods having the same names, but with a ”_jmx” suffix. What is this all about? Well,
they are very similar to the methods described earlier, with the following differences:
1. Object names, and not object name strings, are used to identify the object instance to be
manipulated. For example, instead of using something like this:
ts = AdminControl.queryNames( ‘type=TraceService,*’ )
ts = ts.splitlines()[ -1 ]
print AdminControl.getAttribute( ts, ‘ringBufferSize’ )
ts = AdminControl.queryNames( ‘type=TraceService,*’ )
ts = ts.splitlines()[ -1 ]
tsName = AdminControl.makeObjectName( ts )
print AdminControl.getAttribute_jmx( tsName, ‘ringBufferSize’ )
In this trivial example, it doesn’t make much sense to have the additional conversion of the object
name string value to an object string, just so that a different variant of the routine can be used.
However, if your script is already using object names instead of object name strings, then it might
make sense to use the getAttribute_jmx() method instead.
The getAttributes_jmx() method is a bit different. Earlier, we didn’t see that the
getAttributes() method has an optional second parameter that can be used to identify the
attributes to be returned. For this method, the parameter is required, not optional. So instead of
using something like:
ts = AdminControl.queryNames( ‘type=TraceService,*’ )
ts = ts.splitlines()[ -1 ]
attr = [‘ringBufferSize’, ‘traceSpecification’]
print AdminControl.getAttributes( ts, attr )
Summary
This chapter has been all about the AdminControl scripting object. When you, as a WebSphere
Application Server administrator, need to control or manipulate active resource objects, you will
probably make use of this object and its methods. We have seen that some of these methods sim-
ply allow you to query the AppServer for information about its environment. There are some
really valuable AdminControl methods, however, that are specifically related to the manipula-
tion of MBean attributes. This allows us to dynamically change some of the AppServer envi-
ronment without making a persistent configuration change. It also allows us to make changes to
active MBean objects, which means that the AppServer or application doesn’t have to be recy-
cled (stopped and restarted) for these changes to take effect. This is what makes these methods
really useful and worth learning.
The AdminApp
Object
The AdminApp object operates on applications. The following types of operations can be per-
formed on an application:
1. Information
2. Install
3. Uninstall
4. Modify
AdminApp.help() provides the complete list of method calls, and the details about each
method can be displayed by calling AdminApp.help(‘methodName’ ).
185
An optional scope parameter can be specified to filter or subset the list of applications returned.
For example, if you have a number of applications deployed on individual servers, you might be
interested in only those applications deployed upon a specific server.1
NOTE The optional scope parameter must start with the ”WebSphere:” domain name.
We find that the easiest way to provide a valid scope parameter to the AdminApp.list()
method is to use the MBean for the particular resource. However, this requires that the resource
be active. If that is not the case, the scope parameter should contain elements specified in the
proper hierarchical order. For example:
WebSphere:cell=<cellName>
WebSphere:cell=<cellName>,node=<nodeName>
WebSphere:cell=<cellName>,node=<nodeName>,server=<serverName>
1
We’ll see shortly that the complete server reference can be obtained by specifying ’-server’ for the optional second
parameter to the AdminApp.listModules() method.
The information returned appears to be for human consumption. By that we mean it doesn’t
appear to be easily processed, or parsed, by a script. There’s just so much of it and in various sec-
tions of the text.
One way to process the information from the view() method is to first separate the text
into sections. To do so, identify the sections. Each section is associated with a specific, named
2
If the ’-server’ option is not specified, only the application name and module information will be present on
each line.
task. To obtain the task names for a deployed application, specify ’-tasknames’ as the second,
optional parameter to the view() method. For example:
app = AdminApp.list().splitlines()[ 0 ]
taskNames = AdminApp.view( app, ‘-tasknames’ ).splitlines()3
Given the task names that are listed for a deployed application, you can then view the information
for a specific task by providing the task name as the second parameter to the view() method.
For example:
for name in taskNames[ :-1 ] :
print AdminApp.view( app, ‘-’ + name )
print ‘-’ * 70
Another method you can use to help understand the installation of an enterprise application is the
AdminApp.options() method. This method has a number of uses. The one just mentioned is
obtained by providing a single parameter of an application name. For example:
opts = AdminApp.options( app )
The options() method returns a list of all the options available for editing the specified applica-
tion. What other parameter choices exist for the options() method? Well, here is the complete
list of parameter variations for it. If no parameters are specified, the options() method returns
the list of “general” options that are available for every installable application.
• Application Name—If an application name is specified, the options() method
returns information about all the modifiable options (that is, the ones available for edit-
ing) for the specified application.
• Module Name—If a module name is specified, the options() method returns
information about the modifiable options for the specified module.
• Filename—If a filename is specified, the options() method returns information
regarding the installation the specified file.
• Filename, operation—If a filename is specified with one of the following optional
operations, the options() method returns information related to the installation of the
specified file, and operation:
• installapp
• updateapp
• addmodule
• updatemodule
3
There is an empty or blank line at the end of this call to the view() method. The result of this is that there is an empty
entry at the end of the list that needs to be ignored.
How can the script tell if an application is currently started or stopped? By looking for an MBean
associated with the specific application. If the MBean lookup returns an empty string, then no
active MBean instance exists for the specified application, and the enterprise application is not
started:
bean=AdminControl.queryNames(‘name=%s,type=Application,*’ % appName)
If you happen to have “Command Assistance” enabled on your Administrative console4 and
you display information about the installed applications,5 then “View administrative
scripting command for last action” only shows that the last command executed as
AdminApp.list(). It does not show each and every command or action performed to obtain all
of the information currently displayed. However, it is a reasonable start.
You have probably been wondering if we were ever going to get around to explaining the
actual options that can be used to install, edit, or update an application directly (that is, using the
install(), edit(), or update() methods, instead of the interactive versions of these same
methods). Well, the answer is yes...and no. There is a whole section of the online documentation
related to this topic, entitled “Options for the AdminApp object install, installInteractive, edit,
editInteractive, update, and updateInteractive commands.” There is another related page entitled
4
System administration-> Console Preferences-> Log command assistance commands.
5
Applications-> Enterprise Applications.
“Usage table for the options of the AdminApp object install, installInteractive, update,
updateInteractive, edit, and editInteractive commands,” that also includes information to help us
understand when different options should and should not be used.
A common “first impression,” when these sections are encountered in the documentation is,
“Oh, my goodness!” The list of options is huge. It’s almost 100 options long, in fact.6 It is no wonder
people don’t bother trying to remember all of these. This is exactly why wizards were developed, so
that people like us don’t have to spend time and energy trying to remember all of these things.
Let’s start simple, though. Which scripting commands are required to install an applica-
tion? Well, using nothing but the default installation settings, it is as simple as the following:
AdminApp.install( r’C:\temp\myApplication.ear’ )
AdminConfig.save()
Turning these statements into a script file is pretty straightforward. An example script, named
installApp.py, is available from the download page. It is slightly different from some of the
other scripts in that it allows a parameter to be specified multiple times. This allows the script to
be used to install multiple application EAR files with a single execution.
It also points out what happens when you pass a fully qualified7 Windows filename to a
script. Take a look at how the file name parameter was specified using a “raw string” (that is,
using the r as a string prefix). If this isn’t done, then every backslash would need to be specified
using two backslashes (’\\’).
What happens when a fully qualified Windows filename is passed into a script? Listing
10.5 shows what we’re talking about. Lines 1–3 show a trivial script used to simply display the
values passed into the script as command-line parameters. Line 4 shows how the script is exe-
cuted by wsadmin, and line 7 shows the value of the filename parameter as it occurs when the
script is executing.
6
A total of 94 options are listed in the version 6.1 of the documentation and 103 in 7.0 version of the documentation.
7
A fully qualified filename is one containing the complete path to the file (e.g., ’C:\temp\filename.ext’), not just the
name to the file, or a relative path and filename (i.e., containing ’..’ to refer to the parent directory).
8|C: emppp.ear
9|
10|C:\IBM\WebSphere\AppServer\bin>
The value shown in line 8 is quite surprising. What happened to the nice fully qualified filename
parameter? Well, what happened is that the ’\t’ and the ’\a’ were interpreted as string escape
sequences. The ’\t’ was interpreted as a tab character (hence the space seen after the colon and
before the emp and the ’\a’ as interpreted as an alarm character, that is, a beep will be sounded).
So, what to do about this? A function named fixFileName() is provided in the
WAuJ_utilities module that can help with this. This utility function is used in the
installApp.py example script mentioned earlier. The trivial script shown in lines 2–3 of the
following lines of code could be done using something simple such as the following:
from WAuJ_utilities import fixFileName
for arg in sys.argv :
print fixFileName( arg )
8
The property that is labeled “com.ibm.ws.scripting.traceFile” in the wsadmin.properties file.
One thing to note from these examples is the fact that option names have a hyphen or dash prefix.
This allows the AdminApp method to distinguish between option names, and their values. So,
what’s the best way to list the options needed to install an application, and how should those
options should be specified? Take advantage of the assistance provided by the
installInteractive() method to list what options can, and should, be specified. Then, you
can use the information from the trace file to find out how to specify the options you wish to use.
From this, you can write scripts that can install your applications.
The question that remains is, “What’s the difference between the edit() and update() methods?”
You can distinguish them in this way: To change the options associated with an installed application,
use either the AdminApp.edit() or the AdminApp.editInteractive() method. To change the
contents of the application (that is, to add to, replace, or remove application sub-components), the
AdminApp.update() or AdminApp.updateInteractive() method should be used.
As with the installInteractive() method, you can use the editInteractive()
method to make changes to the configuration settings associated with an installed application.
Once all of the prompt answers have been provided, an edit() operation is performed, and a
message is written to the trace file with the messageID of WASX7278I to show the options that
were specified. You can use the same technique recommended here to locate these options and
write a script to perform this same type of edit command on the application of your choosing.
The AdminApp.updateInteractive() method, unlike the installInteractive()
and editInteractive() methods, requires more than the application name to be specified.
The second parameter to this method is used to identify the content type to be updated. The avail-
able values for the content type parameter are as follows:
• app—Indicates that the application is to be updated, with the “operation” option identi-
fying the kind of operation to be performed on the application.
• file—Indicates that a single file is to be added, removed, or updated at any scope
within the deployed application.
• modulefile—Indicates that a module is to be updated.
• partialapp—Indicates that a partial application is to be updated.
In addition to the application name and the content type, you will need additional options. The
exact options you need will vary depending on the specifics of your enterprise architecture. This
is where the online documentation mentioned earlier comes in very handy. You will need the
online Information Center to find the subset of options that your organization needs.
Let’s work through an example to better understand how to make use of the information that
exists. Looking at the “Usage table...” page in the online documentation, you see that almost every
option is allowed to be specified while using either the updateInteractive() or update()
methods and specifying a content type of “app“. One of the important options to be specified
while using either of the update() methods is the operation option. The allowed values of the
operation option are as follows:
• add—Adds new content.
• addupdate—Adds or updates content based on the existence of content in the application.
• delete—Deletes content.
• update—Updates existing content.
So a reasonable starting place would be to build the list of options to be used for the application’s
update. First, however, it is best to find out which of the options, if any, are required. Reviewing
the “Options for the AdminApp object...” page, you find that only the following options are
required, and each has an associated caveat:
• contents—Required unless the delete operation is specified.
• contenturi—Required if the content type is file or modulefile.
• operation—Required if the content type is file or modulefile. If the content type is
app, the operation type must be update.
Because we have chosen the content type to be app, this means that the -operation option
must be update. So now you can start building the list of options:
options = ‘-operation update’
Then the type of update to be performed will help in defining additional values. For example, if
the application has been revised and you want to update the deployed application using a newly
built EAR file, it could be as simple as follows:
app = AdminApp.list().splitlines()[ -1 ]
ear = r’C:\temp\myApplication.ear’
This causes the interactive update operation to be executed, which prompts you for the allowed
update options and executes the update of the specified application using the contents of the indi-
cated file and the options you supplied. Should the update be successful, a message is logged to the
trace file using the same messageID as mentioned earlier (that is, WASX7278I), containing the
complete update request. It is a simple matter to extract the information from this update request
and to build a script to perform this type of update on your deployed application using these options.
Keep in mind that if an application is active (that is, it is running), then changing any appli-
cation setting causes the application to be stopped and restarted. On an unmanaged application
server, the application will restart after the configuration has been saved. For a deployment man-
ager environment, the application restart will occur after the save and after file synchronization
for the associated node completes.
• export()—This method can be used to copy the contents of a deployed application to a user-
specified file. The two required parameters are the application name and the fully qualified
output file name. The following code snippet demonstrates how this method might be used:
AdminApp.export( ‘myApp’, r’C:\temp\bob.zip’ )
• exportDDL()—This method can be used to copy the Data Definition Language (DDL)
files from the EJB modules of an application to a user-specified directory. The two
required parameters are the application name and the fully qualified directory name.
The following code snippet demonstrates how this method might be used:
AdminApp.exportDDL( ‘myApp’, r’C:\temp\myApp’ )
There is an optional parameter that can be used to specify a specific subset of DDL val-
ues to be exported. Valid options include ddlprefix.
• publishWSDL()—The purpose of publishing the Web Services Description Language
(WSDL) file for an application is to provide clients with the description of the Web ser-
vice.9 This includes identifying the location information for it. So this method can be
used to provide the WSDL information after modifying the endpoint values.
There are two required and one optional parameter allowed for this method. The
required parameters are the application name and the fully qualified output file name.
The following code snippet demonstrates how this method might be used while specify-
ing only the required parameters:
AdminApp.publishWSDL( ‘myApp’, r’C:\temp\myWSDL.zip’ )
The optional parameter is used to specify the partial URL information for each binding
on a per-module basis for the application. The format of this parameter is as follows:
[ [ module [ binding [ partial-URL ] ] ] ]
An example for which might be
[ [ ‘myApp.war’ [ [‘http’ ‘http://localhost:9080’ ] ] ] ]
9
See Chapter 15, “Administering Web Services,” for a discussion of Web services-related AdminTask methods. See
“Exporting the WSDL for a Web Service” in that chapter for additional details.
• taskInfo()—This method can be used to obtain information about a specific task for
a specified application file. There are two required parameters:
• The application file name
• The task name
An example use of this method would be as follows:
earFile = r’C:\temp\myApp.ear’
print AdminApp.taskInfo( earFile, ‘ActSpecJNDI’ )
Summary
AdminApp allows you to install, uninstall, and modify enterprise applications, as well as query
them for information.
You have many options for administering enterprise applications using the AdminApp
scripting object. In the chapters that follow, we explore the hundreds of methods available from
the AdminTask scripting object, many of which are related to enterprise applications.
The AdminTask
Object—Server
Management
Introduction
WebSphere Application Server is not a monolithic piece of code but instead consists of many
discrete parts, such as application components, Java EE-specified containers, connectors,
managers, service providers, and much more. There are many complex relationships between
these parts, as well as products built on top of WebSphere Application Server, such as
WebSphere Enterprise Service Bus, WebSphere Process Server, or even just Feature Packs, that
add even more parts. The modular and inter-related nature of WebSphere Application Server
made maintaining its administrative infrastructure challenging, and it cried out for a change.
The AdminTask object, introduced in WebSphere Application Server V6, addresses the needs of
this modular approach.
Prior to WebSphere Application Server V6, the primary administrative objects were the
ones that have been covered so far in the book:
• AdminConfig—For managing the XML configuration repository
• AdminControl—For managing the runtime state of WebSphere
• AdminApp—A specialized object for managing applications
WebSphere Application Server V6 introduced a crucial change and improvement to WebSphere
Administration: As new functional components are added to the codebase, companion administra-
tive components can be added, too. In the case of the scripting interface, this change appears as the
AdminTask object. But what you might not realize is that the AdminTask object is a façade whose
perceived abilities are assembled dynamically at runtime. Just as new functional components can
199
be added, so too can new administrative commands be registered,1 which are presented via the
AdminTask object.
Although the AdminTask object has been described by some sources as being a higher level
alternative to AdminConfig, it is capable of being used across all administrative categories. To
quote the architects, “The WebSphere command framework lets developers implement more end-
user-friendly and high-level task-oriented commands for common—yet complex—administra-
tive tasks, such as configuration and application management service functions, execution of
JMX MBeans, and so on.” Whenever you can, you are urged to use AdminTask instead of the more
primitive administrative objects. For one thing, an AdminTask command might be authored to
maintain consistency across inter-related configuration and runtime states—a problem that the
primitive administrative objects cannot manage.
This chapter is the first of a series, running from this point through the end of the book,
which largely makes use of the AdminTask object and specific commands. The examples and the
methods discussed in this chapter come from the following AdminTask command groups:
• AdminReports
• ClusterConfigCommands
• ConfigArchiveOperations
• CoreGroupManagement
• GenerateSecurityConfigCommand
• NodeGroupCommands
• PortManagement
• ServerManagement
For the purposes of this chapter’s discussion, it is assumed that several steps have already been
completed, as well as that you have installed WebSphere Application Server version 6.1 or later
and have created a deployment manager profile and two managed profiles. Finally, it is assumed
that you have federated both profiles to create a cell that has a deployment manager and two
nodes. It is not assumed that you have created any application servers.
Starting from this point, we use AdminTask methods to create and delete some servers,
modify some configuration parameters, create and delete clusters and gather information about
the servers in the cell.
1
The details of this capability are described in the IBM WebSphere Technical Journal Article, “Administrative com-
mand framework programming guide for WebSphere Application Server,” at (http://www.ibm.com/developerworks/
websphere/techjournal/0610_chang/0610_chang.html), which explains it in detail and provides instructions for writ-
ing your own AdminTask commands.
The information displayed shows the following for every server in your cell:
• The name of each server
• The name of the node containing the server
• The port number of each port used by the server
• The name associated with each port
This is very useful information. Make a note of the name of each node. You will need this infor-
mation when you create servers and cluster members. If you would like to see the same informa-
tion returned in a slightly different way and limited to only one server, say only the Deployment
Manager, type the following command line:
wsadmin -c “print AdminTask.listServerPorts( ‘dmgr’ )”
Here is yet another useful method, especially when you are troubleshooting your configuration:
print AdminTask.reportConfigInconsistencies()
On a production cell, you want this report to say that there are no items. This method does
not send its output to the screen. Instead, it sends its output to a file. The name and location of
this file are specified in the wsadmin.properties file in each profile directory. The
com.ibm.ws.scripting.validationOutput property controls this.
If you would like a verbose checklist of security-related items, this command line can suffice:
print AdminTask.generateSecConfigReport()
You will likely want to redirect the output from this method to a file. The output is volumi-
nous. However, this output does not take the place of having a genuine security audit per-
formed by professionals. On the other hand, it does list many configuration items that affect
2
Because the ’-c’ wsadmin option is specified, the wsadmin tool will return to the command prompt after the
specified task is completed.
3
Please note that we assume that you have set jython as the default language using wsadmin.properties.
the security of your cell and is a good place to start. The output of this method shows the fol-
lowing information:
• The name that the Admin Console uses for this setting
• The attribute name the Admin Console uses for this setting
• The current value of this setting
• The breadcrumb path in the Admin Console for viewing this value
While this output is very much Admin Console-focused, it is still provides a very helpful check-
list of things to examine. Again, a real security audit would include many things that are not pro-
vided in the output of this method.
ServerType-Related Methods
In this section, let’s examine a few more AdminTask methods that deal with ServerTypes.
These methods are as follows:
createServerType()
getServerType()
listServerTypes()
showServerTypeInfo()
The following realizations, or conclusions, were drawn after investigating these AdminTask
methods:
• Logically associated methods are not always in the same group. For the list shown here,
the createServerType() method is not in the same (ServerManagement) group as
are the other ServerType methods, at least not in the version 6.1 product.4 This issue
has been corrected in the version 7.0 product.
• Grouping and listing methods together in this way can show that something is missing.
For example, no methods exist that allow ServerType entries to be removed or modi-
fied.5 This emphasizes how important it is that the user of the createServerType()
method understand what this method does and why it exists.
• Just because a method exists does not mean that WebSphere Application Server admin-
istrators are expected to, or should, use it. This is particularly true for the
createServerType() method. This method is intended to be used by developers who
need to create a new ServerType. In general, this would only occur for a product that
4
In fact, in version 6.1, the createServerType() command isn’t in any commandGroup. This oversight has
been corrected in version 7.0 of the WebSphere Application Server product.
5
A product request for these commands has been added to the product.
needs to include and make use of a WebSphere Application Server environment. So the
users of this method are not going to be “normal” administrators of, or application
developers for, the WebSphere Application Server product.
• Occasionally, the output of some methods will surprise you. For example, while exe-
cuting an interactive wsadmin session using an Unmanaged node configuration
(wsadmin -conntype none -profileName AppSrv00), the output of the
AdminTask.listServerTypes() method is identical to the output received when
the wsadmin tool is working with a Deployment Manager configuration (wsadmin
-conntype none -profileName Dmgr01), as shown in Listing 11.1.
What is surprising about this list is the lack of entries for the DEPLOYMENT_MANAGER and
NODE_AGENT server types.At least we were surprised until it occurred to us that creating a Deployment
Manager or Node Agent server using scripting may have been considered “potentially dangerous.” But
this means that in order to create a Deployment Manager, an administrator must use either the
manageprofiles command or, if it is available for the environment, the profile management tool.
Predefined items might not match the required and optional values defined for creation meth-
ods. For example, the help text for the createServerType() method, as seen in Listing 11.2,
identifies the required and optional attributes.6
Listing 11.2 createServerType Arguments
*version - The Product Version
*serverType - The ServerType (e.g.: APPLICATION_SERVER)
*createTemplateCommand - The Command used to create a Server Template
*createCommand - The Command used to create a Server
defaultTemplateName - The name of the default Template (non-z/OS)
defaultzOSTemplateName - The name of the default z/OS Template (non-
z/OS)
*configValidator - The name of the Config Validator class
Listing 11.3, on the other hand, shows the output of the ServerTypes.py script, available
from the book’s companion website, which shows that not every “required” parameter is present
6
The createServerType() argument names do not exactly match the attribute names that actually exist.
in every predefined ServerType. It uses the listServerTypes() method to determine the kinds
of servers for which information exists. It then uses the showServerTypeInfo() method to
obtain the list of name/value pairs of attributes for each server type.
One interesting thing to note is that the ServerType named PROXY_SERVER has many
additional attributes that could not be provided within a createServerType() method invoca-
tion. This leads us to believe that the createProxyServer() method could not have been used
to create this default Proxy Server.
At this point, the only unexplained method is getServerType(). So let’s take a look at
how you can take the information from the help text and use it to create a trivial script that uses this
method. The required and optional parameters for the getServerType() method are as follows:
• serverName—The Server Name
• nodeName—The Node Name
From this, you can build an example getServerType() method call:
getServerType( ‘[ -serverName server1 -nodeName myNode01 ]’ )
More importantly, a trivial script that includes this method, as well as the output of executing this
script, is shown in Listing 11.4. Why take the time to do this? So you can see how easy it is to go
from the help text to a working script that uses the parameters identified in the help text for the
specific method.
The examples shown in Listings 11.6 and 11.7 use the variables shown in Listing 11.5. You
should be able to modify the code for your environment just by changing their values.
| ‘ -nodeGroup ‘ + NodeGroupName + \
| ‘ -coreGroup ‘ + CoreGroupName + ‘ ] ]’)
30| print AdminTask.createClusterMember(‘[-clusterName ‘ + \
| Cluster01Name + ‘ -memberConfig [-memberNode ‘ + \
| NameOfSomeNode + ‘ -memberName ‘ + \
| Cluster01Member02 + ‘ -replicatorEntry true]]’)
Line 25 creates an application server called ’happy’ on one of the nodes. The only manda-
tory parameters are the name you choose to call the server and the name of the node where the
server will be located. AdminTask.createApplicationServer() returns the configuration
ID of your new server. That is why the print statement is included.
Now let’s create a cluster. You should think of a cluster as nothing more than a list of lists.
The first list is a list of zero or more servers. The second list is one of zero or more applications
deployed to all of those servers simultaneously. The third is a list of zero or more messaging
buses delivering messages to the cluster.
We created a node group and a core group for the server because some advanced WebSphere
Application Server configurations allow administrators to create policies that determine how traffic
is routed among servers to minimize response time and policies that determine how WebSphere
Application Server reacts to certain server failures. Node groups and core groups become useful in
those advanced topologies. If you are scripting for one of those advanced topologies, you get a
chance to walk through some issues you may encounter when you create and delete node groups,
core groups, and clusters later in this chapter. If you are not scripting for one of those advanced
topologies, you can ignore node groups and core groups and safely remove them from the samples.
If you are using node groups and core groups, you should create them and populate them
before you try to create a cluster that makes use of them. Lines 23 and 24 create a node group and
a core group. Lines 26 and 27 populate the node group and the core group. If you are not using an
advanced topology, you can safely delete these four lines.
Line 28 creates a cluster and performs two steps:
1. The clusterConfig step gives the cluster its name. This step is mandatory.
2. The replicationDomain step is optional. If you want to enable automatic failover
from one cluster member to another and do not want to lose any session information
when that failover takes place, perform this step; otherwise, omit it.
At this point, you have a cluster. If you were to print out the list of configured ports again, you
would see that there are no new servers and no new ports in the cell. A cluster is just an empty list.
By deciding to create a replication domain, you are making session failover possible when and if
you add more than one member server to your cluster. Lines 29 and 30 add some member servers
to the cluster.
Deleting servers is straightforward (see line 43). When you have created clusters, replica-
tion domains, messaging buses, core groups and node groups, you might have to delete some
items in a particular order.
If you want to delete an entire cluster, you do not have to remove individual cluster mem-
bers first. Deleting the cluster on line 53 will also delete all member servers. If you created a repli-
cation domain when you created your cluster, you can delete the replication domain, all the entries
in the replication domain, and the cluster at the same time. This is what was done on line 53.
If you only want to delete one cluster member, use line 49 as an example. Because an entry
for these members was created in the replication domain when the members were created, it was
necessary to clean up that entry when deleting the cluster member. This is why you have a
replicatorEntry step on line 49. If you do not use replication domains, you don’t need this step.
The other thing you should note about line 49 is the configuration ID. Cluster members are
servers. You can get at least two different configuration IDs for them:
1. A configuration ID as a Server
2. Another configuration ID as a ClusterMember
Remember to use the ClusterMember configuration ID as was done on line 45.
You cannot delete a node group until you remove all nodes that are members of the node
group. And you cannot do that until you delete any cluster members that happen to belong to
those nodes (see lines 54 through 59).
A similar rule applies to core groups. Every server must belong to some core group. You can-
not delete a core group that has members. To delete a core group, you must first move its servers to a
different core group. In this example, the DefaultCoreGroup (see lines 50 to 67) was used.
Server-Related Commands
Let’s continue looking at the commands in the ServerManagement group. This time, we delve
into the Server-related commands in this group, specifically:
createApplicationServer()
createGenericServer()
createProxyServer()
createWebServer()
deleteServer()
deleteWebServer()
listServers()
showServerInfo()
showServerInstance()
Starting with the listServers() command, you find that the supported arguments are
serverType and nodeName, which are both optional. This means that the simplest call would
be as follows:
print AdminTask.listServers()
So what? The output looks like the list of configuration IDs produced by this call, seen previously
in Chapter 8, “The AdminConfig Object”:
print AdminConfig.list( ‘Server’ )
Doesn’t it? This output is similar, yes, but not identical. Don’t be confused. The values returned
by the AdminConfig.list() call are configuration identifiers, whereas the values returned by
the AdminTask.listServers() call are the list of server files (fully qualified paths to
server.xml files) that match the specified arguments.
What about the parameters, or arguments, for the listServers() command? Looking at
the command help text shows that the following optional values can be specified:
1. serverType—The type of Server (for example, APPLICATION_SERVER)
2. nodeName—The name of the node on which the server exists
This means that in addition to the empty parameter list shown here, the following kinds of calls
are also valid:
print AdminTask.listServers( ‘[-serverType APPLICATION_SERVER]’ )
print AdminTask.listServers( ‘[-nodeName %s]’ % myNodeName )
The valid server types are displayed by calling the AdminTask.listServerTypes() com-
mand. Unfortunately, this means that neither DEPLOYMENT_MANAGER nor NODE_AGENT are valid
server types for this command.
Next, let’s take a look at the AdminTask.create*Server() commands, specifically:
createApplicationServer()
createGenericServer()
createProxyServer()
createWebServer()
Why it was decided that separate create commands should be used for each of these server
types, I do not know. It is especially difficult to justify when we look at the help text for each of
these commands. In the help text, we find that the only differences between these commands are
the unique steps that exist to specify values to be configured for each specific server type.
So what parameters exist for these create commands? The first parameter is required7 and is
called the target object. It specifies the name of the node on which the server is to be created.
The target object parameter for the create server commands identifies the name of the target
node, not the configuration ID of the parent object, as was seen with the AdminConfig.create()
method.
The remaining parameters are “named” and must be specified as a string list. This means
that these parameters can be specified either as a list of strings or as a string containing a list. The
former would be specified in this manner:
[ ‘-name1’, ‘value1’, ‘-name2’, ‘value2’ ... ]
The latter requires less typing, so the examples herein use this convention. If, however, you prefer
the former, you are encouraged to use the form that you find the easiest to use (or that has been
required by your particular organization).
The names and descriptions of the parameters that exist for these server creation com-
mands are shown in Table 11.1.
Name Description
*name The only other “required parameter” specifies the name of the server to be
created.8
templateName The name of the template to be used during the creation process.
genUniquePorts Indicates whether unique http ports should be generated for the generated
server (true or false).9
template The location (directory) where the specified template is located. If this
Location value is not provided, it defaults to the system defined location, which is
recommended.
7
It’s required but only if the –interactive option isn’t specified.
8
The online documentation contains a list of characters that are not allowed in object names on a page entitled
“Object names include information that the name string cannot contain.”
9
The default value is true, which is a reasonable default given that it is unlikely that you are going to want conflict-
ing ports to be configured for your environment.
Name Description
specificShortName The server-specific short name is applicable only on z/OS platforms. All
servers should have a unique specific short name comprised of eight or
fewer characters, all uppercase. This parameter is optional, and when it is
not specified, a unique specific short name is automatically assigned.
genericShortName The server-generic short name is applicable only on z/OS platforms. All
members of a cluster should share the same generic short name, and all
individual servers should have unique generic short name. The short name
is comprised of eight or fewer characters, all uppercase. This optional
parameter, if not specified, causes a unique generic short name to be
automatically assigned.
clusterName This name indicates the name of an existing cluster with which this server
is to be created.
ConfigCoreGroup This optional step is valid for either the createApplicationServer and
createProxyServer commands and is used to specify the name of the
core group with which the created server is to be associated.
ConfigProcDef This optional step is valid for the createGenericServer command and is
used to provide the following configuration values for the server being
created:
• startCommand—The command to run when the generic server is
started.
• startCommandArgs—The command-line arguments that will be
passed to the start command.
• executableTargetKind—Specifies whether a Java classname (use
JAVA_CLASS) or the name of an executable Jar file (use
EXECUTABLE_JAR) will be used as the executable target for this
process. This field should be left blank for binary executables.
serverConfig This required step is valid for the createWebServer command and is used
to provide the following configuration values for the server being created:
• configurationFile—configurationFileDesc_2.10
• errorLogfile—errorLogfileDesc_2.
• accessLogfile—accessLogfileDesc_2.
remoteServer This required step is valid for createWebServer command and is used to
Config provide the following configuration values for the administrative server being
created:
• adminPort—Port Number.
• adminUserID—Administrator userID.
• adminPasswd—Administrator password.
• adminProtocol—Administration protocol.
10
Don’t you just love this wonderful description? A product defect has been opened to get this corrected.
createGenericServerTemplate()
createProxyServerTemplate()
createWebServerTemplate()
deleteServerTemplate()
listServerTemplates()
showTemplateInfo()
Let’s start with the easiest of these methods, that is, the listServerTemplates() method,
which can be used to display the current list of configured Server Templates or a subset of this
based on specific values. The help for the listServerTemplates() method indicates that all
of the parameters are optional. So to get a complete list of the configured server templates, you
only have to print AdminTask.listServerTemplates().
You can use the optional parameters to return server templates that match specific charac-
teristics. For example, if you need a list of server templates that are related to Application
Servers, then you could use something like the following:
print AdminTask.listServerTemplates(‘[-serverType APPLICATION_SERVER]’).
Or if you needed the complete configuration identifier associated with the server template named
IHS, you could simply:
print AdminTask.listServerTemplates(‘[-name IHS]’)11
Why do this? Well, the next method (showTemplateInfo()) has a single parameter that identi-
fies the server template about which information is being requested, and this target object is a
server template configuration identifier. This might not be intuitively obvious the first time you
read it, so an example might help make things more clear. Listing 11.8 shows an example use of
the listServerTemplates() and showTemplateInfo() methods.
Another example script (TemplateInfo.py) is available from the book download page
that uses these same methods and formats the output for all of the configured server templates. A
portion of the formatted output can be seen in Listing 11.9. The complete output, at least for the
environment on which the script was executed, was more than 250 lines long and therefore too
long to be included herein.
11
The value of the name must match an existing server template name exactly, so ’[-name ihs]’ is not the same
as ’[-name IHS]’ and will return an empty string.
com.ibm.websphere.baseProductMajorVersion : 6
com.ibm.websphere.baseProductMinorVersion : 0.0
com.ibm.websphere.baseProductVersion : 6.0.0
com.ibm.websphere.nodeOperatingSystem :
description : The APACHE Web Server
Template
isDefaultTemplate : false
isSystemTemplate : true
name : APACHE_60X
The next set of methods in the subgroup that need to be discussed are create*Template()
methods. These methods can be used should you need to create a new server template from which
servers could be easily created. The complete list of these methods is the following:
createApplicationServerTemplate()
createGenericServerTemplate()
createProxyServerTemplate()
createWebServerTemplate()
Each of these methods has the same required and optional parameters, specifically:
• templateName—The name of the server template being created (which should be
unique).
• serverName—The name of the Server from which the template values should be
obtained.
• nodeName—The name of the Node on which the specified Server exists.
• description—Optional descriptive text to be associated with this template.
• templateLocation—Optional location (fully qualified directory and filename)
where the template should be stored.12
How would any of these create*Template() methods be used then? First, create a server of
the desired type and modify the server configuration attributes to suit your specific need. Then
use the specific create*Template() method to create an appropriate template based on this
existing server configuration.
The last method in this subgroup is the deleteServerTemplate() method, which can
be used to remove a user-created template. It cannot be used to remove a template that has an
isSystemTemplate value of true.
JVM-Related Methods
The next methods to be discussed are all related, in some way, to the Java Virtual Machine (JVM):
getJVMMode()
setGenericJVMArguments()
setJVMDebugMode()
12
If the templateLocation is not specified, a default system location is used. This is the recommended practice.
setJVMInitialHeapSize()
setJVMMaxHeapSize()
setJVMMode()
setJVMProperties()
setJVMSystemProperties()
showJVMProperties()
showJVMSystemProperties()
When first looking at this collection of methods, you might be initially surprised by the fact that
there is only one getter method, (getJVMMode()); all of the others are either setter methods or
show methods.
Looking a little deeper, you find that the getJVMMode() and setJVMMode() methods are
specific to the z/OS environment and are used to determine, or change, whether the JVM should
be executing in 31 or 64 -bit mode.
An astute observer might ask some questions at this point. The administrative console
includes a way to delete a custom property,13 but we haven’t seen a way to do this with the
AdminTask object. In fact, if you use the setJVMSystemProperties() method, it appears to
add a new property, even if a property of the same name already exists!
Let’s take a closer look. While having wsadmin connected to an unmanaged application
server, you can use the following command to assign a value of ’1’ to a new “custom property”
named a:
AdminTask.setJVMSystemProperties(‘[-propertyName a -propertyValue 1]’)
However, if you change your mind and decide that the value for this property should actually be
’2’, you could execute this command to make this happen:
AdminTask.setJVMSystemProperties(‘[-propertyName a -propertyValue 2]’)
After making these changes, you need to have the changes made to the configuration files by call-
ing AdminConfig.save(). Interestingly enough, when you restart wsadmin and connect to this
same application server, you can use the showJVMSystemProperties() method to display the
current “custom” or “system” properties:
print AdminTask.showJVMSystemProperties()
Unfortunately, the output is somewhat deceiving. For this specific scenario, the output would be
’[a 2]’, which is what you would expect. If you use the graphical administrative console to
view the custom properties for this same application server, you find two entries. The first is ’[a
1]’, and the second is ’[a 2]’.
Can you create duplicate entries using the graphical administrative console? No, the mech-
anism for adding a new property using the console verifies that the property name is unique.
However, if duplicates exist, you can use the console to remove or modify the extra values. You
are cautioned, though, to remove duplicates using the console rather than leaving them around.14
JVM Properties
In addition to the JVM System Properties, methods exist to display and manipulate the general set-
tings for a specific JVM. Using the console, you can use the same sequence of steps shown earlier
to display the custom properties. By leaving off the last two steps (“Select the Custom Properties
link” and “Select the Java Virtual Machine link”), we find ourselves at the “Process Definition”
page, which displays most of the items the AdminTask object defines as JVMProperties. Listing
11.10 shows some steps you can use to display these properties in a more readable form.
13
Simply select a particular property checkbox and click the delete button.
14
A defect has been opened for this issue, so hopefully it will be resolved soon.
OK, so that demonstrates how you can determine the collection of JVM property set-
tings using the showJVMProperties() method. Interestingly enough, there is also a
setJVMProperties() method that allows you to change any and all of these properties with
one call. For example, you could use it to set the osName property to any value you choose:
AdminTask.setJVMProperties( ‘[-osName “Dos 1.0”]’ )
And should you decide to remove this attribute value, you can use the same kind of call and omit
the value:
AdminTask.setJVMProperties( ‘[-osName]’ )
If you use the setJVMProperties() method to provide values for any of the JVM properties,
why bother with these other methods that only allow us to modify a specific JVM property value?
If you want to change more than one JVM property at the same time, setJVMProperties() is
the way to go. Also if there is ever a JVM property that does not have a specific method, you can
still set it using the setJVMProperties() method. Otherwise, it is whichever you prefer.
setGenericJVMArguments()
setJVMDebugMode()
setJVMInitialHeapSize()
setJVMMaxHeapSize()
Each of these methods has optional parameters to identify the server (serverName) and node
(nodeName)—and for z/OS Application Servers, the process type (processType). Then there is
a required parameter for the specific JVM Property being set. So you can just as easily use the
setJVMProperties() method as any of these to set any of these properties:
AdminTask.setJVMProperties(‘[-genericJVMArguments [-Xquickstart]]’)
z/OS-Specific Methods
The following methods are only appropriate for on the z/OS version of the product, so they won’t
be discussed here:
changeClusterShortName()
changeServerGenericShortName()
changeServerSpecificShortName()
setServerInstance()
Let’s discuss the isFederated() method first. If the configuration profile being processed by
wsadmin is that of a Deployment Manager server, a federated Application Server, or a cluster
member, then the result of calling the isFederated() method will be true; otherwise, it will
be false. This method could be used instead of checking the process type (for example, using
something like AdminConfig.getObjectName() or AdminControl.getAttribute()).
If your script works with a type of managed profile (such as Deployment Manager, Feder-
ated Application Server, or cluster member), it might want to call the getDmgrProperties()
method to get the following values as a list in text string format:
• Hostname
• Profile name
• Port number
What does the result of this call look like? That’s easy enough to find out. You simply have to test
it using an interactive wsadmin session that is working with the Deployment Manager profile. For
this environment, the output looks like the following:
wsadmin>print AdminTask.getDmgrProperties()
[ [port 8879] [name dmgr] [host ragibson] ]
What would you need to do if your script needed to know the port number used to connect to the
Deployment Manager? Using one of the utility methods in WAuJ_utilities, it would be as
easy as:
from WAuJ_utilities import nvTextListAsDict
print nvTextListAsDict( AdminTask.getDmgrProperties() )[ ‘port’ ]
Say what? How does this work? Remember that the nvTextListAsDict() method expects a
list in text string format and returns a dictionary. And you can access an element of a dictionary
using the key, or index, value. All this second line does it create the dictionary and access an indi-
vidual element to get a particular value. If the script needed to work with any of the other values,
then it is likely that the result of calling the nvTextListAsDict() utility method would be
stored in a variable for later processing.
We can’t speak for you, but we’re getting to like these utilities. They make WebSphere
administrative scripts easier to write and a lot easier to understand.
What’s next? Let’s take a look at the getJavaHome() method, which seems to be pretty
straightforward. Wait a minute. Why would the serverName and nodeName parameters be
required? Think about it for a moment. In a federated (or cluster) environment, you need to
uniquely identify the server for which you want to obtain the value of JavaHome, which means
that both the server name and the node name need to be specified. So finding out the Java Home
directory for a particular application server is as easy as15
args = ‘[-serverName server1 -nodeName ragibsonNode01]’
print AdminTask.getJavaHome( args )
15
Generally, it is not recommended to hard-code the server and node name in a script. Nor should this be done in two
steps. However, the line to use to build the argument string to this call would be much longer than would fit on a single
line for this book.
And from this, you can see that setting one or more process definitions would be as easy as:
AdminTask.setProcessDefinition( ‘[-interactive]’ )
Of course, this particular call would prompt you for each of the argument values.
The last method in this group is setTraceSpecification() and is one of the most useful
seen so far. It can be used to dynamically change the trace specification for an application server. If
you have ever had to work with IBM WebSphere Application Server technical support to perform
problem determination, it is quite likely that you would have been asked to change the tracing level
for your application servers. Without scripting, this requires you to use the administrative console
to change the tracing and recycle the application server for the modified tracing to take effect.
Unfortunately, this means that when the application server is started, the modified tracing will be
16
Otherwise, the –serverName parameter would be required, and the –nodeName parameter as well, if the
–serverName were not unique within the configuration.
in place, and all of the application server initialization processing will generate significantly more
messages. If the issue being worked is unrelated to the startup of your application server, then this
additional tracing is of no use.
Now, with this method you can use a simple script to dynamically enable or disable the trac-
ing you need at any time! This is wonderful. So what is required to set a new trace string? Nothing
more than this:
traceString = ‘[-traceSpecification com.ibm.*=all]’
AdminTask.setTraceSpecification( traceString )17
This is pretty neat. In fact, we’re sure some people will take a look at this and say something like,
“Why didn’t they tell me that it was this easy to change the tracing dynamically?”
Reference Section
This section provides detailed information about the AdminTask methods that configure servers.
Of the more than 100 methods in this category, detailed information about the methods you will
likely use most often is included. The methods are divided into categories based on AdminTask
groups, and within those categories, the methods are presented in the order in which you might
have to use them. Numerous sources were drawn from for the information presented in this sec-
tion, and we drew on the most recent version of the help that IBM provides within the AdminTask
scripting object itself, as well as details from several sources within the InfoCenter. There are also
some details that folks from the IBM support staff were kind enough to provide, which were sup-
plemented with things we learned from our own experiences.
Finally, the arguments to each method are divided into groups. The first group is the
Required arguments. The second group is arguments that are not required, but you are very likely
to have to use. The third group is made up of arguments that are optional and are seldom used. The
fourth group is arguments that you will have to supply if you are configuring a secure environment.
The general pattern for calling AdminTask methods is as follows:
AdminTask.methodName( target, \
‘[ -argument value -nextArgument value2 ‘ \
+ ‘-stepName [ -arg01 val01 -arg02 val02 ] ‘ \
+ ‘-nextStepName [ -arg03 val03] -yetAnotherStep ]’ )
There might or might not be a target. If there is, it might be a configuration ID or a name. There
might or might not be arguments as well. Arguments are name/value pairs. There might or might
not be steps, and there might be more than one step. Think of steps as arguments that take either a
list of name/value pairs as their value or no argument at all. Bundle all the arguments and all the
steps into one big list and pass it to the method.
17 Again, it is not normally recommended to do this call on multiple lines. However, even a simple trace string makes
this line too long for the width of this page.
createCoreGroup
Creates a core group.
Required argument:
• coreGroupName—The name of the new core group.
createNodeGroup
Creates a node group.
Target (Mandatory):
The name of the new node group.
Optional arguments that you are likely to use:
• description—Any text you might want to add to describe this part of your bus
topology.
Optional arguments that you are less likely to use:
• shortName—Only z/OS uses short names.
addNodeGroupMember
Add a node to the node group.
Target (Mandatory):
The name of the node group.
Required argument:
• nodeName—The name of the node that will join this group.
removeNodeGroupMember
Remove a node group member from the node group.
Target (Mandatory):
The name of the node group.
Required argument:
• nodeName—The name of the node to remove from the group.
removeNodeGroup
Delete a node group. The node group must be empty before it can be deleted.
Target (Mandatory):
The name of the node group.
moveClusterToCoreGroup
Moves all the member servers from one core group to another.
Required arguments:
• source—The name of the core group the server is to be moved from.
• target—The name of the core group the server is to be moved to.
• clusterName—Move all members of this cluster from the source to the target.
Optional argument that you are less likely to use:
• checkConfig—You would only specify this argument on the advice of IBM sup-
port. By default, it is set to true. All member servers of a cluster must belong to the
same core group. By default, this method throws an exception if that rule is violated.
If you set this argument to false, you are disabling that configuration check. You
would only do this if you were trying to fix a corrupted configuration.
moveServerToCoreGroup
Moves the specified server from one core group to another.
Required arguments:
• source—The name of the core group the server is to be moved from.
• target—The name of the core group the server is to be moved to.
• nodeName—The name of the node containing the server.
• serverName—The name of the server to move from the source to the destination.
deleteCoreGroup
Deletes a core group. This method will fail unless you first remove all member servers. If any
member servers belong to a cluster, you must either delete those member servers or move them to
a different core group before calling this method.
Required argument:
• coreGroupName—The name of the core group you wish to delete.
reportConfigInconsistencies
Checks the configuration repository and reports any structural inconsistencies. Writes any inconsis-
tencies to whatever file you specify using the com.ibm.ws.scripting.validationOutput
property in the wsadmin.properties file. This file is found in the properties directory of each
profile.
ReportConfiguredPorts
Lists every port configured for every server in the entire configuration repository in the profile
from which the command executes. This method works even if no servers are started.
Occasionally used optional argument:
• node—Limit the report to a node.
createCluster
Creates a new cluster with no server members, no deployed applications, and no messaging buses.
You can create a cluster of any application servers, a cluster of proxy servers, or a cluster of OnDe-
mand routers. All members of the cluster will be the same server type. The number of steps and the
names of the steps vary depending on the version of WebSphere Application Server and the product
enhancements you have purchased. The additional steps that are available only on WebSphere
Process Server prepare the messaging buses and messaging databases that Process Server requires.
Steps:
• clusterConfig—This step is required.
Required argument:
• clusterName—The name for this cluster.
createClusterMember
Creates a new server and makes it a member of a cluster.
Target:
Configuration ID of the server cluster. You must supply either this or a clusterName
argument (see next item).
Frequently used optional argument:
• clusterName—The name of the server cluster. You must supply either this or a con-
figuration ID target (see target just described).
Steps:
• memberConfig—This step specifies some basic configuration settings for the new
member of the cluster.
Required arguments:
• memberNode—The new server will be a part of this node.
• memberName—The new server will have this name.
Frequently used optional arguments:
• replicatorEntry—Enable this member to use data replication service for HTTP
session persistence.
• memberWeight—Weight value of new cluster member. You would only specify this
value if you know that some of your cluster members will execute on more powerful
hardware than others. In that case, you would assign the members that execute on the
more powerful hardware higher weights and the members that execute on less power-
ful hardware lower weights.
Occasionally used optional arguments:
• genUniquePorts—Generates unique port numbers for HTTP transports defined in
the server. The default value is true. None of the authors can think of a reason why
you would ever set this value to false.
• specificShortName—Specific short name of cluster member for z/OS plat-
forms. This argument is only used by cluster members that execute on z/OS plat-
forms.
• memberUUID—UUID of new cluster member. By default, a unique identifier is auto-
matically assigned to the cluster member that you are creating. You should probably
not use this argument.
deleteClusterMember
Deletes one cluster member from a cluster.
Target:
Configuration ID of the cluster member. You must supply either the configuration ID or
the arguments listed here.
Frequently used optional arguments: (These arguments are only optional if you
choose to supply the configuration ID target just described.)
• clusterName—Name of server cluster that the cluster member to be deleted
belongs to.
• memberNode—Name of node where the cluster member resides.
• memberName—Name of cluster member to be deleted.
Steps:
• replicatorEntry—This step specifies the removal of a replicator entry for this
cluster member.
Frequently used optional arguments:
• deleteEntry—Deletes the replicator entry that has the server name of this cluster
member from the cluster’s replication domain.
• eventServiceConfig—This step specifies the event service configuration when a
member is deleted from the cluster.
• WebsvcsConfigCoreGroup—Frequently used optional argument.
• coregroupName—The name of the core group.
deleteCluster
Deletes the selected cluster and all members of the cluster.
Target:
Configuration ID of the cluster you want to delete. You must supply either this target or
the argument clusterName (see next item).
Frequently used optional argument:
• clusterName—Name of server cluster to delete. You must supply either this argu-
ment or the target configuration ID (see target just described).
Steps:
• replicationDomain—This step specifies the removal of the replication domain
for this cluster.
exportServer
Export the configuration information of a server to a ZIP file.
Required arguments:
• serverName—The name of the server whose configuration will be archived.
• archive—The fully qualified name of the archive file. Given that the archives are
stored in ZIP format, it is a good idea to end the archive file name in .zip. Regard-
less of what the underlying operating system uses for path delimiters in a file name,
you must use forward slashes ( ’/’ ) to separate path names from each other and
from the file name.
Frequently used optional argument:
• nodeName—The name of node that contains the server you want to export. This
argument is optional if the name of the server is unique within the cell. It becomes a
mandatory argument if two or more servers have serverName.
importServer
Import a server configuration from a configuration archive. This command creates a new server
based on the server configuration defined in the archive.
Required arguments:
• archive—The fully qualified name of the zip file that holds archive information for
a server.
• nodeName—This is the name of the node where you want to create a new server
using the archived configuration (the zip file) as a model.
Frequently used optional argument:
• serverName—By default, the server you create will have the same name as the
server in the archive. If you supply a serverName argument, you can have any
name you want.
generateSecConfigReport
Creates a report listing the current setting of dozens of configuration items that are known to have
security implications. The entire configuration repository of the profile in which this command
executes is examined. This method does not take the place of a real security audit done by experi-
enced professionals.
listApplicationPorts
Displays a list of ports that is used to access the specified application, including the name of every
node and server that has any web module from this application mapped to its web container. For
each of those servers, this method displays the named endpoint the host and the port value of each
virtual host mapped to that web container.
Target (Mandatory):
The name of the application. This must be the display name of the enterprise application
as returned by AdminApp.list().
listServerPorts
Target (Mandatory):
The name of the server.
listServer
Returns configuration IDs for one or more servers. Lists servers of specified server type and node
name. If node name is not specified, whole cell is searched. If the server type is not specified
servers of all types are returned. You can use these configuration IDs anywhere you would use a
configuration ID from AdminConfig.getid() or from AdminConfig.list().
Frequently used optional arguments:
• serverType—Any of the types that AdminTask.listServerTypes() returns
are legal values here.
• nodeName—If you supply this optional argument, you limit the search to servers that
are part of the node you specify.
getServerType
Returns the type of the specified server.
Required arguments:
• serverName—The name of the server.
• nodeName—The name of the node that contains this server.
listServerTypes
Lists the available server types. If you call this method without any target, you will get all the
available server types in the entire cell.
Target:
Configuration ID of a node. If you supply this optional target, you will learn what server
types you can create in that particular node. Without a target, you discover what server
types you can create anywhere in the cell.
showServerInfo
Shows some simple information about a given server. Information includes cell name, node
name, server name, server type, and product version.
Target (Mandatory):
Configuration ID of a server.
showServerTypeInfo
Shows some simple information about a server type. Server type must be one of the types
returned by AdminTask.listServerTypes(). Information includes the name of the template
used to create this type of server, the name of the Java class that validates the configuration of this
type of server, and the product version of this type of server.
Target (Mandatory):
The name of a server type.
createApplicationServer
Creates a new application server. The AdminTask methods that create a proxy server, a web
server, and a generic server are similar.
Target (Mandatory):
The name of the node that will contain the new server. Notice that this is a node name
rather than a configuration ID.
Required argument:
• name—The name of the new server. There are restrictions on the characters that you
can use for the name of a server.18
18
See the online information for a list of characters that are not allowed. The page is titled “Object names: What the
name string cannot contain.”
have a unique specific short name. This parameter is optional, and when it is not
specified, a unique specific short name is automatically assigned. The value should
be eight characters or less and all uppercase.
• genericShortName—The server-generic short name is applicable only on z/OS
platforms. This represents the generic short name of the server. All members of a
cluster should share the same generic short name. Individual servers should have
unique generic short name. This parameter is optional, and when it is not specified, a
unique generic short name is automatically assigned. The value should be eight char-
acters or less and all uppercase.
• templateLocation—The location where the template is stored. WAS uses the sys-
tem-defined location if it is not specified. Using the system-defined location is rec-
ommended. It is not suggested that you supply this argument.
• genUniquePorts—Parameter to generate unique http ports for a server. The default
value for this argument is true. The authors cannot think of any reason for setting it
to false.
Steps:
• ConfigCoreGroup—By default, all servers are part of the DefaultCoreGroup
unless you create a different core group and move the server from the
DefaultCoreGroup to the core group you created. In advanced topologies, core
groups are a useful tool for deciding how to deal with things like high request vol-
umes, network congestion, network latency, and server failures.
Frequently used optional arguments:
• coregroupName—The name of the core group that you want this server to belong
to. The core group must exist before you attempt to execute this step.
createApplicationServerTemplate
Creates a new application server template using the specified server as a model. Creating tem-
plates for a proxy server, a generic server, or a web server is similar.
Required arguments:
• templateName—The name that this template will be called.
• serverName—The name of the server that will serve as the model for this template.
• nodeName—The node that contains the server that will serve as the model for this
template.
Frequently used optional argument:
• description—Any text that you choose to describe this part of your configuration.
deleteServer
Deletes any server.
Required arguments:
• serverName—The name of the server you wish to delete.
• nodeName—The node that contains the server you wish to delete.
setJVMProperties
Set multiple JVM configuration values in one method call. All of these properties are vendor-
independent. All Java virtual machines support them.
Frequently used optional arguments:
• serverName—The name of the server whose process definition is modified. If there
is only one server in the entire configuration, then this parameter is optional.
• nodeName—The name of the node. This is only needed for the server scopes that do
not have a unique name across nodes.
• verboseModeGarbageCollection—Specifies whether to use verbose debug out-
put for garbage collection. The default is not to enable verbose garbage collection.
• initialHeapSize—Specifies the initial heap size available to the JVM code in
megabytes.
• maximumHeapSize—Specifies the maximum heap size available to the JVM code
in megabytes.
• genericJvmArguments—Specifies command-line arguments to pass to the Java
virtual machine code that starts the application server process.
Occasionally used optional arguments:
• disableJIT—Specifies whether to disable the just in time (JIT) compiler option of
the JVM code.
• verboseModeClass—Specifies whether to use verbose debug output for class
loading. The default is not to enable verbose class loading.
setJVMSystemProperties
If you need to set some nonstandard JVM property, this is the method that lets you do it.
Required arguments:
• propertyName—The name of the JVM system property.
• propertyValue—The value you want to assign to that property.
Frequently used optional arguments:
• serverName—The name of the Server whose process definition is modified. If there
is only one server in the entire configuration, then this parameter is optional.
• nodeName—The name of the node. This is only needed for the server scopes that do
not have a unique name across nodes.
Occasionally used optional argument:
• processType—The process type of the server. This is for z/OS only.
setProcessDefinition
If you have to integrate a JBoss server (or any other non-IBM product) into your cell, this is the
method you can call to set the commands that start and stop the non-IBM server. You can also use
it to set the working directory of a WAS server to some non-standard directory. All of the argu-
ments are optional because IBM has no way of knowing what attributes you will have to set in
order to integrate that non-IBM server.
createServerType
This method is intended to be used by developers that need to create a new ServerType. In gen-
eral, this would only occur for a product that needs to include and make use of a WebSphere
Application Server environment. So the users of this method are not going to be “normal” admin-
istrators of or application developers for the WebSphere Application Server product.
Required arguments:
• version—Product version.
Summary
This chapter began our exploration of the complex world of the AdminTask scripting object. We
explored a subset of the methods that manage server configuration. In the chapters that follow,
we explore the methods of AdminTask that control security configuration, database configuration,
and messaging configuration.
Scripting and
Security
The AdminApp, AdminConfig, and AdminTask scripting objects are all useful in configuring Web-
Sphere security. In this chapter, we consider the following security items and present examples of
scripted administration of these issues:
• Create / List / Modify / Remove JAAS (J2C) Aliases
• Enable / Disable Administrative Security
• Enable / Disable Application Security
• Map Java EE Roles to Users and/or Groups
• Enable / Disable Java 2 Security
• Configure Additional LDAP Hosts for Failover
• Federated Registries
• Configure Multiple Security Domains
241
IBM WebSphere Application Server V6.1 Security Handbook (SG246316)—a volume equal in
size to this entire book. In this book, we focus on some of what you, the WebSphere Administra-
tor, can do to configure WebSphere security using scripting.
Loosely speaking, security within WebSphere is manifested in several ways, including the
following:
• Authentication: Used to establish an identity
• User Registry, which is used to establish user identity.
• JAAS (J2C) Authentication Data, which is used with Datasources, SIB resources,
and other JCA-managed resources.
• Authorization: Used to establish permissions or rights
• Role-based Authorization, which assigns permissions to an entity to access Java EE
resources such as Web URLs and EJB methods.
• Java 2 Security, which assigns permissions to Java code to access controlled
resources, such as files, sockets, and so on.
We use AdminApp, AdminConfig, and AdminTask as appropriate to manipulate these security
aspects. By now we assume that you are familiar with AdminConfig.save() and
AdminConfig.reset() and know when to use each, so we will leave them out of our examples.
Listing 12.1 shows a simple method for creating a JAASAuthData object. As a reminder,
the ’\’ character at the end of a line is the standard “continuation character” and is used when
text that should logically be treated as one line does not fit on one line. Remember that
AdminConfig.create() can take a list of lists specifying the creation parameters for the item
being constructed. The parameter list is constructed by listing all of the possible parameters in the
form of nested [key, value]-pairs, and then using a list comprehension to eliminate any for
which the value is None. There are other means by which to construct variable parameter lists,
but you may find this one more concise and clear once you understand the idiom.
In Listing 12.1, this crucial configuration object was created using AdminConfig. But as dis-
cussed in the previous chapter, you are urged to use AdminTask instead of the more primitive
administrative objects whenever you can. If nothing else, with AdminConfig, you need to know
the internal name for what you want to create and have no interactive help in creating it. With
AdminTask, you just need to know what values you want and can have interactive help in building
the command.
WebSphere V7 introduced a new AdminTask command, createAuthDataEntry, for per-
forming the same task just completed using AdminConfig. The parameters for it are the same as for
AdminConfig: an alias, a description, a password, and a user. There is also an optional security
domain name for working with the new security domains feature of WebSphere 7.
Listing 12.2 presents a simple method of invoking createAuthDataEntry. Again, you
make use of a list comprehension to construct a list of lists containing the parameters. However,
this time, you need a flat list for AdminTask. The denest utility method, which is on the FTP
site, takes a list of lists and returns a de-nested list, e.g., converting [[“key1”, “value1”],
[“key2”, “value2”]] to [“key1”, “value1”, “key2”, “value2”]. This provides the
necessary parameter for createAuthDataEntry. Note that although you have to provide the
parameters for the actual configuration item (see Listing 12.1 for a full set), you no longer need to
know details about its parent or its internal type.
1
This is the one time that we will show you the full options list if it extends over a line of text, because we want you to
understand the Python idiom being used. In other cases, if the code does not fit, we’ll elide it, which means using
“...” in place of the full text. See the companion web site for full listings.
So let’s go ahead and use these methods in a wsadmin session connected to a WebSphere
V7 deployment manager. Listing 12.3 shows a wsadmin session loading the code using
execfile and then executing the methods to test them.
(q.v., AdminControl.getNode()). You will not find this in the AdminTask documentation; it
just does it, leading to problems when trying to manipulate JAAS Aliases via scripting. For exam-
ple, in the JAASAliases.py file, you will find code for finding an authentication entry by its
alias name, which can be used to view it, as shown in Listing 12.5.
Notice that the second call failed because yourAlias does not exist, even though that was
the name used when it was created.
It would be a bad idea to modify the code for locating an entry by alias to strip off the prefix
because there is no guarantee that the un-prefixed aliases are unique. It would be potentially dev-
astating to change (or delete, as in section 12.2.4) the wrong authentication entry. If you consider
using AdminControl.getNode() + “/” + alias”, keep in mind that if the entry were cre-
ated in a pre-federated node, you would have an unresolvable mismatch post-federation, due to
the runtime value of AdminControl.getNode(). AdminConfig does not implicitly prefix,
which is why you might prefer to use it, even with WebSphere V7, until this naming issue is
resolved. This way, you can maintain control over the exact alias name used.
Once again, you use the list comprehension idiom to populate the necessary list regardless
of which set of attributes you wish to modify; any for which the value is None will be left out of
the list and thus unmodified. You could use changeJAASAlias or one of the several convenience
methods, such as changeJAASPassword—all of these are in JAASAliases.py.
Listing 12.7 shows a wsadmin session, where you can view the contents of a JAAS alias,
modify it, and view the modified result.
But what about the prefixing issue? Let’s take a look at some examples. First, looking at the
short example in Listing 12.11, notice that AdminTask.deleteAuthDataEntry deleted the
JAAS Alias regardless of whether or not there was a prefix. This is not necessarily a good thing,
as you can see from the longer example in Listing 12.12.
Whoa! What just happened?! Listing 12.12 started with two aliases, in order:
was7host01CellManager01/myAlias and myAlias. We deleted myAlias and found that
the first one, with the prefix, was deleted. We then recreated it, which put the prefixed entry after
the non-prefixed entry and did the delete again. This time the non-prefixed entry was removed. In
both cases, AdminTask.deleteAuthDataEntry() deleted the first JAASAuthData item
whose alias matched after stripping off the prefix, if any. According to Murphy’s Law, the
JAASAuthData item removed would have been the one you can least afford to lose and would
have been crucial to the runtime behavior of your enterprise. And Murphy was an optimist.
Perhaps for now we can agree that it might be a best practice to stick with AdminConfig for
working with JAASAuthData items until this naming issue can be resolved and documented.
This example presumes that your registry is properly configured, which you can assume at this
point. Now you can turn on application security, which requires knowledge of the proper attribute
of the Security object. Listing 12.13 illustrates testing, setting, and verifying the setting.
wsadmin>securityConfigID = AdminConfig.getid(“/Security:/”)
wsadmin>AdminConfig.modify(securityConfigID,[[‘appEnabled’,’true’]])
‘’
wsadmin>print AdminTask.isAppSecurityEnabled()
true
Don’t forget that in order for these settings to take effect, you must save them, synchronize,
and restart the cell. After you’ve enabled application security, you can move on to mapping users
and/or groups to the security roles defined by each application.
As an aside, we find that Administrators working with WebSphere security for the first time
often need to disable Administrative security because they have locked themselves out for one
reason or another. Should this happen to you, use what is possibly the world’s most common
single-line wsadmin command:
$ wsadmin -conntype NONE -c “securityoff”
Yes, it does exactly what you think it does. If the user executing that command has file system
write access to the profile’s config/directory, security will be turned off.
So what you want to do consistently is map users to groups in the user registries and then map
groups to roles within WebSphere. For now, having expressed that best practice, let’s focus on the
mechanics of performing the mappings via scripting. You have the choice of following that prac-
tice or not.
The actual mapping of roles to users and/or groups is provided by the MapRolesToUsers
task of AdminApp, which is available in three contexts: installing, editing, and updating applica-
tions. The content of the MapRolesToUsers is the same for all three, so we’re going to just work
with AdminApp.edit() in this chapter. You can take the same nested list structure and add it as
an option when installing or updating an application.
In MapRoles.py, you find convenience methods for displaying the roles of a single application
or all the applications in your installation.
This is pretty easy, just a list consisting of the task name and a parameter. The roleMappings
item itself is just a list of lists. Each inner list consists of the following five String entries, in
order, and each must be present:
1. Role Name
2. Everyone? (“yes” | “no”)
3. All Authenticated? (“yes” | “no”)
# Give every (and only) authenticated user the Admin role on MyApp
mapOneRoleToUsersOrGroups(“MyApp”, “Admin”, allAuth=”yes”)
Remember that these Java EE roles are not global to WebSphere. Each application has its
own roles and mappings, even if the role names are the same across multiple applications. So
someone might be an Admin for MyApp but not an Admin for YourApp.
unknown provenance that have been automatically downloaded from repositories, for example, by
Maven?
If you are running without Java 2 security enabled, you are permitting whatever code is
installed in your JVM to do whatever it wants. And once you have enabled Java 2 security, some-
one should review the security policy for each and every installed application to ensure that rogue
permissions are not present.
Sound paranoid? Well, this is a chapter about security, and paranoia is a positive, adaptive
trait in a security person. It is not a question of whether or not there are people who want what
you have; it is simply a question of stopping them.
From a scripting perspective, however, there is relatively little for us to do with Java 2
security. Basically, it is a matter of enabling or disabling it and perhaps manipulating the
was.policy file.
The steps to enable or disable Java 2 security are quite straightforward and can be per-
formed with either AdminConfig or AdminTask. To enable Java 2 security, enter the following:
wsadmin> param = ‘-enforceJava2Security true’
wsadmin> AdminTask.setAdminActiveSecuritySettings(param)
The steps to manipulate the was.policy file are to extract it to a known location, modify it, and
then update the file. The AdminConfig object provides the necessary means for “extracting” and
“checking in” the file, as is shown later in the chapter. What you do for manipulating it is up to
you. The fact that you can do this on the fly, rather than via an application update, is arguably of
questionable value, but you might have some emergent need.
With both AdminConfig.extract() and AdminConfig.checkin(), you need the
path to the file in the application. The format of this is as follows:
cell/cellname/applications/app_ear/deployments/app_name/META-
INF/was.policy
An example of using this with the default application is shown in Listing 12.16.
wsadmin> p += “DefaultApplication/META-INF/was.policy”
wsadmin> digest = AdminConfig.extract(p, “/tmp/was.policy”)
... at this point in time, make some change to the file and then ...
wsadmin> AdminConfig.checkin(p, “/tmp/was.policy”, digest)
You can extract the was.policy file to /tmp/was.policy, make some changes (in this
case, just adding a comment to indicate that it has been approved), and replace it. Then you
simply need to restart the application for the new Java 2 security policy to take effect. The digest
is simply a token provided when you extract the file that you must provide back when replacing
the file.
LDAP Failover
If you have configured WebSphere to use LDAP for authentication, you might have asked what
would happen if that were to fail. The answer, of course, is that if the repository is not available, it
cannot authenticate. In case you are wondering—no, a federated registry is not a solution to this
problem.
If anything, a federated registry actually makes the situation more precarious. Consider the
following scenario: In a federated registry, you have an LDAP managed by Human Resources for
employees, another LDAP managed by the Business Partner Liaison office for Business Partners,
and a third LDAP for web customers. Remember that WebSphere enforces unique user identity
across the entire federated space, therefore if any one of those LDAP registries is not available,
WebSphere will not permit login from the others because it cannot ensure that even though an ID
is found in the one registry, that the same ID does not exist in one that failed.
The solution to the problem of LDAP availability is to establish a cluster of (usually repli-
cated) LDAP servers whenever you use LDAP. But having done that, how do you tell WebSphere
to use it? That depends on whether you are working with a standalone LDAP repository or a fed-
erated registry.
For a federated registry, the WebSphere V7 Integrated Solutions Console allows you to add
multiple servers to an LDAP repository, as does the AdminTask.addIdMgrLDAPServer()
scripting command. More on that in the next section. For the remainder of this section, we dis-
cuss the standalone LDAP repository case.
The WebSphere Integrated Solutions Console allows you to enter a single LDAP host in the
form of a host address and port. You could add a load balancer in front of the LDAP cluster, at the
expense of additional hardware, complexity, and network latency—or, if all you need is failover
support, you could simply tell WebSphere about the additional LDAP servers.
Scripting allows you to add as many LDAP hosts as you want, and there is even an exam-
ple in the InfoCenter that makes it all seem rather straightforward. But as simple as it seems on
the surface, you are going to find out that things are not quite so simple when working with the
hosts attribute of LDAPUserRegistry. And because this is hardly the only place where this
lack of simplicity can raise its head, we might as well examine the issues. For example, the
InfoCenter shows that you modify the hosts attribute with a list of lists that you can describe
as follows:
[[[“host” <ip>][“port” <port>]]+]
But let’s start by seeing what there is before making any changes:
wsadmin>AdminConfig.showAttribute(myLDAP, “hosts”)
‘[(cells/was7host01Cell01|security.xml#EndPoint_1)]’
Hello! That doesn’t look like a list of lists containing [[“host” <ip>][“port” <port>]]
pairs. And even though that appears to be a list of something, it is actually a string. Converting the
full range of JACL-formatted strings that smell like a list (which is what wsadmin too often pro-
vides, even though JACL has been deprecated) can be quite a chore, but in this particular case, it
will turn out to be fairly straightforward. You can convert from this string to a list of configuration
ids by the simple expedient of:
hosts=AdminConfig.showAttribute(myLDAP, “hosts”)[1:-1].split(‘ ‘)
Now that you have it, what exactly is it? You can discover that in two ways—first by looking at the
attributes of LDAPUserRegistry and second by looking at what type is associated with the con-
figuration id that was just isolated. Those are checked in Listing 12.17, and you can see what
attributes that particular type has.
As shown in Listing 12.17, the hosts attribute is (logically) a list of configuration ids, each
of which is an EndPoint, each of which has a host and port attribute. Showing the EndPoint
gives us a string, not an interesting data structure to work with. So although adding LDAP servers
is a simple matter of properly formatting a list of lists, doing anything else with them would be a
bit more work. We’re going to show you how to add, set, remove and view the hosts. All of the
code is in the LDAP.py file available from the companion website.
def p(e):
return int(AdminConfig.showAttribute(endpoint, “port”))
def showLDAPHosts(id):
“For an LDAP registry, show all the hosts”
First there’s that long string containing configuration ids. We removed the surrounding
brackets and made a list from it, splitting at the spaces. That provided a list of configuration ids
for EndPoint objects. And then the fun began. If you haven’t yet realized the power of Python
list comprehensions, you should start to do so now. In one concise statement that clearly illus-
trated the desired format, a list comprehension was used to iterate over the list of Endpoint config-
uration ids and produce the desired list of [[“host” <ip>][“port” <port>]] nested lists.
This problem of having to convert from a string formatted data structure that was originally
designed to work with the TCL language to a format you can conveniently use with Python is so
common in WebSphere scripting that such examples are important to understand and study. And
the difference between having this code and not?
wsadmin>AdminConfig.showAttribute(myLDAP, “hosts”)
‘[(cells/was7host01Cell01|security.xml#EndPoint_1)]’
wsadmin>showLDAPHosts(myLDAP)
[[[‘host’, ‘’], [‘port’, 389]]]
This will become useful as you start to manipulate the list of LDAP hosts.
p = [[“hosts”, []]]
p[0][1].extend([[[“host”,h[0]],[“port”,h[1]]] for h in hosts])
AdminConfig.modify(ldapID, p)
The addLDAPHosts method in Listing 12.19 expects us to pass a nested list of ip-address and
port pairs, and modifies the hosts attribute. But please note that although it uses
AdminConfig.modify, it is called add, a point that is illustrated in Listing 12.20.
Remember that when using AdminConfig.modify() to modify something that is a list, the
effect is to append the items to the existing list. The single existing entry on the original list consisted
of an empty host address and the standard LDAP port 389. That single existing entry is the default
value for the hosts attribute of a LDAPUserRegistry object. You can see how to view the actual
host information, rather than the configuration ids for the EndPoint objects.
implementation very simple. Recall that addLDAPHosts() prepares the necessary parameter and
calls AdminConfig.modify() to modify the list, setLDAPHosts() just calls addLDAPHosts()
twice: once with an empty list to clear the value and the other with the desired replace-
ment list.
The fact that calling something called add with an empty list actually deletes the entire
value is certainly a semantically odd side-effect, so if it offends you, you would want to check
that the list is not empty and report an error if an empty list is passed. This would apply not only
to this code, but to any code of your own authorship that similarly modifies a list attribute.
First you get the list of EndPoint configuration ids, just as you’ve done before. Then for
each EndPoint configuration object, you get its host and port values, converting the latter to an
integer. Finally, you loop through the same sort of nested list of hosts that you’ve been using as a
parameter in this section, and if you find a match against an EndPoint, you remove that
EndPoint. And since you have found that host, you can break out of the inner loop and immedi-
ately proceed to compare other EndPoint objects.
This concludes our look at working with multiple LDAP hosts for failover. In addition to
being a practical topic, this example also explores various issues that often come up when work-
ing with a WebSphere configuration, such as:
• What happens when you modify a list?
• How do you handle asymmetric write and read operations (referring to the situation
when you provide data in one form to modify a value, and WebSphere creates and uses a
different type of configuration object instead of the form you provide)? In this case, a
nested list of host values was provided, and thereafter you would need to work with
EndPoint objects created from that data by WebSphere.
Having done that, you can modify the security domain. But there are some nuances here. What the
documentation does not tell you is that when you create a security domain, the code creates a
Security Domain object but returns the configuration id for an AppSecurity configuration object
that was also created for the new security domain.2 So at the time you create a new security domain,
you can use AdminConfig to manipulate the associated AppSecurity object. To do this easily is
essentially a one-time opportunity. After this, if you want to modify the security domain, you
would use AdminTask to do so by name. Listing 12.23 illustrates this point and the equivalence.
2
In WebSphere 7.0.0.0, all of the methods for creating and copying security domains have an apparent defect. They
return the configuration id without the necessary () characters around it—you have to add them in order to use the
configuration id.
How do you add applications or other resources to a security domain? Well, it does not
work quite that way. You can assign the cell to the security domain, but more likely you will
assign a cluster, server, or bus to the security domain.
In Listing 12.24, we have mapped a cluster, and therefore all of the applications in that
cluster, to a new Java 2 security-enabled clone of global security. We also mapped a bus. If you
want to remove a resource from the security domain, it is just as simple, but you invoke
AdminTask.removeResourceFromSecurityDomain instead:
AdminTask.removeResourceFromSecurityDomain(domain + resource)
Listing 12.25 shows you how you can discover which domain is responsible for a resource or
which resources are in a given domain.
r = [“-resourceName”, “Cell=:ServerCluster=TradeCluster”]
print AdminTask.getSecurityDomainForResource(r)
r = [“-resourceName”, “Cell=:SIBus=msgBus”]
print AdminTask.getSecurityDomainForResource(r)
Bus Security
In Chapter 14, “Messaging,” you go through the detailed steps3 to secure a messaging bus. Here is
an overview of these steps:
• Enable administrative security for the cell.
• Enable security for the bus.
• Create (or use an existing) authentication alias to use between messaging engines.
• Create (or use an existing) secure transport chain to use between messaging engines.
• Disable (or delete) insecure messaging transport chains.
• Remove default authorization policies.
• Secure the Distribution and Consistency Service (DCS).
• Secure each messaging engine on the messaging bus.
• Secure any data stores used by the members of the messaging bus.
• Create (or use an existing) authentication alias for transaction recovery.
• Create (or use an existing) authentication alias for mediation.
Datasources
A Datasource will generally need to be configured with one or more of the JAAS aliases created
earlier in this chapter. This is detailed in Chapter 13, “Databases and Authorization.”4 The JCA
manager, or more specifically the underlying Relational Resource Adapter, uses that credential
3
See the topic, “Enabling Bus Security” in Chapter 14 for extensive details.
4
See the discussion of AdminTask.createDataSource() in the reference section of Chapter 13. In particular,
take note of two arguments—the xaRecoveryAuthAlias and the componentManagedAuthentication
Alias.
when interacting with the database server (see Chapter 17 of the IBM WebSphere Application
Server V6.1 Security Handbook).
Web Services
Web services can be secured in multiple ways, some of which are covered in Chapter 15,
“Administering Web Services.”
There might or might not be a target. If there is, it might be a configuration ID or it might be a
name. Targets are usually containment parents. There might or might not be arguments. Argu-
ments are almost always names followed by values. There might or might not be steps. Think of
steps as arguments that require either a list of names followed by values or nothing at all. Bundle
all the arguments and steps into one big list and pass it to the method as shown previously and in
the code samples in this book.
SecurityConfigurationCommands Group
Methods in this command group create, delete, display, and modify many aspects of administra-
tive security. This command group is new with version 7. In many ways, the methods in this
group simplify security configuration. Prior to this version, you must navigate your own way
through WebSphere Application Server’s configuration tree and use the equivalent AdminConfig
commands.
createAuthDataEntry
The createAuthDataEntry command creates an authentication data entry for a J2EE Connec-
tor architecture (J2C) connector. The AuthDataEntry that you create can either be part of the
global security or it can be part of a security domain. Although at a later time you can copy this
authentication data entry from global security to a security domain, it cannot be created in both.
Which of these two behaviors it exhibits depends on whether you choose to pass a
securityDomainName.
Required argument:
• alias—The alias of the authentication data. Think of this alias as the key that Web-
Sphere uses to find the user name and password. This eliminates the need to have
user names and passwords hard-coded into application code or files.
• user—The user name part of the authentication data.
• password—The password part of the authentication data.
deleteAuthDataEntry
Delete an authentication data entry in the administrative security configuration or in a security
domain.
Required argument:
alias—The alias of the auth data.
Frequently used optional argument:
securityDomainName—This argument is only optional if this authentication entry is
part of the global domain rather than a security domain. It is mandatory if the
AuthDataEntry is part of a security domain.
listAuthDataEntries
List authentication data entries in the administrative security configuration or a in a security domain.
getActiveSecuritySettings
This command returns the active security settings for the security domain of interest or the global
security configuration, which includes the following settings:
enableGlobalSecurity (global security only)
adminPreferredAuthMech (global security only)
activeAuthMechanism (global security only)
dynUpdateSSLConfig (global security only)
cacheTimeout
issuePermissionWarning
activeAuthMechanism
enforceJava2Security
appSecurityEnabled
activeUserRegistry
enforceFineGrainedJCASecurity
useDomainQualifiedUserNames
customProperties
Frequently used optional argument:
securityDomainName—This argument is optional, but it is really a switch. If you omit
this argument, you get all the settings from global security. If you pass the name of a
security domain, you get the settings from that domain.
setAdminActiveSecuritySettings
Sets the security attributes on the global security configuration. Starting in version 6, global secu-
rity is called administrative security. This method does not return anything.
Frequently used optional arguments:
• enableGlobalSecurity—Specifies whether to enable global security. Specify
true to enable global security or specify false to disable global security. (Boolean)
• cacheTimeout—Specifies the amount of time, in seconds, before authentication
data becomes invalid. (Integer)
setAppActiveSecuritySetting
Sets the active security settings on a security domain. This method does not return anything.
Required argument:
securityDomainName—Name used to uniquely identify the security domain.
Frequently used optional arguments:
• cacheTimeout—Specifies the amount of time in seconds before authentication data
becomes invalid. (Integer)
unsetAppActiveSecuritySettings
Removes the specified attribute from the security setting.
Required argument:
securityDomainName—Name used to uniquely identify the security domain.
Frequently used optional arguments:
• unsetCacheTimeout—Specifies the amount of time in seconds before authentica-
tion data becomes invalid. (Integer)
• unsetIssuePermissionWarning—Specifies whether to issue a warning during
application installation if the application requires security permissions. Specify true
to enable the warning notification or specify false to disable the warning notifica-
tion. (Boolean)
• unsetEnforceFineGrainedJCASecurity—Specifies whether to enable Java
Platform, Enterprise Edition (Java EE) security. Specify true to enable Java EE
security permissions checking or specify false to disable Java EE security.
(Boolean)
getSingleSignon
Returns information about the single signon settings for global security. This method takes no
arguments.
configureSingleSignon
Configures single signon.
Frequently used optional arguments:
• enable—Set to enable or disable single signon.
• requiresSSL—Set if SSL is required.
• interoperable—Set the single signon interoperability mode.
• attributePropagation—Configures single signon attribute propagation.
• domainName—Configures the domain for single signon.
getUserRegistryInfo
Returns information about a user registry from the administrative security configuration or an
application security domain.
Frequently used optional arguments:
• securityDomainName—Think of this argument as a switch. If you supply the name
of a security domain, you get information about the user registry for that security
domain. Otherwise, you get information about the user registry for global security.
• userRegistryType—The type of the user registry values include
LDAPUserRegistry, WIMUserRegistry, CustomUserRegistry, and
LocalOSUserRegistry.
listInterceptors
List interceptors from the global security configuration or from a security domain.
Frequently used optional argument:
securityDomainName—Think of this argument as a switch. If you supply the name of
a security domain, you get information about the user registry for it. Otherwise, you get
information about the user registry for global security.
SecurityDomainCommands Group
Prior to WebSphere Application Server version 7, security domains did not exist. Therefore, this
command group is new in version 7. Methods in this group give you the ability to create, delete,
display, and modify security domains. These methods give you the ability to add and remove
resources from a given security domain.
createSecurityDomain
Create an empty security domain from scratch.5
Required argument:
securityDomainName
Frequently used optional argument:
securityDomainDescription—Text to describe the purpose of this security domain
in your topology.
copySecurityDomainFromGlobalSecurity
Creates a security domain by copying the global administrative security configuration.6
Required argument:
securityDomainName
Frequently used optional argument:
• securityDomainDescription—Text to describe the purpose of this security
domain in your topology.
• realmName—If an active user registry is defined then a new realm name must be
used in the new security domain.
5
This is the first of three ways to create a security domain.
6
This is the second of three ways to create a security domain.
copySecurityDomain
Creates a security domain by copying some other security domain’s configuration.7
Required argument:
securityDomainName
Frequently used optional argument:
• securityDomainDescription—Text to describe the purpose of this security
domain in your topology.
• realmName—If an active user registry is defined, then a new realm name must be
used in the new security domain.
deleteSecurityDomain
Deletes a security domain.
Required argument:
securityDomainName—Name used to uniquely identify the security domain.
Frequently used optional argument:
• force—When force is set to true, the security domain is deleted without checking if
any resources exist in the domain. This option can be used when the resources in the
security domains are not valid resources.
listSecurityDomains
Returns the names and possibly the descriptions of security domains.
Frequently used optional arguments:
• listDescription—Specify true to include the description of each security
domain in the list returned and false to just return the names of the security
domains.
• doNotDisplaySpecialDomains—Specify true to not include the special
domains in the list of security domains returned and false to display the special
domains.
7
This is the third of three ways to create a security domain.
SecurityRealmInfoCommands
Prior to WebSphere Application Server version 7, security domains did not exist. Therefore, this
command group is new in version 7. Methods in this group give you the ability to add, remove,
and display registry groups and trusted realms.
listRegistryUsers
Returns a list of users in a security realm, security domain, or resource. All the arguments are
optional. If you do not pass any arguments, you get all the users in the global security. You have
the choice of seeing the users with or without their access IDs.
Frequently used optional arguments:
• displayAccessIds—Specify true to return the list of user IDs and access IDs
and false just to return a list of user IDs.
• resourceName—Specifies the name of the resource for which a user list will be
returned.
• securityDomainName—Specifies the name of the security domain for which a
user list will be returned.
• securityRealmName—Specifies the name of the security realm for which a user
list will be returned.
• numberOfUsers—Specifies the maximum number of users to return.
• userFilter—Specifies a filter to be used to get the list of users.
listRegistryGroups
Returns a list of groups in a security realm, security domain, or resource. All the arguments are
optional. If you do not pass any arguments, you get all the groups in the global security. You have
the choice of seeing the groups with or without their access IDs.
Frequently used optional arguments:
• displayAccessIds—Specify true to return the list of group IDs and access IDs,
and false just to return a list of group IDs.
• resourceName—Specifies the name of the resource for which a group list will be
returned.
• securityDomainName—Specifies the name of the security domain for which a
group list will be returned.
• securityRealmName—Specifies the name of the security realm for which a group
list will be returned.
• numberOfGroups—Specifies the maximum number of groups to return.
• groupFilter—Specify a filter to be used to get the list of groups.
listSecurityRealms
List all security realms in the configuration from global security and the security domains.
Requires no parameters.
WIMManagementCommands
This group of methods manipulate WebSphere Application Server’s virtual member manager and
the default user repository that sits behind it. These methods exist in both version 6 and version 7
of WebSphere Application Server.
createUser
Creates a PersonAccount in the default realm.
Required arguments:
• cn—The common name of the entity.
• password—The password of the user.
• sn—The surname of the entity.
• uid—The UID of the PersonAccount.
Occasionally used optional arguments:
• confirmPassword—Used to guarantee and confirm that the confirmPassword is
the same as the password.
• parent—The parent of the entity.
createGroup
Creates a group in the default realm.
Required argument:
cn—The common name of the entity.
Frequently used optional arguments:
• description—A description of a group.
• memberUniqueName—The uniqueName of the member to add or remove.
Occasionally used optional argument:
parent—The parent of the entity.
deleteUser
Deletes a PersonAccount from the default realm.
Required argument:
uniqueName—The name that uniquely identifies an object of a virtual member man-
ager entity.
deleteGroup
Deletes a group from the default realm.
Required argument:
uniqueName—The name that uniquely identifies an object of a virtual member man-
ager entity.
duplicateMembershipOfUser
Makes a user a member of the same groups as another user.
Required arguments:
• copyFromUniqueName—The uniqueName of the virtual member manager entity
from which the membership is copied.
• copyToUniqueName—The uniqueName of the virtual member manager entity to
add to the same groups as the specified copyFromUniqueName entity.
duplicateMembershipOfGroup
Makes a group a member of the same groups as another group.
Required arguments:
• copyFromUniqueName—The uniqueName of the virtual member manager entity
from which the membership is copied.
• copyToUniqueName—The uniqueName of the virtual member manager entity to
add to the same groups as the specified copyFromUniqueName entity.
WizardCommands
These methods report or modify the same security properties as the admin console security wiz-
ard. The methods in this command group are present in both WebSphere Application Server ver-
sion 6 and version 7.
isGlobalSecurityEnabled
Returns either true or false depending on whether the administrative security setting is cur-
rently enabled. Requires no parameters.
setGlobalSecurity
Turns administrative security on or off.
Required argument:
enabled—If this argument is true, turn administrative security on. If this argument is
false, turn administrative security off.
isAppSecurityEnabled
Returns the current application security setting of true or false. Requires no parameters.
JACCUtilityCommands
isJACCEnabled
Returns either true or false depending on whether the Java Authorization Contract for Con-
tainers is enabled. Requires no parameters.
isSingleSecurityDomain
Checks if the current runtime is a single security domain. Returns true or false. Requires no
parameters.
IdMgrRepositoryConfig
addIdMgrLDAPServer
Adds an LDAP server to the LDAP repository configuration.
Required arguments:
• host—The host name for the LDAP server.
• id—The unique identifier of the repository.
Frequently used optional arguments:
• authentication—The authentication method to use.
• bindDN—The binding distinguished name for the LDAP server.
• bindPassword—The LDAP server binding password.
• certificateFilter—If you specify the certificate map mode, use this property to
specify the LDAP filter, which maps attributes in the client certificate to entries in
LDAP.
• certificateMapMode—Specifies whether to map X.509 certificates into an LDAP
directory by exact distinguished name or certificate filter. Specify the certificate filter
to use the specified certificate filter for the mapping.
• connectTimeout—Connection timeout (in seconds).
Databases and
Authorization
The AdminTask scripting object has several groups of methods that directly or indirectly support
data access. In this chapter, we explore the methods from the JDBCProviderManagement and
VariableConfiguration groups.
We use a subset of the commands in these groups to present an example that is not well-
documented elsewhere. Afterward, we list the other commands in these groups, along with a brief
explanation of each.
Database Basics
Any serious enterprise application requires interaction with a database. Given that WebSphere
Application Server is really a network of centrally managed servers, this presents a few interest-
ing issues:
• How do you connect to the database in the first place?
• How do you pool connections to the database for efficiency and performance?
• How do you effectively manage what could be a complex configuration?
The database vendor, or some third-party vendor, supplies a jar file that contains a database
driver, and that database driver allows database connections to the defined. Application modules
deployed to the containers of an application server use that connection to query the database, get
result sets from those queries, and update tables in the database. We, as systems administrators,
create pools of database connections that applications ultimately use. We decide how big those
pools are and how big they will get, and we configure security credentials that allow applications
to access the database.
277
Terminology
DataSource—Creates a pool of database connections and shares that pool among applica-
tions on the same server.
J2C Authentication Alias—A flexible data structure that holds a user ID, password, and
possibly other data as well. All of this is accessible using an alias. The purpose of this data structure
is to enable access to Enterprise Information Systems of all kinds.
JDBC™ Provider—Supplies the actual code that establishes communications between an
application and a database.
A Simple Example
An example script file, named database.py, is available from the book website and contains the
functions shown in this chapter that can be used to create some basic but useful plumbing to support
database connections. If you want to use this script, there are some things you will have to change:
• You will have to change the example node name to a node name that exists in your cell.
• You will have to change the example server name to the name of a server that exists
within that node in your cell.
• If your cell already has any of the JNDI names that we use in the sample script, you will
have to edit these names so that they do not conflict with your existing JNDI names.
• You may have to make some other changes depending on the specifics of the database
you want to use.
You will need some variables for this simple example and will use them throughout it. If your data-
base requires any kind of security credentials, you will need to create a JAAS Authentication Alias.1
uid = “KevinsDataSource-User”
pwd = “SuperTopSecret”
desc = “This is an example of a JAAS Authentication Alias”
DataBaseAccessAlias = “Boss/KevinsDatabaseCredentials”
Notice that the name of the alias is prefixed with the name of one of the nodes, specifically the
Deployment Manager’s node’s name. The reason for this has to do with the way the AdminTask
SecurityConfiguration command group creates and deletes JAAS Authentication Aliases.2
secMgrID = AdminConfig.list( ‘Security’ )
This line of script is used to obtain the configuration ID of WebSphere Application Server’s
security manager. You see sample code like this on many official IBM websites. This code
assumes that there is exactly one Security object in your cell.3 There is more than one way to
1
We cover JAAS Authentication Alias extensively in Chapter 12, “Scripting and Security.”
2
See the discussion about creating a JAAS alias in Chapter 12.
3
That assumption might not always be true. For a discussion of more advanced security configurations, see the “Mul-
tiple Security Domains” section in Chapter 12.
create a JAAS Authentication Alias. This is simply one way. Other choices are discussed in
Chapter 12, “Scripting and Security.”4
jaasID = AdminConfig.create( ‘JAASAuthData’, secMgrID, \
[ [‘alias’, DataBaseAccessAlias], \
[‘description’, desc], \
[‘userId’, uid], \
[‘password’,pwd] ] )
The first piece of real database-related work is creating a JDBCProvider. The JDBCProvider
supplies the database driver class that actually talks to the database. The two things you
absolutely must provide to create a JDBCProvider are the name of a JDBCProvider and the
name of the driver class. Although that satisfies the bare bones minimum application server con-
figuration syntax, it is not enough information to do useful work with a database.
The AdminTask scripting object has a method called createJDBCProvider that pro-
vides a useful configuration environment for a supported database driver. This method requires
more information than the bare bones minimum for a JDBCProvider,5 but it produces a configu-
ration that does useful work. In the next example, we supply some optional arguments in addition
to the required arguments:
p = AdminTask.createJDBCProvider(‘[-scope Node=Node01 ‘ \
+ ‘-databaseType DB2 -providerType “DB2 Using IBM JCC Driver” ‘\
+ ‘-implementationType “XA data source” ‘ \
+ ‘-name KevinsBrandNewProvider ‘ \
+ ‘-description “This is a fairly simple thing to create” ]’)
This JDBCProvider is created at the node scope.6 Once the database type, the provider type, and
the implementation type are specified, if you also specify one of the supported databases,
AdminTask.createJDBCProvider() uses the default JDBCProvider template for that data-
base to fill in some default information about your database driver. The description you specify
will appear in the Administrative Console.
There are two possible choices for implementationType: “XA data source” and “Con-
nection pool data source”. You must specify one of these case sensitive strings.7 The first string
specifies a driver class that gives your JDBCProvider the ability to perform a two-phase
4
See the discussion about creating a JAAS alias in Chapter 12.
5
For a complete list of the attributes of JDBCProvider, type print AdminConfig.attributes
(‘JDBCProvider’).
6
See the reference section at the end of this chapter. Our discussion of the scope parameter of
AdminTask.createJDBCProvider() has examples of how to specify each scope.
7
See the reference section at the end of this chapter for a more complete discussion of the arguments for
AdminTask.createJDBCProvider().
commit. This allows your driver class to participate in transactions that span multiple databases.
The second string specifies a driver class that lacks this ability. Both strings result in a
JDBCProvider that can support pools of connections.
Once you have a JDBCProvider, you can create a DataSource, which manages a pool of
connections to a database. The DataSource created here is as follows:
d = AdminTask.createDataSource( p, \
‘[-name KevinsDataSource -jndiName jdbc/kevinsData ‘ \
+ ‘-description “This DataSource pools connections” ‘ \
+ ‘-category “classroom exercise” ‘ \
+ ‘-dataStoreHelperClassName ‘ \
+ ‘ com.ibm.websphere.rsadapter.DB2UniversalDataStoreHelper ‘ \
+ ‘-componentManagedAuthenticationAlias ‘
+ DataBaseAccessAlias \
+ ‘ -xaRecoveryAuthAlias ‘ + DataBaseAccessAlias \
+ ‘ -configureResourceProperties [ ‘ \
+ ‘[databaseName java.lang.String KevinsToyClassroomDatabase] ‘ \
+ ‘[serverName java.lang.String host01.ibm.com] ‘ \
+ ‘ ] ‘ \
+ ‘]’ )
The name, description, and category of the DataSource are purely descriptive. You can specify
any value you’d like for them. They are there for your benefit and for your documentation. The
componentManagedAuthenticationAlias8 and the xaRecoveryAuthAlias provide the
credentials that the database requires to access data in the database and to roll back failed trans-
actions. The list of lists that follows configureResourceProperties is database-specific
and arbitrary. You can see what you need to supply here, either by examining the documentation
that comes with the database driver class for your database or by calling AdminTask
.createDataSource(‘-interactive’).
8
Some versions of IBM help documents fail to mention this argument. See the reference section at the end of this
chapter for a description of all arguments for this method.
In order for this connection test to work, you might have to configure either the
preTestConfig attribute9 of this DataSource configuration or some attributes of the
DataSource MBean10 for this DataSource or both.
Testing the connection11 verifies that the drivers you installed work properly, that the net-
work between your server and the database works, and that your security credentials work on the
database. The only thing that AdminControl.testConnection() ignores is the JNDI name
that you specified in your JDBCProvider. If your connection passes AdminConfig
.testConnection() but you cannot connect to the database, check the spelling of the JNDI
name and the scope in which you installed that JNDI name. These are the problems you are most
likely to encounter when you try to create JDBCProviders and DataSources:
• Failure to install JDBC driver jar files or installing files in the wrong place
• Specifying an incorrect path to JDBC driver jar files
• Misspelling the names of WebSphere variables in various configurations
• Misspelling the values mapped to WebSphere variables
These problems occur when you create a JDBCProvider, but you won’t see them until you cre-
ate a DataSource and try to test the connection. If your connection fails, make sure the driver
files are where you specified. You should also examine the classpath attribute of your
JDBCProvider and compare that with your file system. If there are any WebSphere variables
in your classpath, print out those variables, too, and make sure that there are no typos.
Typos occur in both the variable names and the variable values. In addition, WebSphere
variables and their values are case-sensitive. The data type of a WebSphere variable is
VariableSubstitutionEntry. You can look at all the VariableSubstitutionEntrys in
your cell or just the VariableSubstitutionEntrys at a particular scope.
print AdminConfig.list( ‘VariableSubstitutionEntry’ )
n = AdminConfig.getid( ‘/Node:nameOfSomeNode/’ )
print AdminConfig.list( ‘VariableSubstitutionEntry’,n )
9
This attribute holds a ConnectionTest object. Its preTestConnection attribute must be set to “true” and
both its retryInterval attribute and its retryLimit attribute must be nonzero integers.
See the comments for the testConnection attribute and the testConnectionInterval attribute of the
10
DataSource MBean under “Useful MBeans” in the reference section at the end of this chapter.
11
For detailed information about this test and the actual SQL query used for this test, see Listing 13.8.
Keep in mind, there was also a bug on some versions of WebSphere Application Server that
caused misinterpretation of classpath if a VariableSubstitutionEntry in a different
scope had an identical symbolic name and a value less than one character long. You might
consider removing any VariableSubstitutionEntry that has a value less than one
character long. In the code here, assume that v holds the configuration ID of a
VariableSubstitutionEntry:
if len( AdminConfig.showAttribute( v, ‘value’ ) ) < 1:
AdminConfig.remove( v )
If you know the symbolic name of the variable and the scope in which it lives, you can use the
methods in the VariableConfiguration command group of AdminTask. If you have a node
named Node01 and a variable in that scope with a symbolic name of LOG_ROOT, the following
line of script displays its value:
print AdminTask.showVariable(
‘[-scope Node=Node01 -variableName LOG_ROOT ]’ )
That ClassNotFoundException speaks for itself. For one reason or another, the application
server cannot find your jar file, or the jar file is corrupted. When you check the classpath attrib-
ute of the JDBCProvider, you can see that the classpath contained a WebSphere variable
called UNIVERSAL_JDBC_DRIVER_PATH:
print AdminTask.showVariables( \
‘[ -variableName UNIVERSAL_JDBC_DRIVER_PATH ‘ + \
‘ -scope Node=Node01 ]’ )
The preceding code showed that the WebSphere variable had no value. After checking the file
system, we found the jar file and fixed the problem with the following code:
AdminTask.setVariable( ‘[-variableName
UNIVERSAL_JDBC_DRIVER_PATH ‘ \
+ ‘ -scope Node=Node01 ‘ \
+ ‘ -variableValue /opt/ibm/db2/V9.5/java ]’ )
The most common configuration problems involving databases are variables with incorrect val-
ues and missing jar files. Both problems are easy to fix.
Many times, your DataSource might work, but the response might be slow. Check the
IBM Documentation12 for procedures to troubleshoot13 slow response and for performance tun-
ing14 information. Common attributes that need modification include minimum and maximum
connections, various timeouts, and various trace strings. Most of these settings involve modify-
ing attributes of the ConnectionPool that belongs to the DataSource. Assuming that ds[2]
holds the configuration ID of a DataSource, the following script changes the values of mini-
mum and maximum connections and various timeouts.15 If you are setting the maximum num-
ber of connections for a server that is part of a cluster, remember to add the maximum
connection number from each server in the cluster and to make sure that your database can
handle that number of connections.
cp = AdminConfig.showAttribute( ds[2], ‘connectionPool’ )
AdminConfig.modify( cp,[ [‘minConnections’, 3],[‘maxConnections’,
8] ] )
AdminConfig.modify( cp,[ [‘connectionTimeout’, 360] ] )
AdminConfig.modify( cp,[ [‘reapTime’, 90],[‘agedTimeout’, 2400] ] )
Remember that none of these modifications to configuration take effect until you synchronize the
nodes in your cell and restart your servers. If you would like to test the modifications you are
about to make without restarting servers, you can change the appropriate attributes of the
DataSource MBean. Changes to MBeans take effect immediately. They disappear when you
stop the server. Keep in mind that you modify the configuration for things like minimum and
maximum connections and various time outs by modifying attributes of a ConnectionPool
configuration object. But you modify the runtime behavior by modifying the attributes of a
DataSource MBean.
In addition to modifying various attributes on the ConnectionPool and the DataSource,
you can also specify the amount of tracing and what components will be traced. Tracing is done
on a per server basis. The trace service controls tracing. You can make permanent changes to the
things you trace by changing the configuration of the trace service.
12
http://www.IBM.com/support/docview.wss?rs=180&uid=swg21247168.
For specific troubleshooting techniques, consider the IBM redbook, WebSphere Application Server v6.1 Problem
13
Determination (SG247461).
14
For concepts and topics that affect system performance, consider Chapter 7 of the IBM redbook, WebSphere Appli-
cation Server v7.0: Concepts, Planning and Design (SG247708).
15
The description of the DataSource MBean in the reference section in the back of this chapter has an extensive dis-
cussion of all of these values and their implications.
Permanent changes do not take effect until you save your configuration and reboot the
server in question. In a network deployment environment, you will have to synchronize your
nodes before you restart your server(s). You can make immediate but temporary changes to the
trace service by calling operations or changing attributes of the TraceService MBean. These
changes disappear when you stop the server. Or you can make immediate changes that survive
server restart by changing both the trace service configuration and the TraceService MBean.
If you need to trace a connection leak, you can use one of the following trace strings:
• ConnLeakLogic=finest
• WAS.j2c=finest
Assume that ts[1] is a string containing the name of an MBean that controls the trace service on
the server of interest to you. The code that follows will append our string to the existing trace
specification. Modifying the traceSpecification attribute directly causes your modifica-
tion to be appended to any existing trace specification. Notice that you should save the old trace
specification before making any modifications.16
oldSpec = AdminControl.getAttribute( ts[1], ‘traceSpecification’ )
AdminControl.setAttribute( ts[1],
‘traceSpecification’, ‘ConnLeakLogic=finest’ )
As soon as this code executes, the application server starts using the new trace specification. At
some point, you will want to go back to your original trace specification. To do that, you need the
following code:17
AdminControl.invoke( ts[1], ‘setTraceState’, oldSpec )
Advanced Settings
In the following code examples, the more advanced settings of JDBCProvider, DataSource,
and ConnectionPool are modified. You might do this because you have complex database
needs, you have to integrate an arcane version of an unsupported database, you are troubleshoot-
ing a database problem, or you are trying to tune database performance. If you have to integrate
an old version of a database driver class or if you have to integrate some exotic and possibly
unsupported database, you might experience problems with the database driver class that appears
to be class loader-related. One option to consider is isolating the database driver class by loading
it from its own class loader. You can do this as long as you (or the default template that creates
your JDBCProvider) do not set a value for the nativepath attribute of your JDBCProvider.
16
Changing the trace specification does not work exactly as you might expect. See the description of the
TraceService MBean in the reference section at the end of this chapter for the different operations that modify the
traceSpecification.
17
Changing the trace specification does not work exactly as you might expect. See the description of the TraceService
MBean in the reference section at the end of this chapter for the different operations that modify the
traceSpecification.
In previous code examples, you saw a JDBCProvider for IBM’s DB2® database. The
default template for DB2 sets a value for nativepath. Therefore, you cannot set the
isolatedClassLoader attribute of our JDBCProvider to true. But if you could, this would be
the line of script to do it:
AdminConfig.modify( p, [ [‘isolatedClassLoader’, ‘true’] ] )
The DataSource object has an interesting attribute called propertySet, which holds a config-
uration ID. If you pass that configuration ID to AdminConfig.show(), you will see what is
effectively a list of configuration IDs. Examining the attributes of each of these configuration IDs
tells you a lot about the tunable features of your database driver. The code in Listing 13.1 shows
you how to find the configuration ID of the list of property sets for a given DataSource. These
features can change from version to version of the driver and from version to version of the product.
print ps
# produces a line that looks like:
# (cells/McG/nodes/N1|resources.xml#J2EEResourcePropertySet_9)
stuff = AdminConfig.show( ps )
print stuff
# prints a list of configuration IDs of property sets
Listing 13.2 shows a dump utility method that displays the data to which each configuration
ID points. The propertySet attribute of a DataSource is a Jacl list. To do anything useful with
that list, you have to write some code to parse a Jacl list. Use the code from Listing 13.1 to display
the raw Jacl list of property sets. Line 04 in Listing 13.2 shows you where in that Jacl list to find the
property set name. Line 07 of Listing 13.2 modifies the Jacl list so that Jython can easily parse it.
And the loop starting on line 10 of Listing 13.2 prints each property set from the list.
What you see when you run the dumpPropertySet method will vary depending on the
DataSource propertySet you are exploring. Some excerpts from the printout are displayed
in Listing 13.3. This is the propertySet from the DataSource for the DB2 provider that was
installed earlier in this chapter.
The top line of each paragraph of the dump will tell you the following:
• The name of the property
• The type of data it expects
• The current value (if any)
The rest of each paragraph of the dump is a description of the property. These descriptions are
exactly what is provided by either the JDBCProvider template or by whoever installed the
JDBCProvider.
driverType java.lang.Integer 4
The JDBC connectivity type of a data source. If you want to use a type
4 driver, set the value to 4. If you want to use a type 2 driver, set
the value to 2. On WebSphere Application Server for Z/OS, driverType 2
uses RRS and supports 2-phase commit processing.
As you can see, there are 64 properties in this particular propertySet. The Derby
DataSource has a propertySet with only eight. The properties just listed are pretty
straightforward; however, Listing 13.4 shows some other properties that shed some light on less
clearly understood driver behavior.
queryCloseImplicit java.lang.Integer
Specifies whether cursors are closed immediately after all rows are
fetched. queryCloseImplicit applies only to type 4 connectivity to DB2
for z/OS database servers. Possible values are
DB2BaseDataSource.QUERY_CLOSE_IMPLICIT_YES (1) and
DB2BaseDataSource.QUERY_CLOSE_IMPLICIT_NO (2). The default is
DB2BaseDataSource.QUERY_CLOSE_IMPLICIT_YES. A value of
DB2BaseDataSource.QUERY_CLOSE_IMPLICIT_YES can provide better
performance because this setting results in less network traffic.
useJDBC4ColumnNameAndLabelSemantics java.lang.Boolean
Specifies how the JDBC driver handles column labels in
ResultSetMetaData.getColumnName, ResultSetMetaData.getColumnLabel, and
ResultSet.findColumn method calls. Possible values are: 0, 1, 2. Please
see the JDBC driver documentation for details.
Other properties illuminate the various ways we impact the security of the communication
between the driver and the database, as shown in Listing 13.5.
securityMechanism java.lang.Integer
Specifies the DRDA security mechanism. Possible values are: 3
(CLEAR_TEXT_PASSWORD_SECURITY), 4 (USER_ONLY_SECURITY), 7
(ENCRYPTED_PASSWORD_SECURITY), 9
(ENCRYPTED_USER_AND_PASSWORD_SECURITY), or 11 (KERBEROS_SECURITY). If
this property is specified, the specified security mechanism is the
only mechanism that is used. If no value is specified for this
property, 3 is used.
kerberosServerPrincipal java.lang.String
For a data source that uses Kerberos security, specifies the name that
is used for the data source when it is registered with the Kerberos Key
Distribution Center (KDC). It should be of the format user@realm.
And yet other properties have implications for debugging problems, as shown in Listing 13.6.
traceLevel java.lang.Integer -1
Specifies the level of trace, determined by a bitwise combination of
constants: TRACE_NONE=0, TRACE_CONNECTION_CALLS=1,
TRACE_STATEMENT_CALLS=2, TRACE_RESULT_SET_CALLS=4,
TRACE_DRIVER_CONFIGURATION=16, TRACE_CONNECTS=32, TRACE_DRDA_FLOWS=64,
TRACE_RESULT_SET_META_DATA=128, TRACE_PARAMETER_META_DATA=256,
TRACE_DIAGNOSTICS=512, TRACE_SQLJ=1024, TRACE_META_CALLS=8192,
TRACE_DATASOURCE_CALLS=16384, TRACE_LARGE_OBJECT_CALLS=32768,
TRACE_SYSTEM_MONITOR=131072, TRACE_TRACEPOINTS=262144, TRACE_ALL=-1.
traceFile java.lang.String
The file to store the trace output. If you specify the trace file, the
DB2 JCC trace will be logged in this file. If this property is not
specified and the WAS.database or com.ibm.ws.db2.logwriter trace group
is enabled, then both WebSphere Application Server trace and DB2 trace
will be logged into the WebSphere Application Server trace file.
traceDirectory java.lang.String
Specifies the directory where the trace file will be created.
Still other properties have implications for performance, as shown in Listing 13.7. These
properties and their values vary from database vendor to database vendor.
xaNetworkOptimization java.lang.Boolean
Specifies whether the XA network optimization is enabled for type 4
connectivity. You might need to disable the XA network optimization in
an environment in which XA Start and XA End are issued from one Java
process, and XA Prepare and XA Commit are issued from another Java
process. With XA network optimization, the XA Prepare can reach the DB2
server before the XA End, which results in an XAER_PROTO error. To
prevent the XAER_PROTO error, disable the XA network optimization. The
default is true, which means the XA network optimization is enabled. If
xaNetworkOptimization is false, which means the XA network optimization
is disabled, then the driver closes any open cursors at XA End time.
fullyMaterializeInputStreams java.lang.Boolean
Indicates whether streams are fully materialized before they are sent
from the client to a database server. The default is false.
The default values for all of these properties work well for the vast majority of situations.
The debugging properties are very useful when things go wrong. The optimizing properties
should not be adjusted until all the traditional optimizations (setting the number of connections,
setting various timeouts, and so on) have been performed. Because all of these settings are a part
of server configuration, none of them take effect until you save the configuration, synchronize all
your affected nodes, and restart the affected servers.
Someday, for whatever reason, you might need to pass specialized, driver-specific values to
the driver. You would do this by creating an entire propertySet for the JDBCProvider or by
modifying one or more existing values in the propertySet. One value you might choose to
modify is the test query. The preTestSQLString holds the SQL query that
AdminControl.testConnection()18 sends to your database. If AdminControl
.testConnection() receives a result set in response to this query, it reports that your server can
connect to your database. If it receives any other response or no response at all, AdminControl
.testConnection() reports that your server cannot connect to your database. That query is one
of the properties you can expect to find in the JDBCProvider’s propertySet. Listing 13.8
shows the description of the preTestSQLString from one database vendor.
You can execute any SQL query you choose, but you want to make sure that the query will
work when you first configure your system. You probably want a query that does not take long to
execute and does not return a lot of data. Listing 13.9 shows how to change one property within a
propertySet. The changes do not take effect until you save your changes, synchronize any
affected nodes, and restart the affected servers.
18
Be aware that you might have to do some additional configuration to make this test work. See the footnotes at the
beginning of “Troubleshooting Configuration Problems” in this chapter.
9| for p in listOfProperties:
10| if AdminConfig.showAttribute( p, ‘name’ ) == propertyName:
11| if propertyValue == “[]”:
12| AdminConfig.modify( p, [[ ‘value’, [] ]] )
13| else:
14| AdminConfig.modify( p, [[ ‘value’, propertyValue ]] )
15| print AdminConfig.queryChanges()
16| break
There might or might not be a target. If there is, it might be a configuration ID or it might be a
name. Targets are usually containment parents. There might or might not be arguments. Argu-
ments are almost always names followed by values. There might or might not be steps as well.
Think of steps as arguments that require either a list of names followed by values or nothing at all.
Bundle all the arguments and steps into one big list and pass it to the method.
JDBCProviderManagement Group
This section details the JDBCProviderManagement Group methods.
createJDBCProvider
This method creates a new JDBCProvider that is used to connect with a relational database for
data access. It uses the default JDBCProvider template for the database in question on the envi-
ronment in which the application server lives to create a useful working installation and configura-
tion for a supported database driver.
Required arguments:
• scope—Scope for the new JDBCProvider. Must be one of the following:
Cell=nameOfYourCell
Node=nameOfSomeNode
Node=nameOfSomeNode,Server=nameOfSomeServer
Cluster=nameOfSomeCluster
Application=displayNameOfSomeApplication
• databaseType19—The type of database used by this JDBCProvider.
• providerType—The JDBCProvider type used by this JDBCProvider.
• implementationType—The implementation type for this JDBCProvider. Use
’Connection pool data source’ if your application runs in a single phase or local
transaction. Use ’XA data source’ to run in a global transaction. You must use one of
those two case-sensitive strings.
Frequently used optional arguments:
• name—The name of the JDBCProvider.
• description—Text to describe the part that this JDBCProvider plays in your topology.
• implementationClassName—The name of the Java class for the JDBC driver imple-
mentation.
• classpath—Specifies a list of paths or jar file names that together form the location
for the resource provider classes. The classpath can contain multiple elements pro-
vided that they are separated with a colon, semicolon, or comma.
• nativePath—Specifies a list of paths that forms the location for the resource provider
native libraries. The native path can contain multiple elements provided that they are
separated with a colon, semicolon, or comma.
createDataSource
This method creates a new DataSource to access the backend data store. Application components
use the DataSource to connect to a database. Each DataSource has a connection pool. This
allows connections to be shared.
Target:
The configuration ID of the JDBCProvider that will provide the actual connections to the
database. This target is required.
19
Print AdminConfig.listTemplates(‘JDBCProvider’) in order to see both providerType and
databaseType available to you.
Required arguments:
• name—The name of the DataSource.
• jndiName—The Java Naming and Directory Interface (JNDI) name for this
DataSource.
listJDBCProviders
This method returns the configuration ID of each JDBCProvider in the specified scope. If you
do not provide a scope argument, you get a list of the configuration IDs of all JDBCProviders.
listDataSources
This method returns the configuration ID of each DataSource in the specified scope. If you do
not provide a scope argument, you get a list of the configuration IDs of all DataSources.
Frequently used optional arguments:
• scope—Scope for the DataSources that are to be listed. If you do not supply this
argument, the default result is to return the configuration IDs of all JDBCProviders.
Permitted values are as follows:
Cell=nameOfYourCell
Node=nameOfSomeNode
Node=nameOfSomeNode,Server=nameOfSomeServer
Cluster=nameOfSomeCluster
Application=displayNameOfSomeApplication
VariableConfiguration Group
You can create, modify, and display WebSphere variables in one of two ways.You can use the three
methods in this group, or you can call AdminConfig.create(), AdminConfig.modify(), and
AdminConfig.show(). The methods in this group are much easier to use. The AdminConfig
methods require you to traverse WebSphere’s configuration tree to the correct scope, then find the
VariableMap within that scope, then find the correct VariableSubstitutionEntry in that
VariableMap. The methods in this group do that search for you.
showVariables
This method displays the name of one or more variables and the values of those variables. It can
be limited to a certain scope, a certain variable name, or both.
setVariable
This method assigns a value to a variable. If the variable does not yet exist, it will be created. If
the variable does exist, any value it currently holds will be changed.
Required arguments:
• variableName—The name of the variable to be created or changed.
Frequently used optional arguments:
• scope—Specifies the location of the variable.xml file you want to search. If you omit
this argument, Cell scope is displayed. Scope can be specified in one of the following
ways:
Cell=nameOfYourCell
Node=nameOfSomeNodeInYourCell
Server=nameOfSomeServer. If you have more than one server with the same name,
you must specify both the node name and the server name. For instance:
Node=Node15,Server=server1
Cluster=nameOfCluster
Application=nameOfApplication
• variableValue—The value of the variable.
• variableDescription—Use this field to describe the role this variable plays in your
topology.
removeVariable
This method deletes a variable.
Required arguments:
• variableName—The name of the variable to be created or changed.
Frequently used optional arguments:
• scope—Specifies the location of the variable.xml file you want to search. If you omit this
argument, Cell scope is displayed. Scope can be specified in one of the following ways:
Cell=nameOfYourCell
Node=nameOfSomeNodeInYourCell
Server=nameOfSomeServer. If you have more than one server with the same name,
you must specify both the node name and the server name. For instance:
Node=Node15,Server=server1
Cluster=nameOfCluster
Application=nameOfApplication
Useful MBeans
In addition to the AdminTask methods that manipulate DataSources and JDBCProviders, it is
sometimes useful to work directly with several MBeans. For each MBean, a subset of its attrib-
utes and a subset of its operations are described. These subsets are the attributions and operations
that are the most useful for debugging and fine-tuning database access.
DataSource MBean
This MBean, as its name implies, controls and reports on the operation of a DataSource. It also
controls and reports on the operation of the connection pool that each DataSource contains.
Each DataSource has its own MBean. Many of the attributes of this MBean are also attributes
of the DataSource configuration item. If you want to change the runtime behavior of a
DataSource without stopping the server that hosts the DataSource, you can change the modi-
fiable attributes of the DataSource MBean. That allows you to experiment and do some trou-
bleshooting without having to synchronize nodes and restart servers.
Interesting Read/Write attributes:
• reapTime - java.lang.Integer—The thread that enforces all the other timeouts
runs once each time this number of seconds expire. All other timeouts are effectively
rounded up to the next even multiple of reapTime.
• minConnections - java.lang.Integer—Once this number of connections has
been opened, the DataSource always keeps at least this number of connections open.
• maxConnections - java.lang.Integer—The DataSource will never open
more than this number of connections.
20
Note that surgeThreshold deals with simultaneous requests, not total requests for connections.
TraceService MBean
This MBean controls the amount of debugging and performance information that an individual
server records. The records could be stored in a file or held in memory. If held in memory, you
can control the size of the memory buffer. Indirectly, that determines the number of events your
server remembers. Although this MBean reports the name of the file used to hold trace results,
this MBean cannot permanently change the name, location of the trace file, or the decision to
store trace results in memory versus in a file. It can, however, do all of that on a temporary basis.
None of these changes will survive a server stop.
Interesting Read / Write attributes:
• ringBufferSize - int—The size of the ring buffer that holds trace events if tracing
is done in memory as opposed to dumping the trace data to a file.
• traceSpecification - java.lang.String—This string determines what the
trace service traces and how much information it captures. If you directly manipulate the
value of this string, your modification is processed by the appendTraceString
operation of this MBean. Your modifications are appended to the existing
traceSpecification. They do not replace the existing traceSpecification. Call
the setTraceState operation if you want to replace the entire traceSpecification.
The tracing is based on Log4J. You can trace IBM Java code and third-party Java code.
You can also trace certain standard events depending on any combination of:
• Which Java package(s) you choose to trace
Summary
Database access is very important to almost every serious enterprise application. In this chapter,
you learned how to manage database connectivity on the WebSphere Application Server platform.
We explored the AdminTask methods you are most likely to need, as well as some MBeans that
figure prominently in database connectivity. We explored ways to troubleshoot database connec-
tivity and performance issues, and we provided both online and print references for further study.
In the next chapter, we explore messaging on the WebSphere Application Server platform.
Messaging
The AdminTask scripting object has several groups of methods that support messaging. In this
chapter, we explore some useful methods from the following groups:
SIBAdminCommands
SIBJMSAdminCommands
SIBAdminBusSecurityCommands
Depending on your version of the product, there are 125 to 175 methods in the command
groups that deal with messaging. Nobody uses all of those methods every day. We have
selected a manageable subset of the methods in these groups to illustrate the main tasks that
have to be performed any time you configure a messaging bus. We also give information that is
not well-documented elsewhere and illustrate our points with a simple example. We then list
the other commands in these groups at the end of this chapter along with a brief explanation of
each.
An Introduction to Messaging
Messaging can be used to integrate legacy applications, to combine existing applications to serve
new business needs, and to add a façade to an existing application. It is a very loosely coupled
method of performing system integration. Messaging requires you to configure two distinct
pieces of plumbing within an application server.
You have to configure some plumbing that prepares the application server with other appli-
cation servers. The AdminTask methods that configure this plumbing are all part of the
SIBAdminCommands command group.
301
You have to configure some additional plumbing that allows an application to be deployed
to that server to send messages and retrieve messages.1 The AdminTask methods that configure
this plumbing are all part of the SIBJMSAdminCommands command group and the
SIBAdminBusSecurityCommands command group.
Messaging Basics
Let’s use email as an example to walk through basic messaging. The sender must know the recip-
ient’s address, but the recipient does not have to be online when the message is sent. Messaging
builds on this pattern.
First, however, let’s get rid of one requirement: The sender does not have to know the recip-
ient’s address information. So when the sender “sends” a message, you can just append that mes-
sage to the end of a table in a database. You can configure2 that imaginary database to be either a
file or real database. Either way, that imaginary database always isolates sender from receiver.
When a recipient wants to “receive” a message, the recipient reads the last row in the data table
and marks it for deletion.
Second, you can hide all of the details from any applications that use messaging. An appli-
cation will ask a factory to provide it with access to a messaging resource. The application will
then either send a message or retrieve a message. The sender can determine whether a message
was delivered, but the sender will not know who retrieved the message or whether the same recip-
ient received two consecutive messages.
Messaging can be set up to deliver a message several ways. It can deliver the message to the
first recipient who retrieves that message; messaging set up in this fashion is called a queue. Mes-
saging can also be set up to retain a message until all registered listeners have acknowledged
receipt of the message; messaging set up in this fashion is called a topic.
In its simplest form, configuring messaging requires you to perform the following configu-
ration steps on the application server:
1. Create the messaging bus itself.
2. Add one or more members to the bus.
3. Create either a queue or a topic.
4. Create a connection factory.
5. Create either a JMSQueue or a JMSTopic.
We explore this in a simple example and then discuss ways in which you might need to improve
this example for your environment.
1
A discussion of the Java Message Service is beyond the scope of this book. For a good introduction, consider
Chapter 33 of http://java.sun.com/j2ee/1.4/docs/tutorial/doc/index.html.
2
See AdminTask.createSIBEngine(). The decision to use a database versus a filestore must be made when the
messaging engine is created.
Terminology
The messaging scheme described in the previous section is called a messaging bus. The queue or
the topic that holds messages for a bus is called a destination. It is convenient to think of a queue
or a topic as a table in an imaginary database. It is convenient also to think of sending a message
as appending a row to that table, as it is convenient to think of retrieving a message as selecting a
row from that table and then marking that row for deletion. There is a lot of complexity hidden
under all that convenient thinking.3 But that metaphor exposes just enough of the details to allow
us to configure a simple messaging bus.
Each application server and each cluster that communicates on the messaging bus is called
a bus member. Each bus member has a messaging engine. The messaging engine gets created
automatically when a server or a cluster is added as a member of a messaging bus. Messaging
engines talk to our imaginary database. The IBM InfoCenter calls this imaginary database a mes-
sage store. This message store can either be a real database or a file in the file system. You create
this message store whenever you do something that creates a messaging engine.4 Messaging
engines also talk to each other.
3
For a lot more formal detail, consider the IBM Redbook SG247297, “Experience J2EE! Using WebSphere Application
Server V6.1,” section 15.1. The additional resources listed in that chapter are also quite helpful.
4
See AdminTask.addSIBusMember() and AdminTask.createSIBEngine() for additional details.
2| import AdminConfig
3| import AdminTask
The following lines create the messaging bus5 and display any messaging buses6 that exist
in a cell.
print AdminTask.createSIBus(‘[-bus ‘ + nameOfBus + ‘ ]’)
print AdminTask.listSIBuses()
What you see of a bus in the configuration files at this point is nothing more than a few elements
in a file called sib-bus.xml. This file lives in your configuration repository. You will find this
5
See AdminTask.createSIBus() in the reference section of this chapter.
6
See AdminTask.listSIBuses() in the reference section of this chapter.
file under cells/buses/nameOfBus. Although this line is necessary for every line of script that fol-
lows, it does not really add any functionality to any server in the cell. Until you add bus members
and destinations, the messaging bus itself is nothing more than a name.
The following code configures some plumbing for one particular application server7 and
displays8 the plumbing you configured.
print AdminTask.addSIBusMember(‘[-bus ‘ + nameOfBus + \
‘ -node ‘ + oneNodeName + ‘ -server ‘ + oneServerName + \
‘ -fileStore ]’)
print AdminTask.listSIBusMembers( ‘[-bus ‘ + nameOfBus + ‘ ]’ )
The code here does several things. It adds a busMembers element to the sib-bus.xml file.
Adding a bus member creates configuration for a messaging engine inside the server or inside the
cluster9 you added to the bus. A messaging engine knows how to talk to the imaginary database
that will act as the middle man standing between message producer and message consumer. In
this example, the imaginary database is actually a file store. If you change one argument and sup-
ply a JNDI name, you can use either an embedded database called Derby or an industrial strength
database such as DB/2 or Oracle.
You could easily modify the code here slightly to configure messaging plumbing for a cluster
instead of a server. All you would have to do is provide the name of a cluster instead of the names of
a node and server.10 Although it is easy to add a cluster as a messaging bus member, it is important
to understand the default behavior of a cluster that becomes a member of a messaging bus.
By default, if you create a cluster with five member servers11 and you make that cluster a
member of a messaging bus, only one server out of the entire cluster will actually send and receive
messages on the messaging bus. This is because, by default, the application server only activates
one messaging engine12 no matter how many servers there are in the cluster. Therefore, in this
7
See AdminTask.addSIBusMember() in the reference section of this chapter.
8
See AdminTask.listSIBusMembers() in the reference section of this chapter.
9
This book assumes that the reader is already familiar with clusters and the reasons for creating and using clusters.
For a good discussion of the fundamentals of clusters, see the WebSphere Application Server documentation at
http://publib.boulder.ibm.com/infocenter/wasinfo/v7r0/index.jsp?topic=/com.ibm.websphere.pmc.nd.iseries.doc/con
cepts/cjn_mdb_endpt_overview.html. For a discussion about how a cluster interacts with a messaging bus, see
http://publib.boulder.ibm.com/infocenter/wasinfo/v7r0/index.jsp?topic=/com.ibm.websphere.pmc.nd.iseries.doc/concepts/
cjn_mdb_endpt_overview.html. The subtopics on this page explain in detail what it means to add a cluster as
a bus member.
10
See AdminTask.addSIBusMember() in the reference section of this chapter.
11
There is nothing magical about the choice of five servers. The point is that no matter how many servers you create in
the cluster, only one will get an active messaging engine. The other servers will be on hot standby, doing nothing but
waiting for the active server’s messaging engine to fail.
12
See “Adding a cluster to a bus” in the WebSphere Application Server documentation at http://publib.boulder.ibm.com/
infocenter/wasinfo/v6r1/index .jsp?topic=/com.ibm.websphere.pmc.nd.doc/concepts/cjt0005_.html.
sample cluster with five member servers, one server is actively communicating on the messaging
bus, and the other four are on hot standby. It is possible to activate more than one messaging
engine per cluster. Administratively, it is easy to do. It is just a matter of writing policies for the
messaging engines in the cluster. There are side effects to doing this that include possible loss of
message order and stranded messages. Make sure you read and understand the WebSphere Appli-
cation Server documentation article on “Workload sharing with queue destinations”13 and all arti-
cles mentioned on that page before proceeding.
Given that we often use clusters to provide workload balancing for applications and (by
default) clusters provide high availability, not load balancing, for messaging engines, it makes sense
to create one cluster to support messaging buses and additional clusters to support applications. This
is especially true for WebSphere Application Server v6.1, since v7 adds additional messaging topol-
ogy options. This is called the remote messaging pattern. There are two diagrams and a short section
of text that describe this pattern in an IBM Redbook®.14 Make sure you understand this material
before you attempt to workload balance the messaging engines in a messaging bus.
So far, there are no tables that you need to care about in this imaginary database. That will
change in the following code sample that creates a queue15 and displays the queue16 after you create it:
options = ‘[-bus’ + nameOfBus + ‘ -name ’ + nameOfQueue
options += ‘-type Queue’ + actualLocationOfQueue
options += ' ‘ -description ' + sibDestinationDescription + ' ]'
print AdminTask.createSIBDestination( options )
id = AdminConfig.getid( '/Node:%s/Server:%s/' % \
( oneNodeName, oneServerName ) )
print AdminTask.listSIBJMSQueues( id )
13
See http://publib.boulder.ibm.com/infocenter/wasinfo/v6r1/index.jsp?topic=/com.ibm.websphere.pmc.nd.doc/concepts/
cjt0014_.html.
See IBM Redbook SG247776, “Leading Practices for WebSphere Dynamic Process Edition v6.2,” section 7.2.2,
14
Remote Messaging Topology Pattern. In particular, notice Figures 7-2 and 7-3.
15
See AdminTask.createSIBDestination() in the reference section of this chapter.
16
See AdminTask.listSIBJMSQueues() in the reference section of this chapter.
17
See AdminTask.listSIBJMSQueues() and AdminTask.showSIBJMSQueue().
18
See AdminTask.listSIBJMSTopics() and AdminTask.showSIBJMSTopic().
given any application the ability to use any of that plumbing. The following code changes that.
Start by creating19 a connection factory and then displaying20 the newly created connection fac-
tory’s attributes, as shown in the following code lines:
factoryVisibility = AdminConfig.getid(connectionFactoryScope)
srvCfgID = AdminConfig.getid( ‘/Node:’ + oneNodeName + \
‘/Server:’ + oneServerName + ‘/’ )
factoryID = AdminTask.createSIBJMSConnectionFactory( \
factoryVisibility, ‘[-name ‘ + nameOfFactory + \
‘ -jndiName ‘ + jndiNameOfFactory + \
‘ -busName ‘ + nameOfBus + \
‘ -category Experiment01 -description ‘ + \
connectionFactoryDescription + ‘ ]’)
print AdminTask.showSIBJMSConnectionFactory( factoryID )
A connection factory gives an application a way to find your messaging plumbing and retrieve a
piece of code that will actually ask the messaging bus to send and receive messages on behalf of
the client application. Think of a connection factory as something that maps the industry standard
Java Messaging Service (JMS) façade to the underlying proprietary Service Integration Bus
implementation. Applications use components of the Java Messaging Service. You configure ser-
vice integration buses (SIB) to integrate components of your enterprise architecture. You must
specify the following in order for the connection factory to do its job:
• How visible the connection factory should be. You can make a connection factory that
an entire cell and an entire node can use. You can restrict the visibility of your connec-
tion factory to just one server or one cluster of servers.
• The name of the bus that will hold the queue or the topic that applications will ulti-
mately use.
• A JNDI name that applications will use when they want to talk to a queue or a topic that
this connection factory knows about. The mapping of the JNDI name to a queue or a
topic on a specific bus is the glue that connects JMS to SIB.
NOTE The description and the category are optional arguments that help you document
your configuration decisions. Any text you supply for these arguments will also be visible to
anybody who uses the Admin Console.
19
See AdminTask.createSIBJMSConnectionFactory() in the reference section of this chapter.
20
See AdminTask.showSIBJMSConnectionFactory() in the reference section of this chapter.
The following code shows how to have a connection factory create a code object—an
SIBJMSQueue—that allows an application to use the messaging bus to send and receive messages.21
The line displays22 attributes of the SIBJMSQueue that was configured.
jmsQueueWrapper = AdminTask.createSIBJMSQueue( srvCfgID, \
‘[-name ‘ + nameOfJMSQueue + ‘ -queueName ‘ + nameOfQueue + \
‘ -busName ‘ + nameOfBus + ‘ -jndiName ‘ + jndiNameOfJMSQueue + \
‘ -description ‘ + jmsQueueDescription + ‘ ]’)
print AdminTask.showSIBJMSQueue( jmsQueueWrapper )
You’ve just completed everything necessary to create the simplest possible messaging queue. All
you needed to accomplish this task were the following AdminTask methods:
• createSIBus
• addSIBusMember
• createSIBDestination
• createSIBJMSFactory
• createSIBJMSQueue
There are a few things you might want to change depending on the needs of your system and the
needs of your customers. We used the file system for our imaginary database. You might choose
to change that to a commercial database product. Extremely demanding security requirements
might require additional constraints. We enable security later in this chapter.
21
See AdminTask.createSIBJMSQueue() in the reference section of this chapter.
22
See AdminTask.showSIBJMSQueue() in the reference section of this chapter.
Listing 14.2 shows some code that deletes this sample bus. Notice that to find the
SIBJMSQueue you created, you have to look for a J2CAdminObject, which is on line 50. Also worth
noting is that to find SIBJMSConnectionFactory, you have to look for a ConnectionFactory—
on line 55. In both cases, you also have to know the name of the object you want. You can see that
while AdminTask.deleteSIBus()23 takes the name of a bus as its parameter, both AdminTask
.deleteSIBJMSQueue()24 and AdminTask.deleteSIBJMSConnectionFactory()25 require
configuration IDs. Unfortunately, we don’t currently have an easy way to locate the configuration
ID, given the name attribute of the configuration item. Therefore, you will see a
findIDbyName() method here.
23
See AdminTask.deleteSIBus() in the reference section of this chapter.
24
See AdminTask.deleteSIBJMSQueue() in the reference section of this chapter.
25
See AdminTask.deleteSIBJMSConnectionFactory() in the reference section of this chapter.
If you delete a messaging bus that uses either a filestore or a Derby database or a Cloud-
scape® database, you might want to make sure you delete the file system directory that contains
that datastore or filestore. If you recreate the messaging bus with the same bus name as a messag-
ing bus you deleted and the new messaging bus refuses to start, check your logs for error mes-
sages that mention a common mode error.26 If you find such an error, delete the directory that
contained the database or filestore for the messaging bus. This is an operating system task. There
are no scripting objects that do this for you. These databases can be found in the profile that holds
the configuration information for your deployment manager. In the root of that profile, look for a
directory that has a name such as databases or devicestores. The directory you need to
delete will be one of the directories under that. The exact names might be version-dependent. See
the WebSphere Application Server documentation for details.
Security
It is difficult to find any resource that concisely delineates the steps you must take to secure a
messaging bus. Because of this, we created an administrative checklist for you. This checklist is
not a substitute for a security audit by a qualified professional. To secure a messaging bus, you
must
• Enable administrative security for the cell.
• Enable security for the bus.
• Create (or use an existing) authentication alias to use between messaging engines. This
step becomes unnecessary beginning with WebSphere Application Server version 7.
• Create (or use an existing) secure transport chain to use between messaging engines.27
• Disable (or delete) insecure messaging transport chains.
26
See details in the WebSphere Application Server documentation at http://publib.boulder.ibm.com/infocenter/
wasinfo/v6r1/index.jsp?topic=/com.ibm.websphere.pmc.nd.doc/ref/rjk_prob0.html. Page down to the section titled
“Problems when you re-create a service integration bus.”
27
Setting up SSL from scratch can involve some work. Depending on how much has already been done and how much of
that you are allowed to reuse, the work could include generating digital certificates, copying those certificates to appro-
priate computers, creating keystores, and configuring servers to use those keystores. Additional details can be found in
the WebSphere Application Server documentation under the topic “Creating a Secure Sockets Layer configuration” at
http://publib.boulder.ibm.com/infocenter/wasinfo/v7r0/index.jsp?topic=/com.ibm.websphere.nd.multiplatform.doc/
info/ae/ae/tsec_sslconfiguration.html.
After you execute this line, look for secure=. Right after that, you should see true. Then look
for permittedChains=. Right after that, you should see SSL_ENABLED. If not, you have to
modify some attributes of the messaging bus.30
28
Setting up SSL from scratch can involve some work. Depending on how much has already been done and how much of
that you are allowed to reuse, the work could include generating digital certificates, copying those certificates to appro-
priate computers, creating keystores, and configuring servers to use those keystores. Additional details can be found in
the WebSphere Application Server documentation under the topic “Creating a Secure Sockets Layer configuration” at
http://publib.boulder.ibm.com/infocenter/wasinfo/v7r0/index.jsp?topic=/com.ibm.websphere.nd.multiplatform.doc/
info/ae/ae/tsec_sslconfiguration.html.
29
See AdminTask.showSIBus() in the reference section of this chapter.
30
See AdminTask.modifySIBus() in the reference section of this chapter.
After you remove the default authorizations,31 you need to create authorized groups and/or users
for your installation,32 as shown in Listing 14.3.
Listing 14.3 Creating New Authorized Users for Secure Messaging Bus
01| secMgrID = AdminConfig.list( ‘Security’ )
02| # create JAAS authentication identity data
03| desc = ‘for users of ‘ + nameOfBus
| # create an arbitrary name for a user ID
04| uid = nameOfBus + ‘-User’
05| pwd = ‘TopSecretPassword’
06| print “In WAS Version 5, user names had to be less”, \
07| “than 12 characters”
08| print “The same restriction applies to WebSphere MQ”
09| print uid,”is”,str( len(uid) ),”characters long”
|
10| jaasID = AdminConfig.create( ‘JAASAuthData’, secMgrID, \
| [ [‘alias’, ‘SimpleBusAuthenticationAlias’], \
| [‘description’, desc], \
| [‘userId’, uid], [‘password’,pwd] ] )
12| print jaasID
The code in Listing 14.3 assumes that there is a user in your user registry with a user ID and
a password that matches information supplied when you created the JAASAuthData. If this is
not true, you will not get any errors when you run the code in Listing 14.3. Your JAASAuthData
won’t get you access when you try to use it. It will fail authentication by your user registry.33 The
code in Listing 14.4 sets the correct permissions for your new user. Be aware that you can set per-
missions for a group instead of a user. There is a parallel series of AdminTask methods, each of
which perform the same functions on a group instead of a user. You have to add a user or group to
the bus connector role to allow that entity to connect to the bus at all. If you enable security for a
bus and it stops working, this is something you should check. You should also check to make sure
that your user is in your user registry.
33
See the WebSphere Application Server documentation for all the administrative steps to enable administrative security.
34
Chain is a WebSphere Application Server data type. Its name is case-sensitive. Notice in the example code, we
search for Chain, not TransportChain.
IBM used on your version of the product. Alternatively, you are free to create your own secure
transport chains and use them for message bus communications.
Message buses also communicate with Distribution and Consistency Services (DCS). This
communication contains the location of messaging resources. By default, DCS requires a valid
LTPA token from any entity that attempts communications with DCS, but the communications
themselves are unencrypted. Thus, anybody with a network sniffer (and a lot of patience) could
discover the location of all of your allegedly secure messaging resources. This would be an unac-
ceptable security hole in many enterprises.
To close this hole, create another core group (which is described in Chapter 11, “The
AdminTask Object—Server Management.”) Make any server or cluster member that will use your
secure message bus a member of that core group. Specify the DCS-secure transport chain as the
transport chain between that core group and DCS.
Finally, you have to provide the configuration ID of your JAAS authentication alias to two
attributes of the ConnectionFactory—authDataAlias and xaRecoveryAuthAlias. This
is done in the following sample code:
c = findIDbyName( ‘ConnectionFactory’, nameOfFactory )
AdminConfig.modify( c, [ [ ‘authDataAlias’, jaasID ], \
[ ‘xaRecoveryAuthAlias’, jaasID ] ] )
Here are two separate authentications that happen on the messaging bus and its assorted compo-
nents. When you send a message, you are really inserting a row into an imaginary database table.
If you configure your messaging bus to use a real database,35 then sending a message might well
require authentication by the database. Any real database used to support messaging is required
to support transactions. When a transaction fails and it needs to be rolled back, there is a separate
35
As opposed to an imaginary database like a filestore.
authentication required by the database. You are free to use the same credentials for both authen-
tications. You just have to remember to configure for both authentications.
Reference Section
In this section, we provide detailed information about the AdminTask methods that configure
messaging buses. Of the hundreds of methods in this category, detailed information is provided
about the methods you will likely use most often. The methods are divided into categories.
Within those categories, we present the methods in the order in which you might have to use
them. We drew on numerous sources for the information we present in this section, as well as the
most recent version of the help that IBM provides within the AdminTask scripting object itself.
We added details from several sources within the WebSphere Application Server documentation
and that folks from the IBM support staff were kind enough to provide. We also supplemented
this with things we learned from our own experience.
Finally, the arguments to each method are divided into groups. The first group is made up
of the required arguments. The second group are arguments that are not required but that you are
very likely to have to use. The third group is comprised of arguments that are optional and are sel-
dom used. The fourth group are arguments that you will have to supply if you are configuring a
secure environment.
The general pattern for calling AdminTask methods is:
AdminTask.methodName( target, \
‘[ -argument value -nextArgument value2 ‘ \
+ ‘-stepName [ -arg01 val01 -arg02 val02 ] ‘ \
+ ‘-nextStepName [ -arg03 val03] -yetAnotherStep ]’ )
There might or might not be a target. If there is one, it might be a configuration ID, or it might be
a name. Targets are usually containment parents of whatever the method touches. There might or
might not be arguments. Arguments are almost always name/value pairs. And there might or
might not be steps—and there might be more than one step. Think of steps as arguments that take
either a list of name/value pairs as their value or no argument at all. Bundle all the arguments and
all the steps into one big list and pass it to the method.
createSIBus
This method creates a messaging bus.
Required argument:
• bus—Every bus has to have a name. This is where you specify the name of the bus you
are about to create.
Optional arguments you might need if you want to secure the bus:
• busSecurity—The default value true enables messaging bus security. Change this
to false to disable bus security. This argument has no effect unless you have already
enabled administrative security.
• InterEngineAuthAlias—For authenticating communications between messaging
engines (used by complex topologies).
• mediationsAuthAlias—For authenticating a message to a mediation layer.
Only needed if you are doing mediations within your SIBus and then only in secure
environments.
Optional arguments that you are likely to use:
• description—Any text you might want to add to describe this part of your bus topology.
• discardOnDelete—The default value is false. This argument decides whether
messages should be deleted from the database that supports a queue if and when a queue
gets deleted.
• HighMessageThreshold—The default is 50,000.
Optional arguments that you are less likely to use:
• configurationReloadEnabled—The default is true. Set this to false if you do
not want to allow bus configuration information to be dynamically reloaded.
• ScriptCompatibility—Default of 6.1 works unless you have version 6 (or earlier)
servers as bus members. In that case, set this value to 6.
• secure—You are not likely to use this argument because it has been deprecated. Use
busSecurity instead.
addSIBusMember
This method configures the plumbing that a server uses to become a member of a bus.
Required argument:
• bus—The name of the bus that this server or cluster will join.
Although the following arguments are not marked “mandatory,” you are required to use some of
them. You have to specify either the server or cluster or WebSphere MQ server that will receive
the extra plumbing that will make it a member of a messaging bus. If you want to add an individ-
ual server to a messaging bus, you must specify the server name and the node name of that server.
If you want to add an entire cluster to the messaging bus, you must specify the name of the cluster,
and you cannot specify a node name or a server name. If you want a WMQ server to host this des-
tination, supply a WebSphere MQ server name. Omit node, server, and cluster arguments.
• node—The name of the node that contains the server you want to add to the messaging bus.
• server—The name of the server you want to add to the messaging bus.
• cluster—The name of the cluster that you want to add to the messaging bus.
• wmqServer—The name of a WebSphere MQ server that you want to add to the messaging
bus
• port—Required if you are adding a WebSphere MQ server to the messaging bus
• channel—Required if you are adding a WebSphere MQ server to the messaging bus
• securityAuthAlias—Required if you are adding a WebSphere MQ server to the
messaging bus
Frequently used optional arguments:
• fileStore—Store messages in the file system instead of in the file system. Do not use
this argument and the dataStore argument.
• dataStore—Store messages in a database instead of in a database. Do not use this
argument and the dataStore argument.
• trustUserIds—You might choose to use this argument if you are making a WMQ
server a bus member.
• transportChain—You might choose to override the default transport chain that com-
municates with an WMQ server.
Occasionally used optional arguments:
• logSize—The size, in megabytes, of the log file.
• logDirectory—The name of the log files directory.
• minPermanentStoreSize—The minimum size, in megabytes, of the permanent store
file.
• maxPermanentStoreSize—The maximum size, in megabytes, of the permanent store
file.
• unlimitedPermanentStoreSize—true if the permanent file store size has no
limit; false otherwise.
• permanentStoreDirectory—The name of the store files directory for permanent data.
• minTemporaryStoreSize—The minimum size, in megabytes, of the temporary store file.
• maxTemporaryStoreSize—The maximum size, in megabytes, of the temporary store file.
• unlimitedTemporaryStoreSize—true if the temporary file store size has no
limit; false otherwise.
• temporaryStoreDirectory—The name of the store files directory for temporary data.
• schemaName—The name of the database schema used to contain the tables for the data
store. This only matters if you are creating data tables, and then it only matters if you have
some special schema that you want to substitute for the standard schema that IBM uses.
• createDefaultDatasource—When adding a server to a bus, set this to true if a
default datasource is required. When adding a cluster to a bus, this parameter must not
be supplied.
createSIBDestination
This method creates either a queue or a topic or a link on an existing bus member to some other bus.
Required arguments:
• bus—The name of the bus that this destination will serve.
• name—Destination name.
• type—Destination type must be one of the following (Alias|Foreign|Port|
Queue|TopicSpace|WebService).
Although the following arguments are not marked “mandatory,” you are required to use some of
them. You have to specify either the server or the cluster or WebSphere MQ server that will host
this destination. If the destination is really a link to some other bus, there are several additional
arguments you must supply. If you want to an individual server to host this destination, you must
specify the server name and the node name of that server. If you want an entire cluster to host this
destination, you must specify the name of the cluster and you may not specify a node name or a
server name. If you want to add a WMQ server as a bus member, supply a WebSphere MQ server
name, a WMQ queue name, and whether or not to use RFH2. Omit node, server, and cluster argu-
ments. If this destination will be an alias for another SIBus, then aliasBus, targetBus, and
targetName must also be supplied. If this destination will be a link to a foreign bus (such as MQ
Series), then foreignBus must also be supplied.
• node—To assign the destination to a server, supply node name and server name but not
cluster name or WebSphere MQ server name.
• server—To assign the destination to a server, supply node name and server name but
not cluster name or WebSphere MQ server name.
• wmqServer—To assign the destination to a WebSphere MQ server, supply a Web-
Sphere MQ server name but not node, server name, or cluster name.
• wmqQueueName—The name of the WebSphere MQ queue for messages. This must be
specified with the WebSphere MQ server name but not node, server name, or cluster
name.
• useRFH2—Determines if messages sent to the WebSphere MQ destination have an
RFH2 header or not. This must be specified with the WebSphere MQ server name but
not node, server name, or cluster name.
Steps:
• defaultForwardRoutingPath—You normally don’t have to set this unless you
have a complex bus topology. If you do have to perform this step, these are the argu-
ments you will have to supply. These arguments are passed as a collection.
• Destination—Destination name. This argument is mandatory.
• bus—Bus name.
createSIBEngine
This method creates a messaging engine for the specified bus member. Normally, you do not need
to call this method because a messaging engine gets created when you add a member to a bus.
Required argument:
• bus—The name of the bus to which the bus member belongs.
Although the following arguments are not marked “mandatory,” you are required to use some of
them. You must use at least one, and possibly two, of the next three arguments in order to properly
identify the bus member that will contain this SIBEngine:
• node—To create a messaging engine on a server, supply node and server name but not
cluster name.
• server—To create a messaging engine on a server, supply node and server name but
not cluster name.
• cluster—To create a messaging engine on a cluster, supply cluster name but not node
and server name.
Frequently used optional arguments:
• description—Use this text to describe the messaging engine.
• fileStore—Indicates that a file store is to be created. No value is needed.
• dataStore—Indicates that a data store is to be created. No value is needed.
Argument that affects bus security:
• authAlias—The name of the authentication alias used to authenticate the messaging
engine to the database.
Occasionally used optional arguments:
• initialState—Whether the messaging engine is started or stopped when the associ-
ated application server is first started. Until started, the messaging engine is unavailable
(Stopped | Started).
• highMessageThreshold—The maximum total number of messages that the messag-
ing engine can place on its message points.
• logSize—The size, in megabytes, of the log file.
createSIBJMSConnectionFactory
This method creates an SIB JMS connection factory at the scope identified by the target object.
Applications need this factory to obtain an SIBJMSQueue object or an SIBJMSTopic object.
Target (mandatory):
The management scope at which this factory is visible. This scope must be a configuration ID.
Required arguments:
• busName—The bus name.
• name—The name of the SIB JMS connection factory.
• jndiName—The JNDI name of the SIB JMS connection factory.
Optional arguments you might need if you want to secure the bus:
• xaRecoveryAuthAlias—The authentication alias used during XA recovery processing.
• userName—The user name that is used to create connections from the connection factory.
• password—The password that is used to create connections from the connection factory.
• targetTransportChain—The name of the protocol that should be used to connect
to a remote messaging engine.
createSIBJMSQueue
This method creates the JMS wrapper object that applications use in order to interact with a
queue on the bus.
Target (mandatory):
The management scope at which this queue is visible. This value must be a configuration ID.
Required arguments:
• busName—The bus name.
• name—The name of the SIB JMS queue.
• jndiName—The JNDI name of the SIB JMS queue.
• queueName—The name of the underlying SIB queue to which the queue points.
createSIBJMSTopic
This method creates the JMS wrapper object that applications use in order to interact with a topic
on the bus.
Target (mandatory):
The management scope at which this topic is visible. This scope must be a configuration ID.
Required arguments:
• busName—The bus name.
• name—The name of the SIB JMS topic.
• jndiName—The JNDI name of the SIB JMS topic.
Frequently used optional arguments:
• topicSpace—The name of the underlying SIB topic space to which the topic points.
• topicName—The topic to be used inside the topic space (for example, books/scripting/
WebSphere).
• description—Any text that describes this topic for the purpose of documenting this
part of your topology. This description will show up in the Admin Console.
• priority—The priority for messages. Whole number in the range 0 to 9.
• deliveryMode—The delivery mode for messages. Legal values are (Application |
NonPersistent | Persistent).
createSIBJMSActivat ionSpec
This method creates the plumbing that activates a Message Driven Bean when an appropriate
message arrives.
Target (mandatory):
Scope of the SIB JMS resource adapter to which the activation specification will be added.
This scope must be a configuration ID.
Required arguments:
• name—Any arbitrary name you would like to call this activation specification.
• jndiName—JNDI name of the activation specification.
• destinationJndiName—JNDI name of an SIBDestination.
Optional arguments you might need if you want to secure the bus:
• authenticationAlias—Security credentials. The configuration ID of a JAASAuthData
object.
• userName—User name.
• password—Password.
• targetTransportChain—The name of the protocol that should be used to connect
to a remote messaging engine.
Frequently used optional arguments:
• busName—Name of the bus to connect to.
• subscriptionDurability—Whether a JMS topic subscription is durable or nondurable.
• subscriptionName—The subscription name needed for durable topic subscriptions.
• clientId—Client identifier. Required for durable topic subscriptions.
• durableSubscriptionHome—Name of the durable subscription home. This identi-
fies the messaging engine where all durable subscriptions accessed through this activa-
tion specification are managed.
• shareDurableSubscriptions—Used to control how durable subscriptions are shared.
• shareDataSourceWithCMP—Used to control how data sources are shared.
Occasionally used optional arguments:
• acknowledgeMode—How the session acknowledges any messages it receives.
• maxBatchSize—The maximum number of messages received from the messaging
engine in a single batch.
• maxConcurrency—The maximum number of endpoints to which messages are deliv-
ered concurrently.
• target—The SIB JMS activation specification new target value.
• targetType—The SIB JMS activation specification new target type value. Legal val-
ues are (BusMember | Custom | ME).
• targetSignificance—This property specifies the significance of the target group.
bus itself, the related JMS artifacts, and possibly some JAASAuthData artifacts. The two groups
of AdminTask methods that you will need any time one of your scripts deletes a messaging buses
and their component parts are as follows:
SIBAdminCommands
SIBJMSAdminCommands
Of the 70+ methods36 in these two groups, the methods you are most likely to need are the follow-
ing when you delete a bus or any of its components.
deleteSIBJMSActivationSpec
This method deletes an SIBJMSActivationSpec.
Target (mandatory):
The configuration ID of theactivation spec to be deleted.
deleteSIBJMSQueue
This method deletes an SIBJMSQueue.
Target (mandatory):
The configuration ID of the JMS queue to be deleted.
deleteSIBJMSTopic
This method deletes an SIBJMSTopic.
Target (mandatory):
The configuration ID of the topic to be deleted.
deleteSIBJMSConnectionFactory
This method deletes an SIBJMSConnectionFactory.
Target (mandatory):
The configuration ID of the connector factory to be deleted.
deleteSIBus
This method both the bus and all of the SIB components that make up the bus. Thus, bus mem-
bers, messaging engines, aliases, and foreign buses get deleted. This command also deletes the
new artifacts that are created when queues are assigned or mediated to a WebSphere MQ server
bus member, including the WebSphere MQ server bus members. However, none of the JMS
plumbing that sits on top of the bus gets deleted. Each of the JMS components must be deleted
separately. You must also separately delete queue managers that are associated with the bus using
WebSphere MQ server definitions (if applicable), messages residing on WebSphere MQ queue
managers (if applicable), or WebSphere MQ queues (if applicable).
36
The exact number will depend on your version of WebSphere Application Server and whether you have licensed any
of the more advanced product offerings.
Required argument:
• bus—The name, not the configuration ID, of the bus you wish to delete. Deleting any
SIB component requires a name rather than a configuration ID.
removeSIBusMember
Remove the configuration for the plumbing that makes a server a member of a messaging bus. Use
this method only if you are trying to remove one bus member. If you want to delete an entire bus, it
is not necessary to call this method. AdminTask.deleteSIBus() will delete all bus members.
Required argument:
• name—The name, not the configuration ID, of the bus this member belongs to.
Frequently used optional arguments:
(You must supply at least one and possibly two of the following optional arguments.)
• node—If the bus member is an individual application server, supply the name of the
node and the name of the server. Do not supply any of the other optional arguments.
• server—If the bus member is an individual application server, supply the name of the
node and the name of the server. Do not supply any of the other optional arguments.
• cluster—If the bus member is a cluster, supply cluster name. Do not supply any of the
other optional arguments.
• wmqServer—If the bus member is a WebSphere MQ server bus member, supply the
name of the WebSphere MQ server. Do not supply any of the other optional arguments.
deleteSIBDestination
Deletes a bus destination. Use this method only if you are trying to remove one bus destination. If
you want to delete an entire bus, it is not necessary to call this method. AdminTask
.deleteSIBus()37 deletes all bus destinations.
Required arguments:
• bus—The name of the bus.
• name—The name of the destination.
Frequently used optional arguments:
(You only need these arguments if the destination you are deleting is a foreign destination
or an alias destination.)
• aliasBus—If the destination to be deleted is an alias destination, then the aliasBus
parameter must be supplied if the alias bus for the destination is not the local bus.
37
See AdminTask.deleteSIBus() in this reference for details.
modifySIBus
This method modifies one or more items that are part of the configuration for a bus.
Required argument:
• bus—The name of the bus that will be modified.
Optional arguments that affect security:
• interEngineAuthAlias—Name of the authentication alias used to authorize com-
munication between messaging engines on the bus.
• mediationsAuthAlias—Name of the authentication alias used to authorize media-
tions to access the bus.
• busSecurity—Enables or disables bus security. This argument has no effect unless
you have already enabled administrative security.
• permittedChains—The permitted transport chains value can be set to one of the fol-
lowing: (ALL | SSL ENABLED | LISTED).
Frequently used optional arguments:
• highMessageThreshold—The maximum number of messages that any queue on the
bus can hold.
• description—Use this field to describe the role this bus plays in your topology.
Occasionally used optional arguments:
• protocol—The protocol used to send and receive messages between messaging
engines and between API clients and messaging engines.
• discardOnDelete—Indicate whether or not any messages left in a queue’s data store
should be discarded when the queue is deleted.
• configurationReloadEnabled—Indicate whether configuration files should be
dynamically reloaded for this bus.
• secure—You are not likely to use this argument because it has been deprecated. Use
busSecurity instead.
modifySIBEngine
This method modifies an SIBEngine. Notice that this method cannot change the decision to use a
filestore versus a database. That decision is made when the messaging engine is created.38
Required argument:
• bus—The name of the bus that will be modified.
Although the following arguments are not marked “mandatory,” you are required to use some of
them depending on whether you are modifying the SIBEngine of a bus member that is a server,
a cluster, or a WebSphere MQ server. If the SIBEngine belongs to a server and that server’s
name is not unique within the cell, then you must specify the node name as well. Remember, all
of the following are names, not configuration IDs:
• node—To specify a server bus member, supply node and server name but not cluster
name or WebSphere MQ server name.
• server—To specify a server bus member, supply node and server name but not cluster
name or WebSphere MQ server name.
• cluster—To specify a cluster bus member, supply cluster name but not node name,
server name, or WebSphere MQ server name.
• wmqServer—To specify an WebSphere MQ server bus member, supply WebSphere
MQ server name but not node name, server name, or cluster name.
Frequently used optional arguments:
• initialState—Whether the messaging engine is started or stopped when the associ-
ated application server is first started. Until started, the messaging engine is unavailable
(Stopped | Started).
• highMessageThreshold—The maximum total number of messages that the messag-
ing engine can place on its message points.
• defaultBlockedRetryTimeout—The default blocked retry interval for destinations
owned by this messaging engine.
modifySIBDestination
This method modifies either a queue or a topic or a link to some existing bus member or a link
to some other bus. Notice that these arguments all modify transport aspects of the bus
destination.
Required arguments:
• bus—The name, not the configuration ID, of the bus that this destination belongs to.
• name—The name, not the configuration ID, of the destination that is being modified.
38
See AdminTask.createSIBEngine() in this reference for details.
• mediationPoints—This step specifies a list of the mediation points that will be used
by users of the alias destination. The arguments for this step are passed as a collection.
Required arguments:
• identifier—The identifier for the mediation point to be used. There will be one of
these for each mediation point in the list.
• defaultForwardRoutingPath—This step specifies a default forward routing path.
The arguments that follow form a collection. The arguments for this step are passed as
a collection.
• destination—The name, not the configuration ID, of the destination where messages
get forwarded.
Optional argument:
• bus—The name, not the configuration ID, of the bus where messages get forwarded.
modifySIBJMSQueue
Modify the attributes of the supplied SIB JMS queue using the supplied attribute values. Notice
that the arguments to this method pretty much focus on modifying the mapping from the JMS
queue facade39—an SIBJMSQueue—to the underlying SIB queue, an SIBQueue. Contrast this
method with AdminTask.modifySIBDestination().
Target (mandatory):
The configuration ID, not the name, of the SIB JMS queue to be modified.
Frequently used optional arguments:
• busName—The name of the bus on which the queue resides.
• name—If you are changing the name of the queue, this is the SIB JMS queue’s new name.
• jndiName—If you are changing the JNDI name for the queue, this is the SIB JMS
queue’s new JNDI name.
• description—If you are changing the description of the queue, this is some text to
explain the purpose of this item in your topology.
• queueName—If you are changing the mapping from the JMS queue to the underlying
SIB queue, this is the name of the underlying SIB queue to which the queue will point.
• deliveryMode—The new delivery mode for messages. Legal values are (Applica-
tion | NonPersistent | Persistent).
• timeToLive—The new time in milliseconds to be used for message expiration.
A discussion of the Java Message Service is beyond the scope of this book. For a good introduction, consider
39
Chapter 33 of http://java.sun.com/j2ee/1.4/docs/tutorial/doc/index.html.
modifySIBJMSTopic
Modify the attributes of the supplied SIB JMS topic using the supplied attribute values. Notice
that this method focuses on modifying both the mapping from the JMS topic facade40 to some
underlying SIB topic, and the structure of a topic space and the topics that are part of that topic
space. Contrast this method with AdminTask.modifySIBDestination(). The JMS topic
façade is an SIBJMSTopic. The underlying SIB topic is part of a SIBTopicSpace.
Target (mandatory):
The configuration ID, not the name, of the SIB JMS topic space or topic to be modified.
Frequently used optional arguments:
• busName—The name of the bus on which the topic resides.
• name—If you are changing the name of the topic, this is the SIB JMS topic’s new name.
• jndiName—If you are changing the JNDI name for the topic, this is the SIB JMS
topic’s new JNDI name.
• description—If you are changing the description of the topic, this is some text to
explain the purpose of this item in your topology.
• topicSpace—If you are changing the hierarchy of topics in an SIB topic space or if
you are changing the mapping of a JMS topic to an SIB topic, this is the name of the
underlying SIB topic space.
• topicName—If you are changing the hierarchy of topics in an SIB topic space or if you
are changing the mapping of a JMS topic to an SIB topic, this is the SIB topic to be used
inside the SIB topic space (for example, stock/IBM or stock/IBM/common or
A discussion of the Java Message Service is beyond the scope of this book. For a good introduction, consider
40
Chapter 33 of http://java.sun.com/j2ee/1.4/docs/tutorial/doc/index.html.
listSIBuses
This method lists the configuration ID of every bus in a cell. It requires no arguments. If you
ever have to write code to change the values of attributes of the messaging bus or any of its
component parts, it is extremely important to make those changes using the
AdminTask.modifySIB* methods we document in the “Modifying a Bus and Bus Compo-
nents” section of this chapter. Even though this method returns configuration IDs, under no cir-
cumstances should you ever use AdminConfig to modify an attribute of any messaging bus
component. Some of those attributes have values that are dynamically generated. The appropri-
ate AdminTask methods respect those values. AdminConfig does not. Extract the name
attribute from the configuration ID and use the AdminTask methods.
showSIBus
This method displays some of the attributes of one particular bus.
Required argument:
• bus—The name, not the configuration ID, of the bus.
listSIBusMembers
This method lists the configuration ID of every member of a bus unless you limit the scope of this
query. In spite of the fact that this method returns a configuration ID, IBM strongly discourages
the use of AdminConfig methods on any part of a messaging bus configuration. You should use
the various AdminTask methods to display or modify messaging bus components:
Required argument:
• bus—The name, not the configuration ID, of the bus.
showSIBusMember
This method displays selected information about a particular bus member.
Required argument:
• bus—The name, not the configuration ID, of the bus.
Frequently used optional arguments:
(These are not really optional arguments. You must use either one or two of them depend-
ing on whether you want an individual server or a cluster or an MQ server.)
• node—To specify a server bus member, supply node, and server name but not cluster
name or WebSphere MQ server name
• server—To specify a server bus member, supply node, and server name but not cluster
name or WebSphere MQ server name.
• cluster—To specify a cluster bus member and supply cluster name, but not node
name, server name, or WebSphere MQ server name.
• wmqServer—To specify an WebSphere MQ server bus member and supply WebSphere
MQ server name but not node name, server name, or cluster name.
listSIBEngines
This method lists the configuration IDs of all the messaging engines within the scope you specify.
The argument(s) you must supply depend on the scope of your query. Acceptable scopes are
either an entire bus, a server in a given node, or a cluster.
Frequently used optional arguments:
(These are not really optional arguments. You must use either one or two of them depend-
ing on whether you want an individual server or a cluster or an MQ server.)
• bus—The bus whose engines are to be listed. You do not have to supply a bus name
unless you want to limit your query to engines that belong to one particular bus. Servers
and clusters can host more than one message bus.
• node—To list messaging engines on a server, supply node and server name but not clus-
ter name.
• server—To list messaging engines on a server, supply node and server name but not
cluster name.
• cluster—To list messaging engines on a cluster, supply cluster name but not node and
server name.
showSIBEngine
This method displays some attributes of one particular messaging engine. Unlike the
listSIBEngines method shown earlier, you cannot request attributes from more than one
messaging engine at a time. Thus, you must provide enough scoping information to narrow the
search to one particular messaging engine.
Required argument:
• bus—The name, not the configuration ID, of the bus that contains the messaging engine
you wish to query.
Frequently used optional arguments:
(Even though these are optional arguments, you must supply either one or two of them.)
• node—To show a messaging engine that belongs to a server, supply node, and server
name but not cluster name.
• server—To show a messaging engine that belongs to a server, supply node, and server
name but not cluster name.
• cluster—To show a messaging engine that belongs to a cluster and supply cluster
name but not node and server name.
• engine—The name of the engine to show.
showSIBJMSConnectionFactory
Return a list containing the SIB JMS connection factory’s attribute names and values.
Target (mandatory):
The configuration ID of the SIB JMS connection factory whose attributes are required.
listSIBJMSQueues
List all SIB JMS queues at the specified scope.
Target (mandatory):
The configuration ID of the server (the scope) at which to find the SIB JMS queues to list.
showSIBJMSQueue
Return a list containing the SIB JMS queue’s attribute names and values.
Target (mandatory):
The configuration ID of the SIB JMS queue whose attributes are required.
listSIBJMSTopics
List all SIB JMS topics at the specified scope.
Target (mandatory):
The configuration ID of the server (the scope) at which to find the SIB JMS topics to list.
showSIBJMSTopic
Return a list containing the SIB JMS topic’s attribute names and values.
Target (mandatory):
The configuration ID of the SIB JMS topic whose attributes are required.
listSIBMediations
This method lists the configuration IDs of all the mediations of a given bus.
Required argument:
• bus—The name, not the configuration ID, of the bus that contains the messaging engine
you wish to query.
showSIBMediation
This method displays some attributes of a given mediation of a given bus.
Required arguments:
• bus—The name, not the configuration ID, of the bus that contains the messaging engine
you wish to query.
• mediationName—The name, not the configuration ID, of the mediation.
Bus Security
The methods in this section come from the SIBAdminBusSecurityCommands group.
removeDefaultRoles
This method is pretty much the first step in securing a bus. As the name implies, it removes all
default authorizations for a given bus.
Required arguments:
• bus—The name, not the configuration ID, of the bus that contains the messaging engine
you wish to query.
removeGroupFromAllRoles
This method does just what the name implies. It revokes all permissions for a given group on a
given bus.
Required arguments:
• bus—The name, not the configuration ID, of the bus.
• group—The name of the group that will be denied all access to the bus.
removeUserFromAllRoles
This method does just what the name implies. It revokes all permissions for a given user on a
given bus.
Required arguments:
• bus—The name, not the configuration ID, of the bus.
• user—The name of the user that will be denied all access to the bus.
addGroupToBusConnectorRole
This method gives a group permission to connect to a bus. Without this permission, no member of
this group will be able to do anything on this bus.
Required arguments:
• bus—The name, not the configuration ID, of the bus.
• group—The name of the group that will be allowed to connect to the bus.
addUserToBusConnectorRole
This method gives a user permission to connect to a bus. Without this permission, this user will
not be able to do anything on this bus.
Required arguments:
• bus—The name, not the configuration ID, of the bus.
• user—The name of the user that will be allowed to connect to the bus.
addGroupToDefaultRole
This method gives a group permission to act in some role on a given a bus. Typically, you will
have to call this method several times to give a particular group enough permissions to be useful.
Required arguments:
• bus—The name, not the configuration ID, of the bus.
• group—The name of the group that will be allowed to perform some role on the bus.
• role—The role name. Allowable values are (Sender | Receiver | Browser |
Creator | IdentityAdopter).
addUserToDefaultRole
This method gives an individual user permission to act in some role on a given a bus. Typically, you
will have to call this method several times to give a particular group enough permissions to be useful.
Required arguments:
• bus—The name, not the configuration ID, of the bus.
• user—The name of the user that will be allowed to perform some role on the bus.
• role—The role name. Allowable values are (Sender | Receiver | Browser |
Creator | IdentityAdopter).
addGroupToDestinationRole
This method grants a group access to a destination for the specified destination role. This method
is not necessary unless you are trying to implement some very fine-grained access control
scheme. It will probably be necessary to call this method several times in order to grant a mean-
ingful set of permissions.
Required arguments:
• bus—The name, not the configuration ID, of the bus.
• destination—The name, not the configuration ID, of the destination.
• type—The destination type. Allowable values are (Queue | Port | Webservice |
TopicSpace | ForeignDestination | Alias).
• group—The name of the group that will receive this access.
• role—The role name. Allowable values are for Queues/Ports/WebServices (Sender |
Receiver | Browser | Creator | IdentityAdopter), for TopicSpaces (Sender
| Receiver | IdentityAdopter), for Aliases (Sender | Receiver | Browser |
IdentityAdopter), and for Foreign (Sender | IdentityAdopter).
addUserToDestinationRole
This method grants a user access to a destination for the specified destination role. This method is
not necessary unless you are trying to implement some very fine-grained access control scheme.
It will probably be necessary to call this method several times in order to grant a meaningful set
of permissions.
Required arguments:
• bus—The name, not the configuration ID, of the bus.
• destination—The name, not the configuration ID, of the destination.
• type—The destination type. Allowable values are (Queue | Port | Webservice |
TopicSpace | ForeignDestination | Alias).
• user—The name of the user that will receive this access.
• role—The role name. Allowable values are for Queues/Ports/WebServices (Sender |
Receiver | Browser | Creator | IdentityAdopter), for TopicSpaces (Sender
| Receiver | IdentityAdopter), for Aliases (Sender | Receiver | Browser |
IdentityAdopter), and for Foreign (Sender | IdentityAdopter).
addGroupToTopicRole
This method gives a group permission to access the topic for the specified role. This method is
not necessary unless you are trying to implement some very fine-grained access control scheme.
Required arguments:
• bus—The name, not the configuration ID, of the bus.
• group—The name of the group that will receive this access.
• role—The role name. Allowable values are (Sender | Receiver | IdentityAdopter).
• topic—The name of the topic.
• topicSpace—The name of the topic space that contains this topic.
addGroupToTopicSpaceRootRole
This method gives a group permission to access a given topic space root for the specified role.
This method is not necessary unless you are trying to implement some very fine-grained access
control scheme.
Required arguments:
• bus—The name, not the configuration ID, of the bus.
• group—The name of the group that will receive this access.
• role—The role name. Allowable values are (Sender | Receiver | IdentityAdopter).
• topicSpace—The name of the topic space that contains this topic.
addUserToTopicRole
This method gives a user permission to access the topic for the specified role. This method is not
necessary unless you are trying to implement some very fine-grained access control scheme.
Required arguments:
• bus—The name, not the configuration ID, of the bus.
• user—The name of the user that will receive this access.
• role—The role name. Allowable values are (Sender | Receiver | IdentityAdopter).
• topic—The name of the topic.
• topicSpace—The name of the topic space that contains this topic.
addUserToTopicSpaceRootRole
This method gives a user permission to access a given topic space root for the specified role. This
method is not necessary unless you are trying to implement some very fine-grained access control
scheme.
Required arguments:
• bus—The name, not the configuration ID, of the bus.
• user—The name of the user that will receive this access.
• role—The role name. Allowable values are (Sender | Receiver | IdentityAdopter).
• topicSpace—The name of the topic space that contains this topic.
listAllDestinationsWithRoles
This method lists all destinations that have roles defined for them on a given bus.
Required arguments:
• bus—The name, not the configuration ID, of the bus.
• type—The destination type. Allowable values are (Queue | Port | Webservice |
TopicSpace | ForeignDestination | Alias).
listAllForeignBusesWithRoles
This method lists all foreign buses that have roles defined for them on a given bus.
Required argument:
• bus—The name, not the configuration ID, of the bus.
listAllTopicsWithRoles
This method lists all topics within a given topic space that have roles defined on them for a
given bus.
Required arguments:
• bus—The name, not the configuration ID, of the bus.
• topicSpace—The name of the topic space to search.
listAllRolesForGroup
This method lists all roles defined on a given group on a given bus.
Required arguments:
• bus—The name, not the configuration ID, of the bus.
• group—The name of the group.
listAllRolesForUser
This method lists all roles defined on a given user on a given bus.
Required arguments:
• bus—The name, not the configuration ID, of the bus.
• user—The name of the user.
listGroupsInBusConnectorRole
This method lists all groups that have permission to connect to this bus.
Required argument:
• bus—The name, not the configuration ID, of the bus.
listGroupsInDefaultRole
This lists all groups in a given role on a given bus.
Required arguments:
• bus—The name, not the configuration ID, of the bus.
• role—The role name. Allowable values are (Sender | Receiver | Browser | Creator |
IdentityAdopter).
listGroupsInDestinationRole
This method lists the groups in the specified role in the destination security space role for the
given destination on a given bus.
Required arguments:
• bus—The name, not the configuration ID, of the bus.
• destination—The name of the destination.
• type—The destination type. Allowable values are (Queue | Port | Webservice |
TopicSpace | ForeignDestination | Alias)
• role—The role name. Allowable values are for Queues/Ports/WebServices (Sender |
Receiver | Browser | Creator | IdentityAdopter), for TopicSpaces
(Sender | Receiver | IdentityAdopter), for Aliases (Sender | Receiver |
Browser | IdentityAdopter), and for Foreign (Sender | IdentityAdopter).
listGroupsInTopicRole
This method lists the groups who have a given role in a given topic in a given topic space on a
given bus.
Required arguments:
• bus—The name, not the configuration ID, of the bus.
• topicSpace—The name of the topic space that contains the topic.
• topic—The name of the topic.
• role—The role name. Allowable values are (Sender | Receiver | IdentityAdopter).
listGroupsInTopicSpaceRootRole
This method lists the users who have a given role in a given topic space on a given bus.
Required arguments:
• bus—The name, not the configuration ID, of the bus.
listUsersInBusConnectorRole
This method lists all users that have permission to connect to this bus.
Required argument:
• bus—The name, not the configuration ID, of the bus.
listUsersInDefaultRole
This lists all users in a given role on a given bus.
Required arguments:
• bus—The name, not the configuration ID, of the bus.
• role—The role name. Allowable values are (Sender | Receiver | Browser |
Creator | IdentityAdopter).
listUsersInDestinationRole
This method lists the users in the specified role in the destination security space role for the given
destination on a given bus.
Required arguments:
• bus—The name, not the configuration ID, of the bus.
• destination—The name of the destination.
• type—The destination type. Allowable values are (Queue | Port | Webservice |
TopicSpace | ForeignDestination | Alias).
• role—The role name. Allowable values are for Queues/Ports/WebServices (Sender |
Receiver | Browser | Creator | IdentityAdopter), for TopicSpaces (Sender
| Receiver | IdentityAdopter), for Aliases (Sender | Receiver | Browser |
IdentityAdopter), and for Foreign (Sender | IdentityAdopter).
listUsersInTopicRole
This method lists the users who have a given role in a given topic in a given topic space on a
given bus.
Required argument:
• bus—The name, not the configuration ID, of the bus.
listGroupsInTopicSpaceRootRole
This method lists the users who have a given role in a given topic space on a given bus.
Required arguments:
• bus—The name, not the configuration ID, of the bus.
• topicSpace—The name of the topic space that contains the topic.
• role—The role name. Allowable values are (Sender | Receiver | IdentityAdopter).
Summary
Conceptually, messaging is simple. It is just an architecture for passing an arbitrary sized mes-
sage from a sender (the producer) to a recipient (the consumer). There are many ways to cus-
tomize41 that simple architecture. That means your configuration for messaging can be simple or
complex according to the needs or your enterprise. We gave you some simple code that you can
extend and enhance according to your needs, and we showed you how to secure a messaging
bus. In the next chapter, we cover Web services.
For many useful details about both messaging architecture and configuration, see “WebSphere Application Server
41
Administering Web
Services
The AdminApp, AdminConfig, and AdminTask scripting objects are all useful in configuring
Web services in WebSphere. In this chapter, we consider the following topics:
What are Web services?
• The Java standards, JAX-RPC (JSR-101) and JAX-WS (JSR-224), used to author Java-
based Web services.
• The Web service for Java EE (JSR-109) specification, which dictates how Java-based
Web services run in environments such as WebSphere.
The WSEE (JSR-109) Deployment models supported by WebSphere:
• SOAP/HTTP using a “Plain Old Java Object” (POJO)
• SOAP/HTTP using a Stateless Session EJB
• SOAP/JMS using a Stateless Session EJB
WebSphere scripting support for Web services:
• The introduction of Web service policies, which can simplify almost inherently complex
administrative tasks related to Web services.
The WS-Security specification, which covers such things as authentication, non-repudiation,
confidentiality, and integrity for Web services and presents examples of scripted administration
of these issues.
345
WS-I Profiles
A WS-I profile is basically a standard that lists other existing standards and explains how to use
them in combination to achieve interoperability—across all languages, operating systems, and
hardware platforms. There are many (some would argue far too many) additional specifications.
Only a very few, such as WS-Security, are true standards. And even amongst those, interpretation
varies because in the real world specifications are not unambiguous.
The WS-I profiles dictate which of the myriad WS-* specifications are actually to be con-
sidered interoperable standards—therefore permissible to use—and how to use them in the
appropriate manner. The WS-I also provides conformance testing tools to help ensure that inter-
operability is achieved.
@WebService
public class PingService {
public String ping(String request) {
return request;
}
}
Developers can implement the class in Rational® Application Developer or other similar
tooling, along with client code, and deliver the resulting EAR file(s) to the administrator for
deployment and administration.
A Java client might be as simple as the code in Listing 15.2.
The sole purpose for showing you these trivial examples is to emphasize the point that there
is nothing magical happening in the programs themselves. Other than an annotation,
@WebService, in the service and the use of PingServiceProxy in the client, there was nothing
“Web service-ish” in either of them. The essential magic to make them Web service providers and
Web service requesters, respectively, happens within vendor-provided code generators or within
WebSphere Application Server1 itself. And that’s the catch and the reason for the code just shown.
Administrators configure the magic (a.k.a., the Web services runtime environment) to make
interesting things, such as WS-Security or other non-default behaviors, happen. A sample partial
WSDL2 for this Web service is shown in Listing 15.3.
Listing 15.3 Partial WSDL Document for the ping Web Service
<message name=”ping”>
<part type=”xsd:string” name=”request”/>
</message>
1
WebSphere Application Server provides the underlying Web service runtime environment.
2
Web Services Descriptor Language. This document tells clients of the service how to request your service and what,
if anything, will return to them when they make a request. For extensive details, see http://www.w3.org/TR/wsdl20/.
<message name=”pingResponse”>
<part type=”xsd:string” name=”return”/>
</message>
<portType name=”PingService”>
<operation name=”ping”>
<input message=”ping”/>
<output message=”pingResponse”/>
</operation>
</portType>
A pre-existing XML type was used here, so there is no section for defining types, and the
binding and service sections are not shown. The resulting messages would be similar to what is
presented in Listing 15.4.
Listing 15.4 SOAP Messages Exchanged Between Client and ping Service
Request message from client:
<soap:Envelope>
<soap:Headers/>
<soap:Body>
<ping>
<request>Hello</request>
</ping>
</soap:Body>
<soap:/Envelope>
Again, this is nothing fancy. But, it gets a lot more complicated when you want to take advan-
tage of additional capabilities, such as digitally signing the messages and encrypting the messages.
When that happens, the code stays the same, and the WSDL stays the same. However, the way you
configure the Web services runtime environment will have to change. The information in the mes-
sage headers will explode in size and complexity. In this example, those headers are empty now. As
you add features to the Web service, the runtime environment must add quite a bit of information to
the header section of each message. The Web services runtime environment decides what to put in
various headers based on configuration data that the administrator’s supply. Much of Web services’
flexibility comes directly from configuration decisions that the administrators make.
• Individual Web service methods can be restricted so that only authorized users can
invoke them.
• An EJB using SOAP over JMS. Developers write a normal Stateless Session Bean—a
type of Enterprise Java Bean (EJB). That EJB is deployed as part of an EJB module into
the EJB container. Because the EJB exposes the Web service interface and does not
natively communicate with JMS, the Web service runtime is responsible for making the
connection. IBM’s JAX-RPC runtime, for example, provides a Message-Driven Bean
(MDB) to help bridge the gap between JMS and the Web service.
• As an administrator, there is more work to do here because you need to create the
JMS resources, that is, JMS queues for exchanging messages and an Activation
Specification to link our request queue to the MDB.
• This model includes the advantages of the EJB using SOAP over HTTP approach
and others, such as: The Web service requester and provider are decoupled in time.
At the time that the request is made, the requester only needs to be able to post to a
queue. Messages from the queue can be delivered when the Web service provider is
available.
• Because this deployment model does not use HTTP, it is not WS-I–compliant. The
reason for this is that there is not an accepted standard for SOAP over JMS across
all of the Java EE vendors. But work is progressing rapidly on such a standard, and
WebSphere V7 has support for the current draft.
Irrespective of the ability to interoperate with other JMS providers, JMS is still not interoperable
with non-Java platforms. Again, the mandate for HTTP is to ensure interoperability between Web
services, regardless of programming language, operating system, or hardware platform.
3
See the “Create and Modify Methods” section in Chapter 8, “The AdminConfig Object,” for details.
In Listing 15.5, you can see four applications: two Web service requesters and two Web ser-
vice providers. The method named and the documentation for AdminTask.listWebServices()
and related methods might lead you to believe that you can use these methods to investigate the
Web services, but look closely at the results in Listing 15.6.
Note, too, that in Listing 15.6, AdminTask.listWebServices()4 only listed the service
provider. If you want to see the client(s), you have to add a parameter as shown in Listing 15.7:
In Listing 15.7, the command has only provided information about JAX-WS clients. If you
are using JAX-RPC-based Web services, these commands provide no information. The
AdminTask methods only provide information for JAX-WS web services and their clients.
[[logicalEndpoint PingServicePort] ]
This might not seem useful, but that logicalEndpoint attribute is necessary for the
AdminTask.listWebServicesOperations command, as shown in Listing 15.9.
4
See details in the reference section of this chapter.
5
See details in the reference section of this chapter.
6
See details in the reference section of this chapter.
[[operation ping] ]
This section has listed the available Web service operation(s), but not sufficiently enough
for the developers to understand nor in sufficient detail to understand the SOAP messages that
might be exchanged. For that, you need the WSDL for the Web services.
The WSDL related for the Web service will be written to the specified location. The .zip is not
really optional. You can specify whichever filename you want, but the result will still be a ZIP-
formatted archive, no matter what you call it. One reason is that WSDL documents support an
import operation. The document can be broken into multiple parts that are reusable components.
For example, the data types might be used in many different Web services using different mes-
sages. So WebSphere writes a ZIP-formatted archive to hold the possibly multiple parts that
makeup the logical document.
7
See details at http://www.w3.org/Submission/WS-Policy/.
• Policy Set Attachment—Associates a Web service with a policy set. Attachments can
be made at any of the following four levels:
• Application
• Web service
• Endpoint
• Operation
WebSphere V7 comes with sample policy set bindings, which you can use as examples for the
ones created here. You can list the available policy sets with AdminTask.listPolicySets()8
as in Listing 15.10.
Those are not all of the available policy sets. AdminTask.listPolicySets() takes a
parameter, policySetType, which can have one of several values: application, system,
system/trust, default, and application. The default is application (yes, despite the
seeming oddity, default is not the default). Regardless, the default does not show all available
policies, so you have to loop through them, as shown in Listing 15.11.
result:
application:
Username SecureConversation
8
See details in the reference section of this chapter.
9
See details in the reference section of this chapter.
# in each listing
policySet=”Username SecureConversation”
print \
AdminTask.getPolicySet([item % locals() for item in args])
result:
[
[version 7.0.0.0]
[name [Username SecureCon6yy4Z hyrgmhdti89iiiiiiiiooi0oo8mj
hi888535tversation]]
[default true]
[type application]
[description [This policy set provides message integrity
by digitally signing the body, the time stamp, and the
WS-Addressing headers. Message confidentiality is provided
by encrypting the body and the signature. Message
authentication is provided by using the Username Token.
This policy set follows the WS-SecureConversation and
WS-Security specifications.]]
]
Listing 15.13 shows that you can obtain details about a different policy set simply by
changing the name that is passed to AdminTask.getPolicySet().
result:
[
[version 7.0.0.0]
[name [Username WSSecurity default]]
[default true]
[type application]
[description [This policy set provides message integrity
by digitally signing the body, time stamp, and
WS-Addressing headers using RSA encryption.
Message confidentiality is provided by encrypting the body
and signature using RSA encryption. Message authentication
is provided by using the Username Token. This policy set
These two seem pretty similar when you look at the descriptions, except for the comment
about WS-SecureConversation. So what is the difference? There are different ways to explore
that topic, but a quick way to do so is to export the two policy sets,10 as shown in Listing 15.14,
and then view the results in an editor.
As it turns out, there are two policies in each of these policy sets: WS-Security and WS-
Addressing. By looking at the XML files for their WS-Addressing policies, you can immediately see
that they are identical, so these two policy sets differ only in their WS-Security policy configuration.
Alternatively, in Listing 15.15, you can see which policies are contained in a policy set by
using the AdminTask.listPolicyTypes()11 command.
10
See the details of AdminTask.exportPolicySet() in the reference section of this chapter.
11
See the details of AdminTask.listPolicyTypes() in the reference section of this chapter.
args.append(“%(policySet)s”)
And Listing 15.16 lists the attributes of the policy via the AdminTask.
getPolicyType()12 command.
But, there is a reason why you won’t see the voluminous output in this book. It is far easier
to view the XML representation of the policy than to view the response from that command. In
12
See details in the reference section of this chapter.
fact, although there are commands for setting the policy attributes, if you need to modify a policy,
you might well want to export13 the policy set, edit the WS-Policy files (those XML files in the
archive), and import14 the modified policy set.
Another important reason for exporting policy sets is that the Rational Application Devel-
oper (RAD) tool used by your programmers can use but cannot create policy sets (as of RAD
7.5.2), so the pattern of use is to export policy sets from WebSphere and import them into RAD.
As you’ve seen, a policy set describes a set of policies for how to apply various Web ser-
vice capabilities, such as WS-Security and WS-Addressing, to Web services. They are sharable
and reusable. In fact, given that you want Web services to be able to interoperate, the requester
and the provider need compatible policies. When they are installed in WebSphere, you would use
the same policy set with each.
Rather than use the default policy sets that come with WebSphere, we recommend you
make a copy. That way, you can avoid accidentally impacting other Web services when you
modify a policy set. A couple of AdminTask commands can help here: AdminTask.
listAttachmentsForPolicySet()15 and AdminTask.copyPolicySet().16 Both are shown
in Listing 15.17.
13
See details of AdminTask.exportPolicySet() in the reference section of this chapter.
14
See details of AdminTask.importPolicySet() in the reference section of this chapter.
15
See details in the reference section of this chapter.
16
See details in the reference section of this chapter.
args.append(“%(newPolicySet)s”)
args.append(“-newDescription”)
args.append(“%(newDescription)s”)
args.append(“-transferAttachments”)
args.append(“%(transferAttachments)s”)
The attachments (uses) of the policy set have been listed and copied, as well as a copy made
without copying any attachments so that there would be no worry about future change(s) uninten-
tionally impacting unrelated Web services.
As indicated, these commands have created the necessary messaging resources used with WS-
Security using the standalone keytool provided with WebSphere’s implementation of Java.17
Because this is using platform-specific bindings, rather than application-specific, let’s start by
copying one of the default bindings provided with WebSphere. You can query the default bindings
with AdminTask.getDefaultBindings().18
wsadmin>print AdminTask.getDefaultBindings()
[ [client [Client sample]] [provider [Provider sample]] ]
And you can easily copy the binding. In this case, you see the provider binding completed in
Listing 15.18, but we’re leaving the consumer binding as an exercise for you.
17
It is located in ${INSTALL_ROOT}/java/bin/keytool[.exe].
18
See details in the reference section of this chapter.
args.append(“%(newBinding)s”)
args.append(“-newDescription”)
args.append(“%(newDescription)s”)
sourceBinding=”Provider sample”
newBinding=”PingProviderBindings”
newDescription=”Bindings for WS-Security w/ the Ping service.”
Now you need to bind the physical keys and keystores to logical references that are used by
the WS-Security policy in our policy set. And this is where things get rather tricky. This is where
things get...ugly, to be honest. The WebSphere Application Server V7 Information Center topic,
Enabling secure conversation using wsadmin scripting, provides an example of what you need to
do. For all intents and purposes, it is presented without any explanation at all. You need to set
properties on the bindings, and there is basically no documentation on what those properties are
and how they need to be set. In cases such as this, once again, you can and should turn to the
Command Assistance feature of the Integrated Solutions Console to see the commands that it
generates. It does not generate optimal commands, but it does provide the necessary properties.
You can also query the current set of properties using AdminTask.getBindings().19
Listing 15.19 shows the code.
Listing 15.19 Getting Binding Information
args=[]
args.append(“-policyType”)
args.append(“%(policyType)s”)
args.append(“-bindingLocation”)
args.append(“%(bindingLocation)s”)
args.append(“-bindingName”)
args.append(“%(bindingName)s”)
policyType=”WSSecurity”
bindingLocation=””
bindingName=”PingProviderBindings”
We’ll spare you the page or two of output that this emits.
19
See details in the reference section of this chapter.
bindingLocation=””
bindingName=”PingProviderBindings”
Now you need to perform the steps to bind the necessary resources for the WSSecurity
policy type. For the purposes of this example, these steps are as follows:
• Add the service’s keystore file as a “trust store.” This allows you to trust requesters
whose public keys are in your keystore.
• Configure the consumer of incoming signed requests to use the newly added trust store.
• Configure the generator used to generate your signed responses to use your keystore
and key.
• Configure the consumer of incoming encrypted requests to use your keystore and key.
• Configure the generator used to generate your encrypted responses to use your keystore
and the client’s key.
The AdminTask.setBinding() command is used for all of these steps. The primary parameter
of interest is one called attributes. You can see partial code for how this is used to add the key-
store as a trust store in Listing 15.21.
20
See details in the reference section of this chapter.
attr=[]
attr.append(pre+”name”)
attr.append(“%(trustAnchorName)s”)
attributes.append(attr)
attr=[]
attr.append(pre+”keystore.type”)
attr.append(“JKS”)
attributes.append(attr)
attr=[]
attr.append(pre+”storepass”)
attr.append(“%(storepass)s”)
attributes.append(attr)
...
keystorePath=”/tmp/pingServiceKeys.jks”
trustAnchorName=”PingServiceTrustStore”
storepass=”storew0rd”
There are many more parameters that need to be set in a working example. Please visit the
companion website, http://www.wasscripting.com, for complete examples.
Actually, one interesting thing is that because of the way AdminTask.setBinding()
works, you can combine many logical steps into one call, as they are all just properties of the
overall policy set binding.
After you have completed a policy set binding, you can export it, as is seen in Listing 15.22.
You might wish to import it into Rational Application Developer 7.5 or edit the bindings by hand
in a text editor.
bindingName=”Provider sample”
pathName=”/tmp/ProviderSampleBinding.zip”
AdminTask.exportBinding([item % locals() for item in args])
policySet=”PingServicePolicySet”
appName=”PingServiceApplication”
attachmentType=”provider”
Listing 15.24 shows the configuration for the client side, also known as the requester side,
of a Web service.
You would never attach the policy sets for both the Web service requester and the Web ser-
vice provider to the same server. We’re just trying to illustrate all of the different constructs for
the -resources parameter to specify the level to which you want the policy set attached and
how those levels relate to one another. You would only build the resource reference out to the
desired level.
Notice, too, that other than the name of the WAR file, the resource specification was identi-
cal for both the Web service requester and provider.
21
See details in the reference section of this chapter.
result:
3263
[resource PingServiceClientApplication]
[resource WebService:/PingServiceClient.war: ... PingServiceService]
[resource WebService:/PingServiceClient.war: ...
PingServiceService/PingServicePort]
[
[resource WebService:/PingServiceClient.war: ...
PingServiceService/PingServicePort/ping]
[policySet PingServicePolicySet]
[policyApplied client]
[providerPolicySet false]
[attachmentId 3263]
[directAttachment true]
]
Listing 15.26 associates a policy set binding with an application and policy set attachment.
Listing 15.26 Associate Policy Set Binding with Application and Policy Set Attachment
args=[]
args.append(“-bindingScope”)
args.append(“%(bindingScope)s”)
args.append(“-bindingName”)
args.append(“%(bindingName)s”)
args.append(“-attachmentType”)
args.append(“%(attachmentType)s”)
attributes=[]
attr=[]
attr.append(“application”)
attr.append(“%(application)s”)
attributes.append(attr)
attr=[]
attr.append(“attachmentId”)
attr.append(“%(attachmentId)s”)
attributes.append(attr)
application=”PingServiceApplication”
attachmentId=”7”
AdminTask.setBinding(argList)
Additional Topics
This last section offers a brief overview of additional Web services functions not covered in detail
within this book.
Enable/Disable Endpoints
You can selectively enable and disable the JAX-WS Web services without having to stop the rest
of the application. This is performed using AdminControl and is discussed in the WebSphere
V7 Information Center topic, Administration of service and endpoint listeners.
WS-Notification
Web services are often point-to-point, but the WS-Notification specification permits them to par-
ticipate in a topic-oriented, publish-subscribe, communication model. WebSphere supports WS-
Notification, and you could configure those resources using scripting. There are a number of
sections in the WebSphere Information Center that provide additional information:
Mediations
Once you are using the Service Integration Bus, you can perform mediation on the incoming and
outgoing messages using SIB Mediations. Mediation refers to the ability to modify the routing
and content of messages. WebSphere comes with a powerful mediation feature built in, although
it is not as easy to use and deploy as the even more powerful capabilities provided by WebSphere
Enterprise Service Bus. For addition information, see the following:
• The WebSphere V7 Information Center topic: Administering Mediations
• IBM developerWorks: Mediations made simple (http://www.ibm.com/developerworks/
webservices/library/ws-mediation/)
Online References
The WebSphere Information Center is always a good source of information that you should
review. There are specific sections for learning about managing Web services, both in general and
specifically via scripting. In addition, we have selected a few of our favorite IBM developer-
Works articles that relate to the topics discussed in this chapter.
For additional reading on configuring WS-Security with WebSphere, we recommend the
IBM developerWorks tutorial, Message-level security with JAX-WS on WebSphere Application
Server v7 (https://www.ibm.com/developerworks/websphere/tutorials/0905_griffith/). It uses the
Integrated Solutions Console and Rational Application Developer, whereas we use scripting, but
it goes into more detail on the underlying WS-Security concepts.
22
See “Exporting the WSDL for a Web Service” section in this chapter for details.
AdminTask.methodName( target, \
‘[ -argument value -nextArgument value2 ‘ \
+ ‘-stepName [ -arg01 val01 -arg02 val02 ] ‘ \
+ ‘-nextStepName [ -arg03 val03] -yetAnotherStep ]’ )
There might or might not be a target. If there is, it might be a configuration ID or a name. There
might or might not be arguments as well. Most often, arguments are name/value pairs. There
might or might not be steps, and there might be more than one step. Think of steps as arguments
that take either a list of name/value pairs as their value or no argument at all. Bundle all the argu-
ments and all the steps into one big list and pass it to the method.
SIBWebServices Group
The methods in this group allow you to create Web services and wrap them around existing exe-
cutables as long as those executables can integrate with a messaging service. The Web services
that this group manipulates are the JAX-WS Web services.
createSIBWSInboundService
Creates an inbound service. This task cannot be performed when wsadmin is started in local mode.
Target (mandatory):
The configuration ID, not the name, of the service integration bus where the inbound ser-
vice will be created.
Required arguments:
• name—The administrative name of the outbound service.
• wsdlLocation—The Web service WSDL location.
Frequently used optional arguments:
• wsdlServiceNamespace—The Web service namespace.
• wsdlServiceName—The Web service name.
• uddiReference—The UDDI reference.
• destination—The name to use for the associated service destination.
Optional arguments that matter if you enable security:
• userId—The user ID to be used if WSDL is obtained through an authorizing proxy.
• password—The password to be used if WSDL is obtained through an authorizing proxy.
createSIBWSOutboundService
Creates an outbound service. This task cannot be performed when wsadmin is started in local
mode.
Target (mandatory):
The configuration ID, not the name, of the service integration bus where the outbound ser-
vice will be created.
Required arguments:
• name—The administrative name of the outbound service.
• wsdlLocation—The Web service WSDL location.
Frequently used optional arguments:
• wsdlServiceNamespace—The Web service namespace.
• wsdlServiceName—The Web service name.
• uddiReference—The UDDI reference.
• destination—The name to use for the associated service destination.
Optional arguments that matter if you enable security:
• userId—The user ID to be used if WSDL is obtained through an authorizing proxy.
• password—The password to be used if WSDL is obtained through an authorizing proxy.
createSIBWSEndpointListener
Create an endpoint listener on a service integration bus. An endpoint listener is the glue that ties a
Web service to a messaging bus.
Target (mandatory):
The configuration ID of the server where the endpoint listener will be created.
Required arguments:
• name—Name of the endpoint listener.
• urlRoot—Root of the endpoint address URL for Web services accessed using this end-
point listener.
• wsdlUrlRoot—Root of the HTTP URL where WSDL associated with this endpoint
listener is located.
Occasionally used optional argument:
• earFile—Location of the endpoint listener application EAR file.
connectSIBWSEndpointListener
Connect an endpoint listener to a service integration bus. An endpoint listener is the glue that ties
a Web service to a messaging bus. This task cannot be performed when wsadmin is started in
local mode.
Target (mandatory):
The endpoint listener to be connected.
Required argument:
• bus—The name of the service integration bus to which the endpoint listener will be
connected.
Occasionally used optional argument:
• replyDestination—Name to use for the connection’s reply destination.
addSIBWSInboundPort
Add an inbound port to an inbound Web service. This task cannot be performed when wsadmin is
started in local mode.
Target (mandatory):
The configuration ID of the inbound service to which the port will be added.
Required arguments:
• name—The name for the inbound port.
• endpointListener—The name of the associated endpoint listener.
Frequently used optional arguments: At least one, and possibly two, of these arguments
is actually required. If the endpoint listener lives in a cluster, you must supply the name of the
cluster. If the endpoint listener lives on an individual server, you must supply the server name and
the node name.
• cluster—The name of the cluster where the associated endpoint listener lives.
• node—The name of the node that contains the server that contains the endpoint listener
with which this port will be associated
• server—The name of the server where the associated endpoint listener lives.
• templatePort—The name of the port in the template WSDL to use as a basis for this
port’s binding.
addSIBWSOutboundPort
Add an outbound port to an inbound Web service. This task cannot be performed when wsadmin
is started in local mode.
Target (mandatory):
The configuration ID of the outbound service to which the port will be added.
Required arguments:
• name—The name for the outbound port.
• endpointListener—The name of the associated endpoint listener.
Frequently used optional arguments:
At least one, and possibly two, of these arguments is actually required. If the endpoint lis-
tener lives in a cluster, you must supply the name of the cluster. If the endpoint listener lives on an
individual server, you must supply the server name and the node name.
• cluster—The name of the cluster where the associated endpoint listener lives.
• node—The name of the node that contains the server that contains the endpoint listener
with which this port will be associated
• server—The name of the server where the associated endpoint listener lives.
• templatePort—The name of the port in the template WSDL to use as a basis for this
port’s binding.
publishSIBWSInboundService
Publish an inbound service to a UDDI registry. This task cannot be performed when wsadmin is
started in local mode.
Target (mandatory):
The configuration ID of the inbound service to be published.
Required argument:
• uddiPublication—The name of a UDDI publication for the inbound service.
Optional arguments that matter if you enable security:
• userId—User ID to be used if publishing is done through an authenticating proxy.
• password—Password to be used if publishing is done through an authenticating proxy.
KeyManagerCommands
A key manager determines which alias to use during the Secure Sockets Layer (SSL) handshake.
There is a default key manager. You can also create a custom key manager.
listKeyManagers
Reports the key managers installed in the product. The arguments serve to limit the scope of the
report.
createKeyManager
Creates a key manager.
Required argument:
• name—Specifies a name to uniquely identify a key manager.
Frequently used optional arguments:
• algorithm—Specifies the algorithm name of the TrustManager or KeyManager.
• scopeName—Specifies the management scope.
• provider—Specifies the provider.
Occasionally used optional argument:
• keyManagerClass—Specifies the custom class that implements the KeyManager
interface. You may not specify this argument if you specify either the provider or the
algorithm argument.
KeyStoreCommands
Keys are managed in keystores so the keystore type can be supported by WebSphere Applica-
tion Server, provided that the keystores can store the referenced key type. You can configure
keys and scope keystores so that they are visible only to particular processes, nodes, clusters,
and so on.
listKeyStoreTypes
List the supported keystore types. This method takes no arguments.
listKeyStores
List keystore objects. For the most part, the arguments serve to limit the scope of the query.
Frequently used optional arguments:
• all—Specifies true to list all keystores. True overrides the scopeName parameter. If
you do not specify this argument, the default value is false.
• scopeName—Limits the query to the specified management scope. This argument only
matters if you omit all or set all false.
• keyStoreUsage—Limits the query to keystores for a particular usage. If you omit this
argument, you get all keystore usages subject to any scope limitation you might have
specified.
createKeyStore
Creates a new keystore.
Required arguments:
• keyStoreName—Specifies the unique name to identify the keystore.
• keyStoreLocation—Specifies the name of the keystore file. This may either be a fully
qualified file name or a relative file name. We recommend passing a fully qualified file name.
• keyStoreType—Specifies one of the predefined keystore types. The value you pass
must be one of the values returned by AdminTask.listKeyStoreTypes().
Frequently used optional arguments:
• scopeName—Specifies the management scope.
• keyStorePassword—Specifies the password to open the keystore. This argument is
specified as optional, but if you try to create a keystore without a password, recent ver-
sions of WebSphere Application Server throw an exception.
• keyStoreDescription—Statement that describes the keystore.
• keyStoreProvider—Specifies the provider for the keystore.
• keyStoreIsFileBased—Keystore is file-based.
• keyStoreUsage—What the keystore can be used for. Permitted values are SSLKeys,
KeySetKeys, RootKeys, DeletedKeys, DefaultSigners, or RSATokenKeys.
• enableCryptoOperations—Specifies true to enable cryptographic operations on
hardware devices.
Occasionally used optional arguments:
• controlRegionUser—Specifies this field if creating a writable keystore object for the
control region’s keyring. This argument only matters in z/OS environments.
• servantRegionUser—Specifies this field if creating a writable keystore object for the
servant region’s keyring. This argument only matters in z/OS environments.
• keyStoreHostList—Specifies a comma-separated the list of hosts where the key-
store is remotely managed.
• keyStorePasswordVerify—Specifies the confirmation of the password to open the
keystore. Most scripts will not pass this value. If your script processes manually
generated responses, this argument exists to save your script the trouble of comparing
two password entries for equivalence.
• keyStoreReadOnly—Specifies whether the keystore can be written to or not.
• keyStoreInitAtStartup—Specifies whether the keystore needs to be initialized at
server startup or not.
• keyStoreStashFile—Specifies whether to stash the keystore password to a file or
not. This only applies to the CMS keystore type.
exchangeSigners
Exchange Signer Certificates between two keystores.
Required arguments:
• keyStoreName1—Keystore name that will exchange signers with another keystore.
• keyStoreName2—Keystore name that will exchange signers with another keystore.
• keyStoreScope1—Specifies the management scope.
• keyStoreScope2—Specifies the management scope.
Frequently used optional arguments:
• certificateAliasList1—Specifies colon-separated list of certificates whose
signer will be added to another keystore.
• certificateAliasList2—Specifies colon-separated list of certificates whose
signer will be added to another keystore.
getKeyStoreInfo
Returns information about a particular keystore.
Required argument:
• keyStoreName—Specifies the unique name to identify the keystore.
Frequently used optional argument:
• scopeName—Specifies the management scope.
listKeyFileAliases
List personal certificate aliases in a keystore file.
Required arguments:
• keyFilePath—Specifies the fully qualified name of the keystore file.
KeySetCommands
The key management infrastructure is based on two basic configuration object types: key sets and
key set groups. WebSphere Application Server uses a key set to manage instances of keys of the
same type. You can configure a key set to generate a single key or a key pair, depending on the key
or key pair generator class. A key set group manages one or more key sets and enables you to con-
figure and generate different key types at the same time. For example, if your application needs
both a secret key and key pair for cryptographic operations, you can configure two key sets, one
for the key pair and one for the secret key that the key set group manages. The key set group con-
trols the auto-generation characteristics of the keys, including the schedule. The framework can
automatically generate keys on a scheduled basis, such as on a particular day of the week and
time of day, so that key generation is done during off-peak hours.
createKeySet
Creates a key set.
Required arguments:
• name—Specifies the name that uniquely identifies a key set.
• password—Specifies the password for the key.
• keyStoreName—Specifies the unique name to identify the keystore.
• aliasPrefix—Specifies the key alias prefix name.
• maxKeyReferences—Specifies the maximum number of keys stored.
Frequently used optional arguments:
• isKeyPair—Specifies true if the key set is a key pair, false otherwise.
• deleteOldKeys—Specifies true to delete old keys during key generation, false to
retain old keys.
• scopeName—Specifies the management scope.
• keyStoreScopeName—Specifies the management scope of the keystore.
• keyGenerationClass—Specifies the class used to generate keys.
generateKeyForKeySet
Generate all the keys in a key set.
Required argument:
• keySetName—Specifies the name that uniquely identifies a key set.
Frequently used optional arguments:
• keySetScope—Specifies the management scope.
• keySetSaveConfig—Specifies true to automatically save the configuration23 with-
out calling AdminConfig.save() after adding the key reference, false to save to the
configuration with a separate command.
modifyKeySet
Modify the attributes of a key set.
Required argument:
• name—Specifies the name that uniquely identifies a key set.
Frequently used optional arguments:
• password—Specifies the password for the key.
• keyStoreName—Specifies the unique name to identify the keystore.
• aliasPrefix—Specifies the key alias prefix name.
• maxKeyReferences—Specifies the maximum number of keys stored.
• sKeyPair—Specifies true if the key set is a key pair, false otherwise.
• deleteOldKeys—Specifies true to delete old keys during key generation, false to
retain old keys.
• scopeName—Specifies the management scope.
• keyStoreScopeName—Specifies the management scope of the keystore.
• keyGenerationClass—Specifies the class used to generate keys.
PolicySetManagement Group
Policies are a very important component of WebSphere Application Server V7 architecture. See
Web Service Policy Sets section earlier in the chapter Web Service Policy Sets for details.
addPolicyType
The addPolicyType command creates a policy type with default values for the specified policy
set. You may indicate whether to enable or disable the added policy type.
23
This is the only method on any of the administrative scripting objects that has such a feature.
Required arguments:
• policyType—Specifies the name of the policy to add to the policy set.
• policySet—Specifies the policy set name.
Frequently used optional argument:
• enabled—If this parameter is set to true, the new policy type is enabled in the policy
set. If this parameter is set to false, the configuration is contained within the policy set,
but the configuration does not have an effect on the system.
createPolicySet
The createPolicySet command creates a new policy set. Policy types are not created with the
policy set. The default indicator is set to false.
Required argument:
• policySet—Specifies the name of this policySet.
Frequently used optional arguments:
• description—Adds a description for the policy set.
• policySetType—Specifies the type of policy set. The type must already exist.
createPolicySetAttachment
Creates a new policy set attachment. This method returns a value; specifically it returns an attach-
ment ID. You will need that when attaching a binding for the policy. You have two choices: You
can either assign it to a value at invocation time, or you can attempt to locate it later, using
AdminTask.getPolicySetAttachments().24
Required arguments:
• policySet—Specifies the policy set name. The policySet must already exist.
• resources—Specifies the names of the application or trust service resources.
Frequently used optional arguments:
• applicationName—Specifies the name of the application. This parameter applies to
application and client attachments. It is not applicable to trust service attachments.
• attachmentType—Specifies the type of policy set attachments. The value for this parame-
ter must be application, client, or system/trust. The default value is application.
24
See AdminTask.getPolicySetAttachments() for details.
listPolicyTypes
Returns a list of the names of the policies configured in the system, in a policy set, or in a bind-
ing. The arguments are optional. They serve to limit the scope of the policy types that are
returned.
Frequently used optional arguments:
• policySet—Specifies the policy set name. For a list of all policy set names, use the
listPolicySets command.
• attachmentType—Specifies the type of policy set attachments. The value for this parame-
ter must be application, client, or system/trust. The default value is application.
• bindingName—Specifies the name for the binding. The binding name is optional when
you are creating a new binding. A name is generated if it is not specified. The binding
name is required when you are changing an attachment to use a different existing binding.
• fromDefaultRepository—Indicates if the command should use the default repository.
• enabled—If this parameter is set to true, only the policy types that are enabled in the
policy set are listed. If this parameter is set to false, all of the policy types in the policy
set are listed.
listPolicySets
Returns a list of all existing policy sets. The arguments are optional. They serve to limit the scope
of the policy sets that are returned.
Frequently used optional argument:
• policySetType—Specifies the type of policy set. Specify application to list appli-
cation policy sets. Specify system/trust to list the trust service policy sets. The
default value for this parameter is application.
• fromDefaultRepository—Indicates if the command should use the default repository.
listAttachmentsForPolicySet
Lists the applications to which a specific policy set is attached.
Required argument:
• policySet—Specifies the policy set name. The policySet must already exist.
listAssetsAttachedToPolicySet
Lists the assets to which a specific policy set is attached.
Required argument:
• policySet—Specifies the policy set name. The policySet must already exist.
Frequently used optional argument:
• attachmentType—Specifies the type of policy set attachments. The value for this parame-
ter must be application, client, or system/trust. The default value is application.
getPolicySet
Returns general attributes, such as description and default indicator, for the specified policy set.
Required argument:
• policySet—Specifies the policy set name. For a list of all policy set names, use the
AdminTask.listPolicySets().
getPolicyType
Returns the attributes for a specified policy.
Required arguments:
• policySet—Specifies the policy set name.
• policyType—Specifies the name of the policy to add to the policy set. The name you
pass must be one of the types returned by calling some form of the
AdminTask.listPolicySets() command.25
25
See AdminTask.listPolicySets() for details.
getPolicySetAttachments
Lists the properties for all attachments configured for a specified application, client, or for the
trust service. All arguments here are optional; however, it is not possible to call this method with-
out arguments. See arguments for details.
Frequently used optional arguments:
• applicationName—Specifies the name of the application. This parameter applies to
application and client attachments. It is not applicable to system/trust service attach-
ments. You may not specify this argument for system/trust service attachments.
• attachmentType—Specifies the type of policy set attachments. The value for this
parameter must be application, client, or system/trust. The default value is application.
• expandResources—Provides expanded information that details the attachment prop-
erties for each resource. An asterisk (*) character returns all Web services.
• attachmentProperties—The attachment-specific properties. This must be some
value that can be converted into a java.util.Properties object.
getBinding
Returns the binding configuration for a specified policy type and scope.
Frequently used optional arguments:
• bindingName—Specifies the name for the binding. The binding name is optional when
you are creating a new binding. A name is generated if it is not specified. The binding
name is required when you are changing an attachment to use a different existing binding.
• policyType—Specifies the name of the policy to add to the policy set. The name you
pass must be one of the types returned by calling some form of the
AdminTask.listPolicySets() command.26
• attributes—Specifies the attribute values to update. If the attributes parameter is
not specified, the command only updates the binding location used by the specified attach-
ment. Any value you pass here must be convertible into a java.util.Properties
object.
• attachmentType—Specifies the type of policy set attachments. The value for this
parameter must be application, client, or system/trust. The default value is
application.
26
See listPolicySets for details.
getDefaultBindings
Returns the default binding names for a specified domain or server.
Frequently used optional argument:
• domainName—Specifies the name of the domain. The domain name is only required
when the domain is not the global security domain.
getRequiredBindingVersion
Returns the binding version that is required for a specified asset.
Required argument:
• assetProps—Specifies the asset, such as the application name.
importPolicySet
Imports a policy set from a compressed archive onto a server environment. A side-effect of the
existence of this method is that you can create policies in one of several ways. You can
manipulate the various parts of a policy with methods in this group, or you can edit XML files in
a text editor and import the complete set of XML files that make up a given policy.
Frequently used optional arguments:
• importFile—Specifies the path name of the archive file to import.
• defaultPolicySet—The name of the default policy set to import.
• policySet—Specifies the policy set name. For a list of all policy set names, use the
listPolicySets command.
• verifyPolicySetType—Verifies the policy set is of this type.
exportPolicySet
Exports a policy set as an archive that can be copied onto a client environment or imported onto a
server environment. A side-effect of the existence of this method is that you can create policies in
one of several ways. You can manipulate the various parts of a policy with methods in this group,
or you can edit XML files in a text editor and import the complete set of XML files that make up
a given policy.
Required arguments:
• policySet—Specifies the policy set name. The policySet must already exist.
• pathName—Specifies the path name of the archive file. It is recommended that you pass
a fully qualified file name. Regardless of the operating system that you use, you should
use a forward slash as a directory delimiter.
copyPolicySet
Creates a copy of an existing policy set. The default indicator is set to false for the new policy set.
You can indicate whether to transfer attachments from the existing policy set to the new policy set.
Required arguments:
• sourcePolicySet—Specifies the name of the existing policy set.
• newPolicySet—Specifies the name of the new policy set.
Frequently used optional arguments:
• newDescription—Adds a description for the policy set or binding.
• transferAttachments—If this parameter is set to true, all attachments transfer
from the source policy set to the new policy set. The default value is false.
validatePolicySet
Validates the policies in the policy set.
Required argument:
• policySet—Specifies the policy set name. For a list of all policy set names, use the
listPolicySets command.
importBinding
Imports a binding from a compressed archive onto a server environment. A side-effect of the exis-
tence of this method is that you can create bindings in one of several ways. You can manipulate
the various parts of a binding with methods in this group, or you can edit XML files in a text edi-
tor and import the complete set of XML files that make up a given binding.
Required argument:
• importFile—Specifies the path name of the archive file to import. It is recommended
that you pass a fully qualified file name. Regardless of the operating system that you
use, you should use a forward slash as a directory delimiter.
Frequently used optional arguments:
• bindingName—Specifies the name for the binding. The binding name is optional
when you are creating a new binding. A name is generated if it is not specified. The
binding name is required when you are changing an attachment to use a different exist-
ing binding.
exportBinding
Exports a binding as an archive that can be copied onto a client environment or imported onto a
server environment. A side-effect of the existence of this method is that you can create bindings
in one of several ways. You can manipulate the various parts of a binding with methods in this
group, or you can edit XML files in a text editor and import the complete set of XML files that
make up a given binding.
Required arguments:
• bindingName—Specifies the name for the binding. The binding name is optional
when you are creating a new binding. A name is generated if it is not specified. The
binding name is required when you are changing an attachment to use a different exist-
ing binding.
• pathName—Specifies the path name of the archive file. It is recommended that you pass
a fully qualified file name. Regardless of the operating system that you use, you should
use a forward slash as a directory delimiter.
copyBinding
Creates a copy of an existing binding.
Required arguments:
• sourceBinding—Specifies the name of the existing binding.
• newBinding—Specifies the name of the binding to which the bindings are copied.
Frequently used optional arguments:
• domainName—Specifies the name of the domain. The domain name is required when
newBinding is part of a security domain. This argument is not required when
newBinding is part of the global security domain.
• newDescription—Adds a description for newBinding.
27
See Chapter 12, “Scripting and Security,” for additional information about security domains.
setBinding
Updates the binding configuration for a specified policy type and scope. Use this command to add
a server-specific binding, update an attachment to use a custom binding, edit binding attributes,
or remove a binding. Although strictly speaking, none of the arguments here are required, as a
practical matter, you will find yourself passing bindingName very often.
Frequently used optional arguments:
• bindingName—Specifies the name for the binding. The binding name is optional
when you are creating a new binding. A name is generated if it is not specified. The
binding name is required when you are changing an attachment to use a different exist-
ing binding.
• bindingScope—Specifies the scope of the binding. The binding scope is only required
when you are changing an attachment to use an existing named binding or when you are
removing a named binding from an attachment.
• attachmentType—Specifies the type of policy set attachments. The value for this
parameter must be application, client, or system/trust. The default value is
application.
• replace—If you set this value to true, the new attributes provided from the command
replace the existing attributes. The default value is false.
• attributes28—Specifies the attribute values to update. If the attributes parame-
ter is not specified, the command only updates the binding location used by the speci-
fied attachment.
• policyType—Specifies the name of the policy to add to the policy set. This name
must be one of the names returned by AdminTask.listPolicyTypes().29
WebServicesAdmin Group
The methods in this group provide information about JAX-WS Web services provided by appli-
cations. The entire group is read-only. If you wish to change a JAX-WS Web service, you must
edit the WSDL file using the AdminApp.edit() method. If you wish to view any details of a
JAX-RPC Web service, you must examine the WSDL file.30 If you wish to change a JAX-RPC
Web service, you must edit the deployment.31
28
The system will attempt to create a Java Properties object from whatever value you pass here. That means you must
pass some Jython type that can be converted into a java.util.Properties object.
29
See AdminTask.listPolicyTypes() in this chapter.
30
See the AdminApp.publishWSDL() method description.
31
See AdminApp.edit() method and AdminApp.update() method as described in Chapter 10, “The
AdminApp Object.”
listWebServices
This method lists the deployed Web services in enterprise applications. As of this writing, if there
is no application name supplied, then all the Web services in the enterprise applications will are
be listed.
Frequently used optional arguments:
• application—The deployed enterprise application name that contains Web services.
• client—Set true if you want client information about the service. Either set to false
or omit it entirely to get server information about the service.
Steps:
1. J2EEWSStep—Lists the Web services.
listWebServiceEndpoints
Lists the Web service endpoints that are port names defined in a Web service in an enterprise
application.
Required arguments:
• application—The enterprise application name that contains the Web service(s).
• module—The module name within the aforementioned application that contains the
Web service(s).
• service—The Web service name within the aforementioned module whose attributes
you want.
Frequently used optional argument:
• client—Set to true if you want client information about the service. Either set to
false or omit it entirely to get server information about the service.
Steps:
1. J2EEWSStep—Lists the logical endpoints that are port names in a Web service.
listWebServiceOperations
Lists the Web service endpoints that are port names defined in a Web service in an enterprise
application.
Required arguments:
• application—The enterprise application name that contains the Web service(s).
• module—The module name within the aforementioned application that contains the
Web service(s).
• service—The Web service name within the aforementioned module whose attributes
you want.
• logicalEndpoint—The name of the logical endpoint within the Web service within
the aforementioned module whose attributes you want.
Frequently used optional argument:
• client—Set true if you want client information about the service. Either set false
or omit it entirely to get server information about the service.
Steps:
1. J2EEWSStep—Lists the operations in a Web service endpoint.
getWebService
Gets the attributes for a given Web service in a given enterprise application.
Required arguments:
• application—The enterprise application name that contains the Web service(s).
• module—The module name within the aforementioned application that contains the
Web service(s).
• service—The Web service name within the aforementioned module whose attributes
you want.
Frequently used optional argument:
• client—Set to true if you want client information about the service. Either set it to
false or omit it entirely to get server information about the service.
Steps
1. J2EEWSStep—Lists the attributes for a Web service.
listServices
Lists the services based on generic query properties. It provides more generic query functions than
listWebServices, listWebServiceEndpoints, listWebServiceOperations, and
getWebService commands.
One of the differences between Version 6.x and Version 7.0 of the product is the addition of some
script libraries to version 7.0 that provide routines to assist with common administration functions.
This chapter is primarily a reference to these modules, with some comments about their structure
and use. We would have preferred to include lots of examples with this chapter, but due to space
limitations, we chose to have a section in the companion website (http://www.wasscripting.com)
for these examples.
Library Organization
In the installation directory structure, you will find a new directory under the <WAS_HOME> direc-
tory named scriptLibraries. Within this directory, there are the following sub-directories:
• application
• resources
• security
• servers
• system
• utilities
Each of these sub-directories contain (either directly or indirectly)1 a directory named V70, which
in turn contains one or more Jython script files with a filename extension of .py. Using a
1
The resources subdirectory contains four directories (J2C, JDBC, JMS, and Provider), each of which contains a
V70 directory.
393
recursive directory listing of files with this extension, you can find the complete list of script
library files shown in Listing 16.1.2
How are these files made available to your scripts? Well, when the wsadmin command is
started, these directories are automatically added to the sys.path variable. The fact that these
directory names are added to the sys.path variable can be shown using a trivial loop construct,
as seen in Listing 16.2.4
2
One way to do this on *ix type systems would be to execute (find . -name “*.py”) from the scriptLibraries
directory.
3
The directory prefix was removed to allow the filenames to better display within this book.
4
The <WAS_HOME>\optionalLibraries\jython\Lib directory contains the standard Jython class files, and the
last entry (i.e., <WAS_HOME>\scripts) was added by the WAuJ.py profile.
C:/IBM/WebSphere/AppServer70/scriptLibraries/resources/Provider/V70
C:/IBM/WebSphere/AppServer70/scriptLibraries/security/V70
C:/IBM/WebSphere/AppServer70/scriptLibraries/servers/V70
C:/IBM/WebSphere/AppServer70/scriptLibraries/system/V70
C:/IBM/WebSphere/AppServer70/scriptLibraries/utilities/V70
C:\IBM\WebSphere\AppServer70\scripts
wsadmin>
Is there anything else? Oh, yeah. All of the Jython files in these directories are automati-
cally imported during the wsadmin environment initialization. You can see this using the dir()
command when wsadmin is first started, as shown in Listing 16.3.5
Listing 16.3 Autoloading of scriptLibraries
wsadmin>dir()
[‘AdminApp’, ‘AdminApplication’, ‘AdminAuthorizations’, ‘AdminBLA’,
‘AdminClusterManagement’, ‘AdminConfig’, ‘AdminControl’, ‘AdminJ2C’,
‘AdminJDBC’, ‘AdminJMS’, ‘AdminLibHelp’, ‘AdminNodeGroupManagement’,
‘AdminNodeManagement’, ‘AdminResources’, ‘AdminServerManagement’,
‘AdminTask’, ‘AdminUtilities’, ‘Help’, ‘TypedProxy’, ‘__builtin__’,
‘__doc__’, ‘__name__’, ‘bsf’, ‘imp’, ‘main’, ‘nested_scopes’, ‘sys’,
‘wasroot’]
wsadmin>
Some of the items returned by the dir() command prove quite useful. For example, if you
print <moduleName>.__file__, where <moduleName> is the name of the scripting library
file, the result is the fully qualified path and filename to the file from which the code was
imported. With having just looked at the scripting libraries directory structure, it should be no
surprise to see from where these files were imported.
The steps outlined here illustrate the fact that all of the *.py files within these directories
are automatically imported and are shown in Listing 16.4.
1. Create a trivial Jython file containing a function and save it in one of these directories, or
you can even create a new subdirectory under scriptLibraries directory (lines 1–7).
2. Start an interactive wsadmin scripting environment (lines 8–11). Note how the print
statements from the script file are displayed during the initialization phase of wsadmin
(lines 10–11).
3. Use the dir() command to verify that the new module exists and contains the defined
function (lines 14–17).
5
Remember that both nested_scopes and wasroot were added by the WAuJ.py profile.
OK, this shows that you can “add your own” library modules and have them automatically
loaded by wsadmin when it starts. In fact, you can also decide whether you want to include all, or
even any, of the existing script libraries. If not, you only need to move, remove, or rename the files
(so they no longer have an extension of .py).6
WARNING If you choose to do this, it will make your environment different from the one
created as part of the product installation process. As such, it could potentially interfere with
a future product update (such as installation of a Fix Pack or cumulative fix). Be sure to doc-
ument any and all changes to the scriptLibraries directory and provide a process for
reliably duplicating the expected and required environmental changes. It would also be rea-
sonable to include a mechanism for verifying that the expected files and changes are in place
and possibly restoring the original directory structure and contents prior to a product update.
This raises an interesting question, specifically, “What’s the best way to make libraries
available for a scripting environment?” Let’s review the options:
1. You could specify a file as a command-line option when wsadmin is started, using, for
example, something like wsadmin -profileName myLibrary.py ....
6
Remember, though, that the *.py files are compiled to filename$py.class in the same directory, so these too
need to be moved, removed, or renamed.
2. You could modify the appropriate wsadmin.properties file and include the fully
qualified path and filename on the com.ibm.ws.scripting.profiles directive, as
was suggested in Chapter 7, “Introduction to Admin Objects,” where the WAuJ.py pro-
file script was discussed.
3. You could create a new library file in an existing (or in a new) directory under
scriptLibraries.
4. You could create a scripts directory under <WAS_HOME> and place the library files
in it. This directory, if it exists, is added to the sys.path variable by the WAuJ.py
profile script.7
What’s the difference between placing a module in this scripts directory and placing it in
a subdirectory under scriptLibraries? The main difference is that during the initial-
ization of wsadmin, only the files with an extension of .py under the
scriptLibraries directory are automatically loaded (imported). Consequently, all of
these modules and their objects become immediately available for use by your scripts.
For modules in the scripts directory to be made available, just as with the library routines
provided with Jython, one of the various import statements would need to be used.
Is this a big deal? To some, it can be. Some people and organizations prefer the simplified approach
of not automatically loading library files. This means that before a library routine can be used, the
presence of an import statement documents which library routines or objects will be used by a
script. If you tend to execute many, small scripts and do not require the collection of script library
files, then the overhead associated with the automatic loading might not be to your liking.
On the other hand, you or your organization might prefer to standardize a set of library rou-
tines and objects that must be available for your scripting environment. In this case, you might
prefer to use, expand, or extend modules in the scriptLibraries directory structure.
• Display the help text and methods for the module (should the optional method/proce-
dure name be unspecified) or
• Display the help text for a specific module method/procedure name (should a valid
method/procedure name be provided).
We were hoping that it would be as useful as those seen earlier in Chapter 7. Unfortunately, the
help text for the script library modules does not have as much detail about the parameters as
expected. The parameters are not identified as required or optional, nor is any description about
7
WAuJ.py was covered in the first section of Chapter 7.
the parameters provided. That’s the bad news. The good news is that we have the source code to
each of the library modules to examine should we need to understand the following:
• A specific parameter and whether it is required or optional
• How the parameters are used within the method
• The wsadmin scripting objects that are used to implement the method
• How the library method parameters are related to the scripting object method parameters
The script that was used to display all of the script library help text is available on the download page
and is named ScriptLibrariesHelp.py. The sample output file that was generated when the script
was run is also available from the download page and is named ScriptLibrariesHelp.out.
Listing 16.5 shows one way to execute this script and some abbreviated output.8
One of the things that you can note about this script is how it refers to each of the script
library modules as an object. This is true even though the library modules are written in Jython,
instead of Java, which is pretty neat.
Because each of the library modules includes a help method, and each help method acts in
the same way, the help methods for the library modules are not discussed here.
8
If you choose to execute this script yourself, you are encouraged to redirect the output to a file because the output
generates more than 4,000 lines of text.
should cause an exception to be thrown. If, instead, you prefer to have the library method termi-
nate with a failure message, specify ’true’ for this value. Listing 16.6 shows an example use of
the default failonerror parameter (lines 3–11), as well as what happens if a value of ’true’
is provided (lines 12–22). Note how the interactive wsadmin session is terminated by the
uncaught exception.
Because this option parameter is on each and every one of the methods to be discussed, we
won’t describe it each and every time.
implemented.9 One of the similarities is that like the AdminTask object, many of the script
library methods are associated together into groups. For example, in the AdminApplication
object, in both the source code comment block at the beginning of the file and in the help text, the
53 methods are associated into the following six command groups:
Group 1: Install and uninstall applications (13 methods)
Group 2: Queries application configurations (8 methods)
Group 3: Update applications (14 methods)
Group 4: Export applications (3 methods)
Group 5: Configure application deployment (9 methods)
Group 6: Administer applications (6 methods)
What do you notice about these method names? Some of them are extremely long! It would be
very unlikely that anyone could type those long names without making at least one mistake.
Thank goodness for copy and paste. The good news about the long names, though, is the fact that
the purpose of the method is more likely to be understood just by looking at the method name.
Another thing that might catch your attention when you first look at these methods is the
fact all of them have something to do with installing or removing an application. What do these
9
Warning: Unfortunately, these script library files have some lines indented using spaces and others using tab charac-
ters. This is not a best practice, and a product defect has been opened to get this fixed. This warning is provided in case
you use an editor that uses other than the “default” operating system tab stops.
methods do that the AdminApp.install() method does not? Nothing. In fact each of these
methods uses the specified parameters to perform a specialized form of the
AdminApp.install() method. That is what these scripting libraries are all about—showing
you how you might want to build your own collection of specialized routines to perform actions
for your environment in a way that conforms to your policies and procedures.
What other differences exist between these methods and those found in the other scripting
objects? Unlike the other scripting objects, the scripting library methods:10
1. Display a message block with the method name and all specified parameter values.
2. Automatically save the configuration if the method changes the configuration.
3. Use positional parameters in the method signature, which forces all parameters to be
specified in the statements where the methods are called.
4. Display a message, upon exit, indicating the success or failure of the requested action.
What does this message block look like? Listing 16.7 shows an example interactive session
where one of the AdminApplication install methods gets invoked. Please note that this
example does something that I do not expect you to do, which is assign a reference to the function
to be called to a variable (fun, for example). The only reason for using this technique in this
example was to shorten the statement where the function was called to fit on a single line in this
book without having the line wrapped.
10
Other than the help() method, which returns the appropriate help text.
...
ADMA5013I: Application myApp installed successfully.
OK: installAppWithNodeAndServerOptions(‘myApp’, ‘C:\\referen...
The good thing about the installation methods in the AdminApplication module is that
they show how easy it can be to develop modules and methods that suit your particular needs. If
your workplace has guidelines for applications, they can be implemented and enforced by library
methods such as these. For example, you might be asked to use a specific set of installation
options or even use a particular naming convention for items. With scripting libraries like these,
you can enforce any kind of protocol or convention that is appropriate for your team, organiza-
tion, or business.
Yet another thing to consider is the value of grouping related methods together in a module.
In the case of this group of methods in the AdminApplication module, almost all of them can
be used to install an application. The only method that is not is the one that can be used to remove
an application (AdminApplication.uninstallApplication(), for example). Because the
application already exists, the only parameter that needs to be provided is the name of the appli-
cation to be removed.
Looking at the code used to implement the uninstallApplication() method, you can
see exactly how it does its job:
1. It verifies that the appName parameter value is not an empty string.
2. It verifies that the specified application is a deployed object (using the AdminConfig.
getid() method).
3. A message banner is displayed that identifies the task being performed and the values
being used to do the job.
4. It uses the AdminApp.uninstall() method to remove the application.
5. It uses the AdminConfig.save() method to save the configuration changes.
6. A status message is displayed indicating the success or failure of the task.
Almost all of the methods in the script library modules follow this same format. Those methods
with more parameters require more instructions to verify that every required parameter is valid,
but the concept is the same. One of the really nice things about the fact that these library modules
is that should you decide that you do not like something (for example, the ubiquitous banner mes-
sages that get displayed by each library method), you have a number of options:
1. You could edit the script library files (for example, to remove or disable the messages).11
2. You could create your own library files containing the same methods but in a different
library files that have your own versions of the code (such as without the messages).
11
This is not recommended because the script library files could be replaced during some product update.
This option has definite possibilities because these would be “new” library files and
would be unlikely to be replaced by a product update.
3. You could delete the scriptLibraries directory and all of its contents. This option
appeals to some because of the reduced number of module imports to be performed dur-
ing the wsadmin initialization phase.
4. You could leave the scriptLibraries in place but not make use of any of the library
files or the methods contained therein. This option appeals to those interested in devel-
oping their own script libraries, using their own standards and practices.
12
In addition to true and false, there is a possibility of -1 being returned should an error be encountered. In addi-
tion, an exception may also be raised. So you might want to consider calling these methods within a try/except
statement.
13
Unfortunately, there is a mistake in the code. In AdminApplication on line 4336, the value to be appended
should be nodeName, instead of node. So, if the getAppDeployedNodes() method is called to display the nodes
on which an application is deployed, and the application is deployed on a cluster, a NameError exception will be
generated.
14
I’m surprised that these grammatically incorrect names are used. I would have thought that they would be named some-
thing like updateSingleFileInAnAppWithUpdateCommand() and deleteSingleFileFromAnAppWithUpdate
Command().
must provide the application name, the fully qualified path and filename, and the content URI for
the specific file within the application.
The next few methods deal with manipulating (that is, adding, updating, or deleting) partial
applications to a deployed application. To do this, an input archive file (normally with a zip
extension) must be prepared. Then, one of the following methods should be executed:
• addPartialAppToAnAppWithUpdateCommand()
• updatePartialAppToAnAppWithUpdateCommand()
• deletePartialAppToAnAppWithUpdateCommand()
The addPartialAppToAnAppWithUpdateCommand() method uses the contents of the speci-
fied archive file to add things to a specific application. To do this, only the name of the application
to be updated and the (fully qualified) name of the input archive file need to be specified.
Likewise, the updatePartialAppToAnAppWithUpdateCommand() method will also
use the AdminApp.update() method to modify existing portions of a particular application. It
does so using the contents of the specified archive file, and the deletePartialAppToAnApp
WithUpdateCommand() method uses the specified archive file to remove parts of an existing
application.
The last method in this group, that is, updateEntireAppToAnAppWithUpdate
Command(), also uses the AdminApp.update() method and an input archive file to modify
an existing application. However, it’s not certain why it was decided that the following options
be included on this call:
usedefaultbindings
nodeployejb
MapWebModToVH
15
The reason this exception gets generated is because the method includes code to display the parameter values and to
do so has each parameter name displayed and tries to use the string concatenation operator (’+’) to concatenate the
parameter name with the parameter value. Unfortunately, this operator does not allow a number to be concatenated to
a string; only two strings may be concatenated.
16
A test is made to see if the parameter is an empty string or not. A non-empty string is “presumed valid.”
17
This is really unfortunate because the online documentation (http://publib.boulder.ibm.com/infocenter/
wasinfo/v7r0/index.jsp?topic=/com.ibm.websphere.base.doc/info/aes/ae/rxml_7libapp4.html) indicates that the
enableSSLTracking attribute has been deprecated and suggests that an empty string be specified.
startApplicationOnSingleServer()
startApplicationOnAllDeployedTargets()
stopApplicationOnSingleServer()
stopApplicationOnAllDeployedTargets()
startApplicationOnCluster()
stopApplicationOnCluster()
18
Remember that the file can be found under the scriptLibraries directory under the WebSphere Application
Server installation directory, e.g., <WAS_HOME>\scriptLibraries\application\V70\AdminBLA.py.
process the list of all BLA names, be prepared to handle the BLA entries for which no
description exists.
• createEmptyBLA(blaName, description=’’)—This method can be used to cre-
ate a new BLA and specify an optional description for it. The first parameter is required
and specifies the name of the BLA to be created. This method will either return a string
containing the BLA configuration ID, or an exception will be raised if the specified
BLA can’t be created (for example, if the specified BLA name already exists or an
invalid name was specified).
• deleteBLA(blaName)—This method has only one required parameter, which is the
name of the BLA to be removed. The result of calling this method will either be a string
containing the configuration ID of the BLA that was deleted, or an exception will be
raised to indicate an error occurred.
• startBLA(blaName)—This method has only one required parameter, which is the
name of the BLA to be started. The result of calling this method will either be a string
containing a message indicating that the BLA that was started successfully (even if the
BLA was previously started), or an exception will be raised to indicate an error
occurred.
• stopBLA(blaName)—This method has only one required parameter, which is the name
of the BLA to be stopped. The result of calling this method will either be a string contain-
ing a message indicating that the BLA that was stopped successfully (even if the BLA was
previously stopped), or an exception will be raised to indicate an error occurred.
The Asset-related methods in this library module are as follows:
• importAsset(sourcePath, storageType=’’)—This method has only one required
parameter; that is, the (complete, or fully qualified) sourcePath (path and filename) to
the asset file to be imported into the domain configuration. The optional parameter is
used to identify what information from the specified file should be saved in the asset
repository. The allowed values are as follows:
• ’FULL’—Stores the complete binaries from the source file (this is the default value).
• ’METADATA’—Stores only the metadata portion of the binary files.
• ’NONE’—Stores no binaries in the asset repository.
• exportAsset(assetID, fileName)—This method has two required parameters—
the name of the asset to be exported and the name of the destination file into which the
asset information should be written.
• editAsset(assetID, description, destinationURL, typeAspect,
relationship, filePermission, validate)—This method is used to modify
options specified when the asset was imported. It has seven required parameters, which
makes it one of the most complex methods in the scripting libraries. Unfortunately, the ban-
ner message displayed by this method says that only the assetID is required, but this is
not the case. If less than seven parameters are specified, an error message is displayed indi-
cating that seven parameters are required.19 The parameters to this routine are as follows:
• assetID—Specifies the name of the asset to be modified.
• description—Specifies new descriptive text to be associated with the asset.
• destinationURL—Specifies a new destination URL to be associated with the asset.
• typeAspect—Specifies a new type aspect to be associated with the asset.
• relationship—Specifies a new asset relationship.
• filePermission—Specifies a new asset filePermission configuration.
• validate—Specifies whether the asset should be validated (true), or not (false,
the default).
• listAssets(assetID=’’, includeDescription=’’, includeDeployUnit=’’)—
This method has no required parameters. If specified, the assetID is the name of the
asset to be listed. If this parameter is empty, all registered assets are listed. The other two
optional parameters are boolean values, and each defaults to false. If the
includeDescription parameter is specified as true, the asset description is returned
(should one exist). If the includeDeployUnit parameter is specified as true, infor-
mation about the deployable units within the asset are returned.20
• deleteAsset(assetID)—This method is used to remove the specified asset from the
asset repository. The parameter is required and must exist. The fully qualified assetID
is returned to indicate that the removal operation was a success.
• viewAsset(assetID)—This method is used to display the asset settings stored in the
repository. Only the asset name, or ID, is allowed, and it must be specified.
The methods in the AdminBLA library module related to composition units are as follows:
• addCompUnit(blaName, cuSourceID, deployUnits, cuName, cuDescription,
startingWeight, server, activationPlan)—This method is used to add a
composition unit to a specific BLA. It has eight required parameters, even though the
banner message displayed by this method says that only the blaName and cuSourceID
are required. The parameters to this routine are as follows:
• blaName—The name of the BLA to which the composition unit is to be added.
• cuSourceID—The configuration ID of the composition unit to be added.
• deployUnits—The name of the deployable unit for the asset.
19
If the author of the method had actually wanted there to be optional parameters, then a default value should have
been specified for each (e.g., description=””). A product defect has been opened to get this issue corrected.
20
Remember that Jython has a really nice feature where you can use keywords to assign a single optional parameter by
name, rather than by position. For example, you could execute a command such as AdminBLA.listAssets
(includeDescription=’true’).
no template name is provided, all of the configured template IDs are returned in a list. If a
template name is specified, a list is returned with the matching template IDs if any exist.
• listJMSProviders(JMSProviderName=””)—This method can be used to list the
configured JMS providers. If no provider name is provided, all of the configured
provider IDs are returned in a list. If a provider name is specified, a list is returned with
the matching provider IDs if any exist.
• listGenericJMSConnectionFactories(JMSCFName=””)—This method can be
used to list the generic JMS connection factory IDs. If no JMS connection factory name
is provided, all of the configured factory IDs are returned in a list. If a connection fac-
tory name is specified, a list is returned with the matching factory IDs if any exist.
• listGenericJMSDestinations(JMSDestName=””)—This method can be used to
list the generic JMS destination IDs. If no destination name is provided, all of the con-
figured destination IDs are returned in a list. If a destination name is specified, a list is
returned with the matching destination IDs if any exist.
• listWASQueues(WASQueueName=””)—This method can be used to list the Web-
Sphere Application Server queue IDs. If no queue name is provided, all of the config-
ured queue IDs are returned in a list. If a queue name is specified, a list is returned with
the matching queue ID if one exists.
• listWASQueueConnectionFactories(WASQueueCFName=””)—This method can
be used to list the WebSphere Application Server queue connection factory IDs. If no
queue connection factory name is provided, all of the configured IDs are returned in a
list. If a queue connection factory name is specified, a list is returned with the matching
queue connection factory ID, if one exists.
• listWASTopics(WASTopicName=””)—This method can be used to list the Web-
Sphere Application Server topics. If no topic name is provided, all of the configured
topic IDs are returned in a list. If a topic name is specified, a list is returned with the
matching topic ID if one exists.
• listWASTopicConnectionFactories(WASTopicCFName=””)—This method can
be used to list the WebSphere Application Server topic connection factory IDs. If no topic
connection factory name is provided, all of the configured IDs are returned in a list. If a
topic connection factory name is specified, a list is returned with the matching ID, if one
exists.
• listJMSConnectionFactories(jmscfName=””)—This method can be used to list
the configured JMS connection factory IDs. If no connection factory name is provided,
all of the configured IDs are returned in a list. If a JMS connection factory name is spec-
ified, a list is returned with the matching ID, if one exists.
• listJMSDestinations(jmsdestName=””)—This method can be used to list the
configured JMS destination IDs. If no destination name is provided, all of the configured
IDs are returned in a list. If a JMS destination name is specified, a list is returned with
the matching ID, if one exists.
• createGenericJMSConnectionFactoryUsingTemplate(nodeName, serverName,
JMSProviderName, templateID, JMSCFName, jndiName, extJndiName,
otherAttrsList=[])—This method can be used to create a generic JMS connection
factory using an existing template. The required parameters are as follows:
• nodeName—Defines the node on which the provider is to be created.
• serverName—Defines the server on which the provider is to be created.
• JMSProviderName—Defines the name of the provider with which the connection
factory is to be associated.
• templateID—Defines the template to be used for the creation.
• JMSCFName—Defines the name of the connection factory to be created.
• jndiName—Defines the JNDI name to be used to bind the connection factory to the
namespace.
• extJndiName—Defines the JNDI name to be used to bind the queue into the appli-
cation server namespace.
The optional parameter, otherAttrsList, can be used to specify name/value pairs of values to
be used during the resource creation.
• createGenericJMSDestination(nodeName, serverName, JMSProviderName,
JMSDestName, jndiName, extJndiName, otherAttrsList=[])—This method
can be used to create a generic JMS destination. The required parameters are as follows:
• nodeName—Defines the node on which the provider is to be created.
• serverName—Defines the server on which the provider is to be created.
• JMSProviderName—Defines the name of the provider with which the connection
factory is to be associated.
• JMSDestName—Defines the name of the destination to be created.
• jndiName—Defines the JNDI name to be used to bind the connection factory to the
namespace.
• extJndiName—Defines the JNDI name to be used to bind the queue into the appli-
cation server namespace.
The optional parameter, otherAttrsList, can be used to specify name/value pairs of values to
be used during the resource creation.
• createGenericJMSDestinationUsingTemplate(nodeName, serverName,
JMSProviderName, templateID, JMSDestName, jndiName, extJndiName,
otherAttrsList=[])—This method can be used to create a generic JMS destination
using an existing template. The required parameters are as follows:
• nodeName—Defines the node on which the provider is to be created.
• topic—Defines the name of the topic (as a qualification in the topic space) to be used.
The optional parameter, otherAttrsList, can be used to specify name/value pairs of values to
be used during the resource creation.
• createWASTopicUsingTemplate(nodeName, serverName, JMSProviderName,
templateID, WASTopicName, jndiName, topic, otherAttrsList=[])—This
method can be used to create a WebSphere Application Server topic using an existing tem-
plate. The required parameters are as follows:
• nodeName—Defines the node on which the provider is to be created.
• serverName—Defines the server on which the provider is to be created.
• JMSProviderName—Defines the name of the provider with which the connection
factory is to be associated.
• templateID—Defines the template to be used for the creation.
• WASTopicName—Defines the name of the topic to be created.
• jndiName—Defines the JNDI name to be used to bind the connection factory to the
namespace.
• topic—Defines the name of the topic (as a qualification in the topic space) to be
used.
The optional parameter, otherAttrsList, can be used to specify name/value pairs of values to
be used during the resource creation.
• createWASTopicConnectionFactory(nodeName, serverName, JMSProviderName,
WASTopicCFName, jndiName, port, otherAttrsList=[])—This method can be
used to create a WebSphere Application Server topic connection factory. The required
parameters are as follows:
• nodeName—Defines the node on which the provider is to be created.
• serverName—Defines the server on which the provider is to be created.
• JMSProviderName—Defines the name of the provider with which the connection
factory is to be associated.
• WASTopicCFName—Defines the name of the connection factory to be created.
• jndiName—Defines the JNDI name to be used to bind the connection factory to the
namespace.
• port—Defines the port number to be associated with this resource.
The optional parameter, otherAttrsList, can be used to specify name/value pairs of values to
be used during the resource creation.
• createWASTopicConnectionFactoryUsingTemplate(nodeName, serverName,
JMSProviderName, templateID, WASTopicCFName, jndiName, port,
otherAttrsList=[])—This method can be used to create a WebSphere Application
Server topic connection factory using an existing template. The required parameters are
as follows:
• nodeName—Defines the node on which the provider is to be created.
• serverName—Defines the server on which the provider is to be created.
• JMSProviderName—Defines the name of the provider with which the connection
factory is to be associated.
• templateID—Defines the template to be used for the creation.
• WASTopicCFName—Defines the name of the connection factory to be created.
• jndiName—Defines the JNDI name to be used to bind the connection factory to the
namespace.
• port—Defines the port number to be associated with this resource.
The optional parameter, otherAttrsList, can be used to specify name/value pairs of values to
be used during the resource creation.
• startListenerPort(nodeName, serverName)—This method can be used to start
the listener ports associated with the specified resource. The required parameters are as
follows:
• nodeName—Defines the node with which the listener ports are associated.
• serverName—Defines the server with which the listener ports are associated.
The penultimate group of methods to be described deal with the deletion of clusters and members:
• deleteCluster(clusterName)—This method can be used to delete a cluster. A
single, required parameter exists and is used to specify the name of the cluster to be
deleted.
• deleteClusterMember(clusterName, nodeName, serverMember)—This
method can be used to delete a cluster member. All three parameters are required:
• clusterName—Defines the name of the cluster containing the member to be deleted.
• nodeName—Defines the name of the node on which the member exists.
• serverMember—Defines the name of the server that is the member to be deleted.
The final group of methods in this library module deal with the stopping and starting of clusters
and members:
• startAllClusters()—This method can be used to start all configured clusters.
• startSingleCluster(clusterName)—This method can be used to start the speci-
fied and named cluster.
• stopAllClusters()—This method can be used to stop all configured clusters.
• stopSingleCluster(clusterName)—This method can be used to stop the speci-
fied and named cluster.
• rippleStartAllClusters()—This method can be used to stop and then start all
members of all clusters.
• rippleStartSingleCluster(clusterName)—This method can be used to stop
and then start all members of the specified and named cluster.
• immediateStopAllClusters()—This method can be used to stop all clusters with-
out allowing time for pending operations of the cluster members to complete gracefully.
• immediateStopSingleCluster(clusterName)—This method can be used to stop
the specified and named cluster without allowing time for pending operations of the
cluster members to complete gracefully.
node. If the list of all properties is to be returned, specify the JVMProperty parameter
as an empty string.21
• showServerInfo(nodeName, serverName)—This method can be used to return a
list of information about the specified server name that exists on the given node.
• getJavaHome(nodeName, serverName)—This method can be used to return a
string that identifies the JAVA_HOME directory for the specified server.
• setJVMProperties(nodeName, serverName, classpath, bootClasspath,
initHeapsize, maxHeapsize, debugMode, debugArgs)—This method can be
used to set one or more JVM properties for a particular server. The parameters are
required but might be specified as an empty string. They are as follows:
• nodeName—The name of the node on which the server exists.
• serverName—The name of the server whose properties are to be modified.
• classpath—Specifies the list of directories to be searched for classes by the JVM.
• bootClasspath—Specifies the list of bootstrap classes and resources for the JVM.
• initHeapsize—Defines the initial Heap size (in megabytes) to be used by the
JVM.
• maxHeapsize—Defines the maximum Heap size available for the JVM.
• debugMode—If specified as ’true’, indicates that the JVM should execute in
debug mode.
• debugArgs—If debugMode is specified as ’true’, indicates that debug arguments
to be used by the JVM.
• checkIfServerExists(nodeName, serverName)—This method can be used to
check for the existence of a specific server on a particular node. The result of the call
will be either ’true’ or ’false’.
• checkIfServerTemplateExists(templateName)—This method can be used to
check for the existence of a specific server template name. The result of the call will be
either ’true’ or ’false’.
• configureProcessDefinition(nodeName, serverName, otherAttrList=[])—
This method can be used to define a collection of name/value pairs for the process of a
specific server on a particular node. The last parameter specifies the list of name/value
pairs.
• configureEndPointsHost(nodeName, serverName, hostName)—This
method can be used to define the hostname to be associated with a specific server on a
particular node. The last parameter specifies the “new” hostname.
21
Some might find the returned list awkward to work with and prefer the code shown in Listing 11.10.
22
Why this method displays the information via a print statement, rather than returning it to the caller, we do not know.
for a specific server. Almost all of the parameters are required, and have the following
meanings:
• nodeName—The name of the node on which the server exists.
• serverName—The name of the server being modified.
• traceString—The trace string to be stored.
• outputType—Defines where the trace is to be written, either ’MEMORY_BUFFER’
or ’SPECIFIED_FILE’.
• otherAttrList—An optional name/value pair list of additional attributes to be set.
• configureJavaVirtualMachine(jvmConfigID, debugMode, debugArgs,
otherAttrList=[])—This method can be used to configure the JVM for a specific
server. Almost all of the parameters are required and have the following meanings:
• jvmConfigID—The configuration ID of the JVM being modified.
• debugMode—Indicates that the JVM should execute in debug mode. If this value is
specified as ’true’, then debug arguments must be specified.
• debugArgs—Specifies the arguments to be used by the JVM in debug mode.
• otherAttrList—An optional name/value pair list of additional attributes to be set.
• configureServerLogs(nodeName, serverName, logRoot, otherAttr
List=[])—This method can be used to configure the properties related to log files for
a specific server. Almost all of the parameters are required and have the following mean-
ings:
• nodeName—The name of the node on which the server exists.
• serverName—The name of the server being modified.
• logRoot—The fully qualified directory in which log files should be written.
• otherAttrList—An optional name/value pair list of additional attributes to be set.
• configureJavaProcessLogs(jpdConfigID, logRoot, otherAttrList =[]) —
This method can be used to configure the properties related to Java Process log files for
a specific server. Almost all of the parameters are required and have the following
meanings:
• jpdConfigID—The configuration ID of the Java Process being modified.
• logRoot—The fully qualified directory in which log files should be written.
• otherAttrList—An optional name/value pair list of additional attributes to be set.
• configureRASLoggingService(nodeName, serverName, logRoot, other-
AttrList=[])—This method can be used to configure the properties related to Relia-
bility and Serviceability log service for a specific server. Almost all of the parameters
are required and have the following meanings:
• nodeName—The name of the node on which the server exists.
for a specific server. Almost all of the parameters are required and have the following
meanings:
• nodeName—The name of the node on which the server exists.
• serverName—The name of the server whose state is to be defined.
• parentType—The kind of component that contains the specified server.
• initialState—The desired initial state of the component (i.e., either ’STOP’ or
’START’).
• otherAttrList—An optional name/value pair list of additional attributes to be set.
• configureORBService(nodeName, serverName, requestTimeout, request-
RetriesCount, requestRetriesDelay, connCacheMax, connCacheMin,
locateRequestTimeout, otherAttrList=[])—This method can be used to con-
figure the ORB Service for a specific server. Almost all of the parameters are required
and have the following meanings:
• nodeName—The name of the node on which the server exists.
• serverName—The name of the server whose state is to be defined.
• requestTimeout—The number of seconds to wait before a request expires.
• requestRetriesCount—The number of attempts to be made to send a request.
• requestRetriesDelay—The number of milliseconds to wait between retries.
• connCacheMax—The maximum number of entries allowed in the cache.
• connCacheMin—The minimum number of entries allowed in the cache.
• locateRequestTimeout—The number of seconds that a locate request message is
allowed to wait before it expires.
• otherAttrList—An optional name/value pair list of additional attributes to be set.
• configureTransactionService(nodeName, serverName, totalTran Life-
time Timeout, clientInactivityTimeout, maxTransactionTimeout,
heuristicRetryLimit, heuristicRetryWait, propogatedOrBMTTran Life-
timeTimeout, asyncResponseTimeout, otherAttrList=[])—This method
can be used to configure a Transaction Service for a specific server. Almost all of the
parameters are required and have the following meanings:
• nodeName—The name of the node on which the server exists.
• serverName—The name of the server for which the service is being defined.
• totalTranLifetimeTimeout—The maximum time, in seconds, that a transaction
is allowed to exist before timeout cleanup is initiated.
• clientInactivityTimeout—The maximum time, in seconds, that a client is
allowed to remain inactive.
Summary
This chapter has primarily been a reference for the scripting library modules that are provided
with version 7.0 of the IBM WebSphere Application Server. You are encouraged to take a look at
the code and determine if the modules, as written, suit your needs. You can then choose to use
none, some, or all of these routines in your environment.
449
listApplicationPorts listServerPorts M
command, 232 command, 232 management. See also
listAssetsAttachedToPolicy- listServers() method, 210 administration
Set command, 385 listServerTemplates() AdminClusterManagement
listAttachmentsForPolicySet method, 214 library module,
command, 384 listServerTypes 430-432
listAuthDataEntries command, 233 AdminNodeGroupManage-
command, 265-266 listServerTypes() method, ment library module,
listDataSources, 294 202 445-446
listGroupsInBusConnector- listServices method, 392 AdminNodeManagement
Role method, 341 listSIBEngines method, 335 library module, 446-447
listGroupsInDefaultRole listSIBJMSQueues AdminServerManagement
method, 342 method, 336 library module, 432-445
listGroupsInDestinationRole listSIBJMSTopics databases, 277-280
method, 342 method, 336 advanced settings,
listGroupsInTopicRole listSIBMediations 284-291
method, 342 method, 337 references, 291-300
listGroupsInTopicSpaceRoot listSIBuses method, 334 troubleshooting,
Role method, 342, 344 listSIBusMembers 280-284
listInterceptors command, 270 method, 334 servers, 199-200
listJDBCProviders, 293 listUsersInBusConnectorRole commands, 209-212
listKeyFileAliases method, 343 creating clusters,
command, 380 listUsersInDefaultRole 205-209
listKeyManagers method, 343 examples, 201-202
command, 377 listUsersInDestinationRole JVM methods, 216-217
listKeyStores command, 378 method, 343 JVM properties,
listKeyStoreTypes listUsersInTopicRole 218-219
command, 378 method, 343 JVM system properties,
listModules() method, 201 listWebServiceEndpoints 217-218
listPolicySets command, 384 method, 391 methods, 202-205
listPolicyTypes listWebServiceOperations references, 223-239
command, 384 method, 391 template-related
ListPorts.py, 159 listWebServices method, 391 commands, 214-216
listRegistryGroups literals, 8-15 z/OS methods, 220-223
command, 272 ljust( width ) method, 73 Web services, 352
lists, 12 local mode, 120 exporting WSDL, 355
methods, 67-68 local precedence, 51 KeyManager
Web services, 352-354 locals() method, 81 commands, 377
listSecurityDomains long strings, 8 KeySet commands,
command, 271 long( x[, radix ] ) method, 81 381-382
listSecurityRealms loop statements, 42 KeyStore commands,
command, 273 lower() method, 73 378-381
listServer command, 233 lstrip() method, 73 listing, 353-354
modifying packages, 92 O
AdminControl objects, simple, 129 object-oriented programming.
167-172 sys, 98-99 See OOP
buses, 329 moduleTest.py, 131 objects
configuration, 150 moveClusterToCoreGroup AdminApp, 199
J2C (JAAS) aliases, 245 command, 225 application installation
runtime behavior, 283 moveServerToCoreGroup methods, 204-208
security domains, 261 command, 225 editing, 208-210
modifyKeySet command, 382 multiple security domains, methods, 199-212
modifySIBDestination 261-262 updating, 208-210
method, 330-331 AdminApplication,
modifySIBEngine method, 399-409
330 N
AdminConfig, 149
modifySIBJMSQueue named function parameters,
config ID, 150-155
method, 332 54-55
configuration types,
modifySIBJMSTopic NameError exception, 132
152-153
method, 333 names
containment paths, 151
modifySIBus method, 329 AdminControl object,
create/modify methods,
modules 173-174
160-162
AdminApplication script applications, 203
document manipulation
library, 399-409 filenames, 203
methods, 164
AdminAuthorizations, JNDI, 211
methods, 164-165
428-430 methods, extracting, 135
overview of, 149-150
AdminClusterManage- modules, 203
show/tell methods, 155-
ment, 430-432 variables, 15-16
159
AdminJ2C, 412-414 namespaces, 51
verification, 162-163
AdminJDBC, 414-416 modules, 124
AdminControl, 167
AdminJMS, 416-423 wsadmin, 123
attributes, 174-181
AdminLibHelp, 447 navigating
environment
AdminNodeGroupManage- J2C (JAAS) aliases,
information, 167-172
ment, 445-446 244-245
*_imx methods,
AdminNodeManagement, LDAPUserRegistry, 256
183-184
446-447 scripting libraries,
MBean support
AdminResources, 423-427 393-397
methods, 172-173
AdminServerManagement Web services, 353-355
methods, 181-182
, 432-445 negative indexes, 13
names, 173-174
AdminUtilities, 447 nested_scopes, 90-92
administration, 129-134
errors, 92-94 nodes
documentation,
import statements, 88-90 AdminNodeGroupManage-
145-147
names, 203 ment library module,
Help, 134-145
namespaces, 124 445-446
availability, 133
nested_scopes, 90-92 AdminNodeManagement
dictionary, 69-71
overview, 87 library module, 446-447
instantiation, 66
numbers, 7
SAFARI BOOKS ONLINE allows you to search for a specific answer, cut and paste
code, download chapters, and stay current with emerging technologies.
STEP 2: New Safari users, complete the brief registr ation form.
Safari subscribers, just log in.