Monty Jy Thon
Monty Jy Thon
ce en r fe
2007
r Se s ce vi T e ch ni ca l
on
Andrew Simms
Objectives
Our Holy Grail: To work out some recommended practices for using Jython in WAS scripting How we're going to get there:
Quick look at what's in the WAS 6.1 Application Server Toolkit (AST) Describe the essentials of the Jython language Look at some more advanced Jython features Pick out some key things as we proceed Demonstrate bit and pieces of Jython Suggest some guidelines for what scripts should look like
by generating scriptlets
using the Admin Console Command Assist feature
Outline view (classes & methods & loops) Provides integration with Jython Debugger Has self-evident usage (Eclipse consistent) NO compiler parse errors, NO parameter type checks
2007 WebSphere User Group 5
Jython debugger in the AST Uses local server runtime(s) for wsadmin execution
Can target (compatible) remote servers (using -host -port)
Can run Jacl and Jython scripts But debugging is Jython only
Local v6.1 Breakpoints, step-over etc Variables view (cannot change variable contents) Stack frame view (variables reflect current level)
2007 WebSphere User Group 6
Insert generated code into a script using the Jython Editor script
Will need further editing
Does it produce Jython code in a style you would use if writing from scratch?
Not if you want to use the OO features
2007 WebSphere User Group 8
Indentation and comments Statements Trapping exceptions Data types Strings, tuples and lists Dictionaries Functions (classless methods) Built-in functions
Comments: use # and anonymous string In interactive wsadmin you can't cut and literals: paste comments that spread over two or
more lines. Not a problem for the AST. # This is a comment 'This is a comment' """This is a comment that spreads across many lines between triple-quotes. So a good way to comment out code is to use triple-quotes"""
10
Statements
Much more like Java than Jacl (Tcl) Statement syntax is Java-like:
for x in (1, 2, 3): "else" here is a misnomer print "x=", x always executed unless you use "break" to exit from the for loop else: print "Counter-intuitive that this gets executed"
1
for z in (range(45, 55)): In interactive wsadmin make sure you if z == 50: type the indentation correctly, and you break may need a blank line at the end of blocks. Not a problem for the AST. else: print z else: print "Broke out so this won't get printed"
11
Statements
Multiple assignments (Fibonacci series):
a, b = 0, 1 while b < 1000000: print b a, b = b, a+b This is actually a tuple assignment as we shall see later
2
12
"else" here: if you go to the exceptions then the else doesn't get executed; if you don't go to the exceptions then it does get executed
Try/finally:
try: doStuff finally: doCleanUpStuff finally: always gets executed and any exception re-raised after it executes
13
Numeric types:
Integer, long, float, complex Numeric objects are immutable:
id(v) # -> 791424812 v += 1 id(v) # -> 791818034
Tuples
No
Lists
Yes
Think of a tuple as a constant list, but you can still change any mutable element it may have
len() tells you the sequence length Use empty paired delimiters to get an empty sequence, e.g. L=[]
2007 WebSphere User Group
15
Sequence mutability
Strings are immutable:
s = "one two three four" s[8:-1] = "buckle my shoe" # fails
16
Sequences: Strings
Use single, double or triple quotes Reverse quotes (equivalent to the repr() function):
v = 42 s = `v / 6` type(s) # s is the string '7' not the integer 7 s = int(s) type(s) # now it is
Sequences: Tuples
Contains references to any object type Those objects can be mutable but the tuple itself is immutable No methods available for tuples Represented by round brackets but you don't have to specify them
t = "one", "two", "three", "four" t = ("one", "two", "three", "four") t = (("one", "two", "three", "four")) But do so for clarity
Sequences: Lists
Contains references to any object type The only sequence type that is mutable Represented by square brackets
l = ["one", 2, 3L, 4.0+5.0j] Convert a list to a tuple with list(seq)) and vice versa with tuple(seq)
PyList methods:
append(), count(), extend(), index(), insert(), pop(), remove(), reverse(), sort()
Examples:
l.append(6.0E7) l.count(60000000) l.extend([7, "eight"]) l.index(4+5j) l.insert(3, 2.5) l.pop(1) l.remove(4+5j) l.reverse() l.sort() # # # # # # # # # appends one object to the list 1 (how often does the value occur) appends a list to the list 3 (the index of this value) inserts 2.5 in index 3 2 (and removes it from the list) removes this value from the list reverses the list order sorts the list (in some way)
19
List comprehension A syntax that allows you to create one list from another by applying a function or expression to each member:
[expr for var1 in seq1 if test1 for var2 in seq2 if test2 . . .]
Exploit this to set heap sizes for all of your app servers in one line!
None of the Admin* functions return a true Jython list. [AdminConfig.modify(x, [["initialHeapSize", 64], ["maximumHeapSize", 128]]) for x in 5 AdminConfig.list("JavaVirtualMachine").splitlines() if 14 x.find("nodeagent") == -1 and x.find("dmgr") == -1]
14
20
Connects a set of immutable keys to a set of objects Enclose with curly brackets and colon- and commaseparated values:
chineseLanguages = ["Mandarin Chinese", "Cantonese"] indianLanguages = ["Hindi", "Urdu", "Gujarati"] china = ["Beijing", 1316E6, chineseLanguages] india = ["New Delhi", 1110E6, indianLanguages] cdict = {"China": china, "India": india}
# -> {'China': ['Beijing', 1.316E9, ['Mandarin Chinese', 'Cantonese']], 'India': ['New Delhi', 1.11E9, ['Hindi', 'Urdu', 'Gujarati']]}
21
Examples:
cdict("England") = ["London", 4.8E7, ["Cockney", "Geordie", "Sassenach"]] cdict.update({"Scotland": ["Edinburgh", 1.0E7, ["English"]]}) cdict.get("India") cdict.has_key("Egypt") cdict.keys() cdict.items() cdict.popitem() cdict.setdefault("Egypt") cdict.values() copy=cdict.copy() del cdict["Egypt"] cdict.clear() # # # # # # # # # # returns value if present 0 (not present) ['India', 'China', 'England'] returns a list of tuples pops an item as a tuple appends a key pair if not present returns a list of values performs a shallow copy deletes an entry empties the dictionary
22
Functions
Functions are methods defined outside a class
def myFunction(p1, p2, p3): doSomeStuff return whatever Function names: Don't use underscores as these have special meanings Don't use built-in function names This is really useful not restricted to returning a single value
attr2 is a local variable but attr1 is available externally This is a new attribute assigned externally
23
myFunction("abc") myFunction("abc", "ghi", "jkl", "mno") myFunction(p2="xyz", p1="uvw") myFunction("a", "b", "c", "d", id1="e", id2="f")
This is a great way of keeping a function's signature constant yet allowing arbitrary parameters to be passed to it
2007 WebSphere User Group 24
Doc strings Place an anonymous string literal after a function definition. Its content becomes that functions doc string. Print its documentation using
<name>.__doc__
def someFunction(): """someFunction does something or other""" pass A Jython library becomes self-documenting. Can see this using the AST. someFunction.__doc__ # -> someFunction does something or other
25
Built-in functions
type() type of an object: id() identity of an object: Numeric functions:
hex(), oct(), abs(), ...
Type conversions:
int(3.14159), tuple("abcd"), ...
File handling:
open("/tmp/myFile", "r")
Sequence generators:
range(3, 17, 2) xrange(3, 1234567, 2)
Class attributes:
dot notation also: hasattr(), delattr(), getattr(), setattr()
Many more
2007 WebSphere User Group 26
Namespaces Functional programming Regular expressions Threads Modules and packages Classes Using Java in Jython
27
With this assignment but without the global, Jython sees this bruce as a new bruce
2007 WebSphere User Group
29
Functional programming
Create anonymous functions using lambda forms which have expressions but no statements:
isLeapYear = lambda year: not (year % 400 and (year % 4 or not year % 100)) Note that this print "2000 - ", isLeapYear(2000) returns a function print "2007 - ", isLeapYear(2007) print "2008 - ", isLeapYear(2008) print "2100 - ", isLeapYear(2100)
30
Functional programming
filter iterates over a sequence returning a subset of its values where the called function returns true:
set1 = range(0, 200, 7) set2 = range(0, 200, 3) filter(lambda x: x in set1, set2) # -> [0, 21, 42, 63, 84, 105, 126, 147, 168, 189]
31
Ditto
You can use the reduce() function, which eats a sequence applying a recursive function to it:
Doesn't break fact = lambda num: num > 0 and reduce(lambda x, y: long(x)*long(y), range(1, num + 1)) or 0
32
Functional programming examples using AdminConfig (1) Test whether a name is a valid configurable object:
isValidType = lambda x: x in AdminConfig.types().splitlines() isValidType("JavaVirtualMachine") # -> 1 isValidType("Garbage") # -> 0
Set heap sizes for all of your app servers in one line (as earlier):
map(lambda x: AdminConfig.modify(x, [["initialHeapSize", 64], ["maximumHeapSize", 128]]), 14 filter(lambda x: 10 x.find("nodeagent") == -1 and x.find("dmgr") == -1, 14 AdminConfig.list("JavaVirtualMachine").splitlines()))
33
Functional programming examples using AdminConfig (3) Store just the simple attribute names and append the type name to each:
from __future__ import nested_scopes Contains entries such as: attsToDict = lambda type, dict: {initialHeapSize_JavaVirtualMachine int} map(lambda x: dict(x[0:x.index(" ")] + "_" + type) = x[x.index(" ") + 1:], \ filter(lambda x: x.endswith("*") == 0 and x.endswith("@") == 0, \ AdminConfig.attributes(type).splitlines()))
Build a Jython dictionary of all simple attribute names of all object types:
11 bigDict = {} map(lambda x: attsToDict(x, bigDict), AdminConfig.types().splitlines())
35
15
def setValues(baseType, simpleName, qualifier=None, **setThese): objid = AdminConfig.getid("/" + baseType + ":" + simpleName + "/") for attrUndType, value in setThese.items(): undPos = attrUndType.find("_") if bigDict.has_key(attrUndType): attrName = attrUndType[:undPos] ; attrType = attrUndType[undPos+1:] attrTypeIdList = AdminConfig.list(attrType, objid).splitlines() if qualifier: for listItem in attrTypeIdList: Error checking if listItem.startswith(qualifier): removed to keep this attrTypeId = listItem example simple break else: if len(attrTypeIdList) == 1: attrTypeId = attrTypeIdList[0] AdminConfig.modify(attrTypeId, [[attrName, value]])
36
16
simple changes. Doesn't create or delete objects. Doesn't add or delete attributes to existing objects (e.g. custom properties)
37
Regular expressions Similar to regexp in other languages Can get unreadable use raw strings (introduced by "r") Produce a more readable list of application servers:
import re for appserv in AdminConfig.list("ApplicationServer").splitlines(): print re.sub(r".*\(cells/.+/nodes/(.+)/servers/(.+)\|.+\)", r"\2 on \1", appserv)
12
38
39
Special variables: __name__, __doc__, __file__, __all__ dir(A.B.C), dir(A.B.C.someFunction) tell you what's available
2007 WebSphere User Group 40
41
Not even placing global AdminConfig in C.py works. Global in Jython is not the same as in Jacl
Could change D.py to call execfile("<path>/C.py"), but this collapses everything to a single module you might get name clashes. Would then call listServers() not C.listServers(). Instead you could change C.py and retain the hierarchy:
import com.ibm.ws.scripting.AdminConfigClient as Scripting AdminConfig = Scripting.getInstance() def listServers(): AdminConfig.list("Servers")
42
os.linesep, os.pathsep, os.mkdir(), os.stat(), os.listdir(), os.path.join(), os.path.isfile(), os.path.isdir(), os.path.dirname(), . . . For really robust admin scripts:
import unittest <body of module> if __name__ == '__main__': <test cases>
2007 WebSphere User Group 43
Defining a class:
class class_name[(inheritance)]: <code> class Myclass: """documentation""" <class-level attributes> <method 1>: <instance-level attributes>
Create class-level attributes within a method by prefixing with the class name
2007 WebSphere User Group 44
13
45
Java from Jython A Jython class can only inherit from one Java class, but many Jython classes A Jython subclass cannot access a Java class's:
protected static methods and fields protected instance fields package-protected members
47
Making wsadmin scripts more readable, robust, maintainable, extendable Making interactive administration a more friendly experience Suggested conventions
48
Choice:
Use execfile() to execute those properties files Use the p option on the wsadmin command line
2007 WebSphere User Group 49
EITHER:
Develop a common.py Develop individual .py files that wrap up a bunch of AdminConfig, AdminApp objects
e.g. jdbc.py, appserver.py, cluster.py
execfile() them all and have a single namespace for your entire scripts
OR:
Use Jython packages, modules and classes to structure it in an OO fashion import these and have separate namespaces
2007 WebSphere User Group 50
Good practices Strive for platform independence Never make N calls from a shell script to wsadmin each passing a separate c option
Each involves connecting to WAS Make those N calls from within a wsadmin script
Conventions:
Class names have upper case first char Method and function names in camelCase Spaces around operators and parameters No space before colon in dictionaries Indent consistently either 2 or 4 spaces
2007 WebSphere User Group 52
Summary
Dj vu:
We've seen there are excellent Jython productivity tools in the WAS 6.1 AST We've looked at the basic and some advanced features of the Jython language We've established some recommended practices for Jython scripting
53
References Jython Essentials, Samuele Pedroni & Noel Rappin (O'Reilly) Jython for Java Programmers, Robert Bill (New Riders)
54
55