Tuesday December 20, 2005
Guess where I am...
Guess where I am and what I'm doing with my vacation?
- Scuba diving in Thailand
- Learning Arabic in Egypt
- Playing a djembe (African drum) in Senegal
- Trudging through snow in St. Petersburg
- Teaching English to Estonians
One of the above is true. Take a guess, send it (g_wielenga@yahoo.com), and everyone with the correct answer will get a postcard from me (probably from the airport on the way back).
By the way, you can only enter once... Closing date: 31 December.
Dec 20 2005, 04:09:42 AM PST Permalink
Asterisk! Ampersand! Exclamation Mark! Dollar!
One of the trickiest—and most important—aspects of the MultiView API is the part where you indicate to the user that the file is 'dirty', in other words, unsaved. That's normally done by means of an asterisk. But somehow that's pretty hard to program—the entire API is pretty hard to work with—but I'm trying.
Here's my first stab at the source code for a JBoss deployment descriptor multiview editor. And here's part of the result (note the asterisk):
But, it's still got various weird things happening and I don't understand parts of it. (Probably the first part of the last sentence relates to the second part of the last sentence.) So, anyway, if you enjoy poking around in someone's code, please feel free to poke around in mine—and sorry that there's no tutorial yet, but this API is a lot to deal with.
By the way, I'm on vacation until the 11th of January. And... if you want to know where I'm going... maybe this blog will tell you... in a couple of days time.
Dec 15 2005, 03:10:23 PM PST Permalink
Further Editor Features in NetBeans Modules
I have a pretty amazing colleague in the States, called Dave Havrda. Not only did he provide me with the basis of my jboss-web.xml multiview editor, a few days ago, but yesterday I received something even better. You'll have to check it out for yourself, the picture is really cool (click to enlarge):
If you're itching to get your hands on this source code, you'll have to wait a few more hours while I wrap up a first draft of this new tutorial.
By the way, did you know that Tim Boudreau's Paint App Tutorial has been completely updated? Check it out. That app rocks—it's the closest thing to a Quick Start Guide for NetBeans Platform development as you're going to find.
Postscript: Check out this really cool tip (that I heard about last night at a party) in Martin Adamek's blog!
Dec 14 2005, 12:02:54 AM PST Permalink
NetBeans IDE 5.0 Easter Egg for Christmas
So, I'm quite excited about what I'm about to reveal, but I suspect that there's trouble afoot. It's quite possible that the powers that be—and usability guys like Jano Rojcek—are going to put their foot down and squash this Easter Egg before you get a chance to try it out. In other words, they might remove it from the build. I really hope that they don't, but you never know. So, this is the story: somewhere towards the end of last week, a deadline loomed—the keyboard shortcut card (available under the Help menu in the IDE) had to be finalized so that the localization team could translate it in time for the 5.0 release. While putting the final touches to this card, a number of issues were found (e.g., some shortcuts did not work, etc.). Then, while fixing these issues, a new shortcut was added. Normally (as the usability guys will tell you) this shortcut should not have been a shortcut (because only actions that you perform several times a day get to be shortcuts, all others are only menu items). However, no menu items can be added to the 5.0 release, since it's past code freeze. It's also past code freeze for keyboard shortcuts, however, these are more hidden (i.e., they have no visible representation in the user interface), so this keyboard shortcut got smuggled in to the build! And what does it do? Well, it creates an HTML file that contains the keyboard shortcuts for all the keymap profiles (i.e., 'NetBeans', 'Emacs' and 'Eclipse').
So, think about what this means: until three days ago, there was only a static keyboard shortcut card that had to be manually put together for each release, which is a situation prone to errors (see Issuezilla) and frustration (see me). Now, or, at least, unless someone decides that this shouldn't be included because it is untried, untested, and too late, you can generate a new keyboard shortcut card whenever you change a keyboard shortcut, which means that your keyboard shortcut card will always be up to date.
So, I just went to the Download page and installed the daily build from the 11th of December:
When I go to the Options window, I see (yay!) the Easter Egg shortcut:
And this is what I mapped it to:
Now, when I press Ctrl-Alt-Enter, this is what I see in the config folder in my NetBeans user directory:
And this is the content of the generated keyboard shortcut card! Cool, right? Try it out for yourself, but be quick (or use a daily build from the 11th, or maybe one or two earlier, but not earlier than one or two!), or you might find that it's been snatched away from you...
Dec 12 2005, 02:46:59 AM PST Permalink
Create a Multiview Editor in NetBeans IDE 5.0 (Part 2)
I've applied Dave Havrda's (see yesterday's blog entry) multiview editor to my own data object—one that I made for the JBoss deployment descriptor (jboss-web.xml). Earlier, I made a component palette for this file type (see the NetBeans Component Palette Module Tutorial), and now it has a multiview editor, as you can see when you click the images below to enlarge them (however, the multiview editor seems to cancel out the component palette, which is one of several issues I need to resolve):
While working on this multiview editor (a.k.a. Visual Editor in the NetBeans help files, tutorials, and other documentation), I encountered a lot of "boilerplate code". I find this pretty disturbing. I mean, if there are very large chunks of code that I need to simply copy and paste from one implementation of an API to another, doesn't that mean that there's something wrong with the API? One culprit in this department is the DataEditorSupport class. To me, this just seems like a big container for anything that an editor might need. It's potentially massive, with inner classes such as DataEditorSupport.Env, which I always have to use, but never have to modify. (This is also a big problem in the NetBeans module tutorials—if I know that people don't need to know all the details of what a class is for, because they're simply going to copy and paste it, then there's no need to describe it. But then, it looks really odd to have big chunks of unexplained code in a tutorial.) If we really want people to quickly pick up and use the NetBeans APIs, I think we should hide as much of these things as possible and only force developers to implement the methods that need to be customized. If a method or inner class does not need to be customized, why do I need to include it in my implementation?! I mean, I copied masses of stuff from Dave's simple implementation (shown yesterday) and then adapted it for my own purposes. I know that that's how it's always done, but still think that a lot of it shouldn't be necessary. So, to make things a bit more workable, I used a lot of code folds (I created a code template for these). That makes a huge difference, of course, as you can see below (click to enlarge):
Many cool things flow from using code folds—for example, when you hover your mouse over a code fold, a big pop-up appears with the content of the fold, so that you don't need to open the fold to see what's in it.
Interestingly, adding a multiview editor for a file type is really not very difficult (apart from the aforementioned massive blocks of boilerplate code). And the IDE is very helpful when you're making multiview editors—it provides the New Window Component wizard, which generates the window and all accompanying serialization files all in one go. (And, earlier on, the file type is also recognized by the IDE thanks to files generated by a wizard, in this case the New File Type wizard.) Once you've used the New Window Component wizard, you're off to a solid start. Implement the MultiViewElement (as will be explained in an upcoming tutorial, once I resolve the issues I encountered) and work with the aforementioned implementation of DataEditorSupport, and you're done. I'm making it sound easy, but it's pretty tricky (and without Dave's example code I wouldn't have got very far).
But the end result is pretty cool! A multiview editor is basically a visual form of code completion—you don't need to know all the elements and attributes (or whatever items the file type uses), because the component provides text fields and other components, such as comboboxes and drop-downlists (enabling some properties to be pre-defined, or mandatory, or both) for you to fill in. And, for relatively little work, including a multiview editor in your module for a new file type is sure to be an impressive extra to the more fundamental editor features, such as syntax highlighting. So, watch this space for the announcement of a new tutorial!
Dec 10 2005, 08:17:04 AM PST Permalink
Create a Multiview Editor in NetBeans IDE 5.0 (Part 1)
It's not always easy to get just the right sample code for the NetBeans Module Development tutorials. I've been really lucky in some cases, especially with Andrei Badea's Manifest File Syntax Highlighting module (which forms the basis of the Syntax Highlighting tutorial). But today it was just as good—Dave Havrda, a colleague from the States, who I never met but regularly e-mail with, sent me a module that very nicely demonstrates the NetBeans MultiView API. Here's what it does—you open an XML file of a certain type and you notice that you have two views in the Source Editor (click to enlarge them):
Not bad, huh? Several people have asked about how this is done and, now that I have a working sample (with one or two small issues that need to be resolved), I can create a tutorial. So, if anyone out there has a simple-ish module that illustrates code completion, code folding, or identifier hyperlinking, PLEASE let me know! Those are areas that really need to find their way into a tutorial.
By the way, if you want to contribute to (or read up on) docs on NetBeans module development, check out the new (and growing) NetBeans Module & Platform Development Work-in-Progress Page. Your tips and tricks (or anything else) are 100% welcome!
Dec 09 2005, 03:52:12 PM PST Permalink
JOnAS Plug-in for NetBeans IDE?
Some months ago, when some of the Sun Java Studio Creator developers were in town (i.e., here in Prague), I went out for a few drinks with some of them. At some point, I mentioned that we had put together a NetBeans Server-Skeleton Plug-in Tutorial. When he heard this, one of them laughed and, I remember his response very clearly—he said: "Wow! How big is your audience?!" What he meant was that he didn't think there'd be many people out there interested enough in creating server plug-ins for NetBeans to make the job of creating the tutorial worth the effort. I replied that if there was even one person out there who would find it useful enough to decide to create an additional server plug-in, then the creation of the tutorial would have been time well-spent. Imagine—we currently support the Sun Java System Application Server, JBoss Application Server, Tomcat Web Server, and Weblogic Application Server. If even one server were to be added to that list, that would be five server plug-ins instead of four. That's a big improvement and any new server plug-in would feature very high up on the list of features for the next release.
So, last week I received an e-mail from Manfred Riem, who is the Dutch translator of NetBeans IDE. He's translated a lot of the user interface and he also translates the NetBeans newsletters into Dutch. And guess what he wrote to tell me? He'd found the NetBeans Server-Skeleton Plug-in Tutorial and was in the process of creating support for JOnAS (Java Open Application Server). Now is that cool or what?
He sent me the sources of his plug-in today, because he's too busy with other things at the moment to complete it. But he got pretty far already. Here's what his plug-in looks like in the Projects window:
He's got pretty far, as you might be able to see. In fact, I can already register my JOnAS server (albeit without any server-specific settings) and start it (albeit with a hard-coded server location):
I can also set JOnAS as my target server (although I get an error message when I try to complete the wizard after choosing JOnAS):
So, Manfred's come a long way, but there's still some way to go and currently he's short of time. Is there anyone out there who'd be interested in taking the sources and continuing where Manfred left off? Remember, there's a tutorial (and a lot of NetBeans developers) to help you... If you're interested, please leave a note here or drop me an e-mail.
Dec 08 2005, 12:00:35 AM PST Permalink
Message-Level Web Service Security and Demi Moore
Let's say you want to send a super secret message somewhere, from within an application. A suitably secret message (because you're afraid of Ashton Kutcher or because you're worried that it might be uncool to think that Demi Moore is cool) might be: "Demi Moore is cool." How would you go about sending it? Let's try message-level web service security. And we'll use an IDE. Hmmm... which IDE shall we use. Let's try NetBeans IDE.
- Use wizards in NetBeans IDE 5.0 to create the 'Hi World' web service sample. (See the NetBeans IDE 5.0 Quick Start Guide for Web Services for details. By the way, when I wrote the first quick start doc for web services, in NetBeans IDE 4.1, I consciously decided to use 'Hi World' instead of 'Hello World'. Think about it—I saved you three key strokes for each instance of the phrase. Woohoo.)
However, instead of implementing the web service client in a web application, I implemented it in a J2SE application. This is what the content looks like (everything in this file, apart from the text 'Demi Moore is cool' was created for me by the NetBeans IDE 5.0 wizards):
package org.me.hi; public class Main { public Main() { } public static void main(String[] args) { try { // This code block invokes the HiWSSEIPort:sayHi operation on web service auctionsystem.client.HiWS hiWS = new auctionsystem.client.HiWS_Impl(); auctionsystem.client.HiWSSEI hiWSSEIPort = hiWS.getHiWSSEIPort(); System.out.println(hiWSSEIPort.sayHi("Demi Moore is cool")); } catch(javax.xml.rpc.ServiceException ex) { // TODO handle ServiceException } catch(java.rmi.RemoteException ex) { // TODO handle remote exception } catch(Exception ex) { // TODO handle custom exceptions here } } }Also, note that this is the content of my HiWSImpl file, which is on the service side, in the HiWS project:
package org.me.hi; public class HiWSImpl implements HiWSSEI { public java.lang.String sayHi(String s) throws java.rmi.RemoteException { System.out.println("Received: " + s + "!"); return "Received: " + s + "!"; } } - Download and install the Java Web Services Developer Pack (Java WSDP). Then, add the JAR files that you find in the JWSDP's xws-security\lib folder to both the projects—HIWS and HIWSClient. (I haven't tried any of this for Tomcat, so I suggest you download the JWSDP that is not geared towards Tomcat and that you set the Sun Java System Application Server as the target server for both your projects.)
- On the client side, you need to do the following:
- Override the HiWS-client-wscompile target. Do this by copying it from build-impl.xml into build.xml. Then add the security attribute to the wscompile element (the only addition to the standard target generated for you by the Web Service Client wizard is the security attribute, which is in bold below):
<target name="HiWS-client-wscompile" depends="wscompile-init" unless="wscompile.client.HiWS.notrequired"> <property name="config_target" location="${meta.inf.dir}/wsdl"/> <copy file="${meta.inf.dir}/wsdl/HiWS-config.xml" tofile="${build.generated.dir}/wsclient/wsdl/HiWS-config.xml" filtering="on"> <filterset> <filter token="CONFIG_ABSOLUTE_PATH" value="${config_target}"/> </filterset> </copy> <wscompile security="deployment/xws-security/sendDemiMoore-security.xml" xPrintStackTrace="true" verbose="false" fork="true" keep="true" client="true" import="false" features="${wscompile.client.HiWS.features}" base="${build.classes.dir}" sourceBase="${build.generated.dir}/wsclient" classpath="${wscompile.classpath}:${javac.classpath}" mapping="${build.generated.dir}/wsclient/wsdl/HiWS-mapping.xml" httpproxy="${wscompile.client.HiWS.proxy}" config="${build.generated.dir}/wsclient/wsdl/HiWS-config.xml"/> </target>Notice that the security attribute points to sendDemiMoore-security.xml inside deployment/xws-security. So create those two folders and add an XML file with that name.
- Define the client-side security configuration file. Here's the content:
<xwss:JAXRPCSecurity xmlns:xwss="http://java.sun.com/xml/ns/xwss/config"> <xwss:Service> <xwss:SecurityConfiguration dumpMessages="true"> <xwss:Encrypt> <xwss:X509Token certificateAlias="secretsystem" id="sendDemi" /> <xwss:EncryptionTarget type="uri" value="#sendDemi" /> </xwss:Encrypt> </xwss:SecurityConfiguration> </xwss:Service> <xwss:SecurityEnvironmentHandler> org.me.security.ClientSecurityHandler </xwss:SecurityEnvironmentHandler> </xwss:JAXRPCSecurity>Notice that the configuration file points to org.me.security.ClientSecurityHandler. So create that class in that package structure.
- Define the security handler. Click the
ClientSecurityHandler.java link and paste the code into the class you defined in the org.me.security package.
Notice that the file refers to the deployment/xws-security/client-security-env.properties file. So create that file, in the same package as where the client-side security configuration file (sendDemiMoore-security.xml) is found.
- Define the security properties. Put the following key-value pairs in the properties file:
truststore.url=deployment/xws-security/client-truststore.jks truststore.type=JKS truststore.password=secret
Notice that the file refers to the client-truststore.jks file. We'll create that later. The client should now look as follows (without the JKS files, because you don't have them yet, they'll be created in step 5):
- Override the HiWS-client-wscompile target. Do this by copying it from build-impl.xml into build.xml. Then add the security attribute to the wscompile element (the only addition to the standard target generated for you by the Web Service Client wizard is the security attribute, which is in bold below):
- On the service side, do the following:
- Override the HiWS_wscompile target. Do this by copying it from build-impl.xml into build.xml. Then add the security attribute to the wscompile element (the only addition to the standard target generated for you by the Web Service wizard is the security attribute, which is in bold below):
<target name="HiWS_wscompile" depends="wscompile-init"> <wscompile security="deployment/xws-security/receiveMessage-security.xml" define="true" fork="true" keep="true" base="${build.generated.dir}/wsbinary" xPrintStackTrace="true" verbose="true" nonClassDir="${build.web.dir.real}/WEB-INF/wsdl" classpath="${wscompile.classpath}:${build.classes.dir.real}:${javac.classpath}" mapping="${build.web.dir.real}/WEB-INF/${HiWS.mapping}" config="${HiWS.config.name}" features="${wscompile.service.HiWS.features}" sourceBase="${build.generated.dir}/wsservice"/> </target>Notice that the security attribute points to receiveMessage-security.xml inside deployment/xws-security. So create those two folders and add an XML file with that name.
- Define the service-side security configuration file. Here's the content:
<xwss:JAXRPCSecurity xmlns:xwss="http://java.sun.com/xml/ns/xwss/config"> <xwss:Service> <xwss:SecurityConfiguration dumpMessages="true"> <xwss:Sign/> <xwss:RequireSignature/> </xwss:SecurityConfiguration> </xwss:Service> <xwss:SecurityEnvironmentHandler> org.me.security.HiServerSecurityHandler </xwss:SecurityEnvironmentHandler> </xwss:JAXRPCSecurity>In this file, you can see that a signature is required. Notice that the configuration file points to org.me.security.HiServerSecurityHandler. So create that class in that package structure.
- Define the security handler. Click the
HiServerSecurityHandler link and paste the code into the class you defined in the org.me.security package.
Notice that the file refers to the deployment/xws-security/server-security-env.properties file. So create that file, in the same package as where the service-side security configuration file (receiveMessage-security.xml) is found.
- Define the security properties. Put the following key-value pairs in the properties file:
keystore.url=server-keystore.jks keystore.type=JKS keystore.password=secret
Notice that the file refers to the server-keystore.jks file. We'll create that next. The client should now look as follows (without the JKS file and without the CERT file, because you don't have them yet, they'll be created in step 5, and also without ExtractHeadersMH.java which is referred to later in this blog entry):
- Override the HiWS_wscompile target. Do this by copying it from build-impl.xml into build.xml. Then add the security attribute to the wscompile element (the only addition to the standard target generated for you by the Web Service wizard is the security attribute, which is in bold below):
- Use the Key and Certificate Management Tool. This tool is part of the JDK. Various ways can be adopted to use this tool. I like Ant, so I use the tool via Ant scripts from inside the IDE. (This means I can create keyboard shortcuts, toolbar buttons, and menu items for them. Woohoo!) So first, click the keytool-targets.xml link to get a text file containing the targets. Create an XML file and put the targets into it, exactly as they are in the text file. Put the XML file in the HiWS root directory (i.e., in the same folder as where build.xml is found in the web service project.) Then, here's a really cool thing (which I learnt from Petr Blaha recently). Paste this right below the XML declaration in your build.xml file:
<!DOCTYPE project [ <!ENTITY KeyToolTargets SYSTEM "keytool-targets.xml"> ]>
Now, put this entity reference on a line somewhere below the <import file="nbproject/build-impl.xml"/> line:
&KeyToolTargets;
Neat, right? This way, you keep your keytool targets in a tidy separate file. And, when you expand the build.xml file, you can right-click and run any of the keytool targets, just as if they were inside the build.xml file (but unfortunately, when you double-click a target, the cursor doesn't jump to the keytool-targets.xml file):
Select each of the 5 keytool targets and run them one by one. You'll find files have been generated on the service-side, in the deployment/xws-security folder. Move the client-keystore.jks and client-truststore.jks to the same folder on the client side.
Now deploy the web service and the web service client. If you get the dreaded "SOAP must understand error" message when you run the client, see my blog entry from a few days ago. Basically, you need to create a message handler so that the web service can take the headers out of the client's message. The message handler is very easy to create, as explained in that blog entry.
Finally, all should be well and the web service receives the client's message and proves it by printing the received message in the log file, which is displayed in the Output window, as shown below:
The code and the concepts introduced in this blog entry come from the Sun Education course that I've been converting to NetBeans, called "Developing Secure Java Web Services". I highly recommend this course, because it covers a lot more than the basic steps described above—it goes into a lot of theoretical detail. On top of that, I'd recommend the Security chapter of the free Designing Web Services with the J2EE 1.4 Platform, as well as the chapters relating to Security in the J2EE 1.4 tutorial.
Dec 07 2005, 02:15:41 PM PST Permalink
Organizing my NetBeans IDE 5.0 Projects
Until yesterday, my projects were just like everyone else's—a long list, sorted alphabetically:
Now, however, thanks to a new module by Tim Boudreau (it's in CVS, but I don't know under what name), my life is much neater and simpler—I have folders where I can group related projects:
Thanks a lot Tim!
Dec 06 2005, 09:35:57 AM PST Permalink
Soap Must Understand?! Aaaaaargh!
While rewriting a Sun Education course ("DWS-4487: Developing Secure Java Web Services") to use NetBeans IDE, I must've come across every single unparseably bizarre error that the tiny warped minds of developers have conceived of. The one that takes the cake, as far as I'm concerned, is this one:
Exception in thread "main" javax.xml.rpc.soap.SOAPFaultException: SOAP must understand error
at com.sun.xml.rpc.client.StreamingSender._raiseFault(StreamingSender.java:528)
at com.sun.xml.rpc.client.StreamingSender._send(StreamingSender.java:307)
at auctionsystem.client.AddAuctionUserServiceSEI_Stub.addUser(AddAuctionUserServiceSEI_Stub.java:79)
at auctionsystem.client.AddAuctionUserClient.main(Unknown Source)
Java Result: 1
BUILD SUCCESSFUL (total time: 4 seconds)
You see what it says?! "SOAP must understand error". How on earth is one to know what that means? The answer is simple and immediate—Google. That's where I spent many many hours, until I came across this response, by my web service colleague Rico Cruz (who, with his colleague Peter Williams, helped out the NetBeans J2EE team a lot in the 4.1 release, by providing web service functionality, in co-operation with other developers here in Prague). The thing with Google is that you can really be led up the garden path (and never find your way back), which is what I did a couple of times, but this is Rico's advice:
The SOAP "must understand" error may be indicative of an unhandled SOAP security header at the receiving end (i.e. the web service). Make sure that you have configured the SOAP message handlers at web service end correctly.
I confess that I spent a while avoiding this solution. ("Configure a SOAP message handler? Really? Sounds tough." I thought.) But then I got stuck in and remembered my earlier praise song to message handlers (here). Using the New Message Handler wizard, I generated the template code, and then added this little snippet (googled from elsewhere):
if(shd != null){
Iterator iter = shd.extractAllHeaderElements();
while(iter.hasNext()){
SOAPHeaderElement el = (SOAPHeaderElement)iter.next();
System.out.println("Extracted header: " + el.getElementName().getQualifiedName());
}
}
What's important is the "extractAllHeaderElements()" method. This detaches the element objects from the SOAP header which, apparently, is exactly what is needed when you're using web service security mechanisms such as those provided by <xwss:Sign> elements and <xwss:Encrypt> elements. Once I'd added the snippet above to the generated message handler, and configured it to insert it in all the web services involved in the security framework, the "SOAP must understand" error disappeared.
Dec 05 2005, 04:47:54 AM PST Permalink
Making Life Even Easier for NetBeans Developers
Some developers know exactly what they want when they're creating their application. They don't want to first use a project wizard to create their application and then use the Library Manager to select the libraries they need. For these people, wouldn't it be cool if all the libraries were to be available in the Frameworks panel? (Currently, this additional panel is only available in the Web Application wizard.) And, if you think of web frameworks as consisting of a library (JSF, Struts, whatever) that contains JARs, together with some IDE-specific support for how the libraries are used (syntax highlighting, code completion, samples, etc), then the Frameworks panel in the Web Application project template is already a Libraries panel. So, instead of only making a new library available in the Library Manager, one should also—if one agrees with this thinking—make it available to the Frameworks panel (and then hope that in the next release, the title 'Frameworks' changes to 'Frameworks and Libraries').
To make this happen, the code required is truly minimal. Here's my projects window, and the only additional file required is selected:
The rest of the files you see above are (1) Bundle.properties, which contains this module's localization strings that will be displayed in the Frameworks panel; (2) layer.xml, which has this content for registering the WicketFrameworkProvider.java class in the NetBeans system:
<folder name="j2ee">
<folder name="webtier">
<folder name="framework">
<file name="org-netbeans-modules-wicketsupport-WicketFrameworkProvider.instance"/>
</folder>
</folder>
</folder>
Finally, you see (3) wicket.xml, which is the J2SE library descriptor, an XML file, which registers the Wicket libraries in the Library Manager. (For information on this file, and the Library Manager registration process in general, see NetBeans Project Template Module Tutorial).
So, the only file that needs a little bit of explanation is WicketFrameworkProvider.java. Here it is, in an absolutely simple implementation (since all it does is provide libraries). Below, all the method declarations are in bold, to (hopefully) make things more legible:
public class WicketFrameworkProvider extends WebFrameworkProvider {
public WicketFrameworkProvider() {
super(
NbBundle.getMessage(WicketFrameworkProvider.class, "Wicket_Name"),
NbBundle.getMessage(WicketFrameworkProvider.class, "Wicket_Description"));
}
public Set extend(WebModule webModule) {
FileObject fo = webModule.getDocumentBase();
Project project = FileOwnerQuery.getOwner(fo);
Library lib = LibraryManager.getDefault().getLibrary("wicket");
if (lib != null) {
ProjectClassPathExtender cpExtender
= (ProjectClassPathExtender) project.getLookup().lookup(ProjectClassPathExtender.class);
if (cpExtender != null) {
try {
cpExtender.addLibrary(lib);
} catch (IOException ioe) {
ErrorManager.getDefault().notify(ioe);
}
} else {
ErrorManager.getDefault().log("WebProjectClassPathExtender not
found in the project lookup of project:
"+project.getProjectDirectory().getPath());
}
}
return null;
}
public boolean isInWebModule(WebModule webModule) {
return false;
}
public File[] getConfigurationFiles(WebModule webModule) {
return null;
}
public FrameworkConfigurationPanel getConfigurationPanel(WebModule webModule) {
return null;
}
}
So, here the only method that's interesting is extend(). This is normally where all the action happens when you subclass WebFrameworkProvider. Normally, content is provided for deployment descriptors and configuration files, here in this method. However, since all we're doing is providing libraries, that's also all that happens here. So the Library Manager is looked up and queried for a library called 'wicket'. How do we know for sure that that library is there? Because this module includes the J2SE library desciptor which adds a library called 'wicket' to the Library Manager.
One small point, though—as discussed in yesterday's blog entry, the isInWebModule() method is used by the Project Properties dialog box to populate its Frameworks panel with a list of supported frameworks. Normally, it queries the web.xml deployment descriptor, to see whether the framework's servlet class is there. However, in this case, all we're doing is adding libraries, so there's really nothing to check (however, if someone can tell me how to check whether a library is on a project's classpath, that would be great, because then the isInWebModule() method would check whether the main Wicket JAR files are present, and only then would the Frameworks panel in the Project Properties dialog box be useful for this scenario).
So, anyway, after adding this file, a checkbox with the label 'Wicket' (thanks to the Bundle.properties file) is added to the Frameworks panel in the Web Application project wizard. When the user selects this checkbox and clicks OK, thus exiting the wizard, the libraries are automatically added—thus saving the extra step of having to go to the Library Manager to add the libraries that you knew you needed from the start. A small thing, but cool. But, maybe it's also a first step—maybe other things could be definable in the project wizards? By adding two or three extra panels (all of which the user could choose to ignore by being able to click 'Finish' anywhere), the user might be able to add far more things to their application, before having even typed a single character of code.
Dec 02 2005, 09:57:26 AM PST Permalink
Destroying Struts (or JSF) Support in NetBeans IDE
Here's something fun—create a web application with Struts (or JSF) support in NetBeans IDE 5.0. Then right-click the project, choose Properties, and go to the Frameworks panel in the Project Properties dialog box. You'll see a list of 'Used Frameworks' where the framework(s) you selected previously are listed. Now exit the Project Properties dialog box. Go to your web.xml file and make one tiny change to the servlet-class declaration. For example, just change one letter. Now go back to the Frameworks panel in the Project Properties dialog box. Your framework isn't listed there anymore!
Question: Why?
Answer: Because the IDE looks for the web framework's servlet in the web.xml file's servlet-class declaration to determine whether a framework is supported or not! For example, in the Wicket support module that I'm building (and that will find itself in the NetBeans IDE 5.0 Web Framework Module Tutorial soon), this is my implementation of the isInWebModule method of the NetBeans API's WebFrameworkProvider class:
public boolean isInWebModule(WebModule webModule) {
return WicketConfigUtilities.getActionServlet(webModule.getDeploymentDescriptor()) == null ? false : true;
}
The method above is called in the Project Properties dialog box to determine whether the framework is supported or not. As you can see, it calls another method, getActionServlet in WicketConfigUtilities. This is what it does (exactly the same as what the Struts and JSF equivalents do):
public static Servlet getActionServlet(FileObject dd) {
if (dd == null) {
return null;
}
try {
WebApp webApp = DDProvider.getDefault().getDDRoot(dd);
return (Servlet) webApp
.findBeanByName("Servlet", "ServletClass", "wicket.protocol.http.WicketServlet");
} catch (java.io.IOException e) {
return null;
}
}
So, if the servlet-class declaration in web.xml isn't exactly the same as the Wicket framework's fully-qualified servlet class, null is returned, and the Project Properties dialog box tells you that your application does not support the framework.
It's a pretty safe bet that if you're working with Struts, JSF, or whatever web framework that the IDE supports, you'll have the framework's servlet correctly defined in web.xml. Firstly, it is automatically generated there when you select the checkbox that indicates that you want a particular framework to be supported. Secondly, why would you change that servlet afterwards? Once it's defined, you're unlikely to touch it. Still, if something goes wrong with your web.xml file, and you make some kind of error (any kind of error that results in the servlet-class being incorrectly declared) when recreating the web.xml file, you'll not be able to edit properties in the Frameworks panel (which you couldn't do anyway because they're read-only fields). But, what's probably worse than that, you might be confused into thinking that there's something more seriously wrong than simply a mistake in the servlet declaration (which is a mistake that you'd soon have to solve anyway, because deployment isn't going to work).
So, if you've added support for JSF or Struts to a web application, and you go to the Frameworks panel and find that the framework you added isn't listed there, the only thing that that can mean is that the servlet class is incorrectly defined in the web.xml file. It's a small thing, but good to know, I think, especially in those moments where a lot of things are going wrong all at the same time... (By the way, the converse is equally true: create a web application without any web framework support, then declare the JSF or Struts servlet class in the web.xml file, and the IDE will believe that your application supports the framework, so that the Frameworks panel will inform you that the framework in question is being used.)
Dec 01 2005, 06:17:13 AM PST Permalink








