Wednesday, January 28, 2009

Canonical Python __str__ method

Here's a python class that shows some approaches for building up a meaningful __str__() to display the class's data attributes (like overriding toString() in java). The first way is to show a specific subset (or ordering) of attributes. The second way (currently commented out) just shows all the classes attributessorted by name. I also show how to make it work with a subclass--either leveraging the superclass __str__() method or doing it all from within the subclass. Of course, it should be easy to adjust the output to your own needs (padding, etc).

Nothing earth-shattering here, but it can save some work if it's a big class with lots of attributes. The example should work with modern CPython, including Python 3:

class X:
def __init__(self):
self.a = "apple"
self.b = "banana"
self.c = "cranberry"

def __str__(self):

# to show specific variables
showList = ["a", "b"]

# to show include all variables in sorted order
#showList = sorted(set(self.__dict__))

return ("X(%i):\n" % id(self)) + "\n".join([" %s: %s" % (key.rjust(8), self.__dict__[key]) for key in showList])

class Y(X):

def __init__(self):
X.__init__(self)
self.d = "date"
self.e = "elderberry"

def __str__(self):
showList = ["a","d","e"]

# if you want to use the superclass as-is and supplement from this subclass
# return X.__str__(self) + "\n Y:\n" + "\n".join([" %s: %s" % (key.rjust(8), self.__dict__[key]) for key in showList])

# if you want to do everything from this subclass
return ("Y(%i):\n" % id(self)) + "\n".join([" %s: %s" % (key.rjust(8), self.__dict__[key]) for key in showList])

print(Y())

This outputs:

Y(12172528):
a: apple
d: date
e: elderberry


Okay, but maybe this can just be a helper method of some kind. The class name info can be pulled of of the self.__class__ object, and then the function can be more generic:

def str_impl(anInstance, displayAttributeList):

classLine = "%s.%s(%i):\n" % (anInstance.__class__.__module__, anInstance.__class__.__name__, id(anInstance))
return (classLine + "\n".join([" %s: %s" % (key.rjust(8), anInstance.__dict__[key]) for key in displayAttributeList]))

class XX:

showList = ["a", "b"]

def __init__(self):
self.a = "apple"
self.b = "banana"
self.c = "cranberry"

def __str__(self):
return str_impl(self, self.__class__.showList)


class YY(XX):
showList = ["a","d","e"]

def __init__(self):
X.__init__(self)
self.d = "date"
self.e = "elderberry"

This outputs:

__main__.YY(12172784):
a: apple
d: date
e: elderberry



Note that __main__ is the module since the classes are defined in the "main" scope. The correct module/package would print if I had used one. Again, you wouldn't even need to bother with this for a small class--but for a class with a lot of attributes (which might be a sign it's time to break it up anyway ;-), it saves some tedium.

Friday, January 9, 2009

Connecting to an Oracle Database from ASP.Net/SharePoint

So you’re writing your “Hello Oracle Database” from ASP.Net/SharePoint, and you get this error: “System.Data.OracleClient Requires Oracle Client version 8.1.7 or greater”.

Perhaps you don’t really want to install the 475 Mb Oracle Client on your system just to talk to a database. Some quick googling suggests you can just install the Oracle Instant Client, and if you don’t care about internationalization, you can even go with the Instant Client “Basic Lite” which gets you down to about 18 Mb:

http://www.oracle.com/technology/software/tech/oci/instantclient/htdocs/winsoft.html [32 bit version]

Yeah, it’s an order of magnitude larger than the jdbc jar you’d use if you were connecting from Java, but at least it’s not a half Gig. But what if you don’t even want to install it? This blog entry shows the 4 files you’ll need to from the instant client:

http://www.thewayofcoding.com/2008/02/c-net-programming-tip-connecting-to-an-oracle-database/

In my case, I’m actually developing a SharePoint web part. Therefore, I’d like to make the set of driver files universally available for anything deployed on the system. So I drop those four files:
· oci.dll
· orannzsbb10.dll
· oraocci10.dll
· oraociicus10.dll

into the system driver directory (in this case C:\Windows\System32). And now I’m good to go.
Note: I’m not sure if it’s related, but I did not have to change any permissions as seems to happen when you actually install the client (at least in some cases)—as described here:

http://moustafa-arafa.blogspot.com/2007/04/systemdataoracleclient-requires-oracle.html

I suppose it’s time I update my About Me to say I do .Net now too :-)

Monday, March 17, 2008

IE6 problem with Dojo: Could not load 'dojo.parser'

I encountered this problem when testing with IE 6:

Error: Could not load 'dojo.parser'; last tried './parser.js'

After researching it a bit, it usually occurs as the result of a script that loads before the dojo stuff and which does a document.write. Apparently this confuses dojo. The solution is to use the baseUrl property of djConfig to manually specify the base path (the path to the dojo.js file):
      <script type="text/javascript" src="../dojo_tools/dojo/dojo.js"
djConfig="parseOnLoad: true, baseUrl: '/dojo_tools/dojo/'"></script>

Note the baseUrl should have a trailing '/'.

When dojo loads, if no baseUrl is provided, dojo will try to dynamically determine the base url. However, other scripts can interfere with this (at least on IE), so manually specifying it fixes it.

Thursday, February 28, 2008

Dojo xhr to update a div

Using ajax to update a portlet quickly becomes a requirement when you get a bunch of portlets on a page and reloading everything is slow. So in setting out to use dojo to do this, I figured it required nothing more than setting the innerHTML of my div with the new content. It's not that simple, however, if the panel contains dojo's "dijit" widgets (in this case, I had a dijit.layout.TabContainer returned with the ajax content). BTW, dojo folks, the TabContainer worked flawlessly right out of the box and was clean and simple--nice job. In comparing the before/after, it was apparent that when the div content was rendered when the entire page loaded, dojo/dijit was wiring up the tab elements with all the required events and attributes. However, when the ajax content was set as innerHTML, this wasn't happening. It was a bit tough to figure out mostly because I wasn't sure what to google on to find the solution. I tried a few things, including making the div for the content a dijit.layout.ContentPane--but that's just part of what's needed. Here's what the content pane div looks like:
<div id="ajaxReportBody" dojoType="dijit.layout.ContentPane">
<c:import url="reportBody.jsp" />
</div>

The other piece is to make sure you use setContent() in your xhr load function on the dijit widget (in this case, the content pane div), instead of innerHMTL:
dojo.xhrPost( { 
...
load: function(response, ioArgs) {
...
dijit.byId("ajaxReportBody").setContent(response); // KEY!
return response;
},
...

When you use setContent(), dijit will redo the plumbing in the new content for you. Also note that you must use digit.byId(), not dojo.byId().

Some references indicated that you need an executeScripts="true" on the content pane div. However, this is no longer true AFAICT (I'm using dojo 1.0.2).

BTW, best reference I found on the subject was here.

Tuesday, January 8, 2008

Code formatting in Blogger

is a real PITA. Here's an web page utility (uses javascript) that makes it easier:
Greg Houston's Formatter for blog code
Have a better solution? Post a comment.

Hacking an WSRP portlet request using Groovy

I wanted to invoke a portlet without having to run it through a portal. I have a portlet currently deployed in Oracle Portal and figured it would be "fun" to try invoking it using Groovy--I didn't see any slam-dunk toolkits for this (I didn't look too hard). WSRP uses Soap, so the first step was firing up Wireshark to sniff a real request (sanitized to protect the innocent):

POST /MyPortlet/portlets/WSRPBaseService HTTP/1.1
Host: mycomputer:8080
Connection: keep-alive, TE
TE: trailers, deflate, gzip, compress
User-Agent: RPT-HTTPClient/0.3-3
Oracle-ECID: 86139989405,1
Cookie: JSESSIONID=80f4383422b8fbea0c8532804298a55ba92d09dfb9a6
SOAPAction: "urn:oasis:names:tc:wsrp:v1:getMarkup"
Accept-Encoding: gzip, x-gzip, compress, x-compress
Content-type: text/xml; charset="utf-8"
Content-length: 2165

<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns0="urn:oasis:names:tc:wsrp:v1:types"><env:Body><ns0:getMarkup><ns0:registrationContext><ns0:registrationHandle>C:xxx.xx.xx.xx:-5fd1fa94:11740915845:-7ffe</ns0:registrationHandle></ns0:registrationContext><ns0:portletContext><ns0:portletHandle>E:0:xxx.xx.xx.xx:-5fd1fa94:11740915845:-7ffd</ns0:portletHandle></ns0:portletContext><ns0:runtimeContext><ns0:userAuthentication>wsrp:xxxxxxxx</ns0:userAuthentication><ns0:portletInstanceKey>1179_354032_1179_1_1</ns0:portletInstanceKey><ns0:namespacePrefix>__ns1179_354032_1179_1_1_</ns0:namespacePrefix></ns0:runtimeContext><ns0:userContext><ns0:userContextKey>mylogin</ns0:userContextKey></ns0:userContext><ns0:markupParams><ns0:secureClientCommunication>false</ns0:secureClientCommunication><ns0:locales>en-us</ns0:locales><ns0:mimeTypes>text/html</ns0:mimeTypes><ns0:mode>wsrp:view</ns0:mode><ns0:windowState>wsrp:normal</ns0:windowState><ns0:clientData><ns0:userAgent>Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727) RPT-HTTPClient/0.3-3</ns0:userAgent><ns0:extensions><oracle:GenericExtension xmlns:oracle="http://xmlns.oracle.com/portal/wsrp/v1"><ns0:NamedString name="X-Oracle-Device.MaxDocSize"><ns0:value>0</ns0:value></ns0:NamedString><ns0:NamedString name="X-Oracle-Device.Class"><ns0:value>pcbrowser</ns0:value></ns0:NamedString><ns0:NamedString name="X-Oracle-Device.Secure"><ns0:value>false</ns0:value></ns0:NamedString><ns0:NamedString name="X-Oracle-Device.Orientation"><ns0:value>landscape</ns0:value></ns0:NamedString></oracle:GenericExtension></ns0:extensions></ns0:clientData><ns0:markupCharacterSets>utf-8</ns0:markupCharacterSets><ns0:validNewModes>wsrp:view</ns0:validNewModes><ns0:validNewWindowStates>wsrp:normal</ns0:validNewWindowStates><ns0:validNewWindowStates>wsrp:maximized</ns0:validNewWindowStates><ns0:validNewWindowStates>wsrp:minimized</ns0:validNewWindowStates></ns0:markupParams></ns0:getMarkup></env:Body></env:Envelope>



It would probably take a bit of trial and error to hack that for another portal/portlet, but who knows.

Putting this in groovy (stripping out the JSESSIONID):

def headerLines = """\
Host: mycomputer:8080
Connection: keep-alive, TE
TE: trailers, deflate, gzip, compress
User-Agent: RPT-HTTPClient/0.3-3
Oracle-ECID: 86139989405,1
SOAPAction: "urn:oasis:names:tc:wsrp:v1:getMarkup"
Accept-Encoding: gzip, x-gzip, compress, x-compress
Content-type: text/xml; charset="utf-8"
Content-length: 2165
"""

def postBody = """\
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns0="urn:oasis:names:tc:wsrp:v1:types"><env:Body><ns0:getMarkup><ns0:registrationContext><ns0:registrationHandle>C:xxx.xx.xx.xx:-5fd1fa94:11740915845:-7ffe</ns0:registrationHandle></ns0:registrationContext><ns0:portletContext><ns0:portletHandle>E:0:xxx.xx.xx.xx:-5fd1fa94:11740915845:-7ffd</ns0:portletHandle></ns0:portletContext><ns0:runtimeContext><ns0:userAuthentication>wsrp:xxxxxxxx</ns0:userAuthentication><ns0:portletInstanceKey>1179_354032_1179_1_1</ns0:portletInstanceKey><ns0:namespacePrefix>__ns1179_354032_1179_1_1_</ns0:namespacePrefix></ns0:runtimeContext><ns0:userContext><ns0:userContextKey>mylogin</ns0:userContextKey></ns0:userContext><ns0:markupParams><ns0:secureClientCommunication>false</ns0:secureClientCommunication><ns0:locales>en-us</ns0:locales><ns0:mimeTypes>text/html</ns0:mimeTypes><ns0:mode>wsrp:view</ns0:mode><ns0:windowState>wsrp:normal</ns0:windowState><ns0:clientData><ns0:userAgent>Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727) RPT-HTTPClient/0.3-3</ns0:userAgent><ns0:extensions><oracle:GenericExtension xmlns:oracle="http://xmlns.oracle.com/portal/wsrp/v1"><ns0:NamedString name="X-Oracle-Device.MaxDocSize"><ns0:value>0</ns0:value></ns0:NamedString><ns0:NamedString name="X-Oracle-Device.Class"><ns0:value>pcbrowser</ns0:value></ns0:NamedString><ns0:NamedString name="X-Oracle-Device.Secure"><ns0:value>false</ns0:value></ns0:NamedString><ns0:NamedString name="X-Oracle-Device.Orientation"><ns0:value>landscape</ns0:value></ns0:NamedString></oracle:GenericExtension></ns0:extensions></ns0:clientData><ns0:markupCharacterSets>utf-8</ns0:markupCharacterSets><ns0:validNewModes>wsrp:view</ns0:validNewModes><ns0:validNewWindowStates>wsrp:normal</ns0:validNewWindowStates><ns0:validNewWindowStates>wsrp:maximized</ns0:validNewWindowStates><ns0:validNewWindowStates>wsrp:minimized</ns0:validNewWindowStates></ns0:markupParams></ns0:getMarkup></env:Body></env:Envelope>"""

def url = new URL("http://mycomputer:8080/MyPortlet/portlets/WSRPBaseService")
def conn = url.openConnection()
conn.doOutput = true

headerArray = headerLines.split("\n")
headerArray.each {
iColon = it.indexOf(":")
name = it[0..<iColon]
value = it[iColon+1..-1].trim()
println """Header $name = $value"""
conn.setRequestProperty(name, value)
}

conn.outputStream << postBody
conn.inputStream.eachLine { println it }


Running this produces the following output:

&lt;p class="portlet-font"&gt;Welcome, this is the view mode.&lt;/p&gt;
Current Date/Time is: 2008-01-08 12:20:36.0</ns0:markupString><ns0:locale>en</ns0:locale><ns0:requiresUrlRewriting>false</ns0:requiresUrlRewriting><ns0:cacheControl><ns0:expires>0</ns0:expires><ns0:userScope>wsrp:perUser</ns0:userScope></ns0:cacheControl><ns0:preferredTitle>ComboPortlet</ns0:preferredTitle></ns0:markupContext></ns0:getMarkupResponse></env:Body></env:Envelope>



If you have suggestions for a good library for this, or improvements to the groovy code, please comment.

Friday, September 21, 2007

Opening JBoss AS HTTP Traffic Up To More Than Localhost

JBoss by default binds only to 127.0.0.1  So to open it up, use:

run -b <your machine's IP address>

To really do it right: Secure JBoss wiki page

Blather: I went to show off my latest Seam, Ajax4jsf, Richfaces suggestionBox/autocomplete widget to a coworker on JBoss AS 4.2 and had problem when I tried run against anything but localhost. Even on my own machine, but using my full hostname, the browser behaved strangely, not even giving a decent status code or anything. I used the Firefox Tamper plugin (Tamper + Firebug + Web Tools = web developer nirvana [okay, I stole this tagline from somewhere else in my web travels]) to see that the request status was "pending". Perhaps that is how JBoss goes stealth against port sniffing. Anyway, I figured it was just a security setting based on the principal of requiring developers to have to conscientiously open up security. But after reading the fine manual, I still didn't find it. Turns out this is a very popular question in the forums though. And, it was actually in the readme.html (sadly I missed it there) under "Configuration Issues" for 4.2.0 GA (however, I stopped reading at 4.2.1 GA--seems it should be under 4.2.1 since it still affects it).

For those googling:
Unable to connect connection
Internet Explorer cannot display the webpage