Weblog for Costin Manolache

Technical stuff

Thursday, June 04, 2009

More on FutureTask

Adding to my previous FutureTask post: Future is a very nice interface, but the main problems with FutureTask are the lack of a callback and the clumsy constructor that requires a Callable. I guess their main use case was someone creating a FutureTask that performs a slow operation - as in my example, it is relatively easy to wrap the method in a Callable and then execute the FutureTask in a thread pool. It is possible to add a callback by overriding FutureTask.done(), which is called after FutureTask.set(). There are few tricks to better use FutureTask. Let's say you have an operation that happens in background already, and you're notified with a callback. You want to wrap it in a Future to make it easier to use:
  interface Callback {
    void done(Object1);
  }

  void doSomethingAsync(Callback callWhenDone) {
  }

  class MyFuture extends FutureTask {
    public MyFuture() { 
      // FutureTask _requires_ a callable - even if it's not using it. Let's give him a dummy one.
     super(new Callable() { public Object1 call() { return null; }});
    }
    // set() is protected - need a visible method to let future know the result 
    public void gotTheResult(Object1 result) {
      this.set(result);
    } 
  }	

  Future<div class="youtube-video"><object1> getSomethingFuture() {
    final MyFuture res = new MyFuture();
    // We _don't_ submit it to an executor - so run() will not be called
    doSomethingAsync(new Calback() {void done(Object1 result) {
      // do what innerRun() does - i.e. call innerSet with the result. 
      // innerSet() will set state to RAN , even if the callable was never called.
      res.gotTheResult(result);});
    return res;
  } 


Monday, November 10, 2008

My synergy settings

I have multiple laptops and computers, and sometimes use them at the same time - it is convenient to use a single keyboard
and mouse. The problem is that the config is not fixed - and synergy is quite hard to reconfigure dynamically.

I start a synergys server on each computer whose keyboard I may use, and use a couple of scripts to create tunnels and
restart the clients.

The trick is to not use specific hostnames - but dummy ones, and explicitly set the "-c clientname" param. Then all real
config is done using ssh tunnels - with the extra benefit of

Server:
  synergys -n localhost -a 127.0.0.1:24800

  # optional: ssh to shared server ( if the keyboard host is behind another firewall ):
  ssh -f -N -R 24800:127.0.0.1:24800  public_computer_with_sshd

Server config: ~/.synergy.conf

section: screens<br />      localhost:<br />      up:<br />      down:<br />      left:<br />      right:<br />end<br /><br />section: links<br />      localhost:<br />        down = down<br />        up = up<br />        left = left<br />        right = right<br />     up:<br />        down = localhost<br />     down:<br />       up = localhost<br />     left:<br />       right = localhost<br />     right:<br />       left = localhost<br />end<br /><br /><br />
On client:
  
   ssh -N 24800:127.0.0.1:24800 server &
   echo $! > ~/.synergyssh.pid  

   killall -9 synergyc
   synergyc -n down localhost

I have few client scripts, pointing to different keyboard servers and layouts.



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);
      }
    }
  });

Friday, August 08, 2008

Common-sense on unit testing

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.

About Me

Costin Manolache
View my complete profile