Undirected Ramblings

Thoughts on culture, technology, and anything else that comes to mind.

Available categories: [/] [Technology]

Why Tab Indentation is Evil [Permalink]

Tue Dec 11 16:48:32 EST 2007
Category [Java]

Tab indentation is Wrong. I know this instinctively, but from time to time I forget the actual proof of this and go looking around on the interwebs, only to find a bunch of religious-warlike opinions that are mostly subjective. Yesterday I remembered the Real Reason why tab indentation is objectively horrible. Here we go: tab stops differ between systems, so tab indentation is shown with varying amounts of white space, depending on the system on which the file is displayed. In order to properly indent code, one sometimes (often) needs to indent to a position that does not fall on a tab stop. One example is this:

public Person findPerson(String firstName,
                         String lastName,
                         String zipCode);
In order to line up the arguments with the open paren, an editor using tab indentation is then forced to use a combination of tabs and spaces that is correct only when viewed with tab stops set to the same increment as that on the computer creating the file, thus making the argument that different people viewing code on different machines can use indentation steps to their liking completely invalid. Tab indentation is simply broken for code such as this. I just don't understand why an editor like Eclipse would make tab indentation the default. I've seen so much unreadable code as a direct result of this, it's not funny. Please! For the sake of good taste and human decency, stop using tab indentation! Thank you.

Comments [0] | Trackbacks [0]

Chasing Methods With Interfaces in Eclipse [Permalink]

Wed Jan 24 20:19:43 EST 2007
Category [Java]

Back in the days when I was doing software development full time for one company, we had a few arguments about the relative merits of designing by interface. The product we happened to work on had almost certainly overused interfaces, with nearly a 1:1 relationship of interface to class. It didn't help that they named things horribly, calling the interfaces along the lines of SomeObjectIxf, with the corresponding implementation being SomeObject. (Interfaces are your contract/service, the word you're using when you talk about that component of your application!)

Anyway, one of the main objections to using interfaces when you only have one implementation of an object is that it makes code much more difficult to trace in Eclipse, since when you control-click the method name, Eclipse goes to the interface instead of the object you're looking for. This means you'd have to separately find the implementer of that class, then navigate to that class, remembering which method you were trying to trace, then navigate to the method. Today I learned an easier way. To trace a method through to its implementer from a call on an interface, simply click on the method (no need to highlight, as long as the cursor is in the method name) and type control-t. This will display the type hierarchy of the interface on the page, and then you can down arrow to the implementing classes and hit return. Eclipse will take you to the right method in the implementing class. It's still one step more difficult than just control-clicking, but effectively makes it almost trivial to trace methods, even through calls on an interface.

Comments [0] | Trackbacks [0]

Fun with Linux Routing [Permalink]

Sat May 20 21:49:25 EDT 2006
Category [Java]

I tried running the import program for my photo application today, which parses an XML file with a DTD. It failed with "java.net.ConnectException: Connection refused." This was a bit baffling to me, since the DTD in the document was hosted on the same server that I was running the program. A quick check with netcat confirmed that, in fact, connections were being refused on port 80 to the same host. Even more baffling was that I was still serving web requests to outside hosts with no trouble.

Anyway, to make a long story short, the trouble turned out to be in my routing configuration, which is setup to redirect port 80 to port 8080 and port 443 to 8443 so that I can run Resin as an unprivileged user while still responding to requests on port 80. I had never paid particular attention to the specifics of the common advice I had found on the web (I think in Caucho's documentation, actually) except to note that it worked. My previous routing rules were these:


    iptables -t nat -A PREROUTING -p tcp --dport 80 -i eth0 -j REDIRECT --to-port 8080 -d 66.92.72.224
    iptables -t nat -A PREROUTING -p tcp --dport 80 -i eth0 -j REDIRECT --to-port 8080 -d 66.92.72.225
    iptables -t nat -A PREROUTING -p tcp --dport 80 -i eth1 -j REDIRECT --to-port 8080 -d 66.92.72.224
    iptables -t nat -A PREROUTING -p tcp --dport 80 -i eth1 -j REDIRECT --to-port 8080 -d 66.92.72.225
    iptables -t nat -A PREROUTING -p tcp --dport 443 -i eth0 -j REDIRECT --to-port 8443 -d 66.92.72.224
    iptables -t nat -A PREROUTING -p tcp --dport 443 -i eth0 -j REDIRECT --to-port 8443 -d 66.92.72.225
    iptables -t nat -A PREROUTING -p tcp --dport 443 -i eth1 -j REDIRECT --to-port 8443 -d 66.92.72.224
    iptables -t nat -A PREROUTING -p tcp --dport 443 -i eth1 -j REDIRECT --to-port 8443 -d 66.92.72.225

There are two problems with this. First, the PREROUTING chain seems only to affect packets actually routed by the box, so not locally originated packets. I fixed this by adding a set of similar rules in the OUTPUT chain, which affects packets before routing. From the iptables man page:

            nat:
                  This table is consulted when a packet  that  creates  a  new
                  connection  is encountered.  It consists of three built-ins:
                  PREROUTING (for altering packets as soon as they  come  in),
                  OUTPUT  (for altering locally-generated packets before rout‐
                  ing), and POSTROUTING (for  altering  packets  as  they  are
                  about to go out).

The new lines looked like this:

    iptables -t nat -A OUTPUT -p tcp --dport 80 -i eth0 -j REDIRECT --to-port 8080 -d 66.92.72.224
    iptables -t nat -A OUTPUT -p tcp --dport 80 -i eth0 -j REDIRECT --to-port 8080 -d 66.92.72.225
    iptables -t nat -A OUTPUT -p tcp --dport 80 -i eth1 -j REDIRECT --to-port 8080 -d 66.92.72.224
    iptables -t nat -A OUTPUT -p tcp --dport 80 -i eth1 -j REDIRECT --to-port 8080 -d 66.92.72.225
    iptables -t nat -A OUTPUT -p tcp --dport 443 -i eth0 -j REDIRECT --to-port 8443 -d 66.92.72.224
    iptables -t nat -A OUTPUT -p tcp --dport 443 -i eth0 -j REDIRECT --to-port 8443 -d 66.92.72.225
    iptables -t nat -A OUTPUT -p tcp --dport 443 -i eth1 -j REDIRECT --to-port 8443 -d 66.92.72.224
    iptables -t nat -A OUTPUT -p tcp --dport 443 -i eth1 -j REDIRECT --to-port 8443 -d 66.92.72.225

I loaded the rules and in my testing discovered that the host configured on my second IP address, 66.92.72.225, was coming up with the content from the first IP, trailmagic.com, in my browser. I looked over the rules a few more times and, resorting to the man page once again, discovered that the REDIRECT target "redirects the packet to the machine itself by changing the destination IP to the primary address of the incoming interface." Clearly not what I wanted, since I've got two interfaces in this machine and one virtual interface, each configured with a different IP address. A little more studying turned up the DNAT target, which does exactly what I want (and thought REDIRECT was doing earlier). This probably explains why the commonly-recommended rules seem to work for most people, and are still working on my development machine, namely that most people don't have more than one interface, so it doesn't matter that REDIRECT only uses the primary interface. My final rules look like this:

    iptables -t nat -A PREROUTING -p tcp --dport 80 -i eth0 -j DNAT --to-destination 66.92.72.224:8080 -d 66.92.72.224
    iptables -t nat -A PREROUTING -p tcp --dport 80 -i eth0 -j DNAT --to-destination 66.92.72.225:8080 -d 66.92.72.225
    iptables -t nat -A PREROUTING -p tcp --dport 80 -i eth1 -j DNAT --to-destination 66.92.72.224:8080 -d 66.92.72.224
    iptables -t nat -A PREROUTING -p tcp --dport 80 -i eth1 -j DNAT --to-destination 66.92.72.225:8080 -d 66.92.72.225
    iptables -t nat -A PREROUTING -p tcp --dport 443 -i eth0 -j DNAT --to-destination 66.92.72.224:8443 -d 66.92.72.224
    iptables -t nat -A PREROUTING -p tcp --dport 443 -i eth0 -j DNAT --to-destination 66.92.72.225:8443 -d 66.92.72.225
    iptables -t nat -A PREROUTING -p tcp --dport 443 -i eth1 -j DNAT --to-destination 66.92.72.224:8443 -d 66.92.72.224
    iptables -t nat -A PREROUTING -p tcp --dport 443 -i eth1 -j DNAT --to-destination 66.92.72.225:8443 -d 66.92.72.225


# for local packets
    iptables -t nat -A OUTPUT -p tcp --dport 80  -j DNAT --to-destination 66.92.72.224:8080 -d 66.92.72.224
    iptables -t nat -A OUTPUT -p tcp --dport 80  -j DNAT --to-destination 66.92.72.225:8080 -d 66.92.72.225
    iptables -t nat -A OUTPUT -p tcp --dport 443  -j DNAT --to-destination 66.92.72.224:8443 -d 66.92.72.224
    iptables -t nat -A OUTPUT -p tcp --dport 443  -j DNAT --to-destination 66.92.72.225:8443 -d 66.92.72.225

The DNAT target takes a --to-destination instead of a --to-port and redirects to the specified port on the specified IP address. With the new rules, everything serves correctly to the right ports on the right IP addresses from on or off the server. Problem solved. Maybe next time I'll read the man page before setting up the rules.

Comments [0] | Trackbacks [0]

Maven Repository for Ant [Permalink]

Sat Mar 04 19:56:13 EST 2006
Category [Java]

I recently discovered that the Maven Project has made available some of its tasks for Ant. I've noted previously that Maven's repository feature is quite nice, although I haven't been as attracted to the system as a whole, so this is a great development for those of us using Ant for our build systems. I'll definitely be thinking about integrating this into the build systems I use if I ever get a bit of free time.

Comments [1] | Trackbacks [0]

On Java Web Start and Browsers [Permalink]

Fri Mar 03 17:24:41 EST 2006
Category [Java]

I've been playing around with a few Java Web Start applications lately (most notably the excellent BlogBridge, which I'll likely write about at some point in the future), and one problem I ran into was that, when I clicked on a link to launch in a browser, the link would opoen in the wrong browser. Once I figured out that I could run javaws to bring up preferences and set the browser to Firefox, clicking a link would open a new window, something that in my home is absolutely not tolerated. It appeared that the Web Start software was deciding to add extra arguments to pass to the browser on the command line, to explicitly tell it to open a new window.

Now, I could froth and foam about how many ways this behavior is wrong on the part of Web Start, mainly having to do with ignoring both my GNOME preference for Firefox and my Firefox preference to never open new windows, but I'll spare you my fury. Instead, I'll pass on the workaround I found to solve it. A little bit of searching let me to the conclusion that one can set a property in the deployment.properties file (~/.java/deployment/deployment.properties on Linux) called deployment.browser.args to determine the arguments to pass the browser. All I had to do was add the following line (just below the line that specified the deployment.browser.path), and everything worked perfectly:

deployment.browser.args=%u

The %u means the URL to be passed to the browser, and it seems you're free to add other arguments you'd like to pass. So it looks like this scheme could be used to make any browser work, even if it takes strange and unusual arguments. So in the end, I'm glad Java Web Start provides this configurability. It provides all the flexibility one needs in invoking an external browser. I wish, however, that this had been exposed in the preferences UI, or failing that, explained somewhere more prominently in the documentation (maybe it's there, but my search didn't turn up any official documents).

Comments [1] | Trackbacks [0]

Spring Confusion [Permalink]

Thu Dec 29 14:27:21 EST 2005
Category [Java]

I spent about 6 hours yesterday trying to build a simple utility for my photo software that would replace an image in the database with an image from a file. I was using Spring to manage Hibernate sessions using a HibernateInterceptor to setup the transaction. I couldn't figure out why the session wasn't getting setup, and I was getting "No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here" errors when running the program.

First, I added debugging statements to my code, which showed that when I was getting my bean from the ApplicationContext, my property setter was being called with a valid object, but the value of the field was null on the bean returned by the factory. I still haven't figured that one out. Anyway, eventually I turned up debug logging for the Spring classes and found that advice was being setup for my property accessors but not the method in which I was doing the work. Turns out I the method was private, and setting it to public solved the problem. I haven't found out yet whether or not it's possible to use an interceptor this way for a private method, but it's certainly not straightforward. Here's how my interceptor was setup originally:

  <bean id="hibernateInterceptor"
    class="org.springframework.orm.hibernate.HibernateInterceptor">
    <property name="sessionFactory">
      <ref local="sessionFactory"/>
    </property>
  </bean>

  <bean id="replaceImageManifestation"
    class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="target">
      <bean
        class="com.trailmagic.image.util.ReplaceImageManifestation">
        <property name="sessionFactory">
          <ref local="sessionFactory"/>
        </property>
      </bean>
    </property>
    <property name="interceptorNames">
      <list>
        <value>hibernateInterceptor</value>
      </list>
    </property>
  </bean>

I ended up modifying the configuration to the following, which essentially does the same thing, but also declaratively manages transactions for me:

  <bean id="replaceImageManifestation"
    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <property name="transactionManager">
      <ref local="transactionManager"/>
    </property>
    <property name="target">
      <ref local="replaceImageManifestationTarget"/>
    </property>
    <property name="transactionAttributes">
      <props>
        <prop key="replace*">PROPAGATION_REQUIRED</prop>
      </props>
    </property>
  </bean>

  <bean id="replaceImageManifestationTarget"
    class="com.trailmagic.image.util.ReplaceImageManifestation">
    <property name="sessionFactory">
      <ref local="sessionFactory"/>
    </property>
    <property name="imageManifestationFactory">
      <ref local="imageManifestationFactory"/>
    </property>
  </bean>

Either configuration should work, and I still have beans using the former configuration. The problem was only in the method protection. Now it all works fine, and I know that next time I'll turn on the full debug logging sooner, although it can be hard to parse with all the extra output. Lessons learned:

  1. If something is behaving strangely, turn up debug logging before wasting time trying to figure out weird behavior.
  2. When playing around with spooky hidden code tricks like aspects, check your method protection!

Comments [0] | Trackbacks [0]

Java Session Management Is Broken [Permalink]

Tue Aug 23 20:01:27 EDT 2005
Category [Java]

I just got burned by this while posting the last blog entry, and it's something that's annoyed me for a long time. It's a little unfair to say that Java's session management is broken, I suppose. The problem is more in the way people use it.

Here's the common problem: a site has a form that takes a long time to fill out, such as a field for text that might take a long time to compose. Some people, like me, tend to start filling out a form (or composing a comment, blog entry, etc.), then shift to other work, leaving the form half-filled for hours, maybe days. In the meantime, the server-side session times out, and when the user goes to submit the form, the server simply sends back a login page, blissfully ignoring your carefully entered form data.

Now, the first thing wrong with this is that the session times out. It's entirely possible to never stick information needed for things like form submission in a session object. Granted, Java makes it really easy to stick things in a session and get them back out, which is why people use them so much, but it's not that hard to stick things in a database instead, or in hidden fields within the page. My real complaint with Java is that it doesn't make it easier to make persistent sessions.

Failing the use of a persistent session, a good web developer should work around this problem. There are several possibilities: a login page could forward POST information to the page it was originally intended for; the form could include enough information in hidden fields to complete the submission without the session; the intercepting page could push the form data back into a page that redisplays the form before submission. These approaches aren't necessarily trivial, though, and require diligence on the part of the developer.

I just wish Java made it easier to Do The Right Thing.

Comments [0] | Trackbacks [0]

 

 

May 2012
Sun  Mon  Tue  Wed  Thu  Fri  Sat 
  12345
6789101112
13141516171819
20212223242526
2728293031  
       
<  Apr   May    Jun  >

Available categories: [/] [Technology]

Powered By blojsom   RSS Feed  RSS2 Feed  RDF Feed

html hits: 67887