Jbossworld Presentation

1,062 views

Published on

This are slide from my presentation at JBoss World Orlando 2008.

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
1,062
On SlideShare
0
From Embeds
0
Number of Embeds
7
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Jbossworld Presentation

  1. 1. Agile Development Using Jboss Seam Daniel Hinojosa Evolutionnext Programmer/Developer/Instructor 02/15/08
  2. 2. What is Agile Development? <ul><li>According to Wikipedia: It is a conceptual framework for software engineering that promotes development iterations throughout the life-cycle of the project. </li></ul><ul><li>Each iteration includes development, testing, documentation, and a functioning working product after each iteration. </li></ul><ul><li>Various Agile Methodologies out there </li></ul><ul><ul><li>Scrum, Crystal Clear, XP (Extreme Programming), Feature Driven Development, and more. </li></ul></ul>
  3. 3. About my presentation <ul><li>Agile Methodology agnostic </li></ul><ul><li>All the products are open source </li></ul><ul><li>Best of all, it is workable with JBoss Seam </li></ul><ul><li>Contains working demos </li></ul>
  4. 4. What technologies will be presented? <ul><li>TestNG </li></ul><ul><li>Groovy </li></ul><ul><li>EasyMock </li></ul><ul><li>Hudson </li></ul><ul><li>Subversion </li></ul><ul><li>Cobertura </li></ul><ul><li>DBUnit </li></ul><ul><li>Selenium </li></ul>
  5. 5. TestNG
  6. 6. What is TestNG? <ul><li>A next generation test framework </li></ul><ul><li>A framework that makes use of test groupings </li></ul><ul><li>A framework that doesn't require a test suite. </li></ul><ul><li>A framework that allows data driven testing and support for parameters. </li></ul><ul><li>A framework that uses either annotation-based configuration (>= Java 5.0) or java-doc based configuration (< Java 5.0) </li></ul>
  7. 7. Comparison to JUnit <ul><li>TestNG runs JUnit tests so you don't have tear down any previous JUnit tests. </li></ul><ul><li>TestNG doesn't require Test Suites classes. </li></ul><ul><li>TestNG can groups tests, and run based on regular expressions. </li></ul><ul><li>TestNG isn't tightly integrated into Ant. </li></ul>
  8. 8. Groovy
  9. 9. What is Groovy. <ul><li>Groovy is Groovy, yeah baby. </li></ul><ul><li>Groovy is an optional typed scripting language that runs on the JVM. </li></ul><ul><li>Extends from Java to provide closures, dynamic lists, builders, overloading, coercions and more. </li></ul><ul><li>Low learning curve for Java Developers since it based off the Java language. </li></ul><ul><li>Full Access to Java API, and best of all, you can develop seam entity and action beans using groovy. </li></ul>
  10. 10. Importance of a scripting language in agile development <ul><li>It is your power tool language </li></ul><ul><li>Great for code generation </li></ul><ul><li>Great for test data creation </li></ul><ul><li>Great for generating programming utilities. </li></ul><ul><li>Great for database cleanup, loader, and manipulation. </li></ul>
  11. 11. Getting Started in your Agile Project <ul><li>To start off you need: </li></ul><ul><ul><li>Version control system </li></ul></ul><ul><ul><li>Issue tracking software </li></ul></ul><ul><ul><li>Continuous Integration software </li></ul></ul>
  12. 12. Version Control System
  13. 13. What is Version Control? <ul><li>Also known as VCS (Version Control System) or SCM (Source Code Management) </li></ul><ul><li>It is repository management of multiple versions of your source code. </li></ul><ul><li>In other words, if you messed something up all this week you can go back and get back the working model of your project. </li></ul><ul><li>It also can alert of conflicts, which occurs when two developers working on the same file. </li></ul><ul><li>It's not magical, it does require proper management, and constant check-ins in order to work properly </li></ul>
  14. 14. Open Source List of Common Version Control Systems <ul><li>Subversion (recommended) (Apache/BSD License) </li></ul><ul><li>CVS (well-known) (GPL) </li></ul><ul><li>Mercurial (currently runs OpenJDK) (GPL) </li></ul><ul><li>For a list of open-source and commercial version control software, visit: http://en.wikipedia.org/wiki/Comparison_of_revision_control_software </li></ul>
  15. 15. Subversion <ul><li>Modern SCM that was designed to overcome CVS shortcomings. </li></ul><ul><li>Apache HTTP Server with WebDAV protocol which allows file management over the web. </li></ul><ul><li>Simple syntactical commands (e.g. branching and tagging is merely copying directories) </li></ul><ul><li>All transactions are atomic (do it all, or fail), so there is no corruption. </li></ul>
  16. 16. Setting up subversion <ul><li>Binaries or referral to binaries for Windows, Solaris, Open/FreeBSD can be found at: http://subversion.tigris.org/project_packages.html </li></ul><ul><li>Debian GNU/Linux & Ubuntu, just run the command: apt-get install subversion </li></ul><ul><li>Fedora Core 3 or later, just run the command: yum install subversion </li></ul><ul><li>Windows users can also install using Cygwin </li></ul>
  17. 17. Setting Up Subversion Continued <ul><li>Check if installed right by running the command: svn --version </li></ul><ul><li>Then to create a repository </li></ul><ul><ul><li>Create the directory for the repository using mkdir </li></ul></ul><ul><ul><li>Turn it into a subversion repository using svnadmin create </li></ul></ul><ul><ul><ul><li>Windows: svnadmin create C:my_project_repos </li></ul></ul></ul><ul><ul><ul><li>Linux/Unix: svnadmin create /home/danno/my_project_repos </li></ul></ul></ul>
  18. 18. Setting Up Subversion Continued <ul><li>Importing from filesystem </li></ul><ul><ul><li>svn import -m “importing from filesystem” /home/danno/my_project_to_be_imported </li></ul></ul><ul><li>Importing from CVS </li></ul><ul><ul><li>Requires planning before the ultimate conversion </li></ul></ul><ul><ul><li>Don't do it when intoxicated, or listening to rave music </li></ul></ul><ul><ul><li>When ready you can run cvs2svn command with your options. </li></ul></ul><ul><ul><li>See: http://cvs2svn.tigris.org/cvs2svn.html#prep </li></ul></ul>
  19. 19. Subversion Basic Commands <ul><li>svn add </li></ul><ul><li>svn blame or svn praise </li></ul><ul><li>svn cat </li></ul><ul><li>svn checkout or svn co </li></ul><ul><li>svn cleanup </li></ul><ul><li>svn commit or svn ci </li></ul><ul><li>svn copy or svn cp </li></ul><ul><li>svn delete or svn del or svn rm or svn remove </li></ul>
  20. 20. Subversion Basic Commands Continued <ul><li>svn diff or svn di </li></ul><ul><li>svn export </li></ul><ul><li>svn import </li></ul><ul><li>svn info </li></ul><ul><li>svn list or svn ls </li></ul><ul><li>svn log </li></ul><ul><li>svn merge </li></ul><ul><li>svn mkdir </li></ul>
  21. 21. Subversion Basic Commands Continued <ul><li>svn move or svn mv </li></ul><ul><li>svn status </li></ul><ul><li>svn resolved </li></ul><ul><li>svn revert </li></ul><ul><li>svn switch or svn sw (great power comes with great responsibility) </li></ul><ul><li>svn update or svn up </li></ul>
  22. 22. Quick reference to your trunk, tagging, and branching.
  23. 23. Creating a trunk <ul><li>The trunk directory is where the core development takes place. The trunk is always changing and is not where “code freezes” take place. </li></ul><ul><li>To create the trunk, just create a directory at the root of your repository using: svn mkdir trunk. </li></ul>
  24. 24. Creating a Release Branch <ul><li>A release branch is created when the trunk development is ready for a release. To create a branches directory: </li></ul><ul><ul><li>svn mkdir -m “create branch dir” <repos_root>/branches </li></ul></ul><ul><li>Then create the branch from the trunk: </li></ul><ul><ul><li>svn cp -m “create release branch” <repos_root>/trunk <repos_root>/branches/RB-<version_number> </li></ul></ul><ul><li>RB is a convention acronym for release branch </li></ul>
  25. 25. Switching <ul><li>Now that you have a branch and trunk you can switch between them both </li></ul><ul><li>Caution needs to be used. Commit before switching! </li></ul><ul><li>svn switch, switches repository directory of your choosing </li></ul><ul><li>For example svn switch <repos_root>/branches/RB-<version_number> switches to the branch </li></ul><ul><li>svn switch <repos_root>/trunk switches back to the trunk </li></ul>
  26. 26. Tagging a release <ul><li>A tag directory is like a branch directory, but developers DO NOT make changes to it. It is an artifact for archival purposes. </li></ul><ul><li>Make sure you have a tags directory. </li></ul><ul><ul><li>svn mkdir -m “create tags dir” <repos_root>/tags </li></ul></ul><ul><li>Create the tagged artifact by copying the branch directory </li></ul><ul><ul><li>svn cp -m “Tag release” <repos_root>/branches/RB-<version_number> <repos_root>/tags/REL-<version_number> </li></ul></ul>
  27. 27. More to learn and not a lot of time <ul><li>Pragmatic Version Control Using Subversion </li></ul><ul><li>What I didn't cover </li></ul><ul><ul><li>More tagging strategies </li></ul></ul><ul><ul><li>Repository setup </li></ul></ul><ul><ul><li>Binary handling </li></ul></ul><ul><ul><li>Externals </li></ul></ul><ul><ul><li>and more. </li></ul></ul>
  28. 28. Continuous Integration
  29. 29. Definition of continuous integration <ul><li>A practice in agile development of continually committing your code to a revision control system, and running tests as a community in order to receive instant feedback. </li></ul><ul><li>Benefits include: </li></ul><ul><ul><li>Early detection of integration problems and broken code. </li></ul></ul><ul><ul><li>Shorter feedback cycles </li></ul></ul><ul><ul><li>Stakeholder continually has a working project. </li></ul></ul><ul><ul><li>Constant reporting on health of the project. </li></ul></ul>
  30. 30. List of Continuous Integration Software <ul><li>Hudson </li></ul><ul><li>CruiseControl </li></ul><ul><li>Continuum for Maven </li></ul>
  31. 31. Hudson <ul><li>Hudson works with different build files like Ant and Maven </li></ul><ul><li>Web based, and not XML based </li></ul><ul><li>Nice Interface </li></ul><ul><li>Easy installation </li></ul><ul><li>https://hudson.dev.java.net/ </li></ul>
  32. 32. Setting up Hudson <ul><li>Download the .war file </li></ul><ul><li>Create a directory where the builds will go, and map the environment variable HUDSON_HOME to it. </li></ul><ul><li>Throw it into your favorite servlet container or application server. I don't know I heard JBoss makes one. </li></ul>
  33. 33. Plugins for Hudson <ul><li>A wide variety of plug-ins are available for hudson. </li></ul><ul><li>http://hudson.gotdns.com/wiki/display/HUDSON/Plugins </li></ul>
  34. 34. Bug Tracking Software <ul><li>Use your favorite </li></ul><ul><li>Waiting for the JBoss Seam based bug tracking software ;) </li></ul>
  35. 35. Finally.... <ul><li>We are ready to actually work on the project. </li></ul>
  36. 36. Some behind the scenes took place <ul><li>Installed JBoss Seam on my machine </li></ul><ul><li>I used Seam-gen to create my project, my project is called jboss_world_2008 </li></ul><ul><li>I created the app as an “in-process” project because: </li></ul><ul><ul><li>I was too lazy to do an entire web project for a 90 minute presentation. </li></ul></ul><ul><ul><li>Accurately reflects a project in development. ;) </li></ul></ul><ul><li>A tour of what JBoss Seam created, and also a tour of Subversion, TestNG, Hudson, and Seam together as one. </li></ul>
  37. 37. Unit-testing
  38. 38. Definition of unit-testing <ul><li>From Wikipedia: Unit testing is a procedure used to validate that individual units of source code are working properly. </li></ul><ul><li>In Object Oriented Programming the smallest unit is the method </li></ul><ul><li>Unit-tests should be done at time of method creation </li></ul><ul><li>In fact, it's even better to develop your unit-tests before method creation. This is known as Test Driven Development </li></ul>
  39. 39. Good Advice on Testing <ul><ul><li>Try to make the test the same package as the class being tested. </li></ul></ul>
  40. 40. Some other good advice in developing in Seam <ul><ul><li>There will be many times where you can use the Seam Framework instead of developing your classes and tests. </li></ul></ul>
  41. 41. Entity Bean Testing <ul><li>Java Entity Bean Testing Demo </li></ul><ul><li>Groovy Entity Bean Testing Demo </li></ul>
  42. 42. Session Beans or &quot;Action Beans&quot;
  43. 43. Dependency Injection/Inversion of Control <ul><li>From Wikipedia: Dependency injection (DI) refers to the process of supplying an external dependency to a software component and is a specific form of inversion of control where the concern being inverted is the process of obtaining the needed dependency. </li></ul><ul><li>Seam makes heavy use of DI with annotations to bring services that are required. </li></ul><ul><li>Demo </li></ul>
  44. 44. Interface Oriented Design <ul><li>Strive to make every service or action defined by an interface. </li></ul><ul><li>Allows for better testability. </li></ul><ul><ul><li>Allows you to create Mocks in it's place for unit testing </li></ul></ul><ul><ul><li>It loosely decouples your application. </li></ul></ul><ul><ul><li>Makes for a better Dependency Injected solution. </li></ul></ul><ul><li>EJB3 Stateful and Stateless Session Beans have Local and Remote Interfaces that describe the service. </li></ul>
  45. 45. Unit-testing action beans
  46. 46. Dummies, Fakes, Mocks, & Stubs <ul><li>According to Martin Fowler: </li></ul><ul><ul><li>Dummy objects are passed around but never actually used. Usually they are just used to fill parameter lists. </li></ul></ul><ul><ul><li>Fake objects actually have working implementations, but usually take some shortcut which makes them not suitable for production (an in memory database is a good example). </li></ul></ul>
  47. 47. Dummies, Fakes, Mocks, & Stubs <ul><ul><li>Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what's programmed in for the test. Stubs may also record information about calls, such as an email gateway stub that remembers the messages it 'sent', or maybe only how many messages it 'sent'. </li></ul></ul><ul><ul><li>Mocks are objects pre-programmed with expectations which form a specification of the calls they are expected to receive. </li></ul></ul>
  48. 48. EasyMock <ul><li>EasyMock allows you to mock out a service required for your service, and you as the programmer can act out the behavior of that mocked service. </li></ul><ul><li>Downloadable at easymock.org </li></ul><ul><li>The latest version 2.3 makes great use of generics and makes it's use simpler than previous versions. </li></ul><ul><li>Easy to install; Download easymock and the easymockextension from the website, and include it your lib directory of your seam app. </li></ul>
  49. 49. EasyMock continued <ul><li>The whole idea behind easymock is “simplish”. </li></ul><ul><ul><li>Create the mock object </li></ul></ul><ul><ul><li>Act out the behavior of the mock </li></ul></ul><ul><ul><li>replay() the mock object </li></ul></ul><ul><ul><li>run the method you are testing </li></ul></ul><ul><ul><li>verify() that everything ran as you planned </li></ul></ul><ul><li>Honestly, it will take a while to get your head wrapped around it. Once you see it and realize it's use, it will be invaluable. </li></ul><ul><li>Demo </li></ul>
  50. 50. You talked about Groovy, so what about Groovy? <ul><li>Groovy can use anything built in Java, therefore in order to create mocks in Groovy testing use EasyMock. </li></ul><ul><li>Groovy has a built in EasyMock mechanism inspired by the earlier releases of EasyMock. The learning curve is a bit harder, but it is certainly a viable solution. I recommend sticking to EasyMock. </li></ul><ul><li>Groovy really shines when it comes to creating stubs, using something called Map Coercion. </li></ul><ul><li>Demo </li></ul>
  51. 51. Classextensions of easymock. <ul><li>EasyMock by itself only works with interfaces. </li></ul><ul><li>EasyMock extension creates a mock out of abstract classes. </li></ul><ul><li>Once you have both in your classpath, you can use static imports in your test class to use the same API with knowing that you are using different libraries. </li></ul>
  52. 52. Integration-testing
  53. 53. Definition of integration-testing <ul><li>Actually Microsoft had the better definition: Integration testing is a logical extension of unit testing. In its simplest form, two units that have already been tested are combined into a component and the interface between them is tested. </li></ul><ul><li>In other words, we mocked our entityManager, now let's try to see if a real entityManager with a database works. </li></ul><ul><li>Integration testing doesn't exclusively mean databases, it just means two components. </li></ul>
  54. 54. When to integration test? <ul><li>After the unit test, and of course after the other components you are integrating with is ready and available. </li></ul><ul><li>If your component relies on three other components, and you only have one component to integrate with, you can always use mocks for the not yet available components. </li></ul>
  55. 55. Seam based testing <ul><li>One word AWESOME </li></ul><ul><li>You are able to use JSF expression language within the test to bind components and run the test </li></ul><ul><li>Uses JBoss Embeddable as a “mini-me” of an actual JBoss Server </li></ul><ul><li>In the case of database-based integration testing, you can use DBUnit with Seam to load fake data into the memory database in order to do the tests. </li></ul><ul><li>Demo </li></ul>
  56. 56. Seam based testing caveats and warnings. <ul><li>A little rough to set up </li></ul><ul><li>Classpath order is everything, and the embeddable server is very specific (a.k.a whiny) on where it's classes come from. </li></ul><ul><li>Seam-gen's build.xml is the best reference on how to set that up, or just use seam-gen. </li></ul><ul><li>Documentation didn't specify where to put dbunit files (grrr). I placed a folder in the resources folder and made reference to it from without a beginning slash. </li></ul>
  57. 57. Seam based testing caveats and warnings. <ul><li>Documentation says that integration testing only works on Java 5.0 and not Java 6.0. I was able to make it work for Java 6.0 by adding: <sysproperty key=&quot;sun.lang.ClassLoader.allowArraySyntax&quot; value=&quot;true&quot;/> to the testng task. </li></ul><ul><li>I am not a fan of extending SeamTest or DBUnitSeamTest in order to do my testing, and prefer composition over inheritance. (see Josh Bloch's Effective Java) </li></ul>
  58. 58. JBoss Seam &quot;Mocking&quot; Precedence <ul><li>JBoss Seam gives the ability to mock or stub any component during integration test by giving the users the ability to use the Install annotation. </li></ul><ul><li>@Install(precedence=MOCK) </li></ul><ul><li>The Install annotation ensures that the component annotated will be installed for testing, but not installed during production. Great idea in case that you may want to substitute one component that is not available or that is costly to run (i.e. for pay web services). </li></ul><ul><li>Demo </li></ul>
  59. 59. JSF Based integration testing. <ul><li>Seam allows you to emulate JSF Request Cycles (see next slide). </li></ul><ul><li>Uses anonymous inner class SeamTest.FacesRequest </li></ul><ul><li>Especially useful if you have a complicated JSF page that you wish to mimic. </li></ul><ul><li>Demo </li></ul>
  60. 60. Review of JSF Request Lifecycles
  61. 61. Acceptance-testing
  62. 62. Definition of acceptance-testing <ul><li>According to Wikipedia: In engineering and its various subdisciplines, acceptance testing is black-box testing performed on a system (e.g. software, lots of manufactured mechanical parts, or batches of chemical products) prior to its delivery. In some engineering subdisciplines, it is known as functional testing, black-box testing, release acceptance, QA testing, application testing, confidence testing, final testing, validation testing, usability testing, or factory acceptance testing. </li></ul>
  63. 63. Definition of acceptance-testing <ul><li>My definition: Take your prototype out for a spin! </li></ul>
  64. 64. When to acceptance test? <ul><li>The day before deployment, not really, after unit testing phase, and the integration testing phase, and any other types of testing that you wish to do before including security testing, performance testing, etc. </li></ul>
  65. 65. Selenium <ul><li>Developed by a team of programmers and testers at Thoughtworks and is housed under OpenQA </li></ul><ul><li>A javascript based test tool </li></ul><ul><li>Runs directly in the browser </li></ul><ul><li>Creates a test script in your favorite language </li></ul><ul><li>Has an IDE that can run under Firefox in order to run your test. </li></ul>
  66. 66. Before getting started <ul><li>Make sure that you include ids in all your components, selenium uses ids extensively. This also includes <h:form> </li></ul>
  67. 67. Setting up Selenium IDE for Firefox <ul><li>Retrieve the IDE at http://www.openqa.org/selenium-ide/ using Firefox. The Firefox extension will load on Firefox and would want to restart. </li></ul><ul><li>Currently there are no Selenium IDE's for Safari or IE. </li></ul><ul><li>Create tests on your webapp. </li></ul><ul><li>Demo. </li></ul>
  68. 68. Selenium Core <ul><li>Selenium Core allows you to create tests in a table and run those tests from your website. </li></ul><ul><li>To set it up, download Selenium Core from http://www.openqa.org/selenium-core/ </li></ul><ul><li>Expand the file, and place the core folder in the view folder of your seam application. </li></ul><ul><li>Create Tests and TestSuite </li></ul><ul><li>Visit http://<webservername>:<port>/core/TestRunner.html on your web application. </li></ul><ul><li>Demo </li></ul>
  69. 69. Setting up Selenium Server RC <ul><li>Go to http://selenium-rc.openqa.org/index.html and download seleniumrc </li></ul><ul><li>Expand the file </li></ul><ul><li>In the selenium-remote control folder, go to selenium server folder and run selenium-server.jar </li></ul><ul><li>Then go to selenium-java-client-driver and get the selenium client jar and place it your lib directory </li></ul><ul><li>Create a script from your Selenium IDE, and make a test case out the test. </li></ul><ul><li>Demo. </li></ul>
  70. 70. Headless Linux/Unix server? <ul><li>For Linux, use xvfb, which (IN THEORY) creates virtual frame buffer to emulate a frame terminal. For more information, visit, http://linux.about.com/cs/linux101/g/xvfb.htm </li></ul>
  71. 71. Code Coverage
  72. 72. What is Code Coverage? <ul><li>Utility that measures and calculates the percentage of source code actually covered by tests. </li></ul><ul><li>Code Coverage can improve the quality and predictability of your software. </li></ul><ul><li>Code Coverage only measure the coverage, but not quality of your code or your tests. That is still up to you. </li></ul><ul><li>Code Coverage usually instruments your class file so that it can report the actual coverage in your project. </li></ul>
  73. 73. Open Source Code Coverage <ul><li>Cobertura </li></ul><ul><li>Emma </li></ul>
  74. 74. Cobertura <ul><li>Spanish and Portuguese word for 'Coverage' . </li></ul><ul><li>Can run at the command line or as an ant task. </li></ul><ul><li>Plugins available for Maven. </li></ul><ul><li>Also reports the McCabe cyclomatic code complexity of each class. </li></ul><ul><ul><li>The McCabe complexity shows how complicated you method or code is. </li></ul></ul><ul><ul><li>Strive for a lower McCabe complexity in all your methods. </li></ul></ul>
  75. 75. Setting up Cobertura <ul><li>Download at http://cobertura.sourceforge.net/download.html </li></ul><ul><li>Copy the cobertura.jar, and all the jars in the lib directory into your jboss seam lib folder. </li></ul><ul><li>Apply necessary changes to your build.xml file </li></ul><ul><li>Demo </li></ul>
  76. 76. Using Cobertura <ul><li>Once your Cobertura is complete in your build.xml file, run some of your tests. </li></ul><ul><li>Depending on your folder naming, an HTML report, or an XML report or both should be available for your analysis. </li></ul><ul><li>There is a Cobertura plugin available on Hudson so that code coverage </li></ul><ul><li>Demo </li></ul>
  77. 77. Emma <ul><li>Can run at the command line, as an ant task, or a makefile. </li></ul><ul><li>Two kinds of class instrumentation, offline, and on the fly. </li></ul><ul><li>Plain text, HTML, or XML reporting </li></ul><ul><li>Can instrument jar files, not just .class files </li></ul><ul><li>More information is located at http://emma.sourceforge.net/ </li></ul>
  78. 78. Other tools worth mentioning <ul><li>XMLUnit (xmlunit.sourceforge.net) – helps you assert that two XMLs are equal. </li></ul><ul><li>FitNess (http://fitnesse.org/) </li></ul><ul><li>Dumbster (http://quintanasoft.com/dumbster/) </li></ul>
  79. 79. For more information <ul><li>JBoss Seam http://www.jboss.com/products/seam </li></ul><ul><li>JBoss Seam Forums http://www.jboss.com/?module=bb&op=viewforum&f=231 </li></ul><ul><li>JBoss Seam Wiki http://www.jboss.com/wiki/Wiki.jsp?page=JBossSeam </li></ul><ul><li>Pragmatic Programmer http://www.pragprog.com/ </li></ul><ul><li>Groovy http://groovy.codehaus.org/ </li></ul>
  80. 80. Thank You

×