Thursday, August 14, 2008

Intercepting SIGTERM

The 'proper' way to terminate a java process on unix is by sending SIGTERM, waiting a bit, and then sending SIGKILL. This gives java a chance to clean - using Runtime.getRuntime().getShutdownHook().

If you want to intercept this and do some early cleanup, before letting the others do theirs you need to use sun.misc.Signal - which can also be used to intercept other signals.

Things to do in a shutdownHook ? Flush the logs, finish important background processes and much more.

Code to intercept the signal:

oldSigTERM = Signal.handle(new Signal("TERM"),
new SignalHandler() {
public void handle(Signal signal) {
System.err.println("Quit using SIGTERM hook");
notificationHandler.prepareToQuit();
if (oldSigTERM != null) {
oldSigTERM.handle(signal);
}
}
});

Thursday, March 20, 2008

Using FutureTask

This is what I typically use to convert a sync method to a background Future. The benefit is that it avoids a lot of custom code (creating threads, locks, etc ) and seems simple enough, and it's relatively easy to cut&paste.

Original:

 
Result1 slowMethod1(Param1 p1, Param2 p2) throws Exception1 {
}
Result2 slowMethod2() throws Exception2 {
}

void caller() throws Exception1, Exception2 {
// slowMethod1 and slowMethod2 are independent of each other
Result1 r1 = slowMethod1(p1, p2); // first expensive operation
Result2 r2 = slowMethod2(); // other slow method, not using the result or side-effects of the first
}


New code:

 
Executor bgTasks = Executors.newCachedThreadPool();

Future slowMethod1Future(final Param1 p1, Param2 p2) {
FutureTask fr = new FutureTask(new Callable() {
public Result1 call() {
return slowMethod1(p1, p2);
}
});
bgTasks.execute(fr);
return fr;
}

void caller() {
Future fr = slowMethod1Future(p1, p2);
Result2 r2 = slowMethod2();
try {
Result1 r1 = fr.get();
} catch(InterruptedException e) {
throw new RuntimeException(...);
} catch (ExecutionException e) {
Throwable t = e.getCause();
if (t intanceof Exception1) {
throw (Exception1) t;
} else {
throw new RuntimeException(t);
}
}
}

Wednesday, February 27, 2008

JConsole in local mode and tomcat

After some debugging found that Jconsole will connect locally to a new MBeanServer created via ManagementFactory.getPlatformMBeanServer(). Tomcat will look for an existing MBeanServer and create one if needed - but this will be different than what jconsole uses.

The fix is 2 lines - benefit is that you can start tomcat normally, without any special flag, then connect with jconsole and inspect/modify settings. It looks like they use some signal or other form of communication on Linux, which opens a TCP port.

I'm not sure why someone would ever want to use MBeanServerFactory.findMBeanServer() and createMBeanServer. Sure, in the rarely used sandbox mode, if you want to strongly isolate apps it may be needed - assuming you want each untrusted app to have access to its own server, and grant it create mbean server rights.

Time to send a patch - long time since I haven't done that...

Tuesday, December 25, 2007

OFX download for vanguard

I've been using ofx.py to get my transactions from Vanguard, it stopped working sometimes this month. I have some code to parse and merge the sort-of-xml responses to an .xls file - which for me works much better than any alternative I tried. Moneydance is close, it provides an API that can be used to extract same data and it's a bit easier to setup, but it does some magic and seem to be less stable. Quicken, Money - never found a way to get my data back, and won't work on linux too well.

Made few changes to get it working again, first the setup is:

"caps": [ "SIGNON", "INVSTMT" ],
"fiorg": "vanguard.com",
"url": "https://vesnc.vanguard.com/us/OfxDirectConnectServlet"
The main change besides url is the code to get the transactions, urllib2 seems to default to HTTP/1.0, couldn't find a way to force it to 1.1 so I changed the code to use httplib directly:


garbage, path = urllib2.splittype(self.config["url"])
host, selector = urllib2.splithost(path)
h = httplib.HTTPSConnection(host)
h.request('POST', selector, query,
{ "Content-type": "application/x-ofx",
"Accept": "*/*, application/x-ofx"
})
res = h.getresponse()
response = res.read()
res.close()


Old:


request = urllib2.Request(self.config["url"],
query,
{ "Content-type": "application/x-ofx",
"Accept": "*/*, application/x-ofx"
})
print "RES: ", res, " ", res.status, " ", res.reason
f = urllib2.urlopen(request)
response = f.read()
f.close()

Saturday, September 29, 2007

JAAS and tomcat

The JAAS ( authentication/authorization ) API has been around for many years now - the idea is to use a standard API for all authentication, and plugins to use NT, LDAP, PAM, SSO and any other realm. JAAS seems modeled after PAM - the auth API for linux ( and unix in general).

Tomcat supports JAAS auth and provides a sample LoginModule based on the simple clear-text xml file. Like most other apps using auth, tomcat also have direct modules to authenticate against DB, LDAP/JNDI, files - but it will never cover the same range of auth sources as PAM for example ( http://www.kernel.org/pub/linux/libs/pam/modules.html ).

JAAS has few big problems - it is quite complex, it lacks modules and it lacks users. A benefit of using a tomcat-specific module is that it can be better optimized for the target environment. The only reason to use it would be to use a PAM auth source, there is now a JAAS-PAM implementation http://jaas-pam.sourceforge.net/ - seems very good, LGPL, uses JNI to interface with PAM.

The default JAAS modules from Sun seem quite useless - they can authenticate the current user, not much more. The JDNI module is probably usable, but the tomcat JNDI source seems more customizable and simpler.

Another option that wraps PAM is SysAuth
(GPL2), it defines it's own simpler API, it could be wrapped in JAAS or
in a tomcat module. Due to license and the fact that jaas-pam exists -
probably not worth the effort. Another dead end is ShadowJAAS - it supports unix
user/password authentication, by parsing passwd/shadow files in a SUID
root file.




Thursday, May 11, 2006

JMX names

Sun's advice http://java.sun.com/products/JavaManagement/best-practices.html
  • Allways have type=
  • if singleton ( or one instance per domain ) - no  other key
  • otherwise: add name=
  • for grouping, add group=
  • j2eeType/jsr77 - they kind of agree it's a messs -  I think
  • they do actually define a 'containment scheme', using type=Server.Application.WebModule,..  and  Server=, Application=, etc. Not quite JSR77 - but close enough., and it makes more sense.
  • of course - an easier solution would be to just use  unix-like names name=//servername/appname/webname,
On mbeans, they advise:
  • use standard MBeans - and use the interface with newProxyInstance. Not sure I agree with this one, if you want this kind of programmatic access use RMI/corba/etc if out of process, and the object directly if you are in process - you still have coupling and dependency, but no need for the JMX layer, which is not designed as RPC and is more inefficient than direct calls.
  • advice against DynamicMBeans - instead extend StandardMBean.  I strongly disagree with this one.
  • On model mbeans, the correctly mention that they are hard to use by themself. The fact that they can't have interfaces is false AFAIK, you can define the interfaces if you want and the proxy will be generated, you can construct a dynamic proxy for anything if you want to write the interface. There is a decoupling since the implementation doesn't have to implement the method, but this can happen in any case if one side changes attributes/methods. See the above point on why I think dynamic proxies for JMX are a convoluted and bad idea.
  • recommend using OpenMbeans - good idea, and avoiding RMI-specific features like downloading classes.
As usual for any 'best practice' document - don't believe all they say, ask first what 'practice' they had and how many applications they developed or considered before finding the 'best', and how they relate to your use case.

Tuesday, November 22, 2005

JamVM -- A compact Java Virtual Machine

JamVM - impressive VM, runs tomcat without problems, even eclipse works. All in less than 1/2 M. Speed is decent for simple use. And it supports ARM - so I can play with java and tomcat on my toys.