Announcement - New Forum in the Saloonby Jason Menard - Programming Diversions BartenderJavaRanch has a brand new forum, Programming Diversions!. This is a place to come to in order to have some fun and to flex a bit of the ol' grey matter. In this forum you will find progamming challenges and puzzles of various difficulty that you can solve, or better yet, post your own! You will benefit not only by attempting these yourself, but also by seeing how your fellow programmer attacks these problems. So mosy on over, put on your ten-gallon thinking cap, and let's have some fun!Return to Top |
||||||||||||||||||||||||||||||
Programming Diversions Puzzleby Jason MenardAs a new feature of the JavaRanch Newsletter, and to go along with our new Programming Diversions forum, we will be offering a monthly programming puzzle. Here we now present to you the first of hopefully many such puzzles. Enjoy! WordSearchGiven any N X N grid of letters (where N > 0, N <= 100), and any set of words which may be found in the grid, write a program to find and display the starting and ending grid coordinates for each word. The top left corner of the grid is [0,0] (row 0, col 0), and the bottom right corner of the grid is [N,N]. You may input the grid of letters and the words in the manner of your own choosing. Words in the grid may be found oriented in any direction within the grid (vertical, horizontal, reverse-horizontal, reverse-diagonal-up, diagonal down, etc...). Use the following grid and list of words to test your code. xbcbdjwgpmpcfsh avijureeroltfha bdsheriffnamnev lsuraibvoikoist iakpffrsngtoshr zhdanosourzsrea eicnuludnexerwn rednetrabvasbec mldoarahcdwyvrh auyjvroosendetl pkypuiaciornede sitemapvitralsv rafnopekaminiui umlksreyejmlpir pgetwdmpevitood javaranch moose bartender sheriff drivel reviews uml threads jdbc roundupYou can discuss this puzzle and post your results in the Programming Diversions forum here. Return to Top |
||||||||||||||||||||||||||||||
Small and Simple Web Applications - the Friki Way (Part 3)by Frank CarverAbstractThis article is the third of a series which laments the bloated and unmaintainable state of so many J2EE web applications and looks at ways to keep web applications small, simple and flexible. The series uses the author's Friki software as a case study, and discusses ways to design and build a powerful, flexible and usable web application in less space than a typical gif image. This article continues the coding process begun last time, and finally starts working on real user requirements. On the way it helps take the effort out of rebuilding and re-running tests whenever anything changes. IntroductionIf you've read the first and second articles, you should be aware that the aim of this project is to develop a small, simple and understandable "Wiki" (editable web site) application. We've considered and decided to defer the relatively heavy decision of how to store and retrieve pages by introducing a Java interface, decided on and implemented a simple "template" system to display pages, and are building a supporting test suite as we go along. Before we continue, I'd like to remind everyone of what our "customer" wants. For the purposes of this article, our customer says we will be "done" when we have a Java web application in which:
What do we write next?By now, you should know that we start each new feature by writing a test for it, so the questions should perhaps rather be "what do we test next?". Whichever way you look at it, this is still a tough choice. If we want to make real progress toward our customer's goals, we need to start delivering software which meets those goals. So far, all we have is a repository interface and a template engine, neither of which is mentioned in the list. There are lots of ways of deciding what to do next. Perhaps simply do them in the order they are written in. Maybe do the hardest first so we learn the most. Maybe ask the customer which is most important. I'm sure you can think of many more. In this case I'm going to recommend that we start by choosing the easiest to test. The idea behind starting with the easiest is that the customer goals are all tangled together. The more we can remove from the tangle, the simpler the rest will become. With any luck, by the time we get to the hard tasks, so much will already have been removed that they will be easier, too. The idea behind starting with the easiest to test is that until we have written a test, we can't start writing code, and I want to start writing real code as soon as possible. Using this approach (often known informally as "pick the low-hanging fruit") can be suitable at the start of a new project or large single change, where there are several inter-related requirements which all need to be met for anything to work at all. Beware, though! This approach can become dangerous as soon as something has been delivered which the customers/users can try themselves. At that point it is usually better to pick whichever the customer wants the most, and see how that affects the remaining ones. It is also important to resist the temptation to keep adding more "vital" features which delay this first delivery. The sooner we can get real priority decisions from the customer, the better. We have decided to go for the easiest to test. Which one is it? Goals one and four look like we would need to set up a web server of some sort. To make it work would in turn mean building our software into something which can be deployed to the web server. The tests would maybe try to fetch pages from different URLs and see what they get. Sounds a lot of work before we see any results. Goal five looks like it would need us to build that repository we keep putting off. Goals two and three look as if they can be tested in a similar way to the way we tested the template engine, which seemed pretty easy. I think I'll choose to do goal two first, as completing it might help make goal three easier. First task: "page content may contain links to other pages by name"Let's start with a nice simple, "empty" test to make sure we have everything working. Even with this, we still need to think about how we would use the code we are going to write. One of the simpler ways is to think of it in terms of a formatting process. Some "raw" text from a stored Page will be "formatted" into "processed" text containing links where neccesary. AllTests.java package tests; import junit.framework.*; public class AllTests extends TestCase { public static TestSuite suite() { TestSuite ret = new TestSuite(); ret.addTest(new TestSuite(EmptyTest.class)); ret.addTest(new TestSuite(TemplateTest.class)); ret.addTest(new TestSuite(LinkTest.class)); return ret; } } LinkTest.java package tests; import junit.framework.*; import friki.PageFormatter; public class LinkTest extends TestCase { public void testEmpty() { PageFormatter formatter = new PageFormatter(); assertEquals("", formatter.format("")); } } PageFormatter.java package friki; public class PageFormatter { public String format(String input) { return input; } } Just as with the TemplateEngine, the first test and the first implementation can feel a bit like cheating. But remember, all of this is part of the design process -- we have already designed how to use the formatting code, now we have to make it work for more cases. Next, though, a major design turning point. We know that "processed" page names will need to appear as HTML links, but how should we represent the names of pages in the "raw" text? This is an important decision, users of the system will have to type one of these names in to the browser every time they want to link to another page. The answer is not obvious, either. There are Wikis which use patterns of upper-case and lower-case letters, and automatically recognize things like FrankCarver and FrikiServlet. There are Wikis which use any group of characters wrapped in end characters like [[Frank Carver]] or {:Friki}. There are Wikis which use any alphabetic or alphanumeric word which starts with a special symbol, like @FrankCarver or ~Friki. There are even Wikis which check every word in the text, in case it might be the name of a page, and need no special delimiters at all. This decision is so important, it needs the involvement of the customer. The job of the developers is to explain the options and answer questions to help the customer choose the right compromise between desired features and cost. In this case, our customer grumbles a bit, and settles for the word-starting-with-symbol approach, using '@' as the symbol. He says he may change his mind later, but we knew that already! With this knowledge we can add some more tests to our LinkTest class: public void testNonLink() { PageFormatter formatter = new PageFormatter(); assertEquals("hello", formatter.format("hello")); } public void testEmbeddedLinkSymbol() { PageFormatter formatter = new PageFormatter(); assertEquals("friki@javaranch.com", formatter.format("friki@javaranch.com")); } Both these tests pass with no extra code. Excellent. However, just as with the TemplateEngine test case, we now have the same setup code appearing in three places. It's time to remove the duplication and create a setUp fixture. LinkTest.java package tests; import junit.framework.*; import friki.PageFormatter; public class LinkTest extends TestCase { PageFormatter formatter; public void setUp() { formatter = new PageFormatter(); } public void testEmpty() { assertEquals("", formatter.format("")); } public void testNonLink() { assertEquals("hello", formatter.format("hello")); } public void testEmbeddedLinkSymbol() { assertEquals("friki@javaranch.com", formatter.format("friki@javaranch.com")); } } Now we get to add a test which fails: public void testLink() { assertEquals("<a href='view?hello'>hello</a>", formatter.format("@hello")); } As usual, the next step is to write the simplest solution. Maybe something like: PageFormatter.java package friki; public class PageFormatter { public String format(String input) { if (input.startsWith("@")) { return "<a href='view?" + input.substring(1) + "'>" + input.substring(1) + "</a>"; } return input; } } Good, That works. It's a bit messy, and I can see some duplicated code in there, so lets refactor it to tidy it up. Don't forget to re-run all the tests after every change to make sure nothing has broken. PageFormatter.java package friki; public class PageFormatter { private String symbol = "@"; private String makeLink(String name) { return "<a href='view?" + name + "'>" + name + "</a>"; } public String format(String input) { if (input.startsWith(symbol)) { return makeLink(input.substring(symbol.length())); } return input; } } You can probably guess where we go next. We've done just enough testing to test that we can generate a link, but it's pretty obvious that a Wiki page with just one word is not very useful, even if it is a link to another page. So we need to test that the PageFormatter can find and convert page references wherever they appear in a page. So, we add another test: public void testLinkInPage() { assertEquals("You say <a href='view?hello'>hello</a>, I say goodbye.", formatter.format("You say @hello, I say goodbye.")); } After the last test passed, we refactored the code to be simpler and neater. Now is a chance for a second sort of refactoring, the kind you can do before a change, to make the change itself simpler. I'm pretty sure we'll still need to be able to convert a word to a link if it starts with the special symbol, so let's extract that code as a method, which we can call from the "smarter" code we are about to write. PageFormatter.java package friki; public class PageFormatter { private String symbol = "@"; private String makeLink(String name) { return "<a href='view?" + name + "'>" + name + "</a>"; } public String formatWord(String word) { if (word.startsWith(symbol)) { return makeLink(word.substring(symbol.length())); } return word; } public String format(String input) { return formatWord(input); } } Our new test still fails, of course, but now we have a clean place to put the new code. Of course there will be other changes to this class, but it's often a good idea to "clear the decks" before adding anything major. PageFormatter.java package friki; import java.text.CharacterIterator; import java.text.StringCharacterIterator; public class PageFormatter { private char symbol = '@'; private String makeLink(String name) { return "<a href='view?" + name + "'>" + name + "</a>"; } private boolean startsWith(String word, char symbol) { return word.length() > 0 && word.charAt(0) == symbol; } public String formatWord(String word) { if (startsWith(word, symbol)) { return makeLink(word.substring(1)); } return word; } public String format(String input) { StringBuffer word = new StringBuffer(); StringBuffer ret = new StringBuffer(); CharacterIterator it = new StringCharacterIterator(input); for(char c = it.first(); c != CharacterIterator.DONE; c = it.next()) { if (c == symbol || Character.isLetter(c)) { word.append(c); } else { ret.append(formatWord(word.toString())); word.setLength(0); ret.append(c); } } ret.append(formatWord(word.toString())); return ret.toString(); } } It looks like we've finished one of the user's goals. Hooray!. There are, of course, a few things to note about this code: First, although that "formatWord" method is still there, it has changed a little. The variable "symbol" is now a char rather than a String to make things easier in the "format" method. This restricts future expansion a tiny bit, but that doesn't matter. If anyone really ever wants to use a multi-character word prefix, there isn't much to change. The thing that irritates me most is that I can't use the built-in and nicely descriptive String.startsWith method any more, as there is no version for asking if a String starts with a char. Sigh. Second, the structure of the "format" method looks strangely similar to the TemplateEngine.expand method we developed last time. Bear this in mind, and if we see an opportunity, we should consider refactoring the whole system to remove this duplication. Making Rebuilding SimplerAre you getting fed up with all that typing "javac ..." and "java ..." yet? I know I am. Even if you use an IDE or a command-line history mechanism which hides it, there's still a lot of repetition. We owe it to ourselves and to our customers to stamp this out. The solution I suggest for this is to use a "build tool". A build tool is a program which reads a pre-defined set of instructions and relationships, and uses them to build software for you. A build tool is a kind of specialized scripting language, indeed you can get a long way using just the scripting abilities built in to your system (DOS .bat files, Unix shell-scripts etc.). In this case I recommend the Ant build tool from the Apache project. If you are not already familiar with Ant, you may want to look at Thomas Paul's March 2002 newsletter article, and install Ant as directed. Ant is flexible and powerful, and we will be using some of its more interesting features in later articles. For now, though, we just want to get it to compile and test our code. Before we leap into scripting, we need to understand what we want Ant to do, and we also need to be able to test (even if only by inspection) that it has done it right. The first step is to set up a sensible directory structure for our project, and copy our source files into it. The structure I recommend follows the common Ant pattern of separate directories for separate operations. In particular, note that source code and classes for the delivered application are kept completely separate from the test code. We will likely have more test code than application code by the time we have finished, and we want to keep the delivered application as lean as possible. So we keep test code separate to avoid the risk of delivering any of it. friki | +-----------+----------+ | | src build | | +-----+------+ +---+---+ | | | | delivery tests delivery tests | | | | +-+---+ +-+--+ | | | | | | | | java files java files classes classes
build.xml <project name="friki" default="build" basedir="."> <path id="classpath"> <pathelement location="build/delivery/classes"/> <pathelement path="${java.class.path}"/> </path> <path id="testclasspath"> <pathelement location="build/delivery/classes"/> <pathelement location="build/tests/classes"/> <pathelement path="${java.class.path}"/> </path> <target name="clean"> <mkdir dir="build"/><delete dir="build"/> </target> <target name="compile-delivery"> <mkdir dir="build/delivery/classes/"/> <javac srcdir="src/delivery" destdir="build/delivery/classes" debug="on"> <classpath refid="classpath"/> </javac> </target> <target name="compile-local-test"> <mkdir dir="build/tests/classes"/> <javac srcdir="src/tests/java" destdir="build/tests/classes" debug="on"> <classpath refid="testclasspath"/> </javac> </target> <target name="compile" depends="compile-delivery,compile-local-test"/> <target name="test"> <junit fork="yes" haltonfailure="yes" printsummary="yes" dir="build/tests"> <jvmarg value="-Djava.compiler=NONE"/> <test name="tests.AllTests"/> <classpath refid="testclasspath"/> <formatter type="plain"/> </junit> </target> <target name="build" depends="compile,test"/> </project> This may look complicated, but mostly it's just a way of configuring Ant to understand the directory structure we are using. Each target is equivalent to a public method or function definition, and the final "build" target brings them all together Now, open a command-line, change to the top friki directory, and type ant. As specified on the first line of the build file, if no target name is specified it runs the default "build" target. You should now see a series of messages finishing with something like: test: [junit] Running tests.AllTests [junit] Tests run: 9, Failures: 0, Errors: 0, Time elapsed: 0.156 sec build: BUILD SUCCESSFUL If you get any complaints from Ant, double-check the directory structure and the build.xml file. If you see any failures or errors reported by junit, look in the file friki/TEST-tests.AllTests.txt for more details. If it all works, celebrate! How are We Doing?We still haven't made a Wiki yet! But we have met one of the five user goals. We have continued expanding our test suite to cover everything we have done so far, and have created a directory structure and build script to enable the whole project to be built and tested using a single, simple command. We are poised on the edge of producing a real web application. Next session we'll add more customer features to our Wiki and extend our build script to automatically create a deployable "web application archive" (war) file. Why not try and guess which of the remaining customer goals will be next on the list... Return to Top |
||||||||||||||||||||||||||||||
The Coffee Houseby Solveig HauglandBrenda and Lacey Explain Dating Design PatternsSid and Zeke and the whole town of Deadville were pretty excited last week. They learned all about patterns and how to apply them to their Java programming. It started to get out of hand, and they started coming up with Cattle Design Patterns, Coffee Design Patterns, Massage Parlor Design Patterns, and then it all started to get out of hand.Here's how it all happened. It all started because Zeke said that what he wished he had was some darned Dating Design Patterns. "Finding a woman, and then knowing what the heck to do with her once you've found her, is about as complicated a system as I've come across," he complained. "Why don't these fellers turn their four big brains on something really useful? I can just hack together a system and it'll run, at least, but my server is getting absolutely no client requests for services, if you catch my meaning." Lacey and Brenda, making lattes behind the counter, started laughing. "There are Dating Design Patterns, you ornery old cowpoke. You just need to ask us and we'll give you everything you need to know. We are women, after all, and we can deploy an EJB faster than the rest of you put together." "Oh, stop rubbing it in. I was feeling poorly that day. Anyway, what do you mean? You got some design patterns that are composed of that there three-part rule, which expresses a relation between a certain context, a problem, and a solution?" Sid looked at Zeke like he'd just given birth to a three-horned cow. "You're talkin' funny, mister. You sound like that there Christopher Alexander fella that they was quoting about ever other darned minute." "Well, I just want to use the right terminology. This is important. C'mon, Brenda, Lacey, give us a pattern. We'll sit quiet like and listen to you." "Well, all right." Brenda shut down the latte machine and she and Lacey perched on the counter in front of the big mirror, each with a bed red pencil. "Let's look at first things first. Y'all are moaning about not knowing what to say to a woman , right? You can't get yourself into a conversational state." "Oh lord, yes. That's a tough one. I can't think of anything when I'm sitting there lookin' at a pretty girl," yelled someone in a big black hat in the back. "Well, that's because your CPU is running at 99% and you ain't got no system resources free to think up something to say," replied Lacey. "Even once you calm down a bit, it'd take you several minutes to come up with what you're going to say, package it up in a nice sentence, wait til she's free so you can create a connection, and then send that little conversation over with all the right arguments over to her. Why, she could be three days gone by then." "All right, let's think about this. You want to think of something to say to a lady, but if you wait til you need it in order to come up with what to say, you don't have the system resources to do it, or it takes one heck of a long time. Right?" And Lacey wrote up on the mirror: Problem You want to send a request to a server, but cannot access sufficient system resources to create the request object. And then you feel stupid. Black hat in the back yelled out again, "Well, if I was codin' that problem it's easy. This is connection pooling, plain and simple." "That's all there is to it," said Brenda. "You gotta create a pool of things to say to a gal ahead of time. Just make a whole bunch of'em, and then when it's time you just have to pick one that ain't gonna throw an exception. Always have an extra in mind, too, in case she don't like the first one." And she wrote on the mirror: Solution Use a Diving in the Conversation Pool to create multiple coarse-grained conversational objects that can be used to create connections with a variety of servers. Catch exceptions with a try-again block. "That's an awful neat solution," admitted Zeke. "So what kinds of things could we talk about? I've been told that foaling ain't a proper topic to ask a lady." "Yes, try to stay clear of the whole blood and guts thing," replied Lacey. "It's not that complicated. Just act like you're incredibly interested in her and you're getting paid two bits for every little thing you find out. What's her name, where's she from and why she's here, what she's been doing in town, and at that point if you're on the ball you can offer to show her the hot spots or escort her to anything going on that a lady might like, like a concert or our county fair. It's just a nice classic straightforward gentlemanly approach." And she wrote on the board: Strategies SmallTalk Strategy Ignorant Facade Strategy "I love the Ignorant Facade Strategy too," she went on. "You just pretend not to know stuff and ask. Women have been using this one for years and we call it Ol'Reliable. Because you can always count on people to be opinionated, even a nice well-bred lady from the east. If you ask her when she thinks we're going to invade Iran, or what she thinks you should buy for your sister's new baby since you're just an ignorant man and you need a woman's opinion, or to resolve a debate between you and your friend about whether women appreciate a good display of gunplay, she'll talk to you and make no mistake. This is a great one since men are known far and wide for knowing nothing' about women, and you can ask her about anything woman-oriented, like the right size for a man's belt buckle in proportion to his boots, or you could even ask her to take square-dancing lessons with you since you ain't allowed to sign up alone." "Or there's another approach," said Brenda. "You can get one of us or another respectable lady to walk around with you and start conversations with ladies for you, and then introduce you to them." "Oh, Brenda," exclaimed Lacey in righteous indignation. "That's not a strategy of Diving in the Conversation Pool. That' s a related pattern, and in a whole nother category. The Gang Of Outlaws came up that one, anyway." "Don't get all structuralist on me," yelled Brenda. "I think that a strategy should be more loosely defined so as not to preclude a functionalist approach as appropriate." This, of course, is where things really got out of hand. Yelling epithets like "Aristotelian!" and "Micro-architecture fascist!" the women fought long and hard, cheered on by the rather randy crowd of cowboys until Lacey managed to throw Brenda out the door and into the horsetrough, and started looking around for another challenge. So the cowboys shuffled on home to check their livestock and their servers and their Amazon rankings, but with more knowledge than they'd woken up with, and they dreamed that night of common themes relating to the recurrence of a problem/solution pair, in a particular context (a king-sized bed with lots of baby oil).
Her projects are usually well behaved, sitting in their separate directories
and waiting patiently to be brought up again, but occasionally they get bored
and start checking each other out. Occasionally the projects even have rowdy
parties in the middle of the night and wake up in the wrong directory in the
wrong clothes, which is how dating design patterns thing happened. See additional
results of this improper intermingling of patterns and dating logic at www.datingdesignpatterns.com. You can contact her through her OpenOffice.org training and books Web site,
www.getopenoffice.org, or via solveig@getopenoffice.org. Return to Top |
||||||||||||||||||||||||||||||
Top 10 Ways You Can Get to Know and Love OpenOffice.orgby Solveig HauglandSo, you know you should be using OpenOffice.org, it's free, it's the
Right Thing to Do, but like switching from Hostess Cupcakes to high-fiber
cereal, it's hard to break the habit of MS Office and switch to OpenOffice.org.
Here are a few things to help make the transition less traumatic and more
fun.
For a simple download page (the openoffice.org site is a bit labyrinthian), go to www.getopenoffice.org/download.html Compressed XML also means the files are very very small.
Solveig Haugland is an independent writer and trainer based in Colorado. Among other things, she's the author of the "OpenOffice.org Resource Kit" and "StarOffice 6.0 Companion." She does training for both programs and sells her book/workbook learning kit, and as of September 8th will be an international trainer when she heads to Norway to do a week of training. You can contact Solveig through her OpenOffice.org training and books
Web site, www.getopenoffice.org, or via solveig@getopenoffice.org.
Return to Top |
||||||||||||||||||||||||||||||
JavaRanch at JavaOne 2003by Jessica SantIf you're attending JavaOne, be sure to check out your fellow JavaRanchers! BOF-3061: Certification Roundtable with Michael Ernest and Jessica SantThis informal session offers help, advice, and guidelines for anybody who wishes to start or is following the Sun certification process. This session is not a technical Q&A forum, but rather an interactive forum where the panel answers questions and offers advice in the way of reading lists, tips for study, and tips for the exams. The panel includes Sun certified JavaTM technology platform technologists at all levels, with the added bonus that they help run the JavaRanch Web site, one of the largest independent Java technology communities on the Internet with a strong focus on the certification programs. BOF-2955:JavaTM Technology in the Classroom: Teaching Finance Using Java Technology with Mark Herschberg and Jon GadzikFinance is a field traditionally taught through books and lectures. However the application of the knowledge is often illustrated through executing actions through software. Harvard Business School has sought to revolutionize the teaching of finance by having a game-based lesson model. Software, written to mimic trading applications used on Wall Street, is used extensively to teach each lesson throughout the semester long course. This session discusses how we were able to employ JavaTM technologies to quickly and easily create a such a game, and how these Java technology-based games may enhance the educational experience. BOF-1672: Design Patterns and Best Practices for JavaTM Technology-Based Mobile Applications with Michael Yuan and Ju LongMobile commerce requires sophisticated enterprise backends and pervasive user interfaces. Due to the limitations of mobile devices and wireless networks, some unique design and implementation issues must be addressed when developing end-to-end mobile commerce applications. In this presentation, we discuss design patterns and best practices in mobile application development. We focus on two crucial aspects: smart mobile client and seamless client-server integration. We use several concrete mobile JavaTM technology-based applications, including the Sun Smart Ticket blueprint, as examples. Smart mobile client must take advantage of the performance, reliability, and rich UI benefits offered by thick client technology. At the same time, it must be light enough to fit into and run smoothly on small handhold devices. We discuss the benefits and implementation of MVC and variant patterns, background thread and gauges, cache for performance, reliability, and security. On the integration front, the diversity of mobile applications calls for a variety of integration schemes. We discuss important integration techniques, including Remote method call, asynchronous messaging, binary-over-HTTP, XML, SOAP Web services, SyncML, and session tracking. After this talk, you have a better understandings of the unique challenges facing mobile application development; get familiar with common approaches; be able to judge which pattern is the best based on application circumstances; learn other people's approaches from discussions. This is an intermediate to advanced level session. Prerequisites: Working knowledge on design patterns, client-server model, MIDP, XML, Java technology stream I/O, SOAP Web services, and HTTP. Return to Top |
||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
Return to Top |
||||||||||||||||||||||||||||||
Return to Top |
||||||||||||||||||||||||||||||
June Scheduled Book Promotions
:
Return to Top |