Archive for the ‘code’ Category
maven + growlnotify for notification when your build finishes
Reading time: 1 – 2 minutes
Working on os x with Spaces means I want to read something on another space instead of waiting idly for a 50 second build. But, I don’t want to get distracted. So, I use Growl and growlnotify for notifications of the build’s completion.
#!/bin/sh # this file is called: mvn (and is executable, and added to path before actual mvn command) # capture all args passed in to forward to real mvn ARGS=$* # We need the client's specific settings.xml, so always specify it now /usr/bin/mvn -s /Volumes/TrueCryptClient/opt/maven/conf/settings.xml $ARGS # when you have growlnotify installed and on your path, this will pop it up # when the build is done growlnotify -m "DONE: maven $ARGS"
Note: if you get this error from growlnotify: could not find local GrowlApplicationBridgePathway, falling back to NSDNC, it probably means growl is not started. Start up growl in your System Preferences.
Update: Thanks Cosmin, for the enhancement. Use this snipped in the script. Have an environmental variable for what the notify command is. And say what the build status is in the growl notify.:
if [[ -n $NOTIFY ]]; then
($command && $NOTIFY "Build Complete" && exit 0) || ($NOTIFY "Build Failed" && exit 127)
else
$command
fi
Can you spot Java Puzzler in this snippet?
Reading time: < 1 minute
I ran across this last week. It was marvelous when we saw what was happening, but entirely puzzling at first.
Boolean someFlag = complicatedLogicToFigureOutFlag(); Person person = new Person(someFlag);
Any signs for concern? How about if Person’s constructor is:
Person(boolean someFlag) { this.someFlag = someFlag; }
Any warning signs?
Will it compile?
Read more for the full puzzler.
How to do 3-way merges with Subversion and Kdiff3
Reading time: 4 – 6 minutes
I do not endorse branch based development. I prefer trunk based development. Specifically I like what my colleague Paul calls Branch By Abstraction, coined by Stacy Curl, and recently mentioned by Martin Fowler (All one time ThoughtWorkers, and 2 currently).
If you’re stuck with merging though, 3-way merges make it much easier. Doing it with subversion is easy. Instructions are for Linux.
- apt-get or yum install kdiff3.
- Edit your /etc/subversion/config and fin the line with diff3-cmd, set it to: diff3-cmd=/usr/local/bin/svndiff.sh
- Next, create the file /usr/local/bin/svndiff.sh. See below for the script you’ll want to enter in it.
Now when you get a merge conflict you will choose M and merge will open in kdiff3. On the left is the base revision, in the middle is your working copy, and on the right the incoming change. This is a little more to look at, but it is invaluable when dealing with merges. I wouldn’t go back to 2 way diff ever again.
#!/bin/bash
# tim/paul: this is a copy of the file located at http://www.yolinux.com/TUTORIALS/src/svndiffwrapper.txt
# modified to do a non-conflicting merge automatically. see #HERE#
# Return an errorcode of 0 on successful merge, 1 if unresolved conflicts
# remain in the result. Any other errorcode will be treated as fatal.
# Author: Michael Bradley
#NOTE: all output must be redirected to stderr with "1>&2" as all stdout output is written to the output file
VDIFF3="kdiff3"
DIFF3="diff3"
DIFF="kdiff3"
promptUser ()
{
read answer
case "${answer}" in
"M" )
echo "" 1>&2
echo "Attempting to merge ${baseFileName} with ${DIFF}" 1>&2
$VDIFF3 $older $mine $theirs --L1 $labelOlder --L2 $labelMine --L3 $labelTheirs -o $output 1>&2
bLoop=1
if [ -f $output ]; then
if [ -s $output ]; then
#output succesfully written
bLoop=0
fi
fi
if [ $bLoop = 0 ]; then
cat $output
rm -f $output
exit 0
else
echo "Merge failed, try again" 1>&2
fi
;;
"m" )
echo "" 1>&2
echo "Attempting to auto-merge ${baseFileName}" 1>&2
diff3 -L $labelMine -L $labelOlder -L $labelTheirs -Em $mine $older $theirs > $output
if [ $? = 1 ]; then
#Can't auto merge
rm -f $output
$VDIFF3 $older $mine $theirs --L1 $labelOlder --L2 $labelMine --L3 $labelTheirs -o $output --auto 1>&2
bLoop=1
if [ -f $output ]; then
if [ -s $output ]; then
#output succesfully written
bLoop=0
fi
fi
if [ $bLoop = 0 ]; then
cat $output
rm -f $output
exit 0
else
echo "Merge failed, try again" 1>&2
fi
else
#We can automerge, and we already did it
cat $output
rm -f $output
exit 0
fi
;;
"diff3" | "Diff3" | "DIFF3" )
echo "" 1>&2
echo "Diffing..." 1>&2
$VDIFF3 $older $mine $theirs --L1 $labelOlder --L2 $labelMine --L3 $labelTheirs 1>&2
;;
"diff" | "Diff" | "DIFF" )
echo "" 1>&2
echo "Diffing..." 1>&2
$DIFF $mine $theirs -L $labelMine -L $labelTheirs 1>&2
;;
"A" | "a" )
echo "" 1>&2
echo "Accepting remote version of file..." 1>&2
cat ${theirs}
exit 0
;;
"I" | "i" )
echo "" 1>&2
echo "Keeping local modifications..." 1>&2
cat ${mine}
exit 0
;;
"R" | "r" )
echo "" 1>&2
echo "Reverting to base..." 1>&2
cat ${older}
exit 0
;;
"D" | "d" )
echo "" 1>&2
echo "Runnig diff3..." 1>&2
diff3 -L $labelMine -L $labelOlder -L $labelTheirs -Em $mine $older $theirs
#Exit with return vaule of the diff3 (to write out files if necessary)
exit $?
;;
"S" | "s" )
echo "" 1>&2
echo "Saving for later..." 1>&2
cat ${mine}
#Exit with return vaule of 1 to force writting of files
exit 1
;;
"Fail" | "fail" | "FAIL" )
echo "" 1>&2
echo "Failing..." 1>&2
exit 2
;;
"H" | "h" )
echo "" 1>&2
echo "USAGE OPTIONS:" 1>&2
echo " [A]ccept Accept $labelTheirs and throw out local modifications" 1>&2
echo " [D]efault Use diff3 to merge files (same behavior as vanilla SVN)" 1>&2
echo " [Fail] Kills the command (not suggested)" 1>&2
echo " [H]elp Print this message" 1>&2
echo " [I]gnore Keep your locally modified version as is" 1>&2
echo " [M]erge Manually merge using ${VDIFF3}" 1>&2
echo " [m]erge Same as "M" but attempts to automerge if possible" 1>&2
echo " [R]evert Revert to base version (${labelOlder})" 1>&2
echo " [S]ave Same as 'I' but writes out rold, rnew, and rmine files to deal with later" 1>&2
echo " [diff] Type 'diff' to diff versions $labelMine and $labelTheirsthe before making a descision" 1>&2
echo " [diff3] Type 'diff3' to diff all three versions before making a descision" 1>&2
echo "" 1>&2
;;
* )
echo "'${answer}' is not an option, try again." 1>&2
;;
esac
}
if [ -z $2 ]
then
echo ERROR: This script expects to be called by subversion
exit 1
fi
if [ $2 = "-m" ]
then
#Setup vars
labelMine=${4}
labelOlder=${6}
labelTheirs=${8}
mine=${9}
older=${10}
theirs=${11}
output=${9}.svnDiff3TempOutput
baseFileName=`echo $mine | sed -e "s/.tmp$//"`
#HERE#
diff3 -L $labelMine -L $labelOlder -L $labelTheirs -Em $mine $older $theirs > $output
if [ $? = 1 ]; then
#Can't auto merge
#Prompt user for direction
while [ 1 ]
do
echo "" 1>&2
echo "${baseFileName} requires merging." 1>&2
echo "" 1>&2
echo "What would you like to do?" 1>&2
echo "[M]erge [A]ccept [I]gnore [R]evert [D]efault [H]elp" 1>&2
promptUser
done
else
#We can automerge, and we already did it
cat $output
rm -f $output
exit 0
fi
else
L="-L" #Argument option for left label
R="-L" #Argument option for right label
label1=$3 #Left label
label2=$5 #Right label
file1=$6 #Left file
file2=$7 #Right file
$DIFF $file1 $file2 $L "$label1" $L "$label2" &
#$DIFF $file1 $file2 &
#wait for the command to finish
wait
fi
exit 0Note: I also posted this to a gist on github: svndiff.sh.
Large Web App Architecture: Yes to Thicker Stack on One Hardware Node, No to Beautiful “Redundant” Spiderwebs
Reading time: 4 – 7 minutes
My last client our team worked with had a large ecommerce operation. Yearly revenue in the new site is in the high single digit billions of dollars. This necessitates extremely high availability. I will draw an initially favorable looking configuration for this high availability (“beautiful spiderwebs”), but then tear it apart and suggest an alternative (“Thicker Stack on One Hardware”).
1. “Beautiful Spiderwebs” – Often Not Recommended
Here’s one common way people could implement high availability. Notice how there are always multiple routes available for servicing a request. If one BIG IP goes down, there is another to help. And this could be doubled with multiple data centers, failed over with DNS.
The visible redundancy and complexity in one diagram may be appealing. One can run through scenarios in order to make sure that yes, we can actually survive any failure and the ecommerce will not stop.
So then what could make this my Not Recommended option?
2. Martin’s Reminder how to Think About Nodes
Fowler reminded us in Patterns of Enterprise Application Architecture how to look at distribution and tiers. For some reason people keep wanting to have certain “machines running certain services” and just make a few service calls to stitch up all the services you need. If you’re concerned about performance, though, you’re a looking for punishment. Remote calls are several orders of magnitude greater than in process, or calls within the same machine. And this architectural preference is rarely necessary.
One might lead to the first design with the logic of: “We can run each component on a separate box. If one component gets too busy we add extra boxes for it so we can load-balance our app.” Is that a good idea?
The above is not recommended:
A procedure call between two separate processes is orders of magnitude slower [than in-process]. Make that a process running on another machine and you can add another order of magnitude or two, depending on the network topography involved. [PoEAA Ch 7]
This leads into his First Law of Distributed Object Design: Don’t distribute your objects!
The solution?
Put all the classes into a single process and then run multiple copies of that process on the various nodes. That way each process uses local calls to get the job done and thus does things faster. You can also use fine- grained interfaces for all the classes within the process and thus get better maintainability with a simpler programming model. [PoEAA Ch 7]
3. “Strive for Thicker Stack on One Hardware Node” – Recommended
Observe the recommended approach below. There is still an external load balancer, but after a request is routed to an Apache/Nginx/etc front end, you’re all on one* machine.
If one tier fails on a node, pull the whole node out from rotation. Replace it. And re-enter it in the mix.
Your companies teams have worked together to be able to deploy modular services. So when your ecommerce site needs a merchant gateway processing service, you can include that (library or binary) and run it locally on your node, making a call through to it as needed.
Services are also simpler to deploy, upgrade and monitor as there are fewer processes and fewer differently-configured machines.
(* I understand there may be the occasional exception for remote calls that need to be made to other machines. Possibly databases, mcached obviously third party hosted services, but the point is most everything else need not be remote.)
4. But, Practically Speaking How Far Do We Go?
A caveat first: these benefits get pronounced as you have more and more nodes. (And thus, more and more complex of spiderwebs of unnecessary failover).
Should there be a database server running on each node? Probably not at first. There is a maintenance associated with that. But after sharding your database and running with replication, why not? This way if a node fails, you simply pull it out and replace it with a functioning one.
5. Checklist of Takeaway Lessons
- Keep it local. Local calls orders of magnitude faster than remote calls.
- Make services modular so they don’t need to be remote, yet still have all the organizational benefits of separate teams.
- Simplicity in node-level-redundancy is preferred over tier-level-redundancy.
Often, people think of high availability with terms such as the following: Round Robin, Load Balancing, and Failover. What do you think of? Leave a comment below with how you meet the trade-offs of designing for HA as well as architectural decisions of low latency.
What is grad school for a consultant (or practicing software engineer)
Reading time: 2 – 4 minutes
Does it make sense for practicing software engineer to go to grad school? Technologies change rapidly, and so do our clients and projects. So we have constant opportunities to learn and most importantly to apply ourselves in building production systems. Bonus: putting production systems live into the world teaches a lot more than a good grade in an exam.
I once remember in undergrad my friend getting an offer at Microsoft, but he was torn on going to grad school. Basically his sponsor there told him graduate degrees aren’t worth much, and I’d go so far as to suggest that they can be less useful than varied and interesting real project work.
“Sure, go to cs grad school if it makes your ego feel better, but don’t do it for your career.”
Oh?, my friend said, and if my memory serves me, he went on to grad school.
Everyone’s situation is different. However this is something I’ve struggled with for the last several years: does it make sense to step back and do research, and to do computer science-y things instead of day to day project delivery? Maybe. Maybe not. I’ve more or less made my decision for now. But every few months the nagging urge comes back.
I found these posts helpful for framing my decisions.
- http://jxyzabc.blogspot.com/2008/08/cs-grad-school-part-1-deciding-to-apply.html (the whole multi-part series, actually)
- http://www.stanford.edu/~pgbovine/grad-school-app-tips.htm – says how it is all about research, and really Ph.D. applications are a job application, where you are applying to do research, rather than a place to be taught. (MBA, Med School, and other higher education avenues are a place you pay to be taught.) Masters degrees are different, but generally still have the same theme “you’re getting paid, so you better love (your) research.”
Update: Mark Needham commented about two pointed posts from Penelope Trunk’s blog. Worth reading.
- http://blog.penelopetrunk.com/2008/06/18/seven-reasons-why-graduate-school-is-outdated
Grad School isn’t needed, and it causes more harm than good. Too much focus. Careers change too much. Experience trumps prolonged childlike academic sheltering. (Note: My opinion isn’t so harsh. Your grad school might not apply, it depends on what you want to do). - http://blog.penelopetrunk.com/2009/02/03/dont-try-to-dodge-the-recession-with-grad-school/
She prefers learning by doing, and suggests a feeling of “being lost” is actually helpful for growing.
Fast and Easily Testable GWT JUnit Tests
Reading time: 4 – 6 minutes
GWTTestCase. (It’s too slow). So that means never instantiate or reference a GWT widget in the controller. They must always be decoupled by interfaces. Here’s some of what we learned. Formerly my controller had an async event handler in it that showed a pop up message on a failure.private AsyncCallback asyncCallback = new AsyncCallback() { public void onFailure(Throwable caught) { Window.alert("An error occured, please try again. \n" + caught.getMessage()); } public void onSuccess(PackageDto pkg) { firePackageUpdate(pkg); // throw an event in here that is handled by a // listener, which is the gui code and which has no logic // (logic is in the controller!) } };
java.lang.ExceptionInInitializerError Caused by: java.lang.UnsupportedOperationException: ERROR: GWT.create() is only usable in client code! It cannot be called, for example, from server code. If you are running a unit test, check that your test case extends GWTTestCase and that GWT.create() is not called from within an initializer or constructor. at com.google.gwt.core.client.GWT.create(GWT.java:91) at com.google.gwt.user.client.Window.(Window.java:230) ... 28 more
- Implement the AsyncCallback<T> interface with BaseAsyncCallback<T> , and implement the onFailure() to call Window.alert(). In tests, I would subclass and override onFailure() in tests, preventing the Window.alert() from executing. I generally don’t like subclassing for tests, so I wasn’t too keen on this.
- Implement the AsyncCallback<T> interface with a class BaseAsyncCallback<T>, but this time take in a constructor parameter, FailureHandler (which would be an interface or class of my own.) Then in onFailure(), delegate to the FailureHandler field. In tests, pass a different FailureHandler implementation or subclass, to avoid calling the GWT widget code.
- The recommended solution is to treat this the same way I deal with onSuccess(). Tell a listener that a failure event occurred, and let it handle it.
GWTTestCase or Selenium).- Separate the Controllers from all references to Views (GWT UI objects) by using event listener / notifier interfaces.
- Martin Fowler’s Humble View and Supervising Controller
- MVP post from google code testing blog
- GWT architecture talk by Ray Ryan at google IO this year (pending a sample app using the event bus he describes. See discussion group and watch video below).
Test Driven log4j Logging Code Example
Reading time: 3 – 4 minutes
Update: Added a snippet so that you can easily assert a message was contained in the logged messages.
Frequently logging is not viewed as “important” by engineers as, say, the logic for refunding a customer’s purchase. The customer’s won’t mind, after all, if we forget to log something right? Maybe so, until there are problems and the operational team supporting your application has very little ability to diagnose problems.
I propose logging should be viewed as another user interface, and thus needs its’ own set of acceptance and unit tests. This makes for more tedious and up front work for development teams — however I want to survive in production without a pager going off, and with fewer late night scrambles to ship patches.
Imagine a class that has logic associated with logging. Below you will see a unit test verifying logging statements are correct. Often logging uses statics, and as Misko has said, statics are a death to testabilty. With Guice you can easily inject loggers automatically for the class under construction. This method gets around most of the issues with static loggers, although I still despise statics everywhere.
This is a basic example, but the point is to understand how to hook into appenders and add/change one to use a test appender.
package com.jawspeak.common.testing; import com.google.common.collect.Lists; import org.apache.log4j.AppenderSkeleton; import org.apache.log4j.spi.LoggingEvent; import java.util.List; /** * Use me for spying on test logs and making asserts against them. * * Example how to use: * final SpyLoggerAppenderForTesting spyAppender = new SpyAppenderForTesting(); * final Logger logger = Logger.getLogger(MyClass.class.getName()); * try { * logger.addAppender(spyAppender); * // do something * assertEquals(Lists.newArrayList("Attempted to read such-and-such, but could not: oops"), spyAppender.getMessagesLogged()); * } finally { * logger.removeAppender(spyAppender); // clean up global state * } */ public class SpyLoggingAppenderForTesting extends AppenderSkeleton { private List messages = Lists.newArrayList(); protected void append(LoggingEvent loggingEvent) { messages.add(loggingEvent.getRenderedMessage()); } public List getMessagesLogged() { return messages; } public boolean doMessagesContain(String snippet) { boolean isFound = false; for (String message : messages) { if (message.indexOf(snippet) >= 0) { isFound = true; } } return isFound; } public void close() { } public boolean requiresLayout() { return false; } }
Here’s an example test where we make use of it. Note that we didn’t assert the lists are exactly the same, because in this project we were also using aspects to do logging, and depending on if you ran with or without the aspects enabled, a different number of logging messages would be created.
package com.jawspeak.common.utility; import com.google.common.collect.Maps; import com.jawspeak.common.testing.SpyLoggingAppenderForTesting; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.junit.After; import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; import java.util.LinkedHashMap; import java.util.List; public class SessionSizeLoggingTest { private SpyLoggingAppenderForTesting spyAppender = new SpyLoggingAppenderForTesting(); private Logger logger = Logger.getLogger(SessionSizeLoggingTest.class.getName()); private Level oldLoggingLevel = logger.getLevel(); private SessionSizeLogging sessionSizeLogging = new SessionSizeLogging(); @Before public void setUp() { logger.addAppender(spyAppender); logger.setLevel(Level.TRACE); // set the level in case a log4j.properties or log4j.xml disables this level of logging } @After public void tearDown() { logger.setLevel(oldLoggingLevel); logger.removeAppender(spyAppender); } @Test public void logBytesWhenUnprintable() throws Exception { LinkedHashMap map = Maps.newLinkedHashMap(); map.put("key", new String(new byte[] { 1, 31, 127, -97}, "ISO-8859-1")); String sessionId = "abc123"; sessionSizeLogging.logSessionSize(logger, sessionId, map); List messagesLogged = spyAppender.getMessagesLogged(); assertTrue(spyAppender.doMessagesContain("Session Size for session id: " + sessionId + " (approx. total " + (7 + 3 + 1 + 4 + 1) + " bytes)")); // or use assertTrue(messagesLogged.contains(" key[ 3 bytes] key --> value[ 4 bytes] '\\u0001\\u0031\\u0127\\u0159'")); } // .. many more tests }
This is a trick that I don’t see written about too much, but I recommend it often. And, I’d love to have some readers post enhancements, links, and take testability further with respect to logging.
Wrestling the Untestable Into Testable Code: Example with Test Driven SimpleTagSupport for custom JSP Tag
Reading time: 3 – 5 minutes
Let’s say app servers must be stateless. There is no affinity for a user pinned to a particular app server, so two requests will likely be handled by different Tomcats, Jetty’s, etc. This means nothing can go in HttpSession (we also can’t use clustering). And when it’s ecommerce, we can’t require cookies or that might cost millions in lost revenue. Given these constraints, you have one valid option left: custom url rewriting over all our links (GET’s) and with hidden form fields (POST’s).
You can edit every link and every form to pass some unique id around. But what if you have two or three id’s that need to pass around for legacy reasons? Sounds like a custom tag would be nice. Something you can put in your jsp’s (oh yeah, let’s say we’re using jsp’s too).
This introduces me to the testability challenge. Write your own tag extending SimpleTagSupport that would ensure parameters were always in a link, and write another tag to write out the three hidden input fields inside every form.
But, SimpleTagSupport is part of the good old servlet and jsp API, so it’s very bloated with context objects, deep inheritance, callbacks, and cruft that makes for difficult unit testing. Just look at the public interface, one method: public void doTag() throws JspException, IOException.
Here’s my test driven test case (with 100% coverage, through the public API), which takes advantage of Spring MVC’s MockHttpServletRequest and MockHttpServletResponse objects (which are really fakes). I’m also using Mockito, which I prefer over EasyMock and JMock.
package com.jawspeak.dotcom.tag; import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; import static org.mockito.Mockito.*; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockPageContext; import javax.servlet.jsp.tagext.JspFragment; import java.io.StringWriter; import java.io.Writer; public class StatefulLinkTagTest_SettingSessionId { private StatefulLinkTag statefulLinkTag = new StatefulLinkTag(); private MockHttpServletRequest request = new MockHttpServletRequest(); private MockHttpServletResponse response = new MockHttpServletResponse(); private static final String SESSION_ID = "ADFHE13"; @Before public void given() throws Exception { request.setAttribute("sid", SESSION_ID); statefulLinkTag.setJspContext(new MockPageContext(null, request, response)); JspFragment jspBodyFragment = mock(JspFragment.class); doAnswer(new FakeJspBodyAnswerer()).when(jspBodyFragment) .invoke((Writer) anyObject()); statefulLinkTag.setJspBody(jspBodyFragment); } @Test public void shouldRenderLinkWhenThereIsNoParameter() throws Exception { statefulLinkTag.setHref("/myPage.html"); statefulLinkTag.doTag(); String contentAsString = response.getContentAsString(); assertEquals("<a href=\"/myPage.html?sid=" + SESSION_ID + "\">link text body</a>", contentAsString); } @Test public void shouldRenderLinkWhenThereIsAlreadyAParameter() throws Exception { statefulLinkTag.setHref("/myPage.html?my_param=foo"); statefulLinkTag.doTag(); String contentAsString = response.getContentAsString(); assertEquals("<a href=\"/myPage.html?my_param=foo&sid=" + SESSION_ID + "\">link text body</a>", contentAsString); } /** Mockito Answer implementation to manipulate the parameters we pass * into JspFragment.invoke() due to the ugly servlet API. */ private static class FakeJspBodyAnswerer implements Answer { public Object answer(InvocationOnMock invocationOnMock) throws Throwable { StringWriter writer = (StringWriter) invocationOnMock.getArguments()[0]; writer.write("link text body"); return null; } } }
As for the implementation, it’s pretty straightforward after writing the tests. It doesn’t show covering multiple ID’s appended to the link, but it is now easy to test drive implementing them.
package com.jawspeak.dotcom.tag; import javax.servlet.http.HttpServletRequest; import javax.servlet.jsp.JspException; import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.SimpleTagSupport; import java.io.IOException; import java.io.StringWriter; public class StatefulLinkTag extends SimpleTagSupport { private String href; public void setHref(String href) { this.href = href; } @Override public void doTag() throws JspException, IOException { PageContext pageContext = (PageContext) getJspContext(); getJspContext().getOut().print(createTagText( (HttpServletRequest) pageContext.getRequest())); } private String createTagText(HttpServletRequest request) throws IOException, JspException { StringWriter stringWriter = new StringWriter(); stringWriter.append("<a href=\""); stringWriter.append(href); if (href.indexOf("?") > 0) { stringWriter.append("&sid="); } else { stringWriter.append("?sid="); } stringWriter.append((String)request.getAttribute("sid")); stringWriter.append("\">"); getJspBody().invoke(stringWriter); stringWriter.append("</a>"); return stringWriter.toString(); } }
Questions, comments? Want to bash Java and tell me why I should be using Ruby, Erlang or Scala? For more about the SimpleTagSupport interface check here.
Reminder: OOPSLA Submissions Due March 19th
Reading time: 2 – 3 minutes
I’m involved in helping review the tutorial. Do you have something others would be interested in learning about? Please consider submitting a proposal, but do it fast since they are due March 19th. Here’s what the Tutorials are described as:
OOPSLA tutorials are half-day classes, taught by experts, designed to help software professionals rapidly come up to speed on a specific technology or methodology. Tutorials can be lecture-oriented or participatory.
OOPSLA tutorial attendees deserve the highest standard of excellence in tutorial preparation and delivery. Tutorial presenters are typically experts in their chosen topic and experienced speakers skilled in preparing and delivering educational presentations. When selecting tutorials, we will consider the presenter’s knowledge of the proposed topic and past success at teaching it.
If you’re interested, it’s not too late — and every submission helps ensure the quality of what is selected is the best possible. Do please consider a submission.
Below is the more generic announcement for all OOPSLA things:
OOPSLA 2009 Call for Submissions
http://www.oopsla.org/submit
OOPSLA solicits contributions that explore all facets of programming, systems, languages, or applications. Topics span a range of issues at the intersection between programming languages and software engineering. Moreover, OOPSLA is a key forum for introducing and discussing key programming models, programming methods, and related software engineering ideas, technologies, tools, and applications.
So OOPSLA is seeking contributions that address current software challenges, such as programmer productivity, security and reliability, ultra-large scale systems, and evolving hardware platforms. Of particular interest are those contributions addressing OOPSLA 2009’s focus on:
- Scaling: Multi-Core to Cloud
- Mashups of Models, Data and Code
- Tools for Reliability and Evolution
- Enterprise Agile Management
Here are the important dates:
Call for Papers
March 19, 2009
Due date for Research Program, Onward!, Practitioner Reports,
Educators’ Symposium, Essays, and proposals for Tutorials, Panels,
Workshops, and DesignFest
July 2, 2009
Due date for Posters, Demonstrations, Student Research Competition,
Doctoral Symposium, Onward! Films, and Student Volunteers
OOPSLA 2009
Oct 25-29, Orlando
For more information go to http://www.oopsla.org
Using (These) Anonymous Inner Classes is Probably Too Clever for Your Own Good
Reading time: 3 – 5 minutes
Sometimes it is tempting to have less verbose Java code and be clever. Say you have an object you need to build and set several properties on it, then use it. This way looks clever, but is a bad idea – especially in production code. Read on for why.
TripChoice myTrip = new TripChoice() {{ // look at these clever initialization blocks! setDestination("San Francisco"); setAvailableRoutes(new HashSet() {{ add("LAX-SFO"); add("BUR-SFO"); add("ONT-SFO"); }); }};
This is a huge problem because it can cause a NotSerializableException or create a memory leak. How? Because with that clever anonymous class and initialization block, there is an implicit reference to the outer class’ instance. That outer class will not be garbage collected so long as there is one reference to the anonymous class. Worse, if we ever
Here’s the typical way to do it.
// blah blah, this is typical, and a rather boring looking great big block of text. // (That's also probably scattered over several places in your code when you build these objects). TripChoice myTrip = new TripChoice(); myTrip.setDestination("San Francisco"); Set availableRoutes = new HashSet(); availableRoutes.add("LAX-SFO"); availableRoutes.add("BUR-SFO"); availableRoutes.add("ONT-SFO"); myTrip.setAvailableRoutes(availabileRoutes);
Here’s why this improved version is even not the best:
- It uses setters. Setters allow your object to be constructed in an inconsistent state. There are some situations setters are fine (i.e. form backing objects) but often your code is more clear without setters. In this particular case the setters aren’t egregious, but I still consider them a smell and much more verbose way that constructor injection. Read more about the problem with setter injection here
- It is verbose.
- It is also mutable (often a negative), again a problem due to the use of setters.
So what’s the best way to do it? I have found constructor injection and in our particular example use of Google Collections. As for seeing an implementation of the best solution – just leave a comment.
Below is a full example you can run that illustrates the hard to catch serialization bug.
package com.jawspeak; import com.google.common.collect.Lists; import static org.junit.Assert.*; import org.junit.Test; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.NotSerializableException; import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.List; /** * Understands the danger of anonymous subclasses for lists. */ public class TooCleverForOurOwnGoodTest { @Test(expected = NotSerializableException.class) // UPDATE: Thanks for the reminder from Dennis, below public void serializableDangerBugFromPatricksCleverness() throws IOException { // you think a List would be serializable, which it is. And so are Strings. final String myString = "3"; List strings = new ArrayList() { add("one"); add("two"); // However, because there is an anonymous subclass of ArrayList created, // there is an implicit reference to the outer class, which is **not serializable**. // This is a nice feature, which lets us have closure-ish syntax in java, such as // the following reference to the outer myString. add(myString); // It will throw the exception even without this reference. }}; // call your method that requires args to be serializable ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(strings); // The particular bug I had was even worse, because we were creating leaking a reference // through that List's implicit reference to the outer object. } @Test public void serializableDangerBugSafeButNotClever() throws IOException { // A List is serialiazable. And so are Strings. List strings = new ArrayList(); strings.add("one"); strings.add("two"); // No longer is there a reference to the outer class. // call your method that requires args to be serializable ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(strings); } @Test public void serializableDangerBugSafeAndNiceLooking() throws IOException { // A List is serialiazable. And so are Strings. List strings = Lists.newArrayList("one", "two"); // call your method that requires args to be serializable ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(strings); } }



