Some reader favorites:
EJB fundamentals and session beans
Create a scrollable virtual desktop in Swing
Wizard API updated!
Tim Boudreau has released a new version of the Swing Wizard library (version 0.997) that fixes the WizardException bug reported in JavaWorld's recent Open Source Java Project profile. The article's examples have been reworked to test out the new, improved WizardException. Thanks, Tim, for this helpful fix!
Open Source Java Projects: The Wizard API
Twain has long allowed Win32 programmers to integrate imaging devices into their applications at no cost. Twain allows us to capture images from seemingly disparate devices like flatbed scanners, fingerprint readers, Web cams, and digital cameras. The standard allows Aunt Emma to take a picture at a wedding, acquire the images onto her PC that afternoon, and send the edited pictures to the entire family that night. Thus, when interfacing with image devices, application developers can free themselves from working with arcane and many times proprietary interfaces, and instead concentrate on one interface.
Twain functionality would greatly benefit the Win32 Java community, but, alas, these open-standards benefits have been available for years in the Win32 world, but, because of Java's platform independence, not the Java world. In this article I show how you too can talk Twain by introducing an architecture that integrates a Java 1.4 Swing application with a simple JNI (Java Native Interface)-based package.
Let's start by discussing the architectural layers involved in retrieving a JPEG file from your favorite Twain-enabled device. Twain natively acquires a Win32 DIB (Device-Independent Bitmap), but we will retrieve a Java readable JPEG file. Retrieving such a file involves five architectural layers:
org.scavino.jtwain source code shown later in this article.
Thankfully all these technologies are free.
Now that we have thought out the architectural layers, we now self impose a process. As an OOAD (object-oriented analysis and design) instructor, I insist on an inception phase and mission statement when developing new APIs. My mission is to build the smallest API possible that will satisfy the specified requirements. What requirements you may ask? Rather than enumerating countless never-to-be-read shall statements, I use the Rational Unified Process (RUP) for guidance. As RUP is a use-case-focused process, we start with our "Acquire a Twain Image" use-case, which has one primary flow consisting of several steps to accomplish our result.
You will find the entire use-case here. The document is intentionally human readable and devoid of code mumbo-jumbo. If we write our requirements in plain English, our stakeholders will take the time to understand our use-case. When analysts, management, and testers understand the use-cases, we receive software on time and on budget. Let me paraphrase the primary use-case as follows:
Acquire Twain image steps (Happy Day Scenario):
Technically the use-case will conclude when you add your application-specific requirements.
Now that we have our use-case defined, we can begin to move towards design by creating a UML (Unified Modeling Language) sequence diagram. The diagram below lets us sequentially follow the steps required to fulfill the preceding use-case. The diagram allows us to follow the messages as they touch each class and thus, clearly see how the use-case is being implemented.
Acquire image primary flow. Click on thumbnail to view full-size image.
Without the use-case and flow, we could write large cumbersome APIs that no one will use or, worse yet, come up short during construction.
We can place the above steps into an iteration plan. We finish the iteration when we accomplish all the steps. We can add more features in subsequent iterations once we evaluate feedback from the first iteration. For now, we need only the bare minimum.
When I wrote the first version of the org.scavino.jtwain library, I added almost every function that Twain exposed—not a good idea. My client wanted only the minimum, and I gave
the near maximum. I could have forgone the extra code to maintain, understand, and document.
Our architecture first needs a reliable JPEG decoder that can convert the native Twain DIBs to a format that Java can interpret. The IJL encodes and decodes your JPEG images. In its simplest form, the IJL can convert the native Twain DIBs to JPEGs rather than the default Windows BMP (Bitmap). Since Java natively handles JPEGs and not BMPs, some subsystem must complete the conversion. Choosing which layer handles the conversion is an important decision for several reasons:
ijl15l.lib library in lieu of the smaller ijl15.lib link library. This static library increases the stack size and would ignore potential ijl15l.lib DLL upgrades from Intel. If we wanted new JPEG functionality from the ijl15.dll, we would have to rebuild and test again.
To make this exercise cleaner and less daunting, the static link library option is the best. We won't need to call the cumbersome
GetProcAddress(...) method, and we have one less deployment hassle to manage.
Specifically I modified the TWAIN_UnloadSourceManager() method. I had to ensure all the pointers were set to null, otherwise the DLL would not properly unload the source manager.
After I changed the source code, the Java application responded without errors. The native Win32 environment didn't need these
changes, as the DLL unloaded properly
Though the low-level plumbing is set up, communication between Java and Win32 will still present problems. Java has difficulty integrating with hardware devices because of the Win32 message pump. Java has no real way to connect to the event handlers in the Win32 world. Instead, you must create a proxy window, so it, not the Java application, can receive the Win32 SDK messages.
That approach negates the need to pass the HWND parameter to EZTwain DLL; instead we can use a null HWND as a parameter within the DLL. When the EZTwain 1.x DLL detects a null, it creates a proxy window, hides it, and uses it
for pumping message handlers. The Java client is relieved of the HWND responsibility, simplifying the bridge between the two layers.
Note: That technique proves useful for synchronous hardware devices like Twain or utility libraries that lack a real GUI. With
Twain, you pass it a command, the vendor-supplied dialog appears, the acquisition occurs, and then Twain eventually returns
a DIB. However, be aware that, with TAPI (Telephony Application Programmers Interface) and other asynchronous technologies,
passing a null HWND will not suffice. Further processing of call-back methods may be required. Asynchronous hardware devices need both the application
and the DLL to participate in two-way communication via the Win32 message handlers. As Java clients cannot take part, more
complex solutions are required: perhaps a TCP/IP socket server.
Now we need to map the previous flow of events to an actual interface in the JNI layer. We must write the exact number of JNI methods required to realize the use-case—no more and no less. Strictly adhering to RUP keeps us focused. The sequence diagram depicts the user actor going through the use-case and exercising our API. I detail the methods below:
The JNI method jboolean Java_org_scavino_twain_JTwain_isTwainAvailble() allows an application to test for Twain's existence. This method accomplishes Step 1 in the use-case's primary flow. isTwainAvailble() does not confirm whether your particular Twain device is enabled or even attached to the machine. It merely tests for the
existence of the twain.dll in your path and verifies that you have at least one Twain device installed. This result is cached after the Twain library
has been prodded. A more elaborate exception-handling mechanism could replace the simple boolean return type. Again, the current goal is simplicity, and a future iteration could have exception handling in the interface.
Free Download - 5 Minute Product Review. When slow equals Off: Manage the complexity of Web applications - Symphoniq
![]()
Free Download - 5 Minute Product Review. Realize the benefits of real user monitoring in less than an hour. - Symphoniq