DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Latest Articles - DZone

article thumbnail
Embedding OSGi in Tomcat
My last post embedded OSGi in an application server using Felix, Jetty, and PAX WEB. Here, I’m going to embed Equinox in Tomcat. I originally set out to embed Felix in Tomcat, but the dearth of tools and frameworks available for embedding Felix made using Equinox much easier. I use the word “much” pretty loosely, though, because there were still some hoops I had to jump through to get JSP compilation working. Of course, PAX WEB provided that capability when embedding Jetty in Felix. Unfortunately, no framework stepped forward that offered these capabilities in this embedding scenario. At least, I wasn’t able to find them. I want to keep this post strictly educational (like a tutorial), but I’m going to post a follow-up shortly that discusses these two scenarios. To give you something to chew on in the meantime, both scenarios presented a different set of challenges, and we have a long ways to go before many development teams will be able to leverage OSGi for building web applications. Like I said, I’ll explain why in a different post, but for now let’s move on with this example. Getting Started In the spirit of using the simplest tools possible, all you’ll need for this example is Tomcat, Ant, and Subversion. If you went through the previous example, you’ve already got Ant and Subversion installed. If you already have Tomcat, you should be set. But if not, download Tomcat 6, which is the version I used for this embedding exercise. Checkout HelloWorldEmbedJSP Next, you’ll need to checkout the project from my Google code repository. You can put the project anywhere when checking out, but you’ll have to make sure you know the path relative to each directory so that you can install the necessary bundles. I have the project sitting in a directory right alongside Tomcat. To checkout, open up a Terminal window or DOS prompt and do the following: svn checkout http://kcode.googlecode.com/svn/trunk/osgi/HelloWorldEmbedWebJSP Of course, if you have a Subversion client installed like TortoiseSVN, you can checkout from the directory browser. I don’t use these tools, though. Next step! Build the WebApp This step has nothing whatsoever to do with OSGi. But as a basis for comparision, I felt it would be interesting to package the sample as a web application. Since this is the exact same example I used when embedding Jetty in Felix, it does offer a nice basis for comparing how we can deploy this functionality in different ways. To build the web application, simply navigate to the web directory in the console and type the following: ant The build script spits out a web.war file in the bin directory. Simply take this web.war and copy it to the Tomcat webapps directory. If you haven’t started Tomcat yet, you should do so now. Just startup another DOS prompt or console window, navigate to the Tomcat bin directory, and execute the startup.bat or startup.sh. Once this is done, give it a second to explode the web application, and navigate to http://localhost:8080/web/hi. Like I said, if you went through the exercise on my previous post of embedding Jetty in Felix, you’ll see the same thing here deployed as a web application instead of a bundle. Onto OSGi. The Bridge The Bridge.war web application is the main reason I chose to use Equinox instead of Felix. It provides two very important functions that are critical when embedding OSGi in an application container. In fact, this is one of the items I’ll be speaking about in my next post - how difficult it is to use OSGi with the current generation of application servers. It’s virtually prohibitive. Anyway, here are the two necessary functions provided by the Bridge. Embeds and launches Equinox Tunnels servlet requests from Tomcat to Equinox Deploying the Bridge is easy because it’s a webapp. Just take the Bridge.war from the web/lib directory of the HelloWorldEmbedWebJSP project and drop it into the Tomcat webapps directory. Give Tomcat a second to explode the web application, and test it by accessing http://localhost:8080/bridge/sp_test. You should see a page that says the Servlet Delegate is registered. You’ve now got OSGi embedded within Tomcat with a bridge that will feed requests to Tomcat and pass them onto Equinox. Linux and Mac OS/X users take note. As you’ll recall in the previous examples, we install OSGi bundles from the OSGi console after starting OSGi. Well, since we embedded OSGi in Tomcat, where’s the console? The console is the same console window you used to start Tomcat. But because Tomcat redirects all output to a file, you may not see it. To enable the console, you’ll need to make some changes to the catalina.sh file in the Tomcat bin directory. Windows users shouldn’t have this problem, though I’m sure Windows users are dealing with many other types of problems. Anyway, once you’ve opened catalina.sh, comment out the following line so it looks like this. If you’ve got the same catalina.sh as I do that’s bundled with Tomcat 6, it’s line number 298. #>> "$CATALINA_BASE"/logs/catalina.out 2>&1 & Now, restart Tomcat and voila…in the console you used to start Tomcat, you should see the OSGi console. Type ss to see the list of installed bundles. Onward! Configuring the Environment Before we deploy the bundle, we need to configure the environment. If we weren’t using JSP, we’d be done. But because JSPs require compilation, and the JSPs will run within Equinox, they can’t use the JSP compiler included with Tomcat. We need to include our own JSP compiler, and we’ll use Jasper. I’ve included all the bundles needed in the same directory where you found Bridge.war. To install the bundles, jump over to the OSGi console, and do the following: osgi> install file:path to bundle/ javax.servlet.jsp_2.0.0.v200806031607.jar osgi> install file:path to bundle/ org.apache.commons.el_1.0.0.v200806031608.jar osgi> install file:path to bundle/ org.apache.commons.logging_1.0.4.v20080605-1930.jar osgi> install file:path to bundle/ org.apache.jasper_5.5.17.v200806031609.jar osgi> install file:path to bundle/ org.eclipse.equinox.jsp.jasper_1.0.100.v20080427-0830.jar osgi> install file:path to bundle/ org.eclipse.equinox.jsp.jasper.registry_1.0.0.v20080427-0830.jar Now, type ss to view the state of the bundles. If they aren’t active, you’ll need to start each one of them. Again, in the OSGi console, just type: osgi> start bundle id Dependening on the dependencies, multiple bundles may start. Just do an ss in between each start to see which ones haven’t been started yet. Wash, Rinse, Repeat! Build & Deploy the Bundle Unlike my previous example where I gave you a pre-configured environment that didn’t require you to build anything, we have to do the build and deploy of the bundle ourselves. Why did I do this? Only because Tomcat has a larger footprint than Felix and Jetty, and I didn’t want to put Tomcat in my Google code repository. Building is pretty easy though. We’ve already built and deployed the web application. Building the bundle is done the same way, except we’ll use a different Ant build script. For this step, you can either shut down Tomcat, or open up another DOS or terminal window. Navigate to the HelloWorldEmbedWebJSP/web directory, and type the following: ant -f buildjar.xml The JAR file overwrites the web.war in the bin directory and places a valid OSGi bundle named web.jar there for you. To install the bundle, make sure Tomcat is started, and type the following in the OSGi console: install file:relative path to web.jar/web.jar The bundle gets installed. Start it up using the OSGi start command. We can now access the OSGi enabled web application by navigating to http://localhost:8080/bridge/hi. Again, it’s the exact same functionality as the other web applications we’ve deployed, except using a different deployment topology. To shut down, just type close in the OSGi console. We’re done. If you had any problems, let me know via comments here or by contacting me. Next up…some general notes on OSGi and hopefully messing around with Distributed OSGi. Additional Notes A few additional notes about this exercise. Obviously it appeared a bit more difficult than embedding Jetty in Felix. But were it not for the PAX WEB framework, that exercise would have proven equally difficult. Also, the Bridge.war performs two very important functions for us. Felix has supporting documentation that shows how to embed Felix, but I found no framework that did it for me. The Bridge.war was available, so I used it. But were a bridge available for Felix, it would be easy to deploy that bridge and install web.jar with Felix embedded within Tomcat. From http://techdistrict.kirkk.com
February 17, 2009
by Kirk Knoernschild
· 60,993 Views · 1 Like
article thumbnail
Programming LDAP with Groovy
It all started with a task to do: Print all members of the group within Active Directory, including members of the nested groups. And a deadline: 15 minutes. Given the deadline, I had no chance to get it done in time. Having 15 minutes means you need to get it right from the first run. Googling for groovy ldap brought Gldapo. But after looking at it and seeing how much configuration has to be done, I searched for some alternatives. Groovy LDAP was beautifully simple and had no external dependencies. I downloaded the jar, dropped it into my GROOVY_HOME/lib directory and started to write the script: import org.apache.directory.groovyldap.LDAP ldap = LDAP.newInstance('ldap://ldap.mycompany.com:389/dc=mycompany,dc=com') After reading through the sample scripts, I already had the main part: ldap.eachEntry ('&(objectClass=person)(memberOf=cn=mygroup') { person -> println "${person.displayName} (${person.cn})" } I saved it as listGroup.groovy and ran it from the command line: groovy listGroup It worked out of the box, printing on the console all the members of the group: John Smith (smithj) Amanda McDonald (mcdonaa) Isabelle Dupre (duprei) Of course, the script was not printing members of the nested groups. In order to do that, I had to turn the snippet into the Groovy recurrent function and avoid hardcoding a group's name in favor of taking it as a command line parameter. Here is the entire script: import org.apache.directory.groovyldap.LDAP import org.apache.directory.groovyldap.SearchScope List getMembersOfAGroup(connection, groupName) { def members = [] def result = connection.searchUnique("cn=$groupName”); connection.eachEntry("memberOf=${result.dn}") { member -> if (member.objectclass.contains("group")) members.addAll(getMembersOfAGroup(connection, member.cn)) else members.add("${member.displayName} (${member.cn})") } return members } LDAP ldap = LDAP.newInstance("ldap://ldap.mycompany.com:389/dc=mycompany,dc=com") getMembersOfAGroup(ldap, args[0]).each { println it } If your directory contains circular group relations, the script has to be further adjusted. This detail has been omitted for simplicity reasons. Please note, that the examples in this article work only with Microsoft Active Directory, because they use vendor specific structure and schema elements. In other directory solutions for instance, group membership is often stored in group entries only, while in Active Directory it is stored in both group and member object. But the examples can easily be adjusted to fit another directory's solution, e.g. by modifying filter expressions. What is this LDAP thing you're talking about? LDAP 101: LDAP stands for Lightweight Directory Access Protocol. A directory is a storage organized as a tree of directory entries. The tree usually reflects political, geographical and/or organizational boundaries. Every directory entry consists of a set of attributes (name/value pairs). These attributes are defined in the LDAP schema. Each directory entry has a unique identifier named DN (Distinguished Name). For more information please read Apache Directory introductory article. Project background Groovy LDAP is a small library started by Stefan Zoerner from the Apache Directory project. Its goal was to create minimalistic LDAP API for Groovy, with metaphors understood by the LDAP community (e.g. members of the Apache Directory team). As such, the only two dependencies of Groovy LDAP are: Java SE (5 or later) Groovy 1.0 or later Under the hood, JNDI is used to perform LDAP queries, but fortunately Groovy LDAP hides it and lets you use a bunch of useful methods and objects, instead. It actually reminds me of the time when Netscape LDAP API was widely used. It defines a set of methods to perform basic LDAP operations: create, modify, delete, compare, search. Groovy LDAP is written in Java, not Groovy. The only Groovy dependency is a reference to a Closure class, which is used as a parameter in a couple of search methods. So with the exception of the method taking the closure, others can be also used in Java programs. How to get it The simplest way is to get the binaries from the Groovy LDAP download page. After downloading and expanding the zip file you need to look for groovy-ldap.jar in the dist directory. Drop it into your GROOVY_HOME/lib directory and you’re ready to write your first script. How to build it If you want to build the library on your own, you will need: Apache Ant 1.7.1 Ivy 1.4.1 or later After you download and install Ant, drop Ivy's jar (ivy-1.4.1.jar) into your ANT_HOME/lib directory. Now you can check out the source files from Apache Directory sandbox Subversion repository. Once the files are checked out, just type ant and wait until the distribution jar is built in the dist directory. Connecting to the directory The first thing you will want to do is to connect to the directory. Groovy LDAP offers here two types of connection: anonymous bind and simple bind. Anonymous bind happens when you connect to the directory without providing your credentials. Many directories allow anonymous bind if the client is only reading from the directory. In corporations anonymous bind is often disabled for security reasons. So, in order to connect you need to instantiate LDAP class using newInstance() method, with the following variants: public LDAP newInstance() public LDAP newInstance(url) A non-parameter method connects to the default address, which is localhost:389. It proves to be useful for various short proof-of-concept scripts. The second method takes the url of the directory as a second parameter. If anonymous bind is not allowed or not sufficient there is an equivalent method, taking additionally user credentials: public LDAP newInstance(url, user, password) Once the connection is established, you can perform any other actions. One tip is to always provide a baseDN as a part of the connection url e.g. ldap://ldap.mycompany.com:389/dc=mycompany,dc=com By doing so you define the default base, upon which searches will be performed, which in turn allows you to use convenient one parameter search methods, instead of specifying a search base and scope each time. Reading and searching directory entries You may want to start with checking if a specific directory entry exists: def found = ldap.exists('cn=smithj,dc=mycompany,dc=com') exists() method is searching the directory by DN (Distinguished Name) and returning a boolean result detailing whether an entry was found. As a companion there is read() method, that reads directory entry, specified by its DN: if (found) def entry = ldap.read('cn=smithj,dc=mycompany,dc=com') This method returns either a boolean value or a given entry, accordingly. But there might be cases when you do not want to search by DN, but by another attribute which is also unique. A good example of this is a userId attribute, which is usually unique within a company. def entry = ldap.searchUnique('userId=smithj') This method assumes uniqueness of an object. If more than one result is returned from the search, you will get an exception. When more results are expected, you can use search() method: and then iterate over a result set: results = ldap.search('(objectClass=user)') println 'Found: $results.size entries' results.each { entry -> println entry.dn } Searches can be also performed with more compact and more Groovy method eachEntry() taking a closure as the last parameter: ldap.eachEntry('(objectClass=user)') { entry -> println entry.dn } As you see, when you have the entry object, you can reference all its properties using native map syntax e.g. entry.dn. This is possible, because all result objects returned from Groovy LDAP search methods are Maps or Lists of Maps. But, how does Groovy LDAP know in which subtree you would like to perform your search? It doesn't, because you haven't specified anything else, but the basic query. So it assumed you want to search in baseDN (hopefully specified, when connecting to the directory). When you want to have more control over how the query is performed, there is a different version of search(), searchUnique() and eachEntry() methods that support it e.g. public List or Search class instance as parameters, but we'll leave them as for now. When you deal with LDAP directories as a part of your daily job, you may want to have a look at Apache Directory Studio, a full-fledged LDAP client tool, which allows you to connect, browse and modify any LDAP-compatible directory. It can also be used as diagnostic tool when your query in Groovy LDAP doesn't work as expected. Adding, modifying and deleting directory entries When you know how to search and read from the directory, it's time to do some modifications. Let's start from adding a new entry: def attributes = [ objectclass: ['top', 'person'], cn: 'smithc', displayName: 'John Smith' ] ldap.add('cn=smithc,dc=example,dc=com', attributes) add() method takes DN and a Map with attributes as parameters. You need to remember not to put DN in the attributes map, as it is not an attribute but rather the unique identifier of an entry. Removing a directory entry is even more straightforward: ldap.delete('cn=smithc,dc=example,dc=com') delete() method will throw an exception, if an object with the given DN does not exist. Modifying a directory entry is not very Groovyish for the time being. Adding single attributes is still relatively easy: def dn = 'cn=smithj,dc=mycompany,dc=com' def email = [ email: '[email protected]' ] ldap.modify(dn, 'ADD', email) Performing batch modifications could be more readable using Builder-like syntax.. The current way to do this is the following: def modifications = [ [ 'REPLACE', [email: '[email protected]'] ], [ 'ADD', [phone: '+48 99 999 99 99'] ] ] ldap.modify(dn, modifications) The same operation, using more expressive syntax, would potentially look like: ldap.modify ('cn=smithj,dc=mycompany,dc=com') { replace(email: '[email protected]') add(phone: '+48 99 999 99 99') } Summary As you can see, Groovy LDAP is a neat little library, delivering simple but convenient API to deal with LDAP directories, which makes it an ideal candidate to use in various administrator scripts and short programs. As a project it resides in Apache Directory sandbox, so when you have a chance, contribute and help Groovy LDAP to become an official subproject of the Apache Directory. Thanks I would like to thank Stefan Zoerner and Carolyn Harman for thorough review of the article. Resources Apache Directory Project Groovy LDAP Gldapo Apache Ant Apache Ivy Groovy
February 16, 2009
by Michal Szklanowski
· 53,046 Views · 5 Likes
article thumbnail
JBoss RichFaces with Spring
This article is going to show you how to build a RichFaces application with Spring.
February 16, 2009
by Max Katz
· 203,866 Views
article thumbnail
How to Create Modular Groovy Applications in 5 Steps!
let's create a modular groovy application! why?! modularity is an enabler of scaleability. as your groovy application increases in size, you increasingly need to manage code dependencies, structure your code in units that are larger than packages, and distribute pieces of your application to developers located in different locations and conflicting time zones. welcome to modularity. the netbeans platform already provides it (plus, osgi is coming to the netbeans platform ). beyond modularity, there are specific features that the netbeans platform provides that will remain unique, such as a shared filesystem for intermodular communication and the concept of "context" (i.e., netbeans lookup), which not only applications have (as with the jdk 6 serviceloader class), but netbeans platform objects such as windows themselves. welcome to loosely coupled modularity. now, let's get started. start up netbeans ide 6.5. go to this page and download the groovy console template and use the plugin manager (in the tools menu) to install it into the ide. now, in the new project dialog, you should see this new project template: click next, give your new application a name (such as "helloworld") and a location on disk, and then click finish. expand a few folders and you should now see this: briefly, the template gives you a groovy pojo, with this content: package org.my.app public class demopojo { def foo } the template also gives you a moduleinstall class, which handles the lifecycle of the module: package org.my.app import org.openide.modules.moduleinstall as mi public class installer extends mi { @override public void restored() { for(int i = 0; i < 10; i++) { demopojo dp = new demopojo() dp.setfoo(i) println("number: " + dp.getfoo()) } } } so, we have some standard groovy constructs here, simply to get you started in the ecosystem of the netbeans platform. the module also includes a properties file for internationalization purposes and a layer.xml file, for the module's contributions to the shared filesystem. run the application (i.e., without doing anything at all, no tweaking, no post processing, nothing at all, just run it). look in the output window of netbeans ide and you will see this: so, you can see that you only have the absolute minimum set of modules to start with. also you're using the groovy compiler (thanks to an additional target that's added to the demo module's build.xml file). that's how to get started with modular groovy applications. have fun with groovy on the netbeans platform!
February 14, 2009
by Geertjan Wielenga
· 21,909 Views
article thumbnail
NetBeans Lookups Explained!
Lookups are one of the most important parts of the NetBeans Platform. They're used almost everywhere and most of the time when you ask something on a mailing list the answer is "Use Lookups!". Many times when the use of Lookups is explained it's in a very specific context, e.g. selection management or ServiceLoaders. That makes Lookups look complicated and hard to understand, while actually they are very simple and extremely powerful. That's why I guess it's time to write an article that explains what lookups actually are and how they work. In the subsequent parts I'll explain how they can be used to solve some common problems. Lookup as a Data Structure So first let's have a look at Lookup as a data structure. A Lookup is a map with Class Objects as keys and a Set of instances of the key Class object as values. An additional feature of a Lookup is that you can listen for changes of what's in there. It's as simple as that! If you want to ask a lookup for it's contents, you can do so like this: Lookup lookup = //get a lookup somewhere... Collection strings =lookup.lookupAll(String.class); If you want to listen for changes, you add your Listener to Lookup.Result an inner class that represents a query result. This way you add a Listener that listens for addition or removal of objects of a certain class: Lookup.Result strings = lookup.lookupResult(String.class); strings.allItems(); strings.addLookupListener(new LookupListener(){ @override public void resultChanged(LookupEvent e){ // do something } ); This is how you usually use an existing lookup. If you want to create one, there are some implementations to help you. The most basic one is Lookups.Singleton, a Lookup that only contains one object: Lookup simple = Lookups.singleton("Hello World!"); There's also an implementation for creating a lookup with more than one entry, still with fixed content: Lookups moreElements = Lookups.fixed( "Hello", "World", new Integer(5) ); If you want to use a Lookup to dynamically put in stuff you'll need to choose an implementation that supports that. The most flexible one is using an InstanceContent Object to add and remove stuff: InstanceContent content = new InstanceContent(); Lookup dynamicLookup = new AbstractLookup(content); content.add("Hello"); content.add(5); Listeners registered for the matching class will be informed when something changes. If you would like to query more than one Lookup at a time you can use a ProxyLookup. This for example, combines two of the Lookups created above into one: ProxyLookup proxy = new ProxyLookup(dynamicLookup, moreElements); Lookup.Provider If your Object has a Lookup to store a bunch of stuff, you can make it accessible to others by implementing Lookup.Provider an interface with only one method: public Lookup getLookup(); Again, extremely simple. Someone interested in what's in your Objects Lookup can ask for it and register a listener. In NetBeans TopComponents implement this interface, so you can ask any TopComponent for it's Lookup. The easiest way to get hold of most of the TopComponents is via their ID: TopComponent tc = WindowManager.getDefault().findTopComponent("AnInterestingTopComponent"); Lookup tcLookup = tc.getlookup(); As most TopComponents put into their Lookup whatever is selected, for example the entries in a list, you can add a Listener to track the Selection in a TopComponent. If your for example interested in the selected Nodes you can do it like this: Lookup.result noderesult = tcLookup.lookupResult(Node.class); result.allInstances(); noderesult.addLookuplistener(myLookupListener); That's especially handy when you want to provide a Master-Detail-View. If you want to provide your own Lookup in your TopComponent you do it like this: associateLookup(mylookup); Global Selection Sometimes you might be interested not only in what is selected in one specific TopComponent, but in whatever TopComponent currently has the focus. That's easy as well because NetBeans provides a Lookup that proxies the Lookup of the TopComponent that currently has the focus. To use this you simply need to do this: Lookup global = Utilities.actionsGlobalContext(); You can use this like any other Lookup and register your listeners, no magic involved. Nodes Nodes also implement Lookup.Provider so you can ask them for their Lookup as well. Something useful to store inside a Node's Lookup is the DataObject it may represent. If you're using Nodes you probably do so in combination with the Explorer API to display them. If you do that you'll usually create a lookup for your TopComponent with the help of the ExplorerManager: associateLookup(ExplorerUtils.createLookup ( explorermanager, this.getActionMap() ) ); The resulting Lookup also proxies the content of the selected Nodes Lookup. This way everything someone might be interested in shows up in your TopComponent's Lookup. Service Loader and other uses As you've seen Lookups are actually a very simple yet powerful concept. Some articles here on NetBeans Zone also cover the use of Lookups for loading services in a NetBeans RCP application, which is also an important use. To do that NetBeans provides a default Lookup that looks in certain places for service registrations, e.g. in the META-INF/services folder of a modules jar file and in the modules layer.xml. If you're interested in getting an instance of a Service implementation you can do it like this: Collection services= Lookup.getDefault.lookupAll(ServiceInterface.class); If you register your service in the layer.xml you can get a lookup for a certain Folder like this: Lookup lkp = Lookups.forPath("ServiceProviders"); I guess that's all you need to know to get started with Lookups, so have fun trying it out, it's really simple.
February 12, 2009
by Toni Epple
· 72,352 Views · 7 Likes
article thumbnail
Understanding Web Security Using web.xml Via Use Cases
The deployment descriptor, web.xml is the most important Java EE configuration piece of Java EE Web applications.
February 11, 2009
by Anil Saldanha
· 364,774 Views · 2 Likes
article thumbnail
Integrate OpenOffice with Java without Installing OpenOffice
Until a few days ago, I've always needed to work with the rather cumbersome Office Bean and UNO Runtime when integrating OpenOffice into a Java application. I also had to configure a whole bunch of things to force OpenOffice to play nicely with the Java integration. Two days ago, however, I found out about ODF Toolkit. It seems to be a relatively new project, independent since last year some time, though I could be wrong. What's especially interesting is the ODFDOM: ''ODFDOM is an OpenDocument (ODF) framework. It's purpose is to provide an easy common way to create, access and manipulate ODF files, without requiring detailed knowledge of the ODF specification. It is designed to provide the ODF developer community an easy lightwork programming API, portable to any object-oriented language.'' Here's a snippet of it in action: public static void main(String[] args) { try { OdfDocument odfDoc = OdfDocument.loadDocument(new File("/home/geertjan/test.ods")); OdfFileDom odfContent = odfDoc.getContentDom(); XPath xpath = odfDoc.getXPath(); DTMNodeList nodeList = (DTMNodeList) xpath.evaluate("//table:table-row/table:table-cell[1]", odfContent, XPathConstants.NODESET); for (int i = 0; i < nodeList.getLength(); i++) { Node cell = nodeList.item(i); if (!cell.getTextContent().isEmpty()) { System.out.println(cell.getTextContent()); } } } catch (Exception ex) { //Handle... } } Let's assume that the 'test.ods' file above has this content: From the above, the code listing would print the following: Cuthbert Algernon Wilbert And, as a second example, here's me reading the first paragraph of an OpenOffice Text document: public static void main(String[] args) { try { OdfDocument odfDoc = OdfDocument.loadDocument(new File("/home/geertjan/chapter2.odt")); OdfFileDom odfContent = odfDoc.getContentDom(); XPath xpath = odfDoc.getXPath(); OdfParagraphElement para = (OdfParagraphElement) xpath.evaluate("//text:p[1]", odfContent, XPathConstants.NODE); System.out.println(para.getFirstChild().getNodeValue()); } catch (Exception ex) { //Handle... } } On my classpath I have "odfdom.jar" and "xerces-2.8.0.jar". I don't necessarily have OpenOffice installed, which means I can very easily process a whole bunch of spreadsheets (or other OpenOffice output) without (a) installing OpenOffice and (b) faster than I would otherwise do, since OpenOffice doesn't need to be started up, via the Office Bean or otherwise. In fact, Aljoscha Rittner from Sepix, who told me about this project and who is using it in his commercial applications, reports that his processing has sped up to a fraction of the original, also because he doesn't need to handle the situation where OpenOffice would crash randomly in the middle of long running processes, such as during the night when there's no human interaction for restarting it.
February 7, 2009
by Geertjan Wielenga
· 50,551 Views
article thumbnail
NetBeans Output Window Font Too Small? Now It's Easy to Change!
Ctrl=, Ctrl-- or Ctrl-mousewheel In a fit of pique this evening, I added a much requested feature to the NetBeans output window: Actions for Larger Font and Smaller Font on the popup menu - or you can just Ctrl-mousewheel to rapidly change the font size. Font changes affect all open output windows, and persist across sessions. It just seemed silly to have this issue sitting open for so long. Now we'll see if anyone gets upset with me, since I haven't actually been the owner of the output window code in years. :-)
February 6, 2009
by Tim Boudreau
· 23,474 Views
article thumbnail
Tip: Importing Images into NetBeans
In the 6.5 release I noticed I can import images in two ways: Drag image from outside NetBeans into a project (e.g., a package) in Projects window. Copy an image outside NetBeans (so it is now on clipboard), then paste it onto a package and then it is added. Small tip, but Very useful to me now I know it.
January 30, 2009
by Harris Goldstone
· 49,881 Views · 1 Like
article thumbnail
RFC-compliant Email Address Validator
A PHP function that validates all parts of a given email address, according to RFCs 1123, 2396, 3696, 4291, 4343, 5321 & 5322. I’ve released it under a license that allows you to use it royalty-free in commercial or non-commercial work, subject to a few conditions. It’s almost certainly the first email address validator that correctly lets you put an IPv6 address in for the domain part… I've put this snippet into Google Code where you can be sure of getting the latest version: http://code.google.com/p/isemail/source/browse/#svn/trunk * Test schema documentation Copyright (c) 2010, Daniel Marschall * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of Dominic Sayers nor the names of its contributors may be * used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * @package is_email * @author Dominic Sayers * @copyright 2008-2010 Dominic Sayers * @license http://www.opensource.org/licenses/bsd-license.php BSD License * @link http://www.dominicsayers.com/isemail * @version 2.8.3 - Clarified text for ISEMAIL_IPV6BADCHAR and new test #276 added (too many IPv6 groups with an elision) */ // The quality of this code has been improved greatly by using PHPLint // Copyright (c) 2010 Umberto Salsi // This is free software; see the license for copying conditions. // More info: http://www.icosaedro.it/phplint/ /*. require_module 'standard'; require_module 'pcre'; .*/ /** * Check that an email address conforms to RFCs 5321, 5322 and others * * @param string $email The email address to check * @param boolean $checkDNS If true then a DNS check for A and MX records will be made * @param mixed $errorlevel If true then return an integer error or warning number rather than true or false */ /*.mixed.*/ function is_email ($email, $checkDNS = false, $errorlevel = false) { // Check that $email is a valid address. Read the following RFCs to understand the constraints: // (http://tools.ietf.org/html/rfc5321) // (http://tools.ietf.org/html/rfc5322) // (http://tools.ietf.org/html/rfc4291#section-2.2) // (http://tools.ietf.org/html/rfc1123#section-2.1) // (http://tools.ietf.org/html/rfc3696) (guidance only) // $errorlevel Behaviour // --------------- --------------------------------------------------------------------------- // E_ERROR Return validation failures only. For technically valid addresses return // ISEMAIL_VALID // E_WARNING Return warnings for unlikely but technically valid addresses. This includes // addresses at TLDs (e.g. johndoe@com), addresses with FWS and comments, // addresses that are quoted and addresses that contain no alphabetic or // numeric characters. // true Same as E_ERROR // false Return true for valid addresses, false for invalid ones. No warnings. // // Errors can be distinguished from warnings if ($return_value > ISEMAIL_ERROR) // version 2.0: Enhance $diagnose parameter to $errorlevel // revision 2.5: some syntax changes to make it more PHPLint-friendly. Should be functionally identical. if (!defined('ISEMAIL_VALID')) { // No errors define('ISEMAIL_VALID' , 0); // Warnings (valid address but unlikely in the real world) define('ISEMAIL_WARNING' , 64); define('ISEMAIL_TLD' , 65); define('ISEMAIL_TLDNUMERIC' , 66); define('ISEMAIL_QUOTEDSTRING' , 67); define('ISEMAIL_COMMENTS' , 68); define('ISEMAIL_FWS' , 69); define('ISEMAIL_ADDRESSLITERAL' , 70); define('ISEMAIL_UNLIKELYINITIAL' , 71); define('ISEMAIL_SINGLEGROUPELISION' , 72); define('ISEMAIL_DOMAINNOTFOUND' , 73); define('ISEMAIL_MXNOTFOUND' , 74); // Errors (invalid address) define('ISEMAIL_ERROR' , 128); define('ISEMAIL_TOOLONG' , 129); define('ISEMAIL_NOAT' , 130); define('ISEMAIL_NOLOCALPART' , 131); define('ISEMAIL_NODOMAIN' , 132); define('ISEMAIL_ZEROLENGTHELEMENT' , 133); define('ISEMAIL_BADCOMMENT_START' , 134); define('ISEMAIL_BADCOMMENT_END' , 135); define('ISEMAIL_UNESCAPEDDELIM' , 136); define('ISEMAIL_EMPTYELEMENT' , 137); define('ISEMAIL_UNESCAPEDSPECIAL' , 138); define('ISEMAIL_LOCALTOOLONG' , 139); // define('ISEMAIL_IPV4BADPREFIX' , 140); define('ISEMAIL_IPV6BADPREFIXMIXED' , 141); define('ISEMAIL_IPV6BADPREFIX' , 142); define('ISEMAIL_IPV6GROUPCOUNT' , 143); define('ISEMAIL_IPV6DOUBLEDOUBLECOLON' , 144); define('ISEMAIL_IPV6BADCHAR' , 145); define('ISEMAIL_IPV6TOOMANYGROUPS' , 146); define('ISEMAIL_DOMAINEMPTYELEMENT' , 147); define('ISEMAIL_DOMAINELEMENTTOOLONG' , 148); define('ISEMAIL_DOMAINBADCHAR' , 149); define('ISEMAIL_DOMAINTOOLONG' , 150); define('ISEMAIL_IPV6SINGLECOLONSTART' , 151); define('ISEMAIL_IPV6SINGLECOLONEND' , 152); // Unexpected errors // define('ISEMAIL_BADPARAMETER' , 190); // define('ISEMAIL_NOTDEFINED' , 191); // revision 2.1: Redefined unexpected error constants so they don't clash with the ISEMAIL_WARNING bit // revision 2.5: Undefined unused constants } if (is_bool($errorlevel)) { if ((bool) $errorlevel) { $diagnose = true; $warn = false; } else { $diagnose = false; $warn = false; } } else { switch ((int) $errorlevel) { case E_WARNING: $diagnose = true; $warn = true; break; case E_ERROR: $diagnose = true; $warn = false; break; default: $diagnose = false; $warn = false; } } if ($diagnose) /*.mixed.*/ $return_status = ISEMAIL_VALID; else $return_status = true; // version 2.0: Enhance $diagnose parameter to $errorlevel // the upper limit on address lengths should normally be considered to be 254 // (http://www.rfc-editor.org/errata_search.php?rfc=3696) // NB My erratum has now been verified by the IETF so the correct answer is 254 // // The maximum total length of a reverse-path or forward-path is 256 // characters (including the punctuation and element separators) // (http://tools.ietf.org/html/rfc5321#section-4.5.3.1.3) // NB There is a mandatory 2-character wrapper round the actual address $emailLength = strlen($email); // revision 1.17: Max length reduced to 254 (see above) if ($emailLength > 254) if ($diagnose) return ISEMAIL_TOOLONG; else return false; // Too long // Contemporary email addresses consist of a "local part" separated from // a "domain part" (a fully-qualified domain name) by an at-sign ("@"). // (http://tools.ietf.org/html/rfc3696#section-3) $atIndex = strrpos($email,'@'); if ($atIndex === false) if ($diagnose) return ISEMAIL_NOAT; else return false; // No at-sign if ($atIndex === 0) if ($diagnose) return ISEMAIL_NOLOCALPART; else return false; // No local part if ($atIndex === $emailLength - 1) if ($diagnose) return ISEMAIL_NODOMAIN; else return false; // No domain part // revision 1.14: Length test bug suggested by Andrew Campbell of Gloucester, MA // Sanitize comments // - remove nested comments, quotes and dots in comments // - remove parentheses and dots from quoted strings $braceDepth = 0; $inQuote = false; $escapeThisChar = false; for ($i = 0; $i < $emailLength; ++$i) { $char = $email[$i]; $replaceChar = false; if ($char === '\\') $escapeThisChar = !$escapeThisChar; // Escape the next character? else { switch ($char) { case '(': if ($escapeThisChar) $replaceChar = true; else if ($inQuote) $replaceChar = true; else if ($braceDepth++ > 0) $replaceChar = true; // Increment brace depth break; case ')': if ($escapeThisChar) $replaceChar = true; else if ($inQuote) $replaceChar = true; else { if (--$braceDepth > 0) $replaceChar = true; // Decrement brace depth if ($braceDepth < 0) $braceDepth = 0; } break; case '"': if ($escapeThisChar) $replaceChar = true; else if ($braceDepth === 0) $inQuote = !$inQuote; // Are we inside a quoted string? else $replaceChar = true; break; case '.': if ($escapeThisChar) $replaceChar = true; // Dots don't help us either else if ($braceDepth > 0) $replaceChar = true; break; default: } $escapeThisChar = false; // if ($replaceChar) $email[$i] = 'x'; // Replace the offending character with something harmless // revision 1.12: Line above replaced because PHPLint doesn't like that syntax if ($replaceChar) $email = (string) substr_replace($email, 'x', $i, 1); // Replace the offending character with something harmless } } $localPart = substr($email, 0, $atIndex); $domain = substr($email, $atIndex + 1); $FWS = "(?:(?:(?:[ \\t]*(?:\\r\\n))?[ \\t]+)|(?:[ \\t]+(?:(?:\\r\\n)[ \\t]+)*))"; // Folding white space $dotArray = /*. (array[]) .*/ array(); // Let's check the local part for RFC compliance... // // local-part = dot-atom / quoted-string / obs-local-part // obs-local-part = word *("." word) // (http://tools.ietf.org/html/rfc5322#section-3.4.1) // // Problem: need to distinguish between "first.last" and "first"."last" // (i.e. one element or two). And I suck at regexes. $dotArray = preg_split('/\\.(?=(?:[^\\"]*\\"[^\\"]*\\")*(?![^\\"]*\\"))/m', $localPart); $partLength = 0; foreach ($dotArray as $arrayMember) { $element = (string) $arrayMember; // Remove any leading or trailing FWS $new_element = preg_replace("/^$FWS|$FWS\$/", '', $element); if ($warn && ($element !== $new_element)) $return_status = ISEMAIL_FWS; // FWS is unlikely in the real world $element = $new_element; // version 2.3: Warning condition added $elementLength = strlen($element); if ($elementLength === 0) if ($diagnose) return ISEMAIL_ZEROLENGTHELEMENT; else return false; // Can't have empty element (consecutive dots or dots at the start or end) // revision 1.15: Speed up the test and get rid of "unitialized string offset" notices from PHP // We need to remove any valid comments (i.e. those at the start or end of the element) if ($element[0] === '(') { if ($warn) $return_status = ISEMAIL_COMMENTS; // Comments are unlikely in the real world // version 2.0: Warning condition added $indexBrace = strpos($element, ')'); if ($indexBrace !== false) { if (preg_match('/(? 0) if ($diagnose) return ISEMAIL_BADCOMMENT_START; else return false; // Illegal characters in comment $element = substr($element, $indexBrace + 1, $elementLength - $indexBrace - 1); $elementLength = strlen($element); } } if ($element[$elementLength - 1] === ')') { if ($warn) $return_status = ISEMAIL_COMMENTS; // Comments are unlikely in the real world // version 2.0: Warning condition added $indexBrace = strrpos($element, '('); if ($indexBrace !== false) { if (preg_match('/(? 0) if ($diagnose) return ISEMAIL_BADCOMMENT_END; else return false; // Illegal characters in comment $element = substr($element, 0, $indexBrace); $elementLength = strlen($element); } } // Remove any remaining leading or trailing FWS around the element (having removed any comments) $new_element = preg_replace("/^$FWS|$FWS\$/", '', $element); if ($warn && ($element !== $new_element)) $return_status = ISEMAIL_FWS; // FWS is unlikely in the real world $element = $new_element; // version 2.0: Warning condition added // What's left counts towards the maximum length for this part if ($partLength > 0) $partLength++; // for the dot $partLength += strlen($element); // Each dot-delimited component can be an atom or a quoted string // (because of the obs-local-part provision) if (preg_match('/^"(?:.)*"$/s', $element) > 0) { // Quoted-string tests: if ($warn) $return_status = ISEMAIL_QUOTEDSTRING; // Quoted string is unlikely in the real world // version 2.0: Warning condition added // Remove any FWS $element = preg_replace("/(? 0) if ($diagnose) return ISEMAIL_UNESCAPEDDELIM; else return false; // ", CR, LF and NUL must be escaped // version 2.0: allow ""@example.com because it's technically valid } else { // Unquoted string tests: // // Period (".") may...appear, but may not be used to start or end the // local part, nor may two or more consecutive periods appear. // (http://tools.ietf.org/html/rfc3696#section-3) // // A zero-length element implies a period at the beginning or end of the // local part, or two periods together. Either way it's not allowed. if ($element === '') if ($diagnose) return ISEMAIL_EMPTYELEMENT; else return false; // Dots in wrong place // Any ASCII graphic (printing) character other than the // at-sign ("@"), backslash, double quote, comma, or square brackets may // appear without quoting. If any of that list of excluded characters // are to appear, they must be quoted // (http://tools.ietf.org/html/rfc3696#section-3) // // Any excluded characters? i.e. 0x00-0x20, (, ), <, >, [, ], :, ;, @, \, comma, period, " if (preg_match('/[\\x00-\\x20\\(\\)<>\\[\\]:;@\\\\,\\."]/', $element) > 0) if ($diagnose) return ISEMAIL_UNESCAPEDSPECIAL; else return false; // These characters must be in a quoted string if ($warn && (preg_match('/^\\w+/', $element) === 0)) $return_status = ISEMAIL_UNLIKELYINITIAL; // First character is an odd one } } if ($partLength > 64) if ($diagnose) return ISEMAIL_LOCALTOOLONG; else return false; // Local part must be 64 characters or less // Now let's check the domain part... // The domain name can also be replaced by an IP address in square brackets // (http://tools.ietf.org/html/rfc3696#section-3) // (http://tools.ietf.org/html/rfc5321#section-4.1.3) // (http://tools.ietf.org/html/rfc4291#section-2.2) if (preg_match('/^\\[(.)+]$/', $domain) === 1) { // It's an address-literal if ($warn) $return_status = ISEMAIL_ADDRESSLITERAL; // Quoted string is unlikely in the real world // version 2.0: Warning condition added $addressLiteral = substr($domain, 1, strlen($domain) - 2); $groupMax = 8; // revision 2.1: new IPv6 testing strategy $matchesIP = array(); $colon = ':'; // Revision 2.7: Daniel Marschall's new IPv6 testing strategy $double_colon = '::'; // Extract IPv4 part from the end of the address-literal (if there is one) if (preg_match('/\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/', $addressLiteral, $matchesIP) > 0) { $index = strrpos($addressLiteral, $matchesIP[0]); if ($index === 0) { // Nothing there except a valid IPv4 address, so... if ($diagnose) return $return_status; else return true; // version 2.0: return warning if one is set } else { //- // Assume it's an attempt at a mixed address (IPv6 + IPv4) //- if ($addressLiteral[$index - 1] !== $colon) if ($diagnose) return ISEMAIL_IPV4BADPREFIX; else return false; // Character preceding IPv4 address must be ':' // revision 2.1: new IPv6 testing strategy if (substr($addressLiteral, 0, 5) !== 'IPv6:') if ($diagnose) return ISEMAIL_IPV6BADPREFIXMIXED; else return false; // RFC5321 section 4.1.3 //- //- $IPv6 = substr($addressLiteral, 5, ($index === 7) ? 2 : $index - 6); //- $groupMax = 6; // revision 2.1: new IPv6 testing strategy $IPv6 = substr($addressLiteral, 5, $index - 5) . '0000:0000'; // Convert IPv4 part to IPv6 format } } else { // It must be an attempt at pure IPv6 if (substr($addressLiteral, 0, 5) !== 'IPv6:') if ($diagnose) return ISEMAIL_IPV6BADPREFIX; else return false; // RFC5321 section 4.1.3 $IPv6 = substr($addressLiteral, 5); //- $groupMax = 8; // revision 2.1: new IPv6 testing strategy } $matchesIP = explode($colon, $IPv6); // Revision 2.7: Daniel Marschall's new IPv6 testing strategy $groupCount = count($matchesIP); $index = strpos($IPv6,$double_colon); if ($index === false) { // We need exactly the right number of groups if ($groupCount !== $groupMax) if ($diagnose) return ISEMAIL_IPV6GROUPCOUNT; else return false; // RFC5321 section 4.1.3 } else { if ($index !== strrpos($IPv6,$double_colon)) if ($diagnose) return ISEMAIL_IPV6DOUBLEDOUBLECOLON; else return false; // More than one '::' if ($index === 0 || $index === (strlen($IPv6) - 2)) $groupMax++; // RFC 4291 allows :: at the start or end of an address with 7 other groups in addition if ($groupCount > $groupMax) if ($diagnose) return ISEMAIL_IPV6TOOMANYGROUPS; else return false; // Too many IPv6 groups in address if ($groupCount === $groupMax) $return_status = ISEMAIL_SINGLEGROUPELISION; // Eliding a single group with :: is deprecated by RFCs 5321 & 5952 } // Check for single : at start and end of address // Revision 2.7: Daniel Marschall's new IPv6 testing strategy if ((substr($IPv6, 0, 1) === $colon) && (substr($IPv6, 1, 1) !== $colon)) if ($diagnose) return ISEMAIL_IPV6SINGLECOLONSTART; else return false; // Address starts with a single colon if ((substr($IPv6, -1) === $colon) && (substr($IPv6, -2, 1) !== $colon)) if ($diagnose) return ISEMAIL_IPV6SINGLECOLONEND; else return false; // Address ends with a single colon // Check for unmatched characters if (count(preg_grep('/^[0-9A-Fa-f]{0,4}$/', $matchesIP, PREG_GREP_INVERT)) !== 0) if ($diagnose) return ISEMAIL_IPV6BADCHAR ; else return false; // Illegal characters in address // It's a valid IPv6 address, so... if ($diagnose) return $return_status; else return true; // revision 2.1: bug fix: now correctly return warning status } else { // It's a domain name... // The syntax of a legal Internet host name was specified in RFC-952 // One aspect of host name syntax is hereby changed: the // restriction on the first character is relaxed to allow either a // letter or a digit. // (http://tools.ietf.org/html/rfc1123#section-2.1) // // NB RFC 1123 updates RFC 1035, but this is not currently apparent from reading RFC 1035. // // Most common applications, including email and the Web, will generally not // permit...escaped strings // (http://tools.ietf.org/html/rfc3696#section-2) // // the better strategy has now become to make the "at least one period" test, // to verify LDH conformance (including verification that the apparent TLD name // is not all-numeric) // (http://tools.ietf.org/html/rfc3696#section-2) // // Characters outside the set of alphabetic characters, digits, and hyphen MUST NOT appear in domain name // labels for SMTP clients or servers // (http://tools.ietf.org/html/rfc5321#section-4.1.2) // // RFC5321 precludes the use of a trailing dot in a domain name for SMTP purposes // (http://tools.ietf.org/html/rfc5321#section-4.1.2) $dotArray = preg_split('/\\.(?=(?:[^\\"]*\\"[^\\"]*\\")*(?![^\\"]*\\"))/m', $domain); $partLength = 0; $element = ''; // Since we use $element after the foreach loop let's make sure it has a value // revision 1.13: Line above added because PHPLint now checks for Definitely Assigned Variables if ($warn && (count($dotArray) === 1)) $return_status = ISEMAIL_TLD; // The mail host probably isn't a TLD // version 2.0: downgraded to a warning foreach ($dotArray as $arrayMember) { $element = (string) $arrayMember; // Remove any leading or trailing FWS $new_element = preg_replace("/^$FWS|$FWS\$/", '', $element); if ($warn && ($element !== $new_element)) $return_status = ISEMAIL_FWS; // FWS is unlikely in the real world $element = $new_element; // version 2.0: Warning condition added $elementLength = strlen($element); // Each dot-delimited component must be of type atext // A zero-length element implies a period at the beginning or end of the // local part, or two periods together. Either way it's not allowed. if ($elementLength === 0) if ($diagnose) return ISEMAIL_DOMAINEMPTYELEMENT; else return false; // Dots in wrong place // revision 1.15: Speed up the test and get rid of "unitialized string offset" notices from PHP // Then we need to remove all valid comments (i.e. those at the start or end of the element if ($element[0] === '(') { if ($warn) $return_status = ISEMAIL_COMMENTS; // Comments are unlikely in the real world // version 2.0: Warning condition added $indexBrace = strpos($element, ')'); if ($indexBrace !== false) { if (preg_match('/(? 0) if ($diagnose) return ISEMAIL_BADCOMMENT_START; else return false; // Illegal characters in comment // revision 1.17: Fixed name of constant (also spotted by turboflash - thanks!) $element = substr($element, $indexBrace + 1, $elementLength - $indexBrace - 1); $elementLength = strlen($element); } } if ($element[$elementLength - 1] === ')') { if ($warn) $return_status = ISEMAIL_COMMENTS; // Comments are unlikely in the real world // version 2.0: Warning condition added $indexBrace = strrpos($element, '('); if ($indexBrace !== false) { if (preg_match('/(? 0) if ($diagnose) return ISEMAIL_BADCOMMENT_END; else return false; // Illegal characters in comment // revision 1.17: Fixed name of constant (also spotted by turboflash - thanks!) $element = substr($element, 0, $indexBrace); $elementLength = strlen($element); } } // Remove any leading or trailing FWS around the element (inside any comments) $new_element = preg_replace("/^$FWS|$FWS\$/", '', $element); if ($warn && ($element !== $new_element)) $return_status = ISEMAIL_FWS; // FWS is unlikely in the real world $element = $new_element; // version 2.0: Warning condition added // What's left counts towards the maximum length for this part if ($partLength > 0) $partLength++; // for the dot $partLength += strlen($element); // The DNS defines domain name syntax very generally -- a // string of labels each containing up to 63 8-bit octets, // separated by dots, and with a maximum total of 255 // octets. // (http://tools.ietf.org/html/rfc1123#section-6.1.3.5) if ($elementLength > 63) if ($diagnose) return ISEMAIL_DOMAINELEMENTTOOLONG; else return false; // Label must be 63 characters or less // Any ASCII graphic (printing) character other than the // at-sign ("@"), backslash, double quote, comma, or square brackets may // appear without quoting. If any of that list of excluded characters // are to appear, they must be quoted // (http://tools.ietf.org/html/rfc3696#section-3) // // If the hyphen is used, it is not permitted to appear at // either the beginning or end of a label. // (http://tools.ietf.org/html/rfc3696#section-2) // // Any excluded characters? i.e. 0x00-0x20, (, ), <, >, [, ], :, ;, @, \, comma, period, " if (preg_match('/[\\x00-\\x20\\(\\)<>\\[\\]:;@\\\\,\\."]|^-|-$/', $element) > 0) if ($diagnose) return ISEMAIL_DOMAINBADCHAR; else return false; // Illegal character in domain name } if ($partLength > 255) if ($diagnose) return ISEMAIL_DOMAINTOOLONG; else return false; // Domain part must be 255 characters or less (http://tools.ietf.org/html/rfc1123#section-6.1.3.5) if ($warn && (preg_match('/^[0-9]+$/', $element) > 0)) $return_status = ISEMAIL_TLDNUMERIC; // TLD probably isn't all-numeric (http://www.apps.ietf.org/rfc/rfc3696.html#sec-2) // version 2.0: Downgraded to a warning // Check DNS? if ($diagnose && ($return_status === ISEMAIL_VALID) && $checkDNS && function_exists('checkdnsrr')) { if (!(checkdnsrr($domain, 'A'))) $return_status = ISEMAIL_DOMAINNOTFOUND; // 'A' record for domain can't be found if (!(checkdnsrr($domain, 'MX'))) $return_status = ISEMAIL_MXNOTFOUND; // 'MX' record for domain can't be found } } // Eliminate all other factors, and the one which remains must be the truth. // (Sherlock Holmes, The Sign of Four) if ($diagnose) return $return_status; else return true; // version 2.0: return warning if one is set } $email = '[email protected]'; echo "Testing $email "; echo "$email is " . ((is_email($email)) ? '' : 'not ') . 'a valid email address'; ?>
January 28, 2009
by Snippets Manager
· 3,487 Views
article thumbnail
Pagination: Server Side or Client Side?
Numerous times in your projects you might have to face a situation where you need to pull chunks of data dynamically. The obvious issue that you then face is pagination\sorting and filtering. You then start to think if it would be better to handle it all at the server side or should hold back and handle it on the client side. Well there is no clear winner amongst the two; neither there is a right or wrong approach. The right answer depends on your priorities and the size of the data set to be paginated. If you have large number of pages doing it on client side will make your user download all the data at first which might not be needed, and will defeat the primary benefit of pagination. In such a scenario you are better of requesting pages in chunks from the server via AJAX. So let the server do the pagination. You can also pre-fetch the next few pages the user will likely view to make the interface seem more responsive. However, when implementing it, you need to make sure that you’re optimizing your SQL properly. For instance, I believe in MySQL, if you use the LIMIT option it doesn’t use the index so you need to rewrite your SQL to use the index properly. If there are only few pages, grabbing it all up-front and paginating on the client may be a better choice. That gives you the obvious benefit of faster subsequent page loads. Unless really required we should not choose the Server side pagination in such a case. Server side pagination is better for: Large data set Faster initial page load Accessibility for those not running JavaScript Complex view business logic Resilience to concurrent changes Client side pagination is better for: Small data set Faster subsequent page loads Sort & filter requirements supported fully (unless results greater than max size). To sum up, if you’re paginating for primarily cosmetic reasons, it makes more sense to handle it client side. And if you’re paginating to reduce initial load time, server side is the obvious choice. Of course, client side’s advantage on subsequent page load times diminishes if you utilize Ajax to load subsequent pages. for more information click here Comments\suggestions are welcome.
January 27, 2009
by Nitin Aggarwal
· 75,324 Views · 2 Likes
article thumbnail
An Overview of Servlet 3.0
JSR 315 (Servlet 3.0) is an update to the existing Servlet 2.5 specification. Servlet 3.0 is focussed on extensibility and web framework pluggability, aligning with the goals of Java EE 6. Ease of Development (EoD) will be supported using newer language features. A reference implementation is available in the GlassFish v3 nightly build. The public review contains: Pluggability EoD Async Support Security Enhancements Miscellaneous Changes In this article we will bring you up to speed with what's happening with the Servlet 3.0 specification and give more detail on what is included. Note: this article corresponds to the public review of the specification. As it is not yet final some things may change. The Expert Group Rajiv Mordani from Sun Microsystems is the specification lead with an expert group comprised of many of the most recognisable names in the Java community: Adobe Systems Inc. Apache Software Foundation BEA Systems Ericsson AB Google Inc. Hunter, Jason IBM Icesoft Technologies Inc NCsoft Corporation Oracle Pramati Technologies Prasanna, Dhanji R. SAP AG Ship, Howard M. Lewis Suleiman, Hani Sun Microsystems, Inc. Tmax Soft, Inc. Walker, Joe Wilkins, Gregory John Pluggability Due to the popularity of so many various web frameworks, Servlet 3.0 will make it easier to use and configure the developer's framework of choice. So if you want to add in Struts, or Spring Web Flow it will be easy to do so. Methods to add Servlets and Filters If a ServletContextListener is registered and wants to add a Servlet or Filter, then at the time of context initialization the event that is fired to the Listener can add Servlets and Filters to the context. The methods are addServlet and addFilter. For more details look for the javadocs at the JCP site at http://jcp.org/aboutJava/communityprocess/pr/jsr315/index.html. Web fragments Instead of having just one monolithic web.xml that is used by the developer to declare servlets, filters and other configuration for using the framework, the framework can now include a web-fragment.xml with all it's configuration. A web-fragment is almost identical to the web.xml and can contain all the configuration needed by the framework in the META-INF directory of the framework's jar file. The container will use the information to assembe the descriptor for the application and the application needn't have to use any of the boilerplate configuration in their app for the framework. There are rules that are defined int the specification for conflict resolution, overriding and disabling fragment scanning. Along with the annotations which also can be in libraries the feature is very compelling not only for the developers that use frameworks but also for framework authors to be self sufficient in defining the configuration needed. The great benefit to this is that library providers can supply their own web.xml fragment for use in your webapp. Ease of Development Several new annotations have been defined for ease of development in Servlet 3.0, allowing you to write a Servlet without requiring a descriptor. These annotations reside in the javax.servlet.annotation package. Thanks to the addition of annotations, it is now possible to have Servlet, Filter and ServletContextListener in a war file without a web.xml. It's important to point out that this makes the web.xml optional, rather than redundant. The web.xml may be user to override metadata specified via annotations. Following discussions in the expert group and the community, it was decided that method level annotations were not to be added, so you keep the doGet, doPost methods and need to extend HttpServlet to use them. Let's take a closer look at the annotations present in the Servlet 3.0 specification: Servlet Annotation In Servlet 3.0, servlet metadata can be specified using @WebServlet @WebServlet(name="mytest", urlPatterns={"/myurl"}, initParams={ @InitParam(name="n1", value="v1"), @InitParam(name="n2", value="v2") }) public class TestServlet extends javax.servlet.http.HttpServlet { .... } TestServlet extends HttpServlet, while the meta data provided corresponds with the web.xml as follows: Parameter Annotation Parameter web.xml Servlet name name= URL Pattern urlPatterns={ } Initialization parameters InitParams={ @InitParam{name=””, value=””} .. .. Servlet Filter Annotation ServletFilter meta data is specified using the @ServletFilter annotation public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { .... } public void destroy() { .... } } Parameter Annotation Parameter web.xml URL Pattern urlPatterns={ } Initialization parameters InitParams={ @InitParam{name=””, value=””} .. .. Servlet Context Listener Annotation A ServletContextListener is simply marked with the @WebServletContextListener rather than needing to list it the web.xml file. @WebServletContextListener public class TestServletContextListener implements javax.servlet.ServletContextListener { .... public void contextInitialized(ServletContextEvent sce) { .... } public void contextDestroyed(ServletContextEvent sce) { .... } } Async Support The biggest change made in the specification is the addition of asynchronous processing. The main cases to cover were: Waiting for a resource to become available, such as JDBC or a call to a Web Service. Generating response asynchronously Using exisiting frameworks to generate responses after waiting the for asychronous operation to complete. While the early draft had suspend and resume, the latest specification has two variations of the startAsync() method on ServletRequest. One (startAsync() ) takes no parameters and initialises an AsyncContext with the original request and response. The ( startAsync() ) other takes a request and response as a parameter to initialise the AsyncContext with. Servlets (@WebServlet) and Filters (@ServletFilter) that support asynchronous processing need to be annotated with the supportAsync attribute set. It is illegal to call startAsync if you have a Servlet or Filter that doesn't support asynchronous processing anywhere in the request processing chain. The is also an AsyncListener that can be registered to get notification on timeout and completion of asynchronous processing of the request. This listener can be used to clean up resources if the wrapped request and response were used to create it's AsyncContext. You can forward requests back to the container using the AsyncContext.forward(path) and AsyncContext.forward() methods so frameworks like JSP can create a response. Security Enhancements HTTPServletRequest will be enhanced with methods allowing programmatic login and logout, while ServletRequest will be able to force a login.The logout method will allow an application to reset the authentication state of a request without requiring the authentication to be bound to a HTTPSession. Conclusion The draft is just beginning to be implemented within Glassfish v3. The specification will be a required piece of Java EE 6 and hence all the features described above will be available in all Java EE 6 compatible containers. The presence of the various features described above will make developing Java web appications much easier. Thanks to Rajiv Mordani for his input into this article, and to Shing Wai and Jan Luehe for the code snippets.
January 21, 2009
by James Sugrue
· 77,799 Views · 2 Likes
article thumbnail
Generic Repository and DDD - Revisited
Greg Young talks about the generic repository pattern and how to reduce the architectural seam of the contract between the domain layer and the persistence layer. The Repository is the contract of the domain layer with the persistence layer - hence it makes sense to have the contract of the repository as close to the domain as possible. Instead of a contract as opaque as Repository.FindAllMatching(QueryObject o), it is always recommended that the domain layer looks at something self revealing as CustomerRepository.getCustomerByName(String name) that explicitly states out the participating entities of the domain. +1 on all his suggestions. However, he suggests using composition, instead of inheritance to encourage reuse along with encapsulation of the implementation details within the repository itself .. something like the following (Java ized) public class CustomerRepository implements ICustomerRepository { private Repository internalGenericRepository; public IEnumerable getCustomersWithFirstNameOf(string _Name) { internalGenericRepository.fetchByQueryObject( new CustomerFirstNameOfQuery(_Name)); //could be hql or whatever } } Quite some time ago, I had a series of blogs on DDD, JPA and how to use generic repositories as an implementation artifact. I had suggested the use of the Bridge pattern to allow independent evolution of the interface and the implementation hierarchies. The interface side of the bridge will model the domain aspect of the repository and will ultimately terminate at the contracts that the domain layer will use. The implementation side of the bridge will allow for multiple implementations of the generic repository, e.g. JPA, native Hibernate or even, with some tweaking, some other storage technologies like CouchDB or the file system. After all, the premise of the Repository is to offer a transparent storage and retrieval engine, so that the domain layer always has the feel that it is operating on an in-memory collection. // root of the repository interface public interface IRepository { List read(String query, Object[] params); } public class Repository implements IRepository { private RepositoryImpl repositoryImpl; public List read(String query, Object[] params) { return repositoryImpl.read(query, params); } //.. } Base class of the implementation side of the Bridge .. public abstract class RepositoryImpl { public abstract List read(String query, Object[] params); } One concrete implementation using JPA .. public class JpaRepository extends RepositoryImpl { // to be injected through DI in Spring private EntityManagerFactory factory; @Override public List read(String query, Object[] params) { //.. } Another implementation using Hibernate. We can have similar implementations for a file system based repository as well .. public class HibernateRepository extends RepositoryImpl { @Override public List read(String query, Object[] params) { // .. hibernate based implementation } } Domain contract for the repository of the entity Restaurant. It is not opaque or narrow, uses the Ubiquitous language and is self-revealing to the domain user .. public interface IRestaurantRepository { List restaurantsByName(final String name); //.. } A concrete implementation of the above interface. Implemented in terms of the implementation artifacts of the Bridge pattern. At the same time the implementation is not hardwired with any specific concrete repository engine (e.g. JPA or filesystem). This wiring will be done during runtime using dependency injection. public class RestaurantRepository extends Repository implements IRestaurantRepository { public List restaurantsByEntreeName(String entreeName) { Object[] params = new Object[1]; params[0] = entreeName; return read( "select r from Restaurant r where r.entrees.name like ?1", params); } // .. other methods implemented } One argument could be that the query string passed to the read() method is dependent on the specific engine used. But it can very easily be abstracted using a factory that returns the appropriate metadata required for the query (e.g. named queries for JPA). How does this compare with Greg Young's solution ? Some of the niceties of the above Bridge based solution are .. The architecture seam exposed to the domain layer is NOT opaque or narrow. The domain layer works with IRestaurantRepository, which is intention revealing enough. The actual implementation is injected using Dependency Injection. The specific implementation engine is abstracted away and once agian injected using DI. So, in the event of using alternative repository engines, the domain layer is NOT impacted. Greg Young suggests using composition instead of inheritance. The above design also uses composition to encapsulate the implementation within the abstract base class Repository. However in case you do not want to have the complexity or flexibility of allowing switching of implementations, one leg of the Bridge can be removed and the design simplified From http://debasishg.blogspot.com/
January 20, 2009
by Debasish Ghosh
· 40,705 Views · 1 Like
article thumbnail
Sagas and Workflows Same thing with different names or not?
In a post called "Rhino Service Bus: Saga and State" Ayende said "In a messaging system, a saga orchestrate a set of messages. The main benefit of using a saga is that it allows us to manage the interaction in a stateful manner (easy to think and reason about) while actually working in a distributed and asynchronous environment." I really don't agree with this definition of a saga. The Saga provides a context for set of messages to allow manging an effort for distributed concensus. It does not "orchestrate" messages (that's what workflows are for) - you can read more on Saga's in an excerpt from my SOA patterns book: Saga pattern. Here's the comment I left on Ayende's site: "What you describe is nice except it isn't a Saga it is more of a workflow. The notion of Saga which is originated from databases relates to the overall coordination of state between the different services - or the context for the whole business process. In the coffee shop example you use that would be the whole "transaction" from the point the customer orders her coffee until she either gets it or the transaction is canceled (e.g. it took too long and the customer leaves or the coffee shop is out of milk etc.) Unlike database (or distributed) transaction when/if a saga is aborted the different component of the system might not return to their previous state e.g. if the customer complains that the coffee is not good and gets her money back. the milk is not separated back from the coffee beans and returned to the bottle - rather the coffee cup goes to the trash. Workflow is one strategy a service can take to handle the long running interaction within a saga. In your case the BristaSaga class (which I think should be BristaWF) orchestrate the internal state transitions depending on the different messages that arrive within the saga. In your case you have a hardcoded workflow - but it is also possible to use a workflow engine for the job. By the way, in the above example you could also use a statemachine instead of a WF to manage the process " In another comment Kristofer asked me: Arnon: I'm not 100% sure of how you distinguish a Saga from a Workflow, could you elaborate some more on this? A Saga involves a number of underlying workflows? A Saga might as well contain a number of underlying Sagas? Isn't it just a question of at what level it is initiated? If a Saga should represent the whole transaction / business process, then who should handle it? Couldn't it be implemented as a Saga, exactly as Ayende describes it, by the initiating service (in this case the ordering)?, which then also is given the responsibility to handle restoring the total state etc of underlying/involved services if the transaction is aborted? The possibility to restore state does of course depend on what the specific Saga is handling, some processes might not be able to "rollback" completely, it's rather a question of rolling back all involved parties to a known/acceptable state." The answer is that ,again, Saga is similar to a transaction in the sense that it provides a shared context for an attempt to get a distributed consensus Unlike a transaction which insures ACID properties. Sagas are not. The concept of dissipating that shared context, having each party (service) affect whether the saga should be aborted or successful etc. is what I call a saga. When a saga is aborted the only thing the coordinator can do is pass the status to the participants. Each of the services is responsible to do its best effort to handle the abort (either by rolling back, compensation or whatever) Workflow is another thing altogether. which keeps a context between calls and means externalizing the decisions on the logic flow from the business logic (usually with a workflow engine). You can use workflows within a service (a pattern I call workflodize) or you can use them externally (a pattern I call orchestrated choreography e.g. BPM) You can use either form of workflow to support the implementation of a saga but you can also implement sagas without workflows. In our system we use an "event broker" (see www.rgoarchitects.com/.../EventingInWCF.aspx) the event broker infrastructure dissipates the saga context when you raise a saga event. A service that initialized a saga (by sending the first event) can choose to close the saga (commit) or abort it. etc. We don't currently have any workflow driven services (but some of them use a state machine as an alternative) (I think the term Saga does not describe Ayende's class since the "barista" is just on of the participants in the saga there are other participants.)
January 19, 2009
by Arnon Rotem-gal-oz
· 19,843 Views · 3 Likes
article thumbnail
Hello EclipseLink on the NetBeans Platform
Let's use EclipseLink to set up some very basic database interaction in a NetBeans Platform application. Though it will be the ultimate 'Hello World' scenario, it should show how to get started with database interactivity on the NetBeans Platform, while also yet again showing the benefit of the NetBeans Platform's modular architecture. Of course, feel free to adapt these instructions to your needs, for example, instead of EclipseLink, use TopLink, or Hibernate, or whatever. You should also be surprised by how easy it is, once you know how. We'll simply access a database and display what we find there: Our application will look as follows: Notice that we will have 4 separate modules, which will enable us to easily provide alternative database providers, as well as alternative persistence providers, because the UI module uses generic code that could make use of any alternative backing modules. Let's get started. Create a Java Library and Generate Entity Classes from the Database. Firstly, create a Java Library project. Then use the Entity Classes from Database wizard to generate entity classes from your database. In the wizard, select EclipseLink in the step where you use the wizard to generate a persistence unit. Look at the generated code and notice that, among other things, you have a persistence.xml file in a folder called META-INF, thanks to the wizard. In my case, I chose a Sample database that comes with the IDE, and then I specified I want an entity class for the Customer table, which resulted in the IDE also creating an entity class for the related DiscountCode table: Build the Java Library and you will have a JAR file in the above application's "dist" folder. As you will read in the next step, that JAR file needs to be added as a library wrapper module to the application you will start creating in the next step. Create a NetBeans Platform Application. In the New Project dialog, specify that you want to create a new NetBeans Platform Application. Once you've created it, right-click the Modules node in the Projects window and choose Add New Library. Then select the JAR you created in the previous step. You now have your first custom module in the new application. Create Supporting Library Wrappers. Do the same as you did when creating the library wrapper for the entity class JAR, but this time for the EclipseLink JARs (which are in your GlassFish distro, make sure to include the persistence JAR that you find there too and, if you don't know which ones to include, go back to the Java Library shown in the previous screenshot and then expand the Libraries folder, which will show you which libraries you need). Next, create yet another library wrapper module... for the DerbyClient JAR. Create the UI Module. The final module you will need will provide the UI. So, create a new module (not a Library Wrapper Module, but just a plain NetBeans Module) and add a Window Component via the New Window Component wizard. Set Dependencies. You now have lots of classes all neatly separated into distinct modules. In order to be able to use code from one module in another module, you'll need to set dependencies, i.e., very explicit contracts (as opposed to accidental reuse of code in one place from another place, resulting in unmaintainable chaos). First, the entity classes module needs to have dependencies on the DerbyClient module, as well as on the EclipseLink module. Then, the UI module needs a dependency on the EclipseLink module as well as the entity classes module. (You could split things further so that the EclipseLink module is not a dependency of the UI module, by putting the persistence JAR in one module, with the other EclipseLink JARs separated in a different module.) Now, finally, let's do some coding. Not much needed, though. Add a JTextArea to the TopComponent in the UI module. Then add this to the end of the TopComponent constructor: EntityManager entityManager = Persistence.createEntityManagerFactory("EntityLibPU").createEntityManager(); Query query = entityManager.createQuery("SELECT c FROM Customer c"); List resultList = query.getResultList(); for (Customer c : resultList) { jTextArea1.append(c.getName() + " (" +c.getCity() + ")" + "\n"); } Above, you can see I am referring to a persistence unit named "EntityLibPU", which is the name set in the persistence.xml file. In addition, I am referring to one of the entity classes, called Customer, which is in the entity classes module. Adapt these bits to your needs. Deploy the Application. Start your database server and then run the application. You should see this: Congrats, you've just managed to set up JPA via EclipseLink in a modular NetBeans Platform application... and you only typed 6 lines of code.
January 17, 2009
by Geertjan Wielenga
· 34,484 Views
article thumbnail
JPA's Nasty "Unknown abstract schema type" Error
I'd been trying to debug the following error for days, and it drove me crazy. The problem, in a nutshell, is that JPA refuses to compile one of my NamedQueries, throwing the following error: Error compiling the query [UserVO.findByUserName: SELECT u FROM UserVO u WHERE u.name = :name]. Unknown abstract schema type [UserVO] After numerous Google searches, I concluded that JPA will throw the "Unknown abstract schema type" error when JPA fails to locate your entity class. Most often, this type of error occurs when: You have provided the database table name instead of the entity class name in the JPA query. For example, if you have an entity class called "UserVO", which maps to the table name "users", the query "SELECT u from users u" will throw the above exception. When running JPA in standalone mode, or not in a Java EE container (such as Tomcat 5 or 6), you forget to explicitly list all entity classes in the persistence.xml file, thus causing JPA to fail to locate the entities when compiling the query. Neither of above applied to my case. I have explicitly listed all my entity classes in the persistence.xml and I am sure my JPA query is valid. I have tested my code with different JPA implementations, but always saw the same error. Here's my UserVO class: @Entity(name = "users") @NamedQuery(name = "UserVO.findByUserName", query = "SELECT u FROM UserVO u WHERE u.name = :name") public class UserVO extends BaseVO implements Serializable { ... ... } If I remove the NamedQuery, my JPA works as expected, i.e, I am able to insert, delete, and update the UserVO object. Now, to all my smart readers, can you spot what's wrong in my code? Think about it and then scroll down for the answer... Answer: The culprit is the Entity annotation. I explicitly named the UserVO entity "users". JPA has no problem to map the UserVO entity to the users database table. However, JPA has a problem when compiling the JPA Query: it can't find the UserVO entity in the JPA context because I have renamed the UserVO entity to users. To resolve this, just add a @Table annotation with the table name, as shown in the code below: @Entity @Table(name = "users") @NamedQuery(name = "UserVO.findByUserName", query = "SELECT u FROM UserVO u WHERE u.name = :name") public class UserVO extends BaseVO implements Serializable { ... ... } Haha, stupid me... Anyway, Happy New Year to everyone.
January 13, 2009
by Khoo Chen Shiang
· 54,104 Views
article thumbnail
Open Source : How Do You Stay Up To Date?
I Love the concepts and beliefs behind Open Source. I use Open Source libraries, applications etc. all the time. One of the things I have always found a challenge though, is knowing when a new release comes to be. Not only that, is this a simple point release, a major release or a security release. For the most part I want to stay up to date, especially with the libraries I use, when a security releases is made. Currently I play the, I hope I have the most stable, most secure version. Howeaver, I always thought that having a single place that I can sign-up to be informed about releases would be awesome. Do you have a way to do this or, are you subscribing to a multitude of RSS feeds and mailing lists to stay informed?
January 10, 2009
by Schalk Neethling
· 5,155 Views
article thumbnail
Commands Part 2: Selection and Enablement of IHandlers
In the last tip, we saw that a Handler can be declared separately from a Command. This enables for multiple handler declarations for the same command. We can also customize when a handler is active and visible, thru plugin.xml itself. A handler that doesn't have any of these conditions is called as "default handler". When no other handler is associated with a command in a particular context, then the default handler will be the handler that gets executed. Remember, at any given point of time, there is at most only one handler is associated with a command. Lets have a look into how a particular handler is selected for a given context. A handler can be specified with activeWhen condition using the expression language. Say for our command, we have two different handlers. One should be active when the current selection is an IFile and the other should be active when the current selection is IFolder. The expression for these would look like: I'll save the explanation for the expression language for a separate tip, but for now a short one line desc: the first handler will be enabled when the selection current contains at least one IFile and the second handler will be enabled when the selection contains at least one IFolder. This raises to two questions. 1) What if the selection is just an IProject? In this case, as none of the handlers are eligible, the command is disabled. This is where the default handler, if you have provided one, would be associated with the command (and the command will be enabled). 2) What if the selection contains both IFile and IFolder? Now both the handlers are equally qualified to handle the command. But since the framework cannot pick one randomly the command is simply disabled. Even if you have provided a default handler, it won't be associated with the command, because the other two handlers are more specific than the default one. How is the "specificness" of a handler is defined? It depends on the conditions that you give in the activeWhen expression. The order is defined in the ISources class. You can go thru the complete set there, to get a glimpse of the most commonly used ones, the order from least specific to most specific is like this: Active Context (activeContexts) Active Actions Sets (activeActionSets) Active Shell (activeShell) Active Workbench Window (activeWorkbenchWindow) Active Editor Id (activeEditorId) Active Part Id (activePartId) Current Selection (selection) If a handler has activeWhen defined with active context and the other one with current selection, the second one will be selected as the selection is more specific than the active context. The activeWhen for all the handlers are evaluated and the one that returns true for the most specific condition is selected. When two handlers return true for the available most specific condition (like the selection having both IFile & IFolder in our case), no handler will be associated with the command. All these things are done without even loading your handler in the memory. Even without loading your plugin! In the previous tip, we saw how a handler is selected with the activeWhen expression, when more than one handler is declared. Now assuming a handler is selected, whether to enable the command or not, is determined by the enabledWhen expression. In our previous example, we saw the handler that is active when the selection at least contained one IFile. Now lets we want to enable it only when the total count of the selection is 2. We can specify it as: So the handler will be active and associated with the command, if the selection contains at least one IFile. Still the command will be enabled only if selection has exactly 2 elements. activeWhen and enabledWhen are similar - with respective to the expression language and lazy loading of the plugin until the command is executed. But there is small difference - your handler might be loaded iff the enabledWhen expression returns true and your plugin is already loaded. The enablement algo works this way: No enabledWhen specified, plugin is not loaded - command is enabled No enabledWhen specified, but plugin is loaded - consult handler.isEnabled() and set command accordingly enabledWhen specified, returns false, command is disabled (no matter plugin is loaded or not) enabledWhen specified, returns true, plugin is not loaded - command is enabled enabledWhen specified, returns true, plugin is loaded - consult handler.isEnabled() and set command accordingly So far we saw commands, handlers and their enablements. But what about generalizing a command? That can be done by adding parameters for a command. And that would be the next tip in this series. From http://blog.eclipse-tips.com
January 8, 2009
by Prakash
· 11,564 Views
article thumbnail
Which Java Version Is Used To Run Our NetBeans Installation?
Ever wondered which Java version is used to run your NetBeans instance? I have a lot of JDK's installed and everytime I install a new one it ones to be the default JDK for my computer. To know which JDK is used for running NetBeans we go to Help | About and the dialog box shows which Java version is used: To explicitly tell NetBeans which JDK to use we can use the command-line argument --jdkhome when we start NetBeans. Or we can set the property netbeans_jdkhome in the file netbeans-install-dir/etc/netbeans.conf.
December 23, 2008
by Hubert Klein Ikkink
· 17,015 Views
article thumbnail
Getting Javadoc from Maven Repositories
In my previous tip on NetBeans Zone we learned how to get available sources for a Maven dependency. We can also get Javadoc for the library. The Javadoc must be available of course otherwise NetBeans is not able to download anything. We right-click on Libraries in our project and select Download All Library Javadoc. NetBeans downloads the Javadoc for the libraries if it is available. The icon will change for the library if Javadoc is downloaded. To view the Javadoc we must right-click on the library and select View Javadoc. NetBeans opens a web browser with the Javadoc for the specific library.
December 21, 2008
by Hubert Klein Ikkink
· 12,091 Views · 2 Likes
  • Previous
  • ...
  • 1613
  • 1614
  • 1615
  • 1616
  • 1617
  • 1618
  • 1619
  • 1620
  • 1621
  • 1622
  • ...
  • Next
  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook
×