Before today when I wanted to add a web site's feed to Google Reader from Chrome I would "view source", find the feed URL, then go to google reader to subscribe to the feed. Today I finally got a brain, and checked to see if there's a chrome extension that automates this process, and I found exactly what I wanted. . It's great when someone solves a problem for me!
Friday, December 03, 2010
Tuesday, November 23, 2010
Glassfish JDBCRealm authentication against DSpace user database
A project we're working on at the library requires a DSpace repository webapp to cooperate with a custom data-submission webapp that we're building. We want our custom webapp to authenticate with the same credentials that dspace manages in its internal database. Luckily, our glassfish app-server includes a JDBC security realm that fit this problem perfectly.
It took me several hours of head banging and googling ( http://blogs.sun.com/swchan/entry/jdbcrealm_in_glassfish_with_mysql , http://blogs.sun.com/swchan/entry/jdbcrealm_in_glassfish , http://blogs.sun.com/swchan/entry/assign_groups , http://stackoverflow.com/questions/719708/java-web-application-using-a-custom-realm ) to figure out all the steps to properly configure a glassfish JDBCRealm to authenticate our webapp. I was really glad it worked in the end. I configured a glassfish JDBC security realms with the following properties to access the 'email' and 'password' column's in the dspace 'eperson' database table. The following data in domain.xml can be configured via the glassfish admin webapp
<jdbc-connection-pool datasource-classname="org.postgresql.ds.PGSimpleDataSource" is-isolation-level-guaranteed="false" res-type="javax.sql.DataSource" description="connection to local dspace database" name="dspace"> <property name="DatabaseName" value="dspace" /> <property name="LogLevel" value="0" /> <property name="LoginTimeout" value="0" /> <property name="Password" value="XXXXX" /> <property name="PortNumber" value="0" /> <property name="PrepareThreshold" value="5" /> <property name="ProtocolVersion" value="0" /> <property name="ServerName" value="localhost" /> <property name="SocketTimeout" value="0" /> <property name="Ssl" value="false" /> <property name="TcpKeepAlive" value="false" /> <property name="UnknownLength" value="2147483647" /> <property name="User" value="XXXXX" /> </jdbc-connection-pool> <jdbc-resource pool-name="dspace" description="dspace data source" jndi-name="jdbc/dspace" /> <auth-realm classname="com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm" name="dspaceRealm"> <property name="datasource-jndi" value="jdbc/dspace" /> <property name="jaas-context" value="jdbcRealm" /> <property name="user-table" value="eperson" /> <property name="user-name-column" value="email" /> <property name="password-column" value="password" /> <property name="group-table" value="epersongroup" /> <property name="group-name-column" value="name" /> <property name="assign-groups" value="users" /> </auth-realm>
Finally, we configure our webapp to use the dspaceRealm with the following blocks in WEB-INF/web.xml:
<!-- Login config for production server. See role-mapping in sun-web.xml too. Details of dspaceRealm configuration for glassfish in bLog. <login-config> <auth-method>BASIC</auth-method> <realm-name>dspaceRealm</realm-name> </login-config> <security-role> <role-name>users</role-name> </security-role> <security-constraint> <web-resource-collection> <web-resource-name>Secure Pages</web-resource-name> <url-pattern>/*</url-pattern> <http-method>GET</http-method> <http-method>POST</http-method> </web-resource-collection> <auth-constraint> <role-name>users</role-name> </auth-constraint> </security-constraint> -->
... and WEB-INF/sun-web.xml:
<!-- Enable on production server - see note in web.xml .... <security-role-mapping> <role-name>users</role-name> <group-name>users</group-name> </security-role-mapping> -->
In the end I wanted to send an e-mail to the dspace tech-list, but I was disappointed to discover that there is not a standard way to incorporate JAAS authentication into an application server security realm. All the app servers have a slightly different way of implementing security realms, and the setup I describe above is glassfish specific, but that's good enough for me for now.
Saturday, October 02, 2010
Too Big To Fail
Last week I finished reading Andrew Sorkin's Too Big To Fail. It was a great read! I was engrossed by the story of the events behind the financial system's near collapse in September, 2008, and the handful of personalities that worked to save the system. The book especially gives insight into the monumental bad decision to allow Lehman Brothers to go bankrupt, the acquisition or legal transition of the other big investment banks, the AIG mess, the passage of TARP into law, and the government's subsequent capital injection into U.S. banks in exchange for equity.
Sunday, September 26, 2010
Powershell browse and recycle functions
I just added browse and recycle functions to my powershell profile: Documents/WindowsPowershell/profile.ps1. The browse function opens up an explorer window at a specified path, and the recycle function sends a path to the recycle-bin after prompting for user confirmation.
# Excerpt from profile.ps1 ... $GLOBAL:docs = $home + "\Documents" $GLOBAL:trash = $Env:TEMP $GLOBAL:shell = new-object -com Shell.Application $Env:nodosfilewarning=1 ... function recycle( $path ) { $clean = resolve-path( $path ) $item = $shell.Namespace(0).ParseName( $clean ) $item.InvokeVerb("delete") } function browse( $path ) { $clean = resolve-path( $path ) #echo $clean.path $shell.open( $clean.path ) }
Sunday, September 12, 2010
Simple Parallelism with Scala
Scala provides some great list processing API's, and it's easy to parallelize Scala's list processing with a java executor service. The following demonstration shows a couple easy ways to parallelize list processing. The second by2Groupwise variation processes chunks of a work list in parallel, and reports progress to the user between chunks. Both by2Groupwise and by2Parallel follow a fork-join pattern where a pass over the work list submits callable tasks to an executor, then a subsequent pass waits for the results.
import java.util.Date import java.util.concurrent.{Callable,Executors,ExecutorService} import java.util.logging.{Level,Logger} object Demo { val log = Logger.getLogger( getClass.getName ) implicit def callable[A]( func:() => A ): Callable[A] = new Callable[A] { override def call:A = func() } val poolSize = 4 val exec = Executors.newFixedThreadPool( poolSize ) var lastReport = -1; def reportProgress( soFar:Int, total:Int ):Unit = { val progress = (soFar * 100) / total if ( progress != lastReport ) { log.log( Level.INFO, "Progress: {0}%", Array[Object]( progress.toString ) ) lastReport = progress } } def timer[A]( work: => A ):(Long,A) = { val start = new Date val result = work ( (new Date).getTime - start.getTime, result ) } def by2( arg:Int ):Int = { Thread.sleep( 1000 ) arg * 2 } def by2Sequential( work:Seq[Int] ):Seq[Int] = work.zipWithIndex.map( _ match { case (arg, index) => { reportProgress( index, work.size ) by2(arg) } } ) def by2Parallel( work:Seq[Int] ):Seq[Int] = { work.map( (arg) => exec.submit( () => by2(arg) ) ).map( (future) => future.get ) } def by2Groupwise( work:Seq[Int] ):Seq[Int] = { val groups = work.grouped( poolSize ).toList log.log( Level.FINE, "Frickjack size: {0}", Array[Object]( groups.size.toString ) ) groups.zipWithIndex.map( _ match { case (group,index) => { log.log( Level.INFO, "Scan index: {0}", index ) reportProgress( index, groups.size ) group.map( (arg) => exec.submit( () => by2(arg) ) ).map( (future) => future.get ) } } ).toList.flatten } def main( args:Array[String] ):Unit = { val work = 1 until 10 log.log( Level.INFO, "Seq {0}", Array[Object]( timer( by2Sequential( work ) )._1.toString ) ) log.log( Level.INFO, "Parallel {0}", Array[Object]( timer( by2Parallel( work ) )._1.toString ) ) log.log( Level.INFO, "Groupwise {0}", Array[Object]( timer( by2Groupwise( work ) )._1.toString ) ) exec.shutdown } }
Saturday, August 21, 2010
frickjack.com DNS forwarding to Google Sites
Today I finally wired up my frickjack.com domain configuration with GoDaddy to just redirect (via domain forwarding) to pages hosted on Google Sites. I bought the frickjack.com domain a few years ago with the idea that I'd get a static IP address, and run a web server from home with a bLog, code repostiory, and some demonstration littleware web applications.
I actually did run my own server on an old laptop for a while, but I always felt bad leaving my old laptop running in the corner just to host a site no one looked at anyway. I tried to manage my own bLog with XML and XSL, but Blogger and other hosted solutions are free and easy to use. Similarly, I've been very happy letting Google Code host my littleware project.
Anyway, Google Sites gives me an easy way to put frickjack.com back online as the root node of the graph that connects my disembodied web presence across blogger, facebook, google code, and other sites.
Sunday, June 13, 2010
Bootstrap Bonanza
This post is a copy of this google doc describing littleware's bootstrap process.
I recently reworked the littleware bootstrap and dependency injection process. In the new system Guice manages dependency injection; java's ServiceLoader utility discovers the littleware modules available in the classpath, and OSGi manages startup and shutdown of subsystems. The new bootstrap code also supports different runtime profiles similar in spirit to java EE6 profiles or configurations in Apache Ivy. The new code both simplifies the process an application follows to configure, startup, and shutdown a littleware application; and also simplifies the artifacts that a littleware extension module must provide to register itself with littleware's runtime to expose its functionality to the application.
Littleware has a multi-step bootstrap process. The parent application determines whether to start littleware in a "server", "client", or "app" configuration. With the "client" configuration littleware's bootstrap establishes and authenticates a user session with a remote littleware server (which is another application running a "server" configuration). The "app" configuration allows applications that do not interact with a littleware server to still take advantage of littleware tools that support generic standalone GUI and CLI applications.
The "server", "client", and "app" systems have similar bootstrap processes. A "client" application begins by allocating a ClientBootstrap.ClientBuilder type object:
final ClientBootstrap.ClientBuilder builder = ClientBootstrap.clientProvider.get();
The ClientBuilder automatically loads the ClientModuleFactory service providers registered in the application class path, and gives the application the opportunity to add or remove modules from the bootstrap module set. The ClientBuilder also allows the application to specify a a profile from the AppBootstrap.AppProfile enumeration. The available profiles include AppProfile.SwingApp (the default), AppProfile.JNDI, AppProfile.CliApp, and AppProfile.WebApp.
The ClientBuilder constructs a LoginSetup object that provides methods to manage user authentication including an automatic method that prompts the user for his credentials in a way appropriate to the AppProfile, and returns a ClientBootstrap object. The ClientBootstrap bootstrap method injects and returns an application supplied type.
final ClientBootstrap boot = builder.addModuleFactory( new MyModuleFactory() ).profile( AppBootstrap.AppProfile.CliApp ).automatic(); final MyTool tool = boot.bootstrap(MyTool.class);
The littleware runtime is up and running at this point. The MyTool class should be annotated so Guice injects whatever dependences the application needs.
class MyTool { ... @Inject public MyTool( AssetSearchManager search ) { this.search = search; } ...
Under the bootstrap hood ClientBootstrap loops over the ClientModuleFactory service providers to build a ClientModule (a Guice Module subtype) configured :
factory.build( profile )
ClientBootstrap builds a Guice Injector configured by the resulting collection of ClientModule objects, then loops over the ClientModule collection again to inject the OSGi BundleActivator associated with each module. Next ClientBootstrap launches an OSGi runtime to startup the activators. Finally, ClientBootstrap injects and returns MyTool.class the application passed to the bootstrap() method.
Saturday, May 15, 2010
Stacked Authentication with JAAS
I was happy the other day to find a quick solution to an authentication problem using java's authentication and authorization service ( JAAS). I was configuring JAAS authentication for a littleware based webapp where I wanted most users to authenticate via active directory, but to also have a simple password file to manage authentication for some internal users like "guest". Fortunately, JAAS easily supports this kind of thing. After googling around I stumbled across the JMX com.sun.jmx.remote.security.FileLoginModule which uses a simple password file, and I was already familiar with using the com.sun.security.auth.module.LdapLoginModule for simple authentication against Active Directory. I simply configured the "littleware.login" context in the Glassfish server domain's login.conf file (below) so that authentication via either A.D. LDAP bind or the password file would both be sufficient to certify a user. Works like a charm!
littleware.login { com.sun.security.auth.module.LdapLoginModule SUFFICIENT userProvider="ldap://xxxxxx/dc=auburn,dc=edu" authIdentity="{USERNAME}@auburn.edu" userFilter="(cn:dn:={USERNAME})" useSSL=false debug=true; com.sun.jmx.remote.security.FileLoginModule SUFFICIENT passwordFile="/home/glassfish/.littleware/jaasPasswordFile.txt"; };
Tuesday, April 20, 2010
Scala dependent method type
I'm building a simple JSF-3 web application that implements backing beans in Scala 2.8 One bean includes Enumeration properties that a JSF web-form exposes to clients via a combo-box control configured via a key-value map.
<h:selectOneMenu id="patronType" value="#{sampleBean.patronType}"> <f:selectItems value="#{sampleBean.patronTypes}" /> </h:selectOneMenu>
The sampleBean's definition includes patronType and paronTypes properties which are Enumeration subtypes.
object PatronType extends Enumeration { val Student, Faculty, Other = Value } ... @ManagedBean @RequestScoped class SampleBean extends InjectMeBean { private def enumToMap( enum:Enumeration ):java.util.Map[String,Enumeration#Value] = ((new ImmutableMap.Builder[String,Enumeration#Value]) /: enum.values) ( (builder,member) => builder.put( member.toString, member ) ).build ... @reflect.BeanProperty var patronType:PatronType.Value = PatronType.Student @reflect.BeanProperty val patronTypes:java.util.Map[String,Enumeration#Value] = enumToMap( PatronType ) }
I originally defined the patronTypes property as a mapping from String to PatronType.Value.
@reflect.BeanProperty val patronTypes:java.util.Map[String,PatronType.Value] = ((new ImmutableMap.Builder[String,PatronType.Value]) /: enum.values) ( (builder,member) => builder.put( member.toString, member ) ).build
I introduced the enumToMap method to share that code block between several similar properties with different Enumeration types. Unfortunately - a subtype-specific enumToMap implementation has on output type that depends on an input parameter.
scala> def enumToMap( enum:Enumeration ):java.util.Map[String,enum.Value] = | ((new ImmutableMap.Builder[String,enum.Value]) /: enum.values) ( | (builder,member) => builder.put( member.toString, member ) | ).build <console>:6: error: illegal dependent method type def enumToMap( enum:Enumeration ):java.util.Map[String,enum.Value] = ^
I tried several variations on this theme, but finally settled on the enumToMap implementation that just leverages the Enumeration#Value base type. I googled around while working on this code, and stumbled across the fact that scala includes limited experimental support for dependent method types - that will be very cool if it evolves to production status.
Scala's instance-attached nested types have advantages, but they feel alien to an experienced java developer like me.
scala> class A { | var a = "A" | class B { | var b = "B" | } | var b = new B | } defined class A scala> val a1 = new A a1: A = A@6489f0 scala> val a2 = new A a2: A = A@15c44d6 scala> a1.b = a2.b <console>:9: error: type mismatch; found : a2.B required: a1.B a1.b = a2.b ^
Friday, March 26, 2010
Wisdom
I sometimes find myself thinking as I look back at life "Man! I was an idiot back then!" where "back then" might be ten years ago or last year or yesterday or the previous paragraph.
As time passes, I'll think again, "I was an idiot back then" remembering my thoughts the last time I thought what an idiot I was. Eventually I realize that even as I'm thinking what an idiot I was in the past, that in the future I'll look back on the present and think, "What an idiot!".
In time I'll think "I was an idiot when I thought I was an idiot before, because what I did before was not so idiotic although I was too much of an idiot to realize it at the time" - sort of like multiplying two negatives. Of course it's possible to multiply three negatives, "I was an idiot when I thought I was an idiot for thinking I was an idiot".
I know I'll eventually find myself in some bed after the ravages of parkinsons, alzheimers, and multiple strokes leave me with half my body frozen in place and the other half constantly shaking violently. I'll be thinking, "Where am I ? Who is this person feeding me oatmeal ? Who am I ? This oatmeal tastes good! Where am I ? What is this in my mouth ? It tastes good!".
Sunday, February 14, 2010
Larry Ellison in the Cloud
I enjoyed the webcasts Oracle published to outline its product strategy upon the approval of Oracle's acquisition of Sun Microsystems. I was impressed with most of the ideas presented, and I think Oracle will have some success selling their integrated stack "from disk to whatever". However, I was surprised by Larry Ellison's criticism of "cloud computing" when responding to a question near the very end of the event.
Cloud service providers like Amazon EC2 allow a software service developer to deploy one or more copies of a virtual machine image that provides some online software service. A "cloud" service may be a natural evolution of standard hosting provider, but the ability to dynamically allocate and deploy compute resources opens doors for a "software as a service" (Saas) developer. A developer of some service can quickly provision and deploy a virtual server dedicated to some new customer, or scale an application horizontally or vertically in response to increased client load.
A developer team that codes for the cloud avoids the cost and complexity of maintaining servers, networking switches, or storage in a data center. Managing data center complexity is where Oracle makes a lot of its money. Furthermore, the cloud is a natural platform for free open technologies like LAMP that are free to the developer, and do not provide a clear business model for a technology infrastructure companies like Oracle.
Oracle has tremendous breadth and depth of resources, and I don't think Larry Ellison's cloud myopia will be a problem of any importance, but it's strange when a technology leader comes late to an important idea.
Wednesday, January 27, 2010
Apple iPad, Oracle-Sun, and the State of the Union
It's a big day for announcements and media. First, Apple launched the iPad; which looks like it nearly lives up to the hype. Next, Oracle finalized its acquisition of Sun. Finally, President Obama will give his State of the Union address tonight. I wonder which event will be remembered as the most important years from now ?
Sunday, January 24, 2010
Multiple RMI Services on a Single Port
I recently learned of a solution to a problem I've struggled with using java remote method invocation (RMI) to implement client-server applications. I've used RMI for several years, and I think it's a great technology. RMI makes it easy to implement fast and secure remote procedure call between java clients and servers. RMI has two disadvantages compared to REST over HTTP or CORBA as a network computing platform. First, RMI is tied to java, so non-java clients cannot directly access network services via RMI. A second disadvantage of RMI is that RMI exports each of a server's remote objects on a separate TCP network port, so it's difficult to setup firewall rules for an RMI server that dynamically exports distributed objects as different clients request different services.
It turns out that there's an easy workaround to configure RMI to export all of a server's remote objects through a single firewall-friendly network port. I've known for some time that RMI allows server code to specify the port on which to export a remote object. For example, the HelloService below can pass a network port number to its UnicastRemoteObject super class constructor. However, I did not realize that multiple remote objects can specify the same network port to the RMI engine as long as a single RMISocketFactory manages every object on that port (which is the default behavior).
A contrived example below shows a simple scenario where an application dynamically exports multiple remote objects. At boot time, the server initializes a DirectoryService object, and registers the object with an RMI name service. The DirectoryService dynamically creates a HelloService object for each client call to login(). Because DirectoryService and HelloService both specify port 12345 in their constructor, clients access every service object via the same network port.
public class DirectoryService extends UnicastRemoteObject implements Directory { public DirectoryService() { super( 12345 ); } public login( String name ) throws RemoteObject { return new HelloService( name ); } } … public class HelloService extends UnicastRemoteObject implements Hello { private final String name; public HelloService ( String name ) { super( 12345 ); this.name = name; } public String sayHell() { return “Hello, “ + name + “!”; } }
Sunday, January 17, 2010
Jython ScriptEngine with WebStart
An embedded script engine is a great way to empower an application's users with the ability to customize and extend tools, and java's JSR223 ScriptEngine framework makes it easy to implement.
I recently embedded a Jython ScriptEngine in a littleware based application that runs in a WebStart environment. Problems always arise when integrating two sophisticated software frameworks like jython and webstart, but the jython ScriptEngine ran with WebStart after addressing two small problems.
First, the application links against the "standalone" jython.jar library which bundles the complete jython script engine. Second, the application includes the following jython-specific code to add jython.jar to the python library search path.
... final PySystemState engineSys = new PySystemState(); engineSys.path.append( Py.newString( "__pyclasspath__/Lib" ) ); Py.setSystemState(engineSys); final ScriptEngine jython = new ScriptEngineManager().getEngineByName("jython"); if (null == jython) { throw new IllegalStateException("Failed to load jython ScriptEngine"); } ...
Thursday, January 07, 2010
Windows 7 Cross Domain Drive Map Garbage
I tried to map a network drive cross-domain over VPN on my Windows 7 laptop last night, but my laptop failed to authenticate with the file server. Last month I bought a new Dell Studio 15 laptop with Windows 7 64bit, and I've been very happy with it, so I assumed that the map failed due to some random bad setting. I googled around and sent some e-mail to IT support, and eventually found out that I would have to upgrade to Windows 7 Professional to alter the Windows security policy preventing the drive map. The technical details are here in the "catdogboy" posts.
This map drive issue is my first Windows 7 problem that really annoys me. It's upsetting when something works with XP and Vista, but requires extra money and an upgrade with 7.
Library 2020
Let's assume the following technology trends realize their potential over the next ten years.
- Cloud discovery services like Worldcat, EBSCO, and Serial Solutions successfully federate search across most journals and databases that universities subscribe to.
- Subscription services from Google and others offer access to most out of print books.
- Computer tablets like the iSlate with e-reader software become ubiquitous on university campus, and students obtain all their text books electronically.
What would a University Library look like in this world ? The traditional acquisition, cataloging, archiving, and circulation library and librarian roles become anachronisms. The library completes its already begun transition from a student's content provider of books and journals to become a manager of contracts with third party content and service providers that students access directly. Eventually campus IT or some similar organization assumes responsibility for managing the library provider contracts, and the library space itself completes its transition to student union and learning commons.
An academic library may keep vitality as a publisher and archiver of university authored content from research papers to financial statements. It will be fun to see what happens.