My talk on Spring Integration At TheServerSide.com '09
I did a talk waaay back in March on Spring Integration for TheServerSide Symposium. If you're into Spring and want an hours worth of good wholesome ESB fun, may I humbly suggest you check out the talk. I'd love to know what you think so please feel free to leave a comment!
Tapestry 5.1
Recently, I've been playing with Tapestry 5. The experience has been extremely satisfying. Although there are issues that could be worked on, on the whole this is the most pleasant development environment I've ever use for Java Web development. Frankly, it started as just a way to keep my mind away from a main project I'm working on. I figured I'd give it the five minute test. Actually, this is the third time I 've given it the five minute test, and this time it took. What did it was release 5.1, which sports a few features that indicate that Tapestry 5 is becoming a very "practical" choice, not just the right one.
Tapestries 5.1 sports the ability to gzip compress, as well as consolidate, JavaScript files. It does other things with images and css, too. It's not just yet on par with JAWR - which, honestly, I love - because there's something freeing about knowing that if your page needs libraries x, and y, that there's a component out there that's doing everything possible to make the impact of inclusion of that library acceptable. CSS and JavaScript are to the web what "jars" are to the JVM: an encapsulated packaging of externalized, reusable functionality. Being able to optimize loading them, then, is crucial.
Knowing this, I decided to give it a look. I got into it, just a little. I used the Maven Tapestry archetype and created a separate project. Downloaded Tomcat 6 and even loaded Eclipse 3.4. I imported the Maven project using the m2eclipse plug-in, setup a Tomcat 6 server instance, and deployed my application to the instance. I configured Tomcat to "serve modules without publishing," and disable auto publishing. Then I crossed my fingers and hoped for the best. I loaded the browser and hit the front page. The site that's generated is pretty, but boring. It does, however, prove inviting. I returned to Eclipse, associated the HTML editor to *.TML files, and then started hacking. I started with a change to a .TML file. <h1>Hello, world!</h1>, placed in the middle of the Index.tml file. I refreshed. It worked...! I went to the Index class itself, and added
public String getMyMessage(){
return "Hello, moto.";
}
Then, on the Index.tml file, I added ${myMessage}.
Again, I just refreshed the browser, and it worked! In comparison to Tapestry 3 and 4, this was great. But I've blogged about Zero Turnaround's JavaRebel product and I've certainly seen Tomcat do some neat things with regular Struts projects or Spring MVC projects. I wasn't.. aghast, just yet. Finally, I started getting into it.
I have used the various versions of Tapestry before, so I knew - essentially - what components to expect and essentially what to imagine possible. I had programmer courage. So I was a little more ambitious and decided I'd tackle something a little more ambitious. I started with a component to provide a panel. The panel would have a parameter for a ValidationTracker, which is the object that keeps track of what validations have occurred on a @Form component (very much like ActionErrors/ActionMessages in Struts. The panel would turn red if there were errors in the form it contained. This was a hard thing to do before because Tapestry had issues with the order of the layout of the components.
Suffice it to say, it worked. It was also blissfully simple. No interfaces, not even annotations if I didn't want them. I was able to parameterize the title of the panel using a @Block (like a facet in JSF). In a package adjacent to my test page, I added a simple POJO, with a few accessor / mutators (a Customer class, with the usual sort of properties..). I declared an instance of it on my test page's class and added a @Property annotation to it - I didn't have to even create a java bean style accesor! I added a Form and a few TextField components to the class, too.
@Component(parameters={"value=customer.email"}) private TextField email ;
@Component(parameters={"value=customer.password"}) private TextField password ;
@Component private Form form ;
On my page, the I had:
<form t:id="form">
<t:label for="email" /> <input t:id="email" /> <br/>
<t:label for="password" /> <input t:id="password" /> <br/>
<input t:id="signup" type="submit" />
</form>
This seemed like enough, so I hit refresh and .. unsurprisingly, it worked!
Naturally, this doesn't do anything. I wanted to make the Form component do something on successful submission.
I looked around, and the simplest way to do that was to name a method as though I was descrbing it in English:
void onSuccessFromForm() {
System.out.println( new ReflectionToStringBuilder( this.customer).toString()) ;
}
And of course, that worked! It's worth mentioning that during all of this - method additions, field additions, component adjustments, etc, I've not redeployed or published or even waited for more than a split second even once. The 5 minutes had become an hour. The reason I write this blog is because I'm now well into hour 7, and I'm thoroughly impressed. It's actually fun to work in. If you've ever had that wow! moment in a dynamic language where you just can't beleive how nice it is to hit refresh and work, then you'll appreciate Tapestry. I can't usefully compare it to another Java framework because there's nothing like it. It's liberating. Check out Neal Ford's amazing "On the Lame From The Furniture Police" to watch a discussion on keeping focus, flow while working. In it, he basically discusses just how damaging a minute idle time is when developing an application. Tapestry breaks that cycle for you. No more flow stoppages. I've become impatient with the browser's ability to repaint, actually!
I wholely recommend you take a look at Apache Tapestry 5.1.
My Los Angeles Musings, Seam, Tapestry 5, JavaOne, Spring Workflow, Spring Python and more
Hello, world.
My life has been utterly and completely busy for the last several months. I don't know about you, but I love it when that happens, even if it does take me aay from priority things like maintaining this blog. I'll take this post to sort of stretch my blog legs out again, and then try to establish a blog with more frequency.
When last I wrote, I mentioned that I had moved from Phoenix, AZ to Los Angeles, CA. I started work on April 1 (cool company, nice people, interesting software, moving on...). I worked pretty consistently and started looking for a place to stay as I was at that point lodging with my mom. My wife came from Phoenix, AZ a month later, May 1. She stayed back while I sort of scouted ahead and started work. We've found a nice apartment in Canyon Country, CA, which is, honestly, very pleasant. It's far away from Los Angeles proper that the prices seem acceptable, but close enough that I can make my 20 mile commute in about 24 minutes, which I appreciate. I've also enjoyed (surprise surprise) the weather, which has been beautiful of late. As an example, as I write this it's very, very early in the morning, just after midnight, on Friday, June 5. The temperature is 88F in Phoenix, AZ right now, and 59F here in Los Angeles, CA. Couldn't be happier. Nothing like being able to program with the air conditioning off in the winter. Frankly, I've really just sort of enjoyed the little things.
I don't mean to gloat, but it's amazing what you take for granted when you live here. It doesn't hurt that the economy's so bad it's sort of leveled out the prices, making parts of Los Angeles very approachable for somebody who's used to Phoenix prices. I'm a fan of AT&T's Uverse ISP here in Los Angeles. I had COX cable in Phoenix, AZ. I paid about $130 a month to get two DVRs, cable internet with very limited storage and no ability to share among the bedrooms and almost no channels. Not to mention, I couldn't get a static IP (the shame, the humanity!) without a business account, which given how little I liked them was out of the question as it would've compelled me to accept a year long contract. Needless to say, all of that's been improved, and I pay less, and I have a much wider channel selection, to boot!
Of Web Frameworks
I've had the chance to play with some very cool technologies in depth of late, one of which is Jboss Seam. I've had issues with Java Server Faces in the past, and have even spoken to some of the issues I've had, but nonetheless it works and, when taken together with something like Tomahawk, Facelets and the various Spring integrations, you can be productive using it. Naturally, JSF has it its battlegrounds, and really scalable, stateless applications with Google indexability is not one of them. Knowing that, you can get it to work. Seam rectifies some of this and worsens it, as well. I've had an amazing time sort of rethinking through problems, learning how to approach things the Seam way. If you let your mind wander, it seems like it's very easy to produce terrible code. Essentially, this stems from certain assumptions JSF, and Seam on top of it, make for you.
One of them is that the HTTP Session is infinite. Seam addresses some of these issues by providing a very cool concept called a "conversation" - which I'm sure we've all seen before, but which really is quite refreshing in its application inside of Seam - which models the idea that you have a unit of work that is greater than a single request but smaller than a session. This is fine as it allows you to keep state around and use it as required and then trust that, when the conversation's finished, Seam will reap all that session memory back. Additionally, because Seam components are basically stateful session beans (unless you're using Seam POJOs, in which case they're basically stateful session beans that you can't use on another framework or EJB3 stack..) there's very little clear separation of tiers. You need to find an entity inside of a JSF action listener? Grab an entity manager and issue a query, and then add JSF validation messages if you can't find it! It almost seems like a step back, honestly. This extra state, I find, has required me to whip out a debugger more times than I care to admit. In complex interactions it becomes very difficult to keep track of preconditions and postconditions for a given interaction.
The real shame to me as a person who is very fond of jBPM, Seam doesn't force the concept of conversational state far enough down the throat of the users. JBPM is definitely well integrated, but it's not required. It's also very possible to eschew altogether jPDL based Seam navigation, which makes for an application that has complex continuations and state without rail guards within which to advance. Anyway, giving it credit where credit is due, it's definitely better than raw JSF. I've also come to very much like Ajax4JSF and RichFaces. Part of me cringes when I realize that even simple Ajax requests are basically re rendering the whole page (or, rather, most of the body and several additional script tags), and in the process making the net burden of a given interaction with the server for certain pages on the order of several megabytes of un-cacheable Ajax JavaScript and HTML. The other part of me is utterly stunned with the richness of the results. It does, really, work. Taken together with some of the awesome features Seam itself provides (why couldn't they have just chosen Tapestry? Such apparently talented people working on JSF seems like a crime...)
I can't help but feel, sometimes, that we're heading down the path of ASP.net with JSF. ASP.net is a component based framework, and component based frameworks like Wicket, JSF, and Tapestry all fundamentally are familiar to somebody who knows ASP.net. ASP.net has a slew of components that you can use and which rammed a lot of state down the clients throat to keep the illusion that the programmer was dealing with a Windows Form application. This worked well until, one day, you wanted to override a style attribute on some component that had inline the CSS and no assigned ID. Now, you were fighting with the framework to restore your will. In this way, I feel like JSF is very similar. When I use Ajax4JSF, RichFaces, and Seam in general I am able to easily forget that I'm working n top of a statless protocol where every request has absolutely no idea what happened just one request before it but for the graces of a cookie or a state field in the request. This is why ASP.net MVC was birthed, to provide an approach for those that wanted more fine grained control. In this way, the .NET community has sort of reversed our evolution in the Java community, going from the action-oriented Strutses and Webworks and even Spring MVC, to the componented oriented JSF, Wicket, Tapestry and GWTs of the world.
Using JSF/Seam, I even forget about the cost of state a little bit. State's what it's all about. The Seam proponents will insist that storing state on the HTTP session is far more efficient than in the database, which is inherently less scalable. In theory, I agree with this. However, Seam still hits the database for non cached data (if you have that setup!), and you're still not excused from reconciling optimistic lock exceptions using Seam, and it leaves you with an HTTP Session brimming with state and a HTML that can easily grow to be several megabytes for midly complex UI interactions and their components.
I have met people who were under the illusion that servlets (raw servlets) had a session by default, that it was to be taken for granted. I've spent a long time building applications where the goal was to avoid the session at all costs, until absolutely necessary (make your Struts beans request scope, turn of JSP sessions, and if you're going to do redirect after post, either encode the state in the redirect request or be darned sure you use what's now being called "flash" scope, session persistance in the service of just two HTTP requests.
Anyway, having invested so much in understanding and learning Seam, I decided I might as well give Tapestry 5.1 a chance, as it's been a few years since I had a chance to work with Tapestry, and that was Tapestry 4. I always had a personal fondness for Tapestry. It's always been session friendly by default and to be efficient as a component oriented framework. This has led to some gimmicky approaches (the render/rewind cycle, and lack of support for dynamic (read: programmatic) component creation and attachment)
I spent a little time getting used to it. I have to tell you, given my experience with ZeroTurnaround's JavaRebel javagent for Java class reloading, I really appreciated the intrinsic support for class/component reloading in Tapestry. As a development environment goes, I haven't had this much fun since Python on a web application. Truly amazing. I was somewhat disappointed to see that Tapestry has slackened it's feverish refusal to use the session, and made everything redirect after post unless specified otherwise. The implication here is that there's some session. It's still very efficient, and I've not caught it trying to store an entire backing bean (page or component) in the session yet! If you have a chance, I wholely and completely recommend it. It's lacking support for the things JAWR (a JavaScript/CSS) compression filter) provides - though there seems to be at least some effort aimed at adding it at no additional technical cost to the developer. It just works.
The World At Large
I sat, jaw agape, as the rumor milled tossed around the notion that IBM would buy Sun, and wondered what would become of some of the interesting technologies inside Sun. Imagine my surprise when I woke to find the rumors quashed and Sun bought, by Oracle of all things! I couldn't believe it. Larry Ellision took the stage at JavaOne and reaffirmed interest in JavaFX. JavaFx is one of the few decent options we have in the Java client landscape, and even if I never write an application in JavaFx itself (I once tripped and learned ActionScript 3 and Flex programming, and I don't think I could see the value in switching now..), the work done to support JavaFX has been a boon for the JVM/JDK. Hopefully, this innovation will continue.
SpringSource has been doing a lot of great things of late. Spring Roo is a promsing mechanism by which useful prototype applications can be created on the fly, a sort of Spring-y version of Rail's application generarots. Spring IDE being released for free, which is a boon as somebody who's used OSGi without good tooling, and - most interesting to me - I discovered Spring Workflow, which looks very promising indeed. I am a huge fan of a good BPM engine, and it's something fundamentally hard to do correctly. Enterprise BPM engines are even harder. Hopefully, Spring Workflow will remedy some of this. Finally, I couldn't help but note the amazing progress of Spring Python. I adore Python, and have used it in anger many, many times over the last decade. It's never failed me. I'm pleased to see Spring's offerning not merely being a Java-Spring that happens to be written in Python. This framework seems to be geared towards the Python way, even going so far as to remind people in the (incredible) documentation that if nothing else, the libraries Spring Python provides can, and very well may be, used independant of any XML format!
Additionally, May saw the debut of Google Wave, which seems to be an incredibly cool platform on which to build. I'll be very interested to see what comes of this.
I wonder what the next month will bring. I'll do my best to keep this blog up to date. I've heads down on a lot of work, and a few cool surprises I'll share when appropriate. By the by, I encourage you to follow me on Twitter at http://twitter.com/starbuxman.
Moving to Los Angeles.
What a month! I know this is a little late, but boy has it been a crazy month! April's shaping up to be no less crazy, too.
First, there was much ado about nothing early in the month when the court in Tempe, Arizona scheduled me for jury duty only to relieve me of it the day-of.
Then, on March 17th, I drove to Las Vegas for the conference - my first big speech - at the The ServerSide Java Symposium in Las Vegas (which reminds me, I need to remove that banner on the right side of the page... ) which went off fine enough. More usefully, I have some very interesting new friends. I was especially happy to have had a chance to see the Mandalay Bay Aquarium, which was amazing.
From Las Vegas, I drove to Los Angeles, CA to meet my friend Srinivas who I'd invited to join me for a weekend there. We drove 500 miles in 2 days just inside of Los Angeles, and another 400 when we shared the drive home to Phoenix, Arizona. We went to the Laugh Factory and were delighted to find that Dane Cook was a special, secret guest-of-honor. Awesome!
Then, I came home. I had given notice at my job at Wells Fargo and so the last week of March I spent closing up shop there and preparing for the next step. March 31st was my last, very sad day at Wells Fargo. I said good bye to everyone -- good people I should like very much to keep in contact with -- and packed up a few computers and books (and clothing, I suppose.) and drove to Los Angeles (again!) to start a new job there April 1. My wife and I are moving here, but the first step is getting out here and finding a place to live and so on. At the moment, I'm staying with family and my wife will join me soon.
These last few days have all about getting into the new job - interesting people there, too - and reuniting with some old friends.
Boy, am I glad to be back!
The Times, They Are A Changing
Not to cheapen such an awesome Bob Dylan song, but I felt it was a propos... Things are really going to be busy pretty soon.
Lot's of things are happening in my life right now. It's going to be a pretty turmultuous two months.
For someone who's adamant about encouraging change, and reacting gracefully to change in the software development lifecycle, I'm about to be put to the test. My wife and I are moving to Los Angeles, CA, where I'm from. This will put us closer to family. As I move forward and start speaking and doing more open source in my career, I don't want my vacation time to be spent just going to see family if I can instead spend it going to more conferences and being involved in the software world.
It's a very interesting time to be in software: I haven't felt like this since the late 90s.
I've resigned my current position at my job and am looking forward to the next opportunity. I expect I'll be challenged, and hopefully given a chance to institute oositive change.Getting to that opportunity, could be ... tedious, however. State or continental moves are always challenging.
In the more immediate short term I'm looking forward to The Server Side Symposium in Vegas this week! I'm speaking on EAI and Spring Integration, in particular. It's a very promising new technology and I hope to encuourage people to check it out. If you're coming and you want to read some more on it, there's always the site I just linked to, as well as an article I wrote about it a little while ago, "Getting Started With Spring Integration," on Infoq.com. I definitely encourage you to check those out.
By the by, anybody know of what parties / events are happening after the event? I'd love to meet and greet any of you who are going to be there.
After that, it's off to Los Angeles, where I'll be advance scouting for a place to stay. If anybody wants to grab a beer while I'm there, let me know. I can be reached at josh 'at' my domain name. Or, contact me on Twitter.
Embedding The Apache Mina FTP Server
I had the requirement to provision users of a system with an FTP solution. I wanted something lightweight and very configurable. I chose to embed The Apache Mina FTP Server since it's flexible, imminently hackable, (it's written in Java and is deployed using Maven and Spring) and embeddable. This entry is about that process.
Essentially, I didn't want to have to wrap it in a layer of abstraction just to support adding and removing users and configuration options like their home directory. It also had to be flexible, as there may be different requirements down the line oriented towards security.
My use case is simple: I want to build a processing pipeline for images (who doesn't?). I want users of the system to be able to login to an FTP with their same credentials and upload media. On the server, Spring Integration will watch for uploads and send off a message to the message queue which is where the BPM engine sits, and is waiting to begin image processing on inbound images.
What could be simpler? In this blog entry, I will only discuss addressing the first requirement: provisioning system users with accounts on an FTP server.
I did look at some other alternatives, namely HermesFTP and AxlRadius, which seemed both to be interesting projects. I really have no opinions for - or against - them, Apache just has the backing foundry's name and more sophisticated documentation.
To test, I suggest using FileZilla, because it's powerful, free and features a no-pain installation for the big 3 operating systems,
You can run the application as a stand alone server, but I'm running it as process that piggybacks the web application. In this blog, I'll simply introduce using it a simple public static void main(String [] args) context.
Installation
Getting the server is easy, as I'm using Maven. Below are the dependency elements to add to a POM if you don't already have them. Note the strangeness with slf4j. I don't know if you'll encounter any issues with it in your configuration. My setup was riddled with ClassNotFound exceptions, and the configuration resolved them. You may very well be able to remove the exclusion from the org.apache.ftpserver dependency as well as the two explicit dependencies on slf4j at the top.
I don't include the Spring framework dependencies here, but I do make use of Spring 2.5.x, though I suspect this would run just fine with Spring 2.0. Your mileage may vary.
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.5.3</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.5.3</version>
</dependency>
<dependency>
<groupId>org.apache.ftpserver</groupId>
<artifactId>ftpserver-core</artifactId>
<version>1.0.0</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
Code
Now that the JARs are in place, you need some a Java class to launch it and some configuration.
The java code is below. It loads the Spring application context and punts the chore of configuring the server to it and the Spring XML file I've setup, ftp-server.xml. Once a freshly obtained instance of the server is obtained, the server is started.
package com.foo.integrations.ftp;
import org.apache.ftpserver.FtpServer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) throws Throwable {
ApplicationContext classPathXmlApplicationContext =
new ClassPathXmlApplicationContext("ftp-server.xml");
FtpServer ftpServer = (FtpServer)
classPathXmlApplicationContext.getBean("server");
ftpServer.start();
}
}
.
Configuration
The configuration's the most involved bit, but should be pretty self explanatory shortly. It's included below. The FTP server exposes configuration using a Spring XML Schema, which acts as something of a DSL in this case.
The XML configures the server instance, tells it to defer authentication to a database. It seems like the component provide is expecting data to be available in a table called ftp_user. In this case I modeled a table called ftp_user and created columns in it for testing. The final solution will either be a view on top of existing data that vends the table and columns expected by the component, or a series of triggers that keep a real ftp_user table in sync with the canonical user/password and status data in other tables.
I'm not sure which is more performant, and will address that later. It should be evident how that might work, I hope. In the code below you can see we're giving the database authentication component the SQL queries to use. I'm not sure I want to keep the delete/update functionality in place there. I don't think it's accessible from the FTP protocol, but instead there are APIs that Mina ships with, and I think use of those APIs delegates to these queries.
The dataSource is just like any other dataSource inside of Spring. I'm not using the Apache Commons Connection Pool class here because I didn't want to require more jars for you, dear reader, to try this example out. But use your judgment. If your application server requires something else, then use that.
Finally,
a word about directories. Below, in the <select-user> configuration, I return a result set that contains a column homedirectory. The home directory in this case is not an Operating System home directory (~, for example), but instead the directory the logged in user should be dropped. Here I'm using ficticious UNIX path and suffixing it with the user's ID. The user ID and the path are then returned as the home directory when the user tries to login. As it's configured now, if the user's folder doesn't exist on login then Mina FTP server will create it. This behavior is controllable by setting the create-home attribute on the native-filesystem element below.
I tested this code on Unix and Windows. I set it to run on port 2121, so that I wouldn't have to get access to the privileged port 21 on Unix. The configuration for that is on the nio-listener element. The other interesting behavior which only became evident to me when, surprisingy, it still worked on Windows, is that the path /folder/to/store.. resolved under Windows! Now, I'm not sure if java.io.File has some intrinsic support for POSIX-style paths, or there's some handler registered by cygwin on my particular system, or what, but I tried opening up a grails console and verifying the absolute path of a java.io.File object for "/" and sure enough it returned "C:". So, don't worry if you want to test this on either operating system, I guess!
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://mina.apache.org/ftpserver/spring/v1"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation=" http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/lang
http://www.springframework.org/schema/lang/spring-lang-2.0.xsd
http://mina.apache.org/ftpserver/spring/v1
http://mina.apache.org/ftpserver/ftpserver-1.0.xsd ">
<beans:bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<beans:property name="driverClassName" value="JDBC_DRIVER"/>
<beans:property name="url" value="JDBC_URL"/>
<beans:property name="username" value="YOUR_USER"/>
<beans:property name="password" value="YOUR_PASSWORD"/>
</beans:bean>
<server id="server">
<listeners>
<nio-listener name="default" port="2121"></nio-listener>
</listeners>
<db-user-manager encrypt-passwords="clear">
<data-source> <beans:ref bean="dataSource"/>
</data-source>
<insert-user>INSERT INTO FTP_USER ( user_id, user_password, home_directory,
enable_flag, write_permission,
idle_time, upload_rate, download_rate ) VALUES ('{userid}', '{userpassword}', '{homedirectory}',
'{enableflag}', '{writepermission}', {idletime}, {uploadrate}, {downloadrate})
</insert-user>
<update-user>UPDATE FTP_USER SET user_password
='{userpassword}',home_directory='{homedirectory}',enable_flag={enableflag},
write_permission={writepermission},idle_time={idletime},
upload_rate={uploadrate},download_rate={downloadrate}
WHERE user_id='{userid}'
</update-user>
<delete-user>DELETE FROM FTP_USER WHERE user_id = '{userid}'</delete-user>
<select-user>SELECT user_id as userid, 100000 as maxloginperip ,
100000 as maxloginnumber , user_password as
userpassword, '/folder/to/store/files/uploads/'|| user_id as homedirectory, true as
enableflag, true as writepermission, true as readpermission, 100000 as idletime, 100000 as uploadrate,
100000 as downloadrate FROM FTP_USER WHERE user_id = '{userid}'
</select-user>
<select-all-users>SELECT user_id FROM FTP_USER ORDER BY user_id</select-all-users>
<is-admin>SELECT user_id as userid FROM FTP_USER WHERE user_id='{userid}' AND user_id='admin'</is-admin>
<authenticate>SELECT user_password as userpassword from FTP_USER WHERE user_id='{userid}'</authenticate>
</db-user-manager>
<native-filesystem case-insensitive="false" create-home="true"/>
</server>
</beans:beans>
All in all, I'd say using the FTP Server's been pleasant - except for the ugliness concerning slf4j - and I hope it works for you. I am well aware of the availability of other FTP servers that support database backends, but I really was looking for something lightweight and embeddable, and ideally something I could unit test in Java. This worked out well. It's interesting to see how much of our own dogfood we Java developers manage to get away with using. I used Apache's James email server several years ago. It was very powerful and not a little bit complicated, but it worked, and it was all Java. It scaled and was also very robust, and even with it's wharts was still easier to get working than sendmail. So: I use a Java editor, Java web /application server, Java middleware, Java build tools, Java FTP servers and even a Java text editor. I should really start looking into H2 or Derby and see if I can't close the gap on a completely Java infrastructure stack! It'd be freaking sweet if I could mvn clean install an entire environment (which, for that matter doesn't care which host operating system it's on...)
Now to begin the count down to having a completely Groovy based stack!
The West Wing, House MD, and MythBusters
My favorite show on television used to be The West Wing. The show was witty, and featured arcane, blissfully self contained plots and narrative.. dialogue... banter that would tickle Shakespeare. It was amazing. It was an ideal view of the White House and the men and women inside the executive branch. There were, with rare exceptions, no ludity, no over-the-top romances, no digressions into the characters' personal lives. Except, of course, where these digressions served the episode's plot. The plot - the challenges these characters faced in day-to-day governance - was the only thing respected.
It appealed to me in the same way that The Watchmen (which, btw, I'm going to see tomorrow, days ahead of the US premiere!) appealed to me. It was layered, multi faceted. Each episode featured many continuations that - while they often dovetailed nicely one with another by the end of an episode - didn't always have anything to do with each other in substance. Every show was like an essay. The series took the art of narrative to a new form, and entire episodes were often just very ornate interjections into an argument or discussion. People walking, and talking.
My new favorite TV series is with no qualifications House. I noticed that a lot of other nerds/engineer types like this show, as well. Follow any sampling of the programming world on twitter and you'll see people speaking to their fondness for the show in 140 character exclamations. It's riveting for a problem solver. Dr. Gregory House is a diagnostician in at the ficticious Princeton Plainsboro Teaching Hospital where he and his team tackle medical mysteries deemed otherwise unsolvable. House's character is brisk, lacking all tact. He doesn't suffer fools, hates wishy-washy ideas founded on expressions of feeling. He is a scientist to the last, often refusing to even see his patients and instead letting the symptoms - the facts - stand on their own.
He would make a very fine programmer. He is the quintessential "debugger."
The Wikipedia page I linked you to elaborates on some of the parallels between House's character, a doctor, and Sherlock Holmes, a detective. Their staunch adherence to the facts, their disinterests in what people say or think, and their abilities of deduction. Apparently, Sherlock Holmes himself was based on a doctor, so it's something of a full circle.
Now, I'm wondering what other shows are popular among nerds. I appreciate shows that can pull off the art of satire, of deadpan, well. I also love shows with strong "whodunnit" plots. I appreciate shows aimed at resolution of issues. I love MythBusters. I appreciate shows dripping in irony, and really like a lot of the programs on the BBC, because a lot of that sort of humor is unavailable here in the states.
What do other people watch? What kind of show is interesting to a nerd?
And... we're back!
A lengthy upgrade process caused my blog to die, but it's back!
Usually when I upgrade the software it's not so big a deal, but this version introduced a few new components into the architecture, which complicated things. I really ought to open-source this sucker.
Anyway, there's very little that you - dear reader - would likely see in the new software. But stick around, that's to come!
Obsolescence of Skills
In my last post I talked about habits geared towards acquisition of skills. It does sometimes happen the other way â where you need to unlearn something, or re-frame an existing skill in a different way in order to advance with it. This is a natural part o moving forward in life, of adapting. I like to think that I do an acceptable job of keeping current, of adapting.
The proof is in the pudding: how many skills do I have the have been obsolesced*? I hadn't counted, honestly. I'm still not going to count (not that you will see, anyway!) but you might try taking a look at the Obsolete Skills Wiki to see if anything you've learned has become irrelevant, and whether you've successfully crossed that chasm.
Don't freak out if you see something you swore was still relevant â some of the entries are on the site, but are disputed!
Some are pretty dead on, or scary. "Counting back change" is - saddeningly - appropriate. How many merchants do you know that employee people who can count back change? How many people do the math to leave a 20% tip?
How many things do you know that have become irrelevant?
obsolesce - become obsolete, fall into disuse; "This word has not obsolesced, although it is rarely used"
Has the word "obsolesce" ... obsolesced?
A Weekend With the Voices
My lovely and charming wife is out of town for 5 days, helping my mother out. They're going to go to Philadelphia, and my wife'll get a chance to see some of New York City, as well. I'm excited for her, and happy that my mom invited her, but I'm most looking forward to the chance to get some code done unabated by distractions of living with somebody: synchronized meals, activities, favorite TV shows, etc. No disractions. Not if I can help it.
Often, I will run across an idea or concept that I'd like to explore but don't have the time to immediately pursue. I acrrue these ideas in an email thread sent to myself. I call it my "negative resume" - a listing of all the things I don't have any experience and can't claim to know.
When that list gets too long (for me that's about 10 items), I start popping things off the queue, attacking each entry. The items on the list are usually innocuous. Occasionally I'll add significant changes / ideas that involve starting in on a rapidly new technology. In this case I make sure to either qualify a very specific, obtainable success scenario, or I diminish the other suggestions and move them to another list. In a way, the process is very much like updating a bug tracker.
I'm tracking bugs in my knowledge. Deciding which bug to remedy first requires prioritization.
You can imagine how complicated this process was before I added, "learn basics of Project Managment" to a list!
The last list included the following: "try out H2 database", "See if you can get Seam Framework 2.0 working under Maven," "check out Hibernate Search," "Read a few chapters from Manning's iPhone In Action," and so on. I don't like to let more than 10 things accrue because then there's no chance I could get it push through all of them in a weekend - even with intense focus (which I am not usually blessed with on weekends, above and beyond my day-job hours. )
The sentiment behind these bursts of learning is simple. As my dad always said (I'm sure he still does, he's just no had reason to recite of late...): "It's a sinch by the inch, hard by yard."
This weekend I've got another such list. I'm looking forward to address some of the items on this list with no direction or instinct besides the chorus of prioritizing voices in my head.
What do you want to learn?
