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

The Latest Coding Topics

article thumbnail
Enabling the Hover-Over-Help Feature Using JSP Custom Tags
This article introduces a presentation-tier JEE framework designed to enable the hover-over-help feature without hard coding JavaScript modules in the JSPs in your web or portal applications. The framework is packaged as a jar file for distribution and includes a server-side RESTful web service component and a set of JSP tag handlers which inserts JavaScript and Cascading Style Sheet (CSS) code into HTML files at the page rendering phrase. The targeted users are java developers who only have preliminary experience on writing JavaScript code. 1. Introduction Mouseover is a standard JavaScript event that is raised when the user hovers the cursor over a particular HTML element on a web page. This event has been widely used in web applications for navigation or causing an image or text to change. Hover-over-help, also called hover-over bubble, refers to the process of showing a small popup window when a mouseover event occurs in the browser. The window contains a message to either help the user to use the application or provide additional explanation and data. It is a useful feature which can make your web pages more intuitive and user-friendly and can carry more information on a single page in rich internet applications (RIAs). There are some tips and samples to enable the feature on the internet. However, they are not effective in developing large-scale web applications. Some of caveats include the following: The message contents are directly hard-coded in JavaScript. They are tied-coupled with graphic user interface components, such as text labels in web pages. The re-usability is low. If the same message needs to appear on several pages, the message and the pertaining JavaScript code have to be copied and pasted to each of these pages. It is hard to maintain these duplications in multiple places. The messages are designed to be static and are typically created when the page is designed. It is difficult to insert runtime data into messages on the fly. Portal applications are not completely supported. The framework introduced in this article is designed to address these issues and provides a comprehensive but easy-to-use solution to java developers who don’t have extensive JavaScript experiences. It leverages the JSP taglibary technology, the Dojo framework, and RESTful web services. Reusability in both web and portal environments, performance, and reliability are the factors that have been taken into consideration. 2. Message bubbles and messages 2.1 Message bubbles A message bubble is a rectangle information window containing a message. Each bubble has one color-coded title compartment and one content compartment. The window is decorated by CSS definitions. The image below illustrates a sample message bubble. Figure 1 – a hover-over-help message bubble Bubbles are not viewable in the webpage until the user moves his/her mouse over action labels or images. In this case, the mouse cursor will turn into a finger-pointing hand and the pertaining bubble window will pop up near the hand. 2.2 Data structure The message contents vary from static to dynamic considerably. However, all messages can share a common data structure, which typically consists of four parts: • Message ID: This is the primary key in each message, which is represented as a unique number. Given any single message ID, the framework is able to identify one and only one message. • Message title: This is a character string displayed in the title compartment in a bubble window. • Message content: This is character string that refers to the detail of a help message. The message content can contain HTML elements. • Color code: This is a character string representing the background color scheme of a bubble window. The value must be one of the following strings: “infor”, “data”, “warning”, or “link”. 2.3 Message types Based on the dynamicity of the contents, we categorized all messages into three types. Each of the types is described in this section, with samples provided. 2.3.1 Static Messages This type of message is considered static because its contents always retain the same. A static message can be the definition of a concept, the explanation of a field, or the instruction of a user action. The same messages will appear to any user on the same page when the page is visited. Valid examples include: • This is a example of a static message. • Click on the button below to submit your request. 2.3.2 Variable Messages These messages contain replaceable variables which are represented by tokens. A token is a non-whitespace character string surrounded by “${” and “}”. The token will be completely replaced by its actual value at the page rendering time on the server. The value is based on user data, and normally will not change for a longer-than-user-session period. From users’ perspectives, the same user will see the same message with his customized values when browsing the same page, but different users may see different messages. The following are examples of valid messages in this category: • Your first name ${firstname}. • Your annual goal is to sell ${yourgoalnumber} cars. 2.3.3 Dynamic Messages The messages in this category are the most dynamic ones and contain variables represented by tokens, as well. However, the actual values are populated based on the data associated to the user session. If it happens that a user session is shared by multiple applications, these values may be changed even without a page refresh. This situation typically occurs in portal applications where multiple portlets can access the same user session. It is possible that the same user will read different messages at a different time on the same page. The examples are – • You have talked to ${anumber} clients today. • It is ${servertimestamp} now. 3. Design and implementation In the design, messages are cached at server-side to gain the maximum performance. Two strategies have been implemented to support the hover-over-help feature for each of the message types described in the previous section. 3.1 Message caching Messages can be persisted in a database or flat text file, but regardless of where they are physically stored, they will be loaded and cached at the web container when it starts. The framework includes a class – CacheIntializer which implements the ServerContextListener interface to perform the job. All you need to develop is your own message loader class to retrieve your messages from storage. Your class must implement the com.myuan.tags.bubblemsg.serverside.MessageLoader interface in the framework, and its name must be added as a ContextParameter in the web descriptor. Please refer to the installation section for more details. 3.2 Dojo and CSS Strategy This strategy is designed to support static and variable messages. It can be referred as the push strategy, since help messages are embedded as html elements and pushed to users’ browsers along with the whole web page. No client-server communication is needed once the page download is done. The values will be kept the same until the page is re-loaded again. This strategy relies on a Dojo module to recognize particular “span” elements (listed in list 1) in html files. For each individual message bubble, two span elements are required. The first one represents a visible graphical component in a page, while the second one is the message bubble which isn’t visible for most of the time. When you move the mouse over the first “span” area, an action will be triggered by the browser, and a Dojo method will make the message bubble popped up (illustrated in Figure 1). The “id” attribute in the first “span” element and the “connectid” attribute in the second one are the keys to tie the pair together. These two attributes must have the same value. The value is randomly generated by the custom tags in the framework, which guarantees that the strategy can support both web and portal applications. Households Household A household includes all the persons who occupy a housing unit. Four tag handlers have been developed to support static message and variable message scenarios, respectively. At page-rendering time, the handlers can retrieve help messages from the cache, replace variable tokens in the messages if any, and create and insert value-matched “span” html elements into the web pages. The complete process is detailed in the sequence diagram in figure 2. Figure 2 – sequence diagram for the Dojo and CSS strategy 3.2.1 hohcsstag This tag inserts CSS definitions in JSP pages at the rendering time. It should be placed in the page head element. In the WebSphere Portal environment, this tag should be added in the Default.jsp file. 3.2.2 hohstatictag hohstatictag is a custom tag built for the static message scenario. It has five attributes: msgid: This is the primary key used to identify a message from the cache. This attribute is mandatory. label: This is the text which will be associated with a mouse-over action to display the message. style: This is the style definition that will be used to decorate the label above. This is the place where the user could overwrite CSS arributes for the label. bubblestyle: This is the place where the user could overwrite CSS attributes for the message bubble. img: If you need to enable the hover-over on an image instead of a text label, you can use this attribute and pass the path to your image. If this attribute appears in the tag, the value in the “label” and the “style” attributes will be ignored. A static message example -- Msg_id Msg_title Msg_content Color_cd 1 Household A household includes all the persons who occupy a housing unit. Infor JSP Fragment where the hohstatictag is used – //text //image 3.2.3 hohvariabletag and hohparamtag hohvariabletag and hohparamtag work together to support variable messages. The “hohvariabletag” has the same four attributes as the “hohstatictag” tag. One “hohparamtag” tag holds one name-value pair. The tokens in the message will be replaced with the values passed in from the hohparamtag when html elements are generated. The following is an example of how to use the custom tag. A variable message example-- Msg_id Msg_title Msg_content Color_cd 2 Recognition My retention rate is ${rate} and my goal is ${goal}. data JSP Fragment where the hohvariabletag and hohparamtag are used together – 3.2.4 hohgenerictag This tag has been created to provide a unified API for both static and variable messages. This tag can replace the “hohstatictag” or “hohvariabletag” without any syntax change. But there will be a minor performance cost if you use this tag on the static-message scenario instead of the hohstatictag. 3.3 AJAX strategy AJAX (Asynchronous JavaScript and XML) is a powerful web development technique in creating interactive web applications. The AJAX strategy was developed for the dynamic message scenario. It is a pull-based model, since messages are retrieved by an AJAX module at runtime from the server. This approach can guarantee that the message contains the latest data. When a mouseover event is triggered from a web page, the AJAX module invokes the server-side RESTful web service endpoint. The server-side component picks up the correct message from the message cache, replaces all variable tokens in it with the most current user-session data, and sends the final message back to your browser in the XML format. Upon receiving the response, the AJAX module populates the pertaining information window and pops it up. The complete process is illustrated in the sequence diagram in figure 3. Figure 3 – Sequence diagram for the AJAX strategy One servlet class and three custom tags have been created to support this strategy, and they must be used together in the same page. 3.3.1 HelpMessagesServiceServlet This is an extension of the HTTPSerlvet class. It serves as the RESTful web service endpoint at the server-side. It processes the HTTP request from the client-side AJAX module, constructs the message with the latest data in user’s session, and sends the response in XML format back to the browser. A sample response is listed below. Household infor Household A household includes all the persons who occupy a housing unit. 3.3.2 hohajaxtag This tag inserts AJAX methods in a JSP which will be invoked by the hohdynatag below. It has two attributes. The namespace can be used to pass a portlet’s namespace into the tag in the portal environment. In a web application the value of the attribute can be left blank. The serviceurl attribute must be the valid URL for the HelpMessagesServiceServlet. In the WebSphere Portal environment, this tag should be added in the Default.jsp file. // Portal environment // Web environment 3.3.3 hohdynatag and hohdynaparamtag The hohdynatag has four attributes as same as the “hohstatictag” tag, and it will generate a “span” element. Each hohdynaparamtag establishes a mapping between one token in the message and one key used in user’s session to refer to the actual value. These mappings will be sent to the RESTful endpoint as HTTP parameters. When a user’s mouse moves over the area in a page represented by the span tag, the following events will occur sequentially at the client’s browser: • OnMouseOver events will be fired by the browser. • The Ajax method generated by the hohajaxtag will be invoked. The method will make an HTTP request to the RESTful service endpoint and will be waiting for the response. • Upon receiving the response, the AJAX method will parse it to get the actual help message. • The AJAX method will display the message bubble in the browser. Below is a valid utilization of these tags. 4. Installation The installation procedure is fairly straight forward. After adding the jar file – MYTagLib.jar -- into the /WEB-INF/lib directory in your web project, you can use the deployment descriptor editor in RAD/RSA to complete the installation: Develop your own message loader class and add a context parameter with the name “BubbleMsgLoaderClass” and the value as the fully qualified name of your class. Figure 4 – adding your class name as a Server Context Parameter Create a listener. The class name is: com.myuan.tags.bubblemsg.serverside.CacheInitializer, and the class is shipped in the TagLib.jar file. Figure 5 – creating the listener with the shipped class Add the servlet class in the framework into the deployment descriptor in your web project. The servlet class is also shipped in the MYTagLib.jar. Figure 6 – creating a servlet with the shipped class Define the taglib element in the /WEB-INF/web.xml file. Figure 7 – adding the tag lib references Define the tag extension in your JSP pages. The and the uri directive must match. The prefix identifies the tags in the tag library within the jsp page. For example: 5 Conclusion The framework packaged in the MYTagLib.jar can enable the hover-over-help feature in a web or portal application without adding any JavaScript/CSS code into JSP pages during the development phrase. This approach can make it simpler to create and maintain these pages. The framework has been tested in web applications running on WebSphere Application Server (WAS) 6.0 and 6.1, as well as in portal applications running on WebSphere Portal 5.1 and 6.0.
October 21, 2008
by Ming Yuan
· 39,604 Views · 1 Like
article thumbnail
Adding Color and Font preferences
You had that nice looking editors and views. You loved the button color and the geeky font. But your boss didn't. Solution? Put a preference so that the user can choose which ever he likes ;-) Ok. That may not be the real rationale, but for a valid reason, you wanted to have Color and Font preferences in the PreferencePage. The obvious answer for us (the plugin develoepers) would be to add ColorFieldEditor & FontFieldEditor in our existing PreferencePage. But its not obvious for the user to look into your plugins Preference Page for changing them. Eclipse already provides a PreferencePage for these customizations: Colors and Fonts page ( General->Appearance->Colors and Fonts ) Users might be looking into this place to change the colors & fonts. As you can see in the above image it categorizes the available preferences; gives a filter to search; provides space for description and preview; and a tool tip for the current value of the preference. This is much more than the *FieldEditor right? In this tip let us see how to add our preferences into that and access them. You need to extend the org.eclipse.ui.themes extension point for adding your content into this page. I would like to provide one category with one color preference and one font preference. The extension is: An example theme category Your description goes here Description for this font Guess all the elements are self explanatory - except for the value element. For colorDefinition the value element will be the COLOR_* constants defined in the SWT class. You can specify your custom colors thru comma separated RGB values like 125,245,96. For fontDefinition it would be fontname-style-height. Now our UI will look like: To get the values stored in the preferences, you need to use the IThemeManager: IThemeManager themeManager = PlatformUI.getWorkbench().getThemeManager(); ITheme currentTheme = themeManager.getCurrentTheme(); ColorRegistry colorRegistry = currentTheme.getColorRegistry(); Color color = colorRegistry.get("com.eclipse-tips.blog.preferences.colorDefinition"); FontRegistry fontRegistry = currentTheme.getFontRegistry(); Font font = fontRegistry.get("com.eclipse-tips.blog.preferences.fontDefinition"); Once you get the current theme, you can get the preferences stored by giving the appropriate ids defined in the plugin.xml What you have seen is just the tip of the iceberg. The themes extension point has much more functionalities (The Preview is one such example). I'll explain them later, but you can see the Extension Point description here. This is an extract from http://blog.eclipse-tips.com/2008/08/adding-color-and-font-preferences.html
October 15, 2008
by Prakash
· 13,878 Views
article thumbnail
A Simple Manual Mock Example
Creating and using a mock object is semantically very much like using a stub, except that a mock will do a little more than a stub - it will save the history of communication so that it can later be verified. Let's add a new requirement to our LogAnalyzer class. It will have to interact with an external web service that will receive an error message whenever the LogAnalyzer encounters a filename whose length is not too long. [img_assist|nid=5444|title=|desc=|link=url|url=http://www.manning.com/osherove/|align=left|width=142|height=178]Unfortunately, the web service we'd like to test against is still not fully functional, and even if it were, it would have taken too long to use it as part of our tests. Because of that, we'll refactor our design and create a new interface that we can use to later create a mock object of. The interface will have the methods we will need to call on our web service, and nothing else. Figure 1 shows how the test will work with our MockWebService. [img_assist|nid=5443|title=|desc=|link=none|align=none|width=485|height=350] First off, let's extract a simple interface that we can use in our code under test, instead of talking directly to the web service. public interface IWebService { void LogError(string message); } This interface will serve us when we want to create stubs as well as mocks, without needing to have an external dependency on a project we have no control of. Next, we'll create the mock object itself. It may look like a stub, but it contains one little bit of extra code that makes it a mock object. public class MockService:IWebService { public string LastError; public void LogError(string message) { LastError = message; } } Our mock implements an interface just like a stub, but saves some state for later, so that our test can then assert and verify that our mock was called correctly. Listing 1 shows what the test might look like: Listing 1: The log analyzer under test actually calls our mock object, which holds on to the string that is passed into the implemented method, and later asserted in the test. [Test] public void Analyze_TooShortFileName_CallsWebService() { MockService mockService = new MockService(); LogAnalyzer log = new LogAnalyzer(mockService); string tooShortFileName="abc.ext"; log.Analyze(tooShortFileName); Assert.AreEqual("Filename too short:abc.ext", |#1 mockService.LastError); |#1 } public class LogAnalyzer { private IWebService service; public LogAnalyzer(IWebService service) { this.service = service; } public void Analyze(string fileName) { if(fileName.Length<8) { service.LogError("Filename too short:" |#2 + fileName); |#2 } } } Annotation #1: The assert is done against the mock service, and not against the class under test Annotation #2: The method part we're going to test Notice how the assert is performed against the mock object, and not against the LogAnalyzer class. That's because we are testing the interaction between LogAnalyzer and the web service. We still use the same dependency injection techniques, but this time the stub also makes or breaks the test. That's why it's a mock object. Also notice that we are not writing the tests directly inside the mock object code. There are several reasons for this. We'd like to be able to re-use the mock object in other test cases, with other asserts on the message. If the assert is found inside the mock object, whoever is reading the test will have no idea what we are asserting. We will be hiding essential information from the test code, which hinders the readability and maintainability aspect of the test. In many scenarios in your tests, you might find that you need to replace more than one object for the test to be able to work, which involves combining mocks and stubs. This article is taken from the book The Art of Unit Testing. As part of a chapter on interactive testing using mock objects, this segment shows how to create and use a mock object and helps differentiate mock objects from stubs.
October 13, 2008
by Schalk Neethling
· 31,566 Views
article thumbnail
How to Parse and view Outlook .msg Files programmatically
This article shows that how can you parse and view Outlook .msg files using your own code in C# applications where Microsoft Office Outlook is not required for it. A separate Outlook msg Viewer Demo (attached with this article) is also available to guide you for parsing and reading Outlook .msg files using Aspose.Network library. How to Parse and View Msg File contents Programmatically In this section, we will present the code that we used in the demo to show the msg file contents. Loading an Msg File Aspose.Network library provides MapiMessage class for loading and parsing msg files. You can load the msg file using a single line of code by calling FromFile() static method and passing the path of the msg file. [C#]MapiMessage msg = MapiMessage.FromFile(“C:\\SomeFolder\\SomeMsgFile.msg”); [VB.NET]Dim msg As MapiMessage = MapiMessage.FromFile(“C:\\SomeFolder\\SomeMsgFile.msg”) Getting the From, To, Cc and Subject from Msg File MapiMessage class exposes properties and collections for getting subject, to, cc and from. Following is the sample code for getting these properties. [C#]// subjectif (msg.Subject != null)Console.WriteLine(msg.Subject);elseConsole.WriteLine("no subject");// senderif (msg.SenderEmailAddress != null)Console.WriteLine(msg.SenderEmailAddress);elseConsole.WriteLine("No sender");// toif (msg.DisplayTo != null)Console.WriteLine(msg.DisplayTo);elseConsole.WriteLine("No one in To");// ccif (msg.DisplayCc != null)Console.WriteLine(msg.DisplayCc);elseConsole.WriteLine("No one in cc"); [VB.NET]' subjectIf Not msg.Subject Is Nothing ThenConsole.WriteLine(msg.Subject)ElseConsole.WriteLine("no subject")End If' senderIf Not msg.SenderEmailAddress Is Nothing ThenConsole.WriteLine(msg.SenderEmailAddress)ElseConsole.WriteLine("No sender")End If' toIf Not msg.DisplayTo Is Nothing ThenConsole.WriteLine(msg.DisplayTo)ElseConsole.WriteLine("No one in To")End If' ccIf Not msg.DisplayCc Is Nothing ThenConsole.WriteLine(msg.DisplayCc)ElseConsole.WriteLine("No one in cc")End If Getting the Text Body and Rtf Body of the Message We can get Text and Rtf body of the message by using properties of MapiMessage class. Following the sample code to get these. [C#]// text bodyif (msg.Body != null)Console.WriteLine(msg.Body);elseConsole.WriteLine("no text body.");// rtf bodyif (msg.BodyRtf != null)Console.WriteLine(msg.BodyRtf);elseConsole.WriteLine("No Rtf body."); [VB.NET]' text bodyIf Not msg.Body Is Nothing ThenConsole.WriteLine(msg.Body)ElseConsole.WriteLine("no text body.")End If' rtf bodyIf Not msg.BodyRtf Is Nothing ThenConsole.WriteLine(msg.BodyRtf)ElseConsole.WriteLine("No Rtf body.")End If Getting the Attachments From Msg File and Saving to Disk MapiMessage class provides the Attachments collection for getting all the attachments in the message (msg) file. MapiMessage.Attachments property returns the object of type MapiAttachmentCollection. You can use a foreach loop to iterate through the attachments collection and list the attachments. Attachment class contains the Save() method for saving the individual attachment to the disk. Following is the sample code to get the list of attachments and saving to disk. [C#] // iterate through the Attachments collection foreach (MapiAttachment att in msg.Attachments) { try { // show attachment name on screen Console.WriteLine(att.LongFileName); // save in local drive/folder att.Save(att.LongFileName); } catch (Exception ex) { Console.WriteLine(ex.Message;) } } [VB.NET]' iterate through the Attachments collectionFor Each att As MapiAttachment In msg.AttachmentsTry' show attachment name on screenConsole.WriteLine(att.LongFileName)' save in local drive/folderatt.Save(att.LongFileName)Catch ex As ExceptionConsole.WriteLine(ex.Message;)End TryNext att Getting the MAPI Properties of the Msg File You can get the MAPI Properties from the Msg file using the “Properties” collection of the MapiMessage class. Following is the sample code to get all the MAPI properties present in the message file. [C#]try{Aspose.Network.Outlook.MapiProperty mapi = Aspose.Network.Outlook.MapiProperty)dictionaryEntry.Value;if (mapi.Name.Trim().Length > 0){// display name of MAPI propertyConsole.WriteLine(mapi.Name);// display value of the MAPI propertyConsole.WriteLine(mapi.ToString());}catch (Exception e){Console.WriteLine(e.Message);} [VB.NET]TryDim mapi As Aspose.Network.Outlook.MapiProperty = Aspose.Network.Outlook.MapiProperty)dictionaryEntry.ValueIf mapi.Name.Trim().Length > 0 Then' display name of MAPI propertyConsole.WriteLine(mapi.Name)' display value of the MAPI propertyConsole.WriteLine(mapi.ToString())End IfCatch e As ExceptionConsole.WriteLine(e.Message)End Try More about Aspose.Network for .NET Aspose.Network is a suite of .NET components for network programming with support for .NET logging framework, Microsoft Exchange Server and allows parsing an Outlook document with drag & drop features. It provides new iCalendar engine and SSL support for SMTP, POP3 & IMAP protocols with other mail merge features. You can import & export emails in MHT & EML formats. It supports all the features of SMTP, MIME, S/MIME, POP3, FTP, WhoIs, DNS, ICMP, IMAP, HTTP, SOCKS 4/4A & SOCKS 5 components.
October 8, 2008
by rouletteroulette rouletteroulette
· 67,505 Views
article thumbnail
A Look Inside the JBoss Microcontainer, Part I -- Component Models
Looking at the current state of Java, we can see that POJOs (Plain Old Java Objects) rule the land yet again. Their dominance stretches from enterprise applications to middleware services. At JBoss we were known for our modular JMX-based kernel. The application server was nothing more than a bunch of flexible MBeans and a powerful MicroKernel in the middle. But, as you could feel the change is coming, we still wanted to be ahead of the pack. We could see different POJO based component models popping up all over the place (EJB3, JPA, Spring, Guice, … to name a few), yet nothing was out there that would bind them all, flattening out the differences on a single component model. Hence the Microcontainer project was born. The JBoss Microcontainer project is about many things. The Microcontainer's features range from reflection abstraction, a virtual file system, a simple state machine to transparent AOP integration, a new classloading layer, a deployment framework and an OSGi framework implementation. I'll try to address them all over a short series of articles that will be published here on DZone. This article will examine the Microcontainer's component models. Read the other parts in DZone's exclusive JBoss Microcontainer Series: Part 1 -- Component Models Part 2 –- Advanced Dependency Injection and IoC Part 3 -- the Virtual File System Part 4 -- ClassLoading Layer Part 5 - the Virtual Deployment Framework Part 6 - The Scanning Library What is a component model? What do we consider a component model? First of all, what do we consider being a component? One abstract way to express this would be that “components are reusable software programs that you can develop and assemble easily to create sophisticated applications.” To consider a bunch of components as an actual model, we also need to declare what kind of interactions we allow. JMX MBeans are one example of a component model. Their interactions include executing MBean operations, referencing attributes, setting attributes and declaring explicit dependencies between named MBeans. As mentioned, we had advanced JMX handling already with the MicroKernel. And as expected, the Microcontainer brought extensive POJO support. The default behavior and interactions in the Microcontainer are what you also normally get from any other IoC container and are similar to the functionality that MBeans provided: plain method invocations for operations, setters/getters for attributes and explicit dependencies. However, having only this functionality would mean we didn't get much further than just relieving the pain of declaring MBeans, hence it was only logical for us to do something more. I'll leave the discussion of these new IoC features for the next article in the series. There are many existing POJO component models out there, Guice and Spring being amongst the most popular. Effective integration with these frameworks was an important goal for us. Demo environment setup Before we begin, I'd like to first describe the various parts that constitute the demo. All the source code can be found at this location of our Subversion repository: • http://anonsvn.jboss.org/repos/jbossas/projects/demos/microcontainer/branches/DZone_1_0/ The project is fully mavenized, so it should be easy to adjust it to your IDE. I will first go over the sub-projects within the demo and describe their usage. At the end of my article series, I will provide a more detailed look at what certain sub-projects do. Below are the JBoss Microcontainer demos and sub-projects that are relevant for this article: • bootstrap (as the name suggests, it bootstraps the Microcontainer with demo code) • jmx (adds the JMX notion to demo's bootstrap) • models (source code of our components / services) The demo has only one variable you need to set - demos home - but even this one can be optional if you checked-out your project into the \projects\demos directory. Otherwise, you need to set the system property demos.home (e.g. -Ddemos.home=). You should now be able to run JMXMain as a main class. Make sure you include the models sub-project in the classpath, since some of the services require additional classes in the classpath, several more then what the jmx sub-project expects. Once the Microcontainer is booted it starts to scan the ${demos.home}/sandbox directory for any changes. Now all we need to do is provide a deployable unit and drop it in there. Models Let’s now turn our attention to the models sub-project. This is where the previously mentioned deployable unit should come from. You can see if everything is in place by building the models sub-project (mvn package) and dropping it into the sandbox. You should get a bunch of debug and info messages on the console log, showing how the Microcontainer got booted. Any error message indicates some problems. Let’s go over exactly what the models sub-project does, its integration code and try to redeploy it. If we look at the models src/main/resources/META-INF directory, we'll see plenty of -beans.xml resource files and one -service.xml. You’ll notice that each has a meaningful name that matches the source code package from models's src/main/java/org/jboss/demos/models directory. Let's dissect them one by one, starting with the ones that have no dependencies. org.jboss.demos.models.plain.PojoFactory This is a simple Micrcocontainer beans descriptor file. Anyone who crossed paths with some other IoC’s configuration file should be familiar with it. And, as I already mentioned, I'll follow up on more advanced usage in the next article. The next file shows what we have done to support Spring integration: Note that this file's namespace is different from the previous Microcontainer bean’s plain-beans.xml file. The urn:jboss:spring-beans:2.0 namespace points to our version of the Spring schema port, meaning you can describe your beans Spring style, but it's the Microcontainer that's going deploy then, not Spring's bean factory notion. public class Pojo extends AbstractPojo implements BeanNameAware { private String beanName; public void setBeanName(String name) { beanName = name; } public String getBeanName() { return beanName; } public void start() { if ("SpringPojo".equals(getBeanName()) == false) throw new IllegalArgumentException("Name doesn't match: " + getBeanName()); } } Although the SpringPojo bean has a dependency on Spring lib via implementing BeanNameAware interface, this dependency is only there to expose and mock some of the Spring's callback behavior (see SpringBeanAnnotationPlugin for more details). Since we introduced Spring integration, let's have a look at Guice integration. As Guice users know, Guice is all about type matching. Configuration of Guice beans is done via Modules which means that in order to generate beans, one must implement a Module. Two important parts to watch from this file are PojoModule and GuiceKernelRegistryEntryPlugin. The first one is where we configure our beans: public class PojoModule extends AbstractModule { private Controller controller; @Constructor public PojoModule(@Inject(bean = KernelConstants.KERNEL_CONTROLLER_NAME) Controller controller) { this.controller = controller; } protected void configure() { bind(Controller.class).toInstance(controller); bind(IPojo.class).to(Pojo.class).in(Scopes.SINGLETON); bind(IPojo.class).annotatedWith(FromMC.class).toProvider(GuiceIntegration.fromMicrocontainer(IPojo.class, "PlainPojo")); } } The second class provides integration with the Microcontainer: public class GuiceKernelRegistryEntryPlugin implements KernelRegistryPlugin { private Injector injector; public GuiceKernelRegistryEntryPlugin(Module... modules) { injector = Guice.createInjector(modules); } public void destroy() { injector = null; } public KernelRegistryEntry getEntry(Object name) { KernelRegistryEntry entry = null; try { if (name instanceof Class) { Class clazz = (Class)name; entry = new AbstractKernelRegistryEntry(name, injector.getInstance(clazz)); } else if (name instanceof Key) { Key key = (Key)name; entry = new AbstractKernelRegistryEntry(name, injector.getInstance(key)); } } catch (Exception ignored) { } return entry; } } Notice how we created an Injector from the Modules and then did a lookup on it for matching beans. In mbeans-service.xml we declare our legacy usage of MBeans: What’s interesting to note here is how we injected a POJO into an MBean. The preceding demonstrated our first interactions between different component models. In order to allow for MBean deployment via the Microcontainer, we had to write entirely new component model handling code. See the system-jmx-beans.xml for more details. The code from this file lives in the JBossAS source code: system-jmx sub-project. One note here, this is currently only possible with JBoss's JMX implementation, since the system-jmx code uses some implementation details. Now what if we wanted to expose our existing POJOs as MBeans, registering them into an Mbean server? @org.jboss.aop.microcontainer.aspects.jmx.JMX(exposedInterface=org.jboss.demos.models.mbeans.PojoMBean.class, registerDirectly=true) As you can see from looking at any of the beans in this file, in order to expose your POJOs as MBeans, it’s simply a matter of annotating them with an @JMX annotation. You can either expose the bean directly or its property: Here we see how you can use any of the injection lookup types by either looking up a plain POJO or getting a handle to an MBean from the MBean server. One of the injection options is to use type injection, which is also sometimes called autowiring: The FromGuice bean injects the Guice bean via type matching, where PlainPojo is injected with a common name injection. We then test if Guice binding works as expected: public class FromGuice { private IPojo plainPojo; private org.jboss.demos.models.guice.Pojo guicePojo; public FromGuice(IPojo plainPojo) { this.plainPojo = plainPojo; } public void setGuicePojo(org.jboss.demos.models.guice.Pojo guicePojo) { this.guicePojo = guicePojo; } public void start() { f (plainPojo != guicePojo.getMcPojo()) throw new IllegalArgumentException("Pojos are not the same: " + plainPojo + "!=" + guicePojo.getMcPojo()); } } This only leaves us with an alias component model. Even though the alias is quite a trivial feature, in order to implement it as a true dependency, it has to be introduced as a new component model inside the Microcontainer. The implementation details for this is part of the AbstractController source code: springPojo Here we’ve mapped the SpringPojo name to the springPojo alias. The beauty of having aliases as true component models is that it doesn't matter when the real bean gets deployed. This means that the alias will wait in a non-installed state until the real bean triggers it. Conclusion We've seen how we can deploy simple Microcontainer beans, legacy MBeans, Guice POJOs, Spring beans and aliases. And since all of this is controlled by the Microcontainer, we saw how easily we can mix and match the different component models. I can easily say, with the level of abstraction we put in our component model design, the sky is the limit on what we can handle. An example of this is the upcoming OSGi services, but that's another story, another article. Stayed tuned for my next article which will provide a detailed look at the Microcontainer's IoC functionality. About the Author Ales Justin was born in Ljubljana, Slovenia and graduated with a degree in mathematics from the University of Ljubljana. He fell in love with Java seven years ago and has spent most of his time developing information systems, ranging from customer service to energy management. He joined JBoss in 2006 to work full time on the Microcontainer project, currently serving as its lead. He also contributes to JBoss AS and is Seam and Spring integration specialist. He represent JBoss on 'JSR-291 Dynamic Component Support for Java SE' and 'OSGi' expert groups.
October 1, 2008
by Ales Justin
· 57,383 Views
article thumbnail
Ant or Gant?
Yes, this is exactly what I am frequently asked by my clients and many developers. It isn't easy to answer this question. There are several projects using Ant. Should you run away from Ant just because there is a new cool tool out there called Gant? Should you switch to Gant just because you dislike XML? Not at all. Let's take a closer look and see what might make you switch to Gant. When to choose Gant? 1. Complicated Build Files. If your ant build files are becoming too complicated, and hard to manage, it's time to see if using Gant can help. Let me explain what I mean by complicated build files. If you have too much of conditional logic within your build files, say something similar on the lines shown below in Listing 1: Code Listing 1: Or even something like this where you might be supporting deployment to different application servers based on some property in your build.properties as shown in listing 2. Code Listing 2: Things get out of hand when you have conditional logic as shown above in your build scripts. The listings I have are just the skeleton, imagine what happens when we start adding the actual deployment logic for all these application servers. It doesn't matter how you refactor this, it is still going to be very complicated. Trust me, I have written build scripts which were several thousand lines, and refactoring them was not a trivial task. 2. Custom Ant Tasks. I myself am guilty of writing many of these. There are many situations which arise in projects where we create custom ant tasks. It is simple once you know how to write one, and than for every complicated task you need to perform, you involuntarily will start writing custom ant tasks. Anyone writing a custom ant task will: a. Create a new class that extends Ant’s org.apache.tools.ant.Task class. b. For each attribute, write a setter method. c. Write an execute()method that does what you want this task to do. There isn't anything wrong in doing the above, but imagine each time you want to make a small change, you will have to make changes within your Java source code, compile, test, and re-package. 3. Scripting. You can extend Ant further by not writing custom ant tasks, but by using small snippets of code written in an interpreted language like JRuby, BeanShell, or Groovy. These code snippets can be placed within your build files or in separate text files. If you are using Groovy's Ant task, your build file might look something like this: Code Listing 3: import some.package import another.package def fullpath = "${.basedir}/${defaulttargetdir}" def somefile = new SomeFile(projectName:"${pname}", buildLabel:"${label}", buildTime:"${new Date()}") def xml = "${fullpath}/dashboard.xml" new File(path).write(somefile.generateReport()) ant.xslt(in:path, out:"${properties.defaulttargetdir}/some.html", style:"${properties.defaulttargetdir}/lib/report-style.xsl") Imagine having several lines of XML in your build files which have many of these small snippets of scripts. I myself don't like mixing and matching build files with code snippets. If you have a team where everyone is in the same page, everything works fine. What if a team member has no clue about any of the Scripting languages? He/She will have no clue how to make minor changes when things go badly. If you have all the above or even one of the above three cases, you seriously need to consider using Gant. To quote Aristotle: For the things we have to learn before we can do them, we learn by doing them." So, lets see how easy it is to learn Gant and see how things can improve. This part covers the very basics of Gant. The next part, will dive deeper into Gant by using it with a sample project to build an application, and we will also see how to use it with our CI Server. What's Gant? Gant is a build tool that uses both Groovy and Ant. With Gant, you describe your build process using Groovy scripts. Stated simply, Gant allows you to specify the build logic using Groovy instead of XML. The next thing you may ask is " Is Gant a competitor to Ant?". Let me quote from the Gant web site to make thing more clear here : Whilst it might be seen as a competitor to Ant, Gant uses Ant tasks for many of the actions, so Gant is really an alternative way of doing builds using Ant, but using a programming language rather than XML to specify the build rules. Download and Install Gant. In order for Gant to work, you should have Groovy installed. You can download and follow the installation instructions for Groovy here. As I said earlier also, in order to use Gant, you should have knowledge of Groovy as well. If you have never written Groovy code before, there are many interesting books on Groovy like: 1. Groovy in Action 2. Groovy Recipes 3. Groocy Refcardz You can also read the getting started guide on the Groovy web site, which should give you a good starting point. Download the latest version of Gant from here. Gant is currently at version 1.4.0. Unzip it to a folder. If you already have your GROOVY_HOME set, that's all you need to use Gant. Getting Started. Open a console, and type gant. You should see a message as shown below: meera-subbaraos-macbook-9:~ meerasubbarao$ gant Cannot open file build.gant meera-subbaraos-macbook-9:~ meerasubbarao$ You are all set at this point to use Gant in your projects. Help Information: Open a console, and type gant -h. This will provide you with all the necessary help information you need as shown below: meera-subbaraos-macbook-9:CodeMetricsProject meerasubbarao$ gant -h usage: gant [option]* [target]* -c,--usecache Whether to cache the generated class and perform modified checks on the file before re-compilation. -n,--dry-run Do not actually action any tasks. -C,--cachedir The directory where to cache generated classes to. -D = Define to have value . Creates a variable named for use in the scripts and a property named for the Ant tasks. -L,--lib Add a directory to search for jars and classes. -P,--classpath Specify a path to search for jars and classes. -T,--targets Print out a list of the possible targets. -V,--version Print the version number and exit. -d,--debug Print debug levels of information. -f,--file Use the named build file instead of the default, build.gant. -h,--help Print out this message. -l,--gantlib A directory that contains classes to be used as extra Gant modules, -p,--projecthelp Print out a list of the possible targets. -q,--quiet Do not print out much when executing. -s,--silent Print out nothing when executing. -v,--verbose Print lots of extra information. Create a new file called build.gant at the root of your project. Did a similarity between Ant and Gant strike you here? Ant build files are usually called build.xml, and they are created as a common practice within the root of your project folder as well. If you have written or even modified Ant build files, you will know that it contains one project element, which in turn contains a name,the default target and the base directory. Code Listing 4: So for example, sayHello target in Ant would look something like this: Lets create the sayHello target, and also see how to set it as the default target in Gant as well. A Gant target has a name and a description: Code Listing 5: target ( target-name : target-description ) { groovy code sequence } The above sayHello target in Gant would translate as shown below: target(sayHello:"Saying hello"){ Ant.echo(message:"Hello Javalobby") } Now, open a command window and type gant at the root of the project where the build.gant file exists. You should be able to see a output like: meera-subbaraos-macbook-9:CodeMetricsProject meerasubbarao$ gant Target default does not exist. Gant is complaining that we haven't set a Default target. Lets see how to do the same: Default target: Within Ant, you define the default target from within the project element as seen in Listing 4. The default target is the target called if no target is specified from the command line. There however is no project tag within Gant. There are two ways of specifying the default target as shown below: 1. You simply create a target whose name is default. target ( 'default' , 'The default target.' ) { aTarget ( ) 2. or even simply: setDefaultTarget ( aTarget ) In order to get our sayHello target working, we need to add one of the above scripts to our build.gant file. Code Listing 6: setDefaultTarget(sayHello) or target ("default": "The default target." ) { sayHello ( ) } Complete listing of build.gant: target(sayHello:"Saying hello"){ Ant.echo(message:"Hello Javalobby") } /* target ("default": "The default target." ) { sayHello ( ) } */ setDefaultTarget(sayHello) And you should be able to see: meera-subbaraos-macbook-9:CodeMetricsProject meerasubbarao$ gant [echo] Hello Javalobby meera-subbaraos-macbook-9:CodeMetricsProject meerasubbarao$ That was easy! If you have build files and it is becoming unmanageable by your team, there is a tool out there which can convert your Ant scripts to Gant scripts as well. I haven't used it, but you can try it here. In this part of the series, we learned when to move over from Ant to Gant, downloaded and installed Gant, and finally wrote a simple gant build file. In the next part of this series, we will see Gant in Action within a simple Java project. And as always, keep us posted here if you are encountering any problems getting started with Gant. Stay tuned.
September 23, 2008
by Meera Subbarao
· 52,280 Views
article thumbnail
Importing XML Data Into A SQLite Table
For inserting into a SQLite table, use the code as follows: //DB Connection private var dbconn:SQLConnection; //Query Statement private var sqlQuery:SQLStatement; //Create Table Statement private var sqlCreateTable:SQLStatement; //Insert Statement private var sqlInsert:SQLStatement; //Import Statement private var sqlImport:SQLStatement; /** * This is for importing xml data to a SQLite table * @param node xml node * @param user the user whos data this is * */ public function importPostXML( node:XMLNode, user:User ):void { var query:String = "INSERT INTO posts (" + "post_url," + "post_hash," + "post_desc," + "post_tags," + "post_time," + "post_extended," + "post_shared," + "post_replace," + "post_user)" + "VALUES ( " + ":post_url," + ":post_hash," + ":post_desc," + ":post_tags," + ":post_time," + ":post_extended," + ":post_shared," + ":post_replace," + ":post_user)"; sqlImport = new SQLStatement(); sqlImport.sqlConnection = dbconn; sqlImport.addEventListener( SQLEvent.RESULT, onSQLSave ); sqlImport.addEventListener( SQLErrorEvent.ERROR, onSQLError ); sqlImport.text = query; sqlImport.parameters[":post_url"] = node.attributes.href; sqlImport.parameters[":post_hash"] = node.attributes.hash; sqlImport.parameters[":post_desc"] = node.attributes.description; sqlImport.parameters[":post_tags"] = node.attributes.tag; sqlImport.parameters[":post_time"] = node.attributes.time; sqlImport.parameters[":post_extended"] = node.attributes.extended; sqlImport.parameters[":post_shared"] = node.attributes.shared; sqlImport.parameters[":post_replace"] = node.attributes.replace; sqlImport.parameters[":post_user"] = user.user_name; sqlImport.execute(); trace( "Importing XML to SQLite Database" ); }
September 21, 2008
by Jonnie Spratley
· 15,931 Views · 1 Like
article thumbnail
Using JSF and Flex Components Together
Exadel Fiji extends JavaServer Faces (JSF) by allowing the use of Flex components within a JSF page. Fiji stands for “Flex and JSF Integration.” When using Fiji components, developers use Flex with the same component-based approach to building user interfaces that they are familiar with from JSF. This means that Flex components are bound to standard JSF managed beans. Fiji is a framework that provides the following: A library of ready-to-use Flex charting components for JSF A universal wrapper that allows the use of any Flex component within a JSF page Most importantly, with Fiji, you can bind Flex components to the same JSF-managed beans properties or methods (or Seam components or Spring beans) used by the rest of your JSF application. The current version ships with the following ready-to-use charts: Column chart Stacked column chart Bar chart Stacked bar chart Line chart For example, here is a screenshot of a Flex component inside a JSF page [img_assist|nid=5013|title=|desc=|link=none|align=undefined|width=341|height=398] You can see all Fiji components in action at http://livedemo.exadel.com/fiji-demo Now that I have given you a short introduction to Fiji, you are probably wondering what problem Fiji is trying to solve. Let's see. Why Fiji? Let's start with the basics. JavaServer Faces (JSF) is a standard (Java EE) framework for building Web user interfaces out of components. Today, we are interested in building Rich Internet Applications, so RichFaces was created takes JSF a step further by allowing the easier building of AJAX-based applications in JSF. (In case you don't know, RichFaces offers a large number of ready-to-use AJAX components.) While JSF has been constantly growing, one area where it's still lacking is in displaying rich and interactive charts, graphs, and other similar visuals. Even with AJAX, any serious charting is extremely difficult, not to mention the testing that would be required for different browsers. It really comes down to two things. First, the technologies used behind JSF such as HTML, JavaScript, and CSS are not meant for displaying rich and interactive visual data (possible, but very difficult). Second, people have much higher expectations from a browser. The browser alone was never meant to display such visual data. It was primarily meant to display text and static images. So, in the end, it's not really JSF’s fault, we are simply asking the underlying technologies (HTML, JavaScript, CSS, the browser) to do too much. Of course, there is hope. We can use a Flash player to display rich and interactive charts. Adobe Flash With Flex, complex rich applications can be compiled and then run inside a Flash player. A Flash player is a virtual machine that installs as a plug-in into any browser. Because the application (built with Flex) is running inside a virtual machine, it provides a far more superior environment for rich and interactive charts and graphs than the browser alone (which just interprets HTML, JavaScript, etc.). The obvious next question is: So, why not use Flex and JSF components together right now? While it's possible to use Flex and JSF components inside the same page, the two technologies are not aware of each other. This means that JSF components are bound to JSF managed beans (or Seam components or Spring beans) while Flex is bound to completely different objects. This kind of integration is equivalent to inserting an image into a JSF page – in other words, not much integration. Back to Fiji This is a good place to revisit Fiji. Fiji is the perfect fit for helping with the above problem. Not only does Fiji provide ready-to-use chart components and a universal wrapper to use any Flex component, but, with Fiji, you can bind Flex components to standard JSF managed beans. As a JSF developer, you just use the standard and the familiar JSF component-centric approach, while now also being able to use Flex components. So, where does it make sense to use Fiji. One scenario is if you have an existing JSF application and you would like to insert richer content based on Flash while still using your existing model (JSF managed beans, Seam components or Spring beans). This content can be charts, graphs or any other rich content. Another situation where Fiji would make sense is where you have an existing JSF application, but want to use a Flash-based user interface (instead of HTML/JavaScript). By using Fiji, you can still use the existing model part of your application. However, to be honest, it wouldn't make sense to use Fiji if you have an existing Flash-only application and are using a service like GraniteDS, BlazeDS, or Exadel Flamingo. Now, I think we are ready for examples. Using Fiji There are three basic steps to get started. Download project Download JAR file and add them to project template Open the project in your favorite IDE Download Project template Download and unzip the project template. Download Fiji JAR files Go to http://exadel.com/web/portal/fiji and click on Download to download Fiji distribution Unzip the downloaded file In the next step you are going to copy JAR files from lib folder to fiji/web/WEB-INF/lib directory 1. If running Tomcat 5.5, copy all files 2. If you are running Tomcat 6, copy all files except: ¦ el-api.1.0.jar ¦ el-impl-1.0.jar Import Project Import the project into your favorite IDE. Here is how to do it in JBoss Tools (same steps for JBoss Developer Studio). Select File/Import Select Other Select JSF Project Point to the web.xml file location in the project Click Next Keep all setting as they are (I'm assuming you have a server defined) Click Finish To tell you the truth, installing Fiji is very simple. It's basically a RichFaces project (has to be RichFaces version 3.2.2 or higher) plus the JAR files for Fiji: fiji-api-1.x.x.jar fiji-ui-1.x.x.jar flamingo-service-jsf-1.6.x.jar - to use HttpService via component. Covered later in article. Besides using HttpService, if you would like to use DataServices (AMF format), you need two additional JAR files: amf-serializer-1.6.x.jar That's it. Nothing else is needed, not even changes to web.xml. Using Bar Chart Let's start with a simple example using bar chart. The first step is to create the data for the chart. Because we can easily bind charts to JSF managed beans, that's where we are going to create our data. The Java bean looks like this: public class BarChartBean { public BarChartBean() { } private Integer[] data; public Integer[] getData() { return data; } @PostConstruct public void init () { data = new Integer[5]; data[0] = 5; data[1] = 2; data[2] = -3; data[3] = 10; data[4] = 9; } } To make it a JSF managed bean we need to register it in a JSF configuration file: barChartBean fiji.BarChartBean session So far this is just basic JSF. Let's now create the page. Open start.xhtml. Look at the top, the page already contains a namespace for the Fiji tag library. Insert the following between tags: is just like a standard JSF component. The value attribute is bound to chart data inside the managed bean. sets the chart name. Save everything and run the page. You should get the following: [img_assist|nid=5014|title=|desc=|link=none|align=undefined|width=672|height=394] Let's try another example, this time using column chart. I'm sure most of you still remember the Summer Olympics, so we'll take the medal count and display it in the chart. Using the column chart You can reuse the same page or create a new page if you would like. If you create a new page, make sure to include the namespace for Fiji. We are going to take the top three countries (USA, China, and Russia) and display their gold, silver and bronze medal count. As before, let's start with data for the chart. The Java bean looks like this: public class MedalsBean { private Map medalsData = new LinkedHashMap(); private ArrayList colors = new ArrayList(); private ArrayList names = new ArrayList(); private Integer[] medalsChina = new Integer[]{51, 21, 28}; private Integer[] medalsUSA = new Integer[]{36, 38, 36}; private Integer[] medalsRussia = new Integer[]{23, 21, 28}; @PostConstruct private void init() { medalsData.put("China", medalsChina); medalsData.put("USA", medalsUSA); medalsData.put("Russia", medalsRussia); names.add("Gold"); names.add("Silver"); names.add("Bronze"); colors.add("#DAA520"); colors.add("#C0C0C0"); colors.add("#B87333"); } public Map getMedalsData() { return medalsData; } public ArrayList getColors() { return colors; } public ArrayList getNames() { return names; } public Integer[] getMedalsChina() { return medalsChina; } public Integer[] getMedalsUSA() { return medalsUSA; } public Integer[] getMedalsRussia() { return medalsRussia; } } Because we now display three bars per country (one for each medal), we use a Map object and inside it put an array of integers representing the medal count. To make it a JSF managed bean, we need to register is in a JSF configuration file: medalsBean fiji.MedalsBean request Now we are ready to build the page. The page is not much different than in the first example: Running the page will produce the following: [img_assist|nid=5015|title=fiji3|desc=|link=none|align=undefined|width=339|height=404] While the integration with JSF is neat (we can easily use JSF managed beans as a data model for Flex components), we can even take it a step further. It's possible to click on a Flex chart, send an AJAX request and do a partial page update. Let's see how it's done. Event handlers Fiji components have event handlers such as onitemclick which are very similar to the standard DHTML event handlers such as onkeyup. Going back to our example, let's say we want to click on any bar and display the medal information outside the chart. When a bar is clicked, an AJAX request will be sent to the server, properties will be set, and then rerendered. The changes to the managed bean are minimal. All we do is add three properties: private String countrySelected; private String medalTypeSelected; private String medalCountSelected; // getter and setters methods Don't forget to generate getters and setters. This is how our page now looks. We use the most popular tag from RichFaces, to attach an event (onitemclick) to the parent component, . When a bar is clicked on a chart, an Ajax request is sent to the server passing three arguments defined by the tag. The tag automatically takes the value from value attribute and assigns it to property defined in the assignTo attribute. The following three arguments are passed: event.x – is the x-axis data. In our case, it is the country name event.y – is the y-axis data. In our case, it is the medal count event.name – is the the active bar. In our case, it will be the medal type selected I have also set noEscape=”true” for each . This is necessary in order for the value to be treated as JavaScript code instead of being enclosed in single quotes and just passed to the server as a parameter. Finally, we rerender the information inside the panel grid. As you can see, we are using standard RichFaces techniques to send and rerender information even though we are mixing in Flex components. Using the universal wrapper So far I have shown you how to use charting components that ship with Fiji. Obviously you might want to use other, existing Flex components or maybe even build your own. To use any other Flex components, we use the universal wrapper or component. We will use one of the charts provided by amCharts.com. Note: We can use their charts for free. The only limitation is that a small URL will appear pointing to their Web site. I don't think it's such a limitation for such nice charts. The SWF file for the chart as well as chart data are included in the template under web/ampie directory. You can also download them from here: SWF file – ampie.swf Settings file – ampie_settings.xml Data file – ampie_data.xml The page looks like this: Using the src attribute of , we point to a Flash component. The Flash component can also be loaded as a resource by using src=“resource:///file.swf”. This particular Flash component (ampie.swf) requires some data. The data is being passed using the standard JSF attribute, . When a Flash object is rendered on a page, it has a special flashVars attribute that provides arguments to the Flash module. In our case, the tags with their information are rendered as flashVar arguments to the Flash component. This is how the charts gets its data. Running the page will produce the following: [img_assist|nid=5016|title=|desc=|link=none|align=undefined|width=539|height=384] In case you need to update the data for the chart, one possible way is to rerender the Flash component using the standard RichFaces approach. Using As a final example, I'm going to show you how to use together with . This will allow us to send a parameter from a Flash component to a JSF managed bean. Let's start with the Flash part. This is the Flex application we want to use in our JSF page: hello.mxml: It's a pretty simple MXML file which you can compile either in Flex Builder or just from the command line after installing Flex SDK >mxmlc hello.mxml I have also provided the SWF file inside the template (and here hello.swf ) in case you want to skip the compilation step. The MXML file will produce the following: [img_assist|nid=5017|title=|desc=|link=none|align=undefined|width=267|height=110] Now, let's look at the JSF page: is used to include the Flash component as we did before. The service attribute points to a JSF managed bean with a method called greeting: public Object greeting(Object value){ if(value != null){ return "What's up, "+value+"?"; } else { return "What's up, unknown?"; } } It also has to be registered in a JSF configuration file: serviceBean fiji.ServiceBean request I will cover HelloDecoder and HelloEncoder later. When running this page, we will get something very similar to the previous image; however, now it's inside a JSF page and, if we enter a value for Username and click Submit, we will get the following. [img_assist|nid=5018|title=|desc=|link=none|align=undefined|width=271|height=118] The question is, how are we able to send a request to the JSF managed bean from the Flash component? It's done via the component: We define an endpoint with the name of fiji. If you look back at the MXML file, we have the following: private function send():void { userRequest = new HTTPService(); userRequest.url = Application.application.parameters.fiji; userRequest.addEventListener("result", httpResult); var param:Object = {}; param["hello"] = username.text; userRequest.send(param); } Inside the Flex component, the HTTP URL points to Application.application.parameters.fiji which in turn points to the Fiji endpoint defined in the JSF page by tag. When the Submit button inside the Flash is clicked, the URL is resolved. This is a standard JSF request and that's how we invoke the serviceBean.greeting method inside a JSF managed bean. The URL is again passed via the flashVars attribute when the page is rendered. Finally, the initial label value is set via {Application.application.parameters.text} Its value is set via this tag: Decoders and Encoders First, why do we even need these decoders and encoders? Well, when using the Flex HttpService, the data is being sent to the server and returned in XML format. The JSF managed bean that we are using doesn't know anything about XML. It simply returns a string value. So, in order to convert the request into a format that the managed bean understands, we use a decoder. When we invoke a method, the value returned has to be encoded in order for the Flash module to understand it. I know, it sounds complicated, but it's really not. The decoder shown below will be called by Fiji and the value returned will be passed to the greeting(Object) method inside a JSF managed bean. The decoder will just pull the value from the XML sent by the request. public class HelloDecoder implements FlexDecoder , Serializable { private static final String ENDPOINT_PARAM = "hello"; public Object decodeRequest(FacesContext context, UIComponent component) { return context.getExternalContext().getRequestParameterMap().get(ENDPOINT_PARAM); } } When the greeting(Object) method inside the JSF managed bean returns a value, this encoder will be called to convert the response back to XML format. public class HelloEncoder implements FlexEncoder { private static final String VALUE = "value"; public void encodeObject(FacesContext context, UIComponent component, Object object) throws IOException { ResponseWriter responseWriter = context.getResponseWriter(); responseWriter.startElement(VALUE, component); responseWriter.writeText(object, null); responseWriter.endElement(VALUE); } } You can implement different encode and decode methods in case your Flash module requires the XML request/response to be in a specific format. Summary This article showed how you can use JSF and Flex component together while using standard JSF managed beans to provide data for the Flash components. That's what makes this framework unique. As a developer, you can continue using the standard component-centric JSF approach, but now you are able to inject even richer content using Flash. To learn more, please visit the Fiji home page: http://exadel.com/web/portal/fiji About the Author Max Katz is a Senior Systems Engineer at Exadel. He has been helping customers jump-start their RIA development as well as providing mentoring, consulting, and training. Max is a recognized subject matter expert in the JSF developer community. He has provided JSF/RichFaces training for the past three years, presented at many conferences, and written several published articles on JSF-related topics. Max also leads Exadel's RIA strategy and writes about RIA technologies in his blog, https://exadel.com/newsroom/blog/. He is an author of Practical RichFaces book (Apress). Max holds a BS in computer science from the University of California, Davis.
September 16, 2008
by Max Katz
· 114,191 Views · 1 Like
article thumbnail
Javadoc or Doxygen?
In the last two articles, "Reverse-engineer Source Code into UML Diagrams" and "Visual Documentation of Ant Dependencies in 3 Simple Steps" we saw how easy and valuable it was to automate technical documentation. By using open source tools, we were easily able to provide good technical documentation within a few minutes, and at no cost at all. We were also able to keep this up-to date by adding additional tasks to our Ant build files, and run them from our CI Server(Hudson in our case) on commit and nightly builds, and also publish the results. In this article, I will be showing you how to use yet another tool called Doxygen for generating technical documentation based on your source code. We all have used Javadoc and have been using it for a long time, right? So, you may ask what's the need to have another tool which produces the same HTML documentation? Doxygen has a slight edge over Javadoc and here are a few reasons why you should consider using the same: With Javadoc you have to remember all the HTML tags, you need to embed within your code comments. However, with Doxygen code comments are much more concise and polished, without the need for any HTML. Doxygen can also generate a variety of diagrams, we will take a look at some of them later. Doxygen also provides a structured view on the source code. As I mentioned in 2 above in the form of various diagrams, cross-referenced and syntax highlighted code. You get all the above benefits even if the code does not have any comments at all. Last but not the least, Doxygen is a documentation system not for just Java but also for various other languages like C++, C, Java, Objective-C, Python, IDL (Corba and Microsoft flavors), Fortran, VHDL, PHP, C#. So, without wasting further time, lets see what we need to get started with Doxygen. Step 1. Download, Install Doxygen. Download the binary distribution for Doxygen for the operating system you are using. I downloaded the binary distribution for Mac OS X called Doxygen-1.5.6.dmg. Installation is very simple, just drag the doxygen icon from this folder to the Applications folder, or wherever you want to keep it; as shown. I dropped it within my Applications folder. Just be sure to remember where you dragged it. To uninstall, just delete the file. It is completely self-contained. Step 2: Configure Doxygen. To generate documentation using Doxygen, you will need a configuration file called the Doxyfile. You can generate this file in two ways; either by using the Doxygen wizard or by using the command line option. Lets see how to use both these options to generate the configuration file: a. Command line. Open a command window and type the following as shown below: You should be able to locate the configuration file created within your default user folder. The file looks like this: # Doxyfile 1.5.6 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = b. Wizard Option. Launch the Doxygen application, and you should be able to create the configuration file using the wizard approach as shown below. The user interface is quite intuitive so I am going to skip explaining this in detail. The wizard approach was the one I used to get the initial settings for the configuration file. which you can always modify later. A few options in my Doxygen configuration file are as follows: # Doxyfile 1.5.6 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = PetStore PROJECT_NUMBER = 1.0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = NO EXTRACT_PRIVATE = NO EXTRACT_STATIC = NO EXTRACT_LOCAL_CLASSES = YES #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html GENERATE_TREEVIEW = YES Step 3. Doxygen and Ant. In order to use Doxygen, we need an Ant task. There is already an Ant task written for Doxygen which you can download from here. As always, since using Mac, when I downloaded the binaries and tried to use them, I got the ever famous error message : java.lang.UnsupportedClassVersionError: Bad version number in .class file So, had to do download the source, compile, and jar it up. Copy this library to your projects folder. Next, lets start making changes to our build file. 3.a: Lets define the Doxygen task. 3.b: To generate HTML documentation: 3.c: Lets combine them in target and run: [doxygen] Exec: /Applications/Doxygen.app reports/Doxyfile BUILD FAILED /CodeMetricsProject/build.xml:91: Doxygen not found on the PATH. Total time: 7 seconds 3.d: So, to launch Doxygen not in the path. we make change to the doxygen task as shown below: Lets run the target again and see if it fixed things.Yes indeed. generate-doxygen-docs: [doxygen] Exec: /Applications/Doxygen.app/Contents/Resources/doxygen reports/Doxyfile BUILD SUCCESSFUL Total time: 8 seconds 4. Integrate with Hudson. 4.a Modify Hudson Job. Once you have an Ant target working, calling this from your CI server is trivial. Within Hudson, select your Job, click on configure and add this new target to be called when running the build. 4.b Publish the reports. 4. c: Sample Reports. Force a build, and take a detailed look at the reports generated by Doxygen as shown below: I have given you a brief overview of Doxygen in this article, how to configure the same, and use it effectively to generate technical documentation on a continuous basis; either on commit builds or nightly builds. The Doxygen web site has lots of information on how to use it with other programming languages and also has tutorials in languages other than English as well. As always, if you are having trouble getting Doxygen to work, leave a comment or check out the Doxygen web site.
September 10, 2008
by Meera Subbarao
· 49,790 Views · 1 Like
article thumbnail
PHP bad practice: the use of extract()
Working with complex data structures in PHP requires the use of associative arrays. Even PHP classes are an extension of this concept. There are always disadvantages when one does not have alternatives (e.g. strictly defined data structures - see “struct” in C), but at least there are lots of built-in functions that work with arrays. Operations such as sorting, searching, merging, iterating with foreach are thus supported out-of-the-box for associative arrays. One operation is perhaps a little too dynamic in nature, with unexpected side-effects. It is the extract() function. The problem According to the documentation, the extract() function imports variables from an array into the current symbol table. In its simplest form, extract(array("a"=>3)) will assign the value 3 to the variable $a. The problem here is that you need to know what keys the array holds, both when calling the function and maintaining it. Let us consider this simple function declaration: function display_user_details($user) { extract($user); echo 'User name: '.$user_name." "; echo 'User age: '.$user_age." "; } Calling this function with the argument array("user_name" => "Mike", "user_age" => 20) is a valid operation. But whenever you call this function, you need to check which key refers to which piece of the user’s data. So even in its simplest form, the usage of extract() raises issues. Factor in that there are multiple ways of doing the extraction, based on combinations between the $extract_type and $prefix arguments: EXTR_OVERWRITE - if there is a collision, overwrite the existing variable EXTR_SKIP - if there is a collision, don’t overwrite the existing variable EXTR_PREFIX_SAME - if there is a collision, prefix the variable name with $prefix EXTR_PREFIX_ALL - prefix all variable names with $prefix EXTR_PREFIX_INVALID - only prefix invalid/numeric variable names with $prefix EXTR_IF_EXISTS - only overwrite the variable if it already exists in the current symbol table, otherwise do nothing EXTR_PREFIX_IF_EXISTS - only create prefixed variable names if the non-prefixed version of the same variable exists in the current symbol table EXTR_REFS - extracts variables as references All this suggests that there are several options to choose from but the code becomes harder to understand. The more entries the array has, the more the extract() call does and harder to trace the data becomes. The solution My suggestion is to keep it simple. There are at least three alternatives: work directly with the array: $user["user_name"] doesn’t look that bad after all explicitly “import” the variables: $user_name = $user["user_name"] use function arguments with default values: function display_user_details($user_name, $user_age = 18) Depending on your specific needs, there might be other alternatives. But any of the above three will make your code easier to maintain and extend.
September 9, 2008
by Robert Enyedi
· 31,526 Views
article thumbnail
32 bit JDK on a 64 bit Ubuntu System
If you have more than 3GB on your machine and you’re running Ubuntu you’ve probably had to figure out how to access that additional memory – the default Ubuntu desktop kernel will only allow access to the first 3GB. You can install the server kernel, but that’s been tuned for a server with different latency settings, etc. You can recompile the desktop kernel with HIGHMEM64 set, but then you’re stuck building the video drivers yourself. My latest strategy has been to use the 64 bit kernel. 64 bit support is not bad now and most apps run normally. Of course they use about double the memory. If you’re running a lot of Java processes this 64 bit tax is very noticeable. For my needs, 32 bit Java is fine, even with a 64 bit kernel. Ubuntu/Debian ship a 32 bit JRE (ia32-sun-java6-bin). This package provides only the runtime environment (no javac) and the client VM so it has limited usefulness for a developer. To install the 32 bit JDK from Sun on a 64 bit system you can use java-package. I’ve been running Eclipse and all my development applications and finally have some free memory again. Installation First, download the latest 32 bit JDK (not JRE) from Sun. At the time this was jdk-6u7-linux-i586.bin for me. Install java-package: sudo apt-get install java-package Now use java-package to build a .deb package from the binary you downloaded. You have to trick it into building the 32 bit package: DEB_BUILD_GNU_TYPE=i486-linux-gnu DEB_BUILD_ARCH=i386 fakeroot make-jpkg jdk-6u7-linux-i586.bin This should generate a .deb package. For some reason the package name has the _amd64 suffix. Install the package: sudo dpkg -i sun-j2sdk1.6_1.6.0+update7_amd64.deb Use update-alternatives to select the new JDK. It was installed at /usr/lib/j2sdk1.6-sun for me. sudo update-alternatives --config java If you run java -version you should see the correct version: java version "1.6.0_07" Java(TM) SE Runtime Environment (build 1.6.0_07-b06) Java HotSpot(TM) Server VM (build 10.0-b23, mixed mode) 32 bit Eclipse I had to reinstall the 32 bit version of Eclipse (since SWT contains native code). I also had to delete my ~/.eclipse directory or Eclipse wouldn’t start (this requires reinstalling new versions of any plugins). Finally, add the new JRE in Java->Installed JREs using the install location (/usr/lib/j2sdk1.6-sun) and select it as the default. From http://dmy999.com/
September 9, 2008
by Derek Young
· 100,348 Views
article thumbnail
An Introduction to Aspect-Oriented programming with JBoss AOP
JBoss Application Server ships with support for aspect-oriented programming, so you can use AOP in your applications deployed in JBoss AS. JBoss AS 5, which is currently available as a community release, has AOP built into its core. However, JBoss AOP is also available as a standalone framework for use in your other applications. This article will take a simple example, and use JBoss AOP to add to its behaviour, while explaining some of the core functionality of JBoss AOP. We will look at encapsulating cross-cutting concerns into aspects, have a look at around advices vs the new lightweight advices in the upcoming JBoss AOP 2.0 release, and also look at using interface-introductions and mixins to add interfaces to your classes. Table of Contents Our Core Application Our Core Application The application we will look at is is a simple banking application. It has a BankAccount class: package bank; public class BankAccount { int accountNumber; int balance; public BankAccount(int accountNumber) { System.out.println("*** Bank Account constructor"); this.accountNumber = accountNumber; } public int getAccountNumber() { return accountNumber; } public int getBalance() { return balance; } public void debit(int amount) { System.out.println("*** BankAccount.debit()"); balance -= amount; } public void credit(int amount) { System.out.println("*** BankAccount.credit()"); balance += amount; } } In addition it has a main Bank class: package bank; import java.util.HashMap; import java.util.Map; public class Bank { static Map bankAccounts = new HashMap(); public static void transfer(BankAccount from, BankAccount to, int amount) { from.debit(amount); to.credit(amount); } public static void main(String[] args) { System.out.println("*** Creating account 1"); BankAccount acc1 = new BankAccount(1); acc1.credit(150); bankAccounts.put(acc1.getAccountNumber(), acc1); System.out.println("*** Creating account 2"); BankAccount acc2 = new BankAccount(2); acc2.credit(230); bankAccounts.put(acc2.getAccountNumber(), acc2); System.out.println("*** Balance acount 1: " + acc1.getBalance()); System.out.println("*** Balance acount 2: " + acc2.getBalance()); //Transfer some money System.out.println("*** Transfer 50 from account 1 to account 2"); transfer(acc1, acc2, 50); System.out.println("*** Balance acount 1: " + acc1.getBalance()); System.out.println("*** Balance acount 2: " + acc2.getBalance()); } } As you can see, we create two bank accounts with their account numbers, set the initial balances, and then transfer 50 from account1 to account 2. Running this simple example we get the following expected output: *** Creating account 1 *** Bank Account constructor *** BankAccount.credit() *** Creating account 2 *** Bank Account constructor *** BankAccount.credit() *** Balance acount 1: 150 *** Balance acount 2: 230 *** Transfer 50 from account 1 to account 2 *** BankAccount.debit() *** BankAccount.credit() *** Balance acount 1: 100 *** Balance acount 2: 280 The code for this example can be found in the listing1/ folder of . Logging as a Cross-Cutting Concern One of the main uses of AOP is to extract out cross-cutting concerns. Say we wanted to add some logging whenever an object is created, when its fields are set, and when its methods are called. The “obvious” way to do that in our example would be to go in and add logging statements to various points of our application. The problem with this approach is that there might be lots of places to edit, scattered around our system, so we would need to identify those places, make our changes, and recompile our application. To turn this behaviour off, we would need to remove our logging statements again and recompile our code again. So the “obvious” way both leads to bloat, and is difficult to turn on and off. Using AOP we can encapsulate this cross-cutting code in an aspect. The aspect itself is just a normal class, which can hold state, extend other classes, everything you can do in a normal Java class. package bank; import org.jboss.aop.joinpoint.ConstructorInvocation; import org.jboss.aop.joinpoint.FieldWriteInvocation; import org.jboss.aop.joinpoint.MethodInvocation; public class LoggingAspect { public Object log(ConstructorInvocation invocation) throws Throwable { try { System.out.println("C: Creating BankAccount using constructor " + invocation.getConstructor()); System.out.println("C: Account number: " + invocation.getArguments()[0]); return invocation.invokeNext(); } finally { System.out.println("C: Done"); } } public Object log(MethodInvocation invocation) throws Throwable { try { System.out.println("M: Calling method " + invocation.getMethod().getName()); System.out.println("M: Amount " + invocation.getArguments()[0]); return invocation.invokeNext(); } finally { System.out.println("M: Done"); } } public Object log(FieldWriteInvocation invocation) throws Throwable { BankAccount account = (BankAccount)invocation.getTargetObject(); System.out.println("F: setting field " + invocation.getField().getName() + " for BankAccount " + account.getAccountNumber()); System.out.println("F: Field old value " + account.getBalance()); System.out.println("F: New value will be " + invocation.getValue()); try { return invocation.invokeNext(); } finally { System.out.println("F: Field new value " + account.getBalance()); System.out.println("F: Done"); } } } The actual code implementing the cross-cutting concerns is encapsulated in methods called advice methods. For the type of advice methods that we are looking at now, around advice, the signature and format of the advice method is as shown here: public Object (org.jboss.aop.joinpoint.Invocation invocation) throws Throwable { //Do something before try { return invocation.invokeNext(); } finally { //Do something after } } The invocation parameter can be of type org.jboss.aop.joinpoint.Invocation, or one of its subclasses. Some of these are shown in the LoggingAspect, and which of the overloaded log methods gets called depends on what is being called once we apply our aspect. In the LoggingAspect we are able to handle calls to an object's constructor (the first log() method, starting on line 9), calls to an object's methods (the second log() method, starting on line 23) and calls to set a field (the third log() method, starting on line 37). These “events” are called joinpoints in AOP terminology. The invocation contains information about what field/method/constructor is being called. It also allows access to any arguments, and the object on which we are making the call. The around advice methods also contain a call to Invocation.invokeNext(), which propogates the call chain. If there are several advice methods applied to the target joinpoint, this call invokes the next advice in the chain. If this is the last advice in the chain, or as in our example, we are the only advice in the chain, the target joinpoint is called when we call Invocation.invokeNext(). To apply our aspects, we need some configuration to declare our aspects, and to select the joinpoints in our application where the advice methods should be applied. In JBoss AOP the easiest way to do this is with an xml configuration file, typically called jboss-aop.xml. First we declare our aspect: A binding has a pointcut to choose which methods we should apply the advice to. In this case we have a constructor expression that selects the constructor of the bank.BankAccount class that has an int parameter. Note that all class names used in pointcut expressions must be fully qualified. The word new is a special identifier within the pointcut language to pick out a constructor. Next, the around part of the binding says that we should apply the log advice from the bank.LoggingAspect to the joinpoints matched by its pointcut. In other words, when we call BankAccount's constructor, the first LoggingAspect.log() method, which takes a ConstructorInvocation, is invoked. The previous binding's pointcut only captures one joinpoint. The next one uses a wildcard in place of the method name, so we pick out all methods returning void that take an int parameter, regardless of their name. It looks a lot like the constructor expression in the previous binding, but also contains the return type of the methods we are interested in. This pointcut picks out BankAccount.debit() and BankAccount.credit(), and invokes the second LoggingAspect.log() method, which takes a MethodInvocation, when these methods are called. Finally, we have a binding capturing writes to the balance field of the BankAccount class. In this case we are using a wildcard in place of the type's name, and the third LoggingAspect.log method, which takes a FieldWriteInvocation, will be invoked when the field's value is set: In addition to wildcards, you can also capture whole inheritance hierarchies of classes, use typedefs for complex class expressions, all classes belonging to a package, and as we will see use annotations to capture a wide range of jonpoints. To run this application with aop enabled, you need to pass in a few extra parameters into the jvm when starting it up, as we can see in the example's build.xml The jboss.aop.path parameter contains the path to the jboss-aop.xml that declares our aspects and binds advice methods to joinpoints. The -javaagent switch points to the JBoss AOP library, which in turn turns on load-time weaving. When a class is first loaded, JBoss AOP will intercept that event and modify the bytecode of the class to add the hooks required to trigger the aspects for our selected joinpoints. In addition to weaving at load-time, you can weave the classes using our aopc post-processor. An example of this is shown in the example's build.xml. Running the example with load-time weaving yields the following output, now with quite a lot of extra information coming from our logging aspect: *** Creating account 1 C: Creating BankAccount using constructor public bank.BankAccount(int) C: Account number: 1 *** Bank Account constructor C: Done M: Calling method credit M: Amount 150 *** BankAccount.credit() F: setting field balance for BankAccount 1 F: Field old value 0 F: New value will be 150 F: Field new value 150 F: Done M: Done *** Creating account 2 C: Creating BankAccount using constructor public bank.BankAccount(int) C: Account number: 2 *** Bank Account constructor C: Done M: Calling method credit M: Amount 230 *** BankAccount.credit() F: setting field balance for BankAccount 2 F: Field old value 0 F: New value will be 230 F: Field new value 230 F: Done M: Done *** Balance acount 1: 150 *** Balance acount 2: 230 *** Transfer 50 from account 1 to account 2 M: Calling method debit M: Amount 50 *** BankAccount.debit() F: setting field balance for BankAccount 1 F: Field old value 150 F: New value will be 100 F: Field new value 100 F: Done M: Done M: Calling method credit M: Amount 50 *** BankAccount.credit() F: setting field balance for BankAccount 2 F: Field old value 230 F: New value will be 280 F: Field new value 280 F: Done M: Done *** Balance acount 1: 100 *** Balance acount 2: 280 The code for this example can be found in the listing2/ folder of . Externalising Security Checks Logging is the common example used for introductions to AOP, so let's try doing something more interesting. Say we want to make sure that only users with the correct permissions can call a method. We could annotate our methods from BankAccount as follows: package bank; public class BankAccount { int accountNumber; int balance; @Roles(roles= {"admin"}) public BankAccount(int accountNumber) { System.out.println("*** Bank Account constructor"); this.accountNumber = accountNumber; } ... @Roles(roles= {"admin"}) public void debit(int amount) { System.out.println("*** BankAccount.debit()"); balance -= amount; } @Roles(roles= {"admin", "user"}) public void credit(int amount) { System.out.println("*** BankAccount.credit()"); balance += amount; } } So only users with the role “admin” can create BankAccount instances and debit accounts, while users with the role “admin” or “user” can credit accounts. We have created a security.properties file to configure users and their roles: admin=password;admin,user guest=password;user There is a user called 'admin' whose password is 'password' who has the roles 'admin' and 'user', and a user called 'guest' whose password is 'password' who only has the role 'user'. We can then apply a SecurityAspect to the methods annotated with the @Roles annotation. Note that like everything else in the pointcut language the annotations need to be fully qualified. The “..” in place of the parameters in the pointcut expressions means we want this aspect to be applied to all constructors and methods annotated with @Roles regardless of the parameters it takes. The SecurityAspect then checks that the correct user is used: package bank; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; import java.util.Arrays; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import org.jboss.aop.joinpoint.Invocation; public class SecurityAspect { Map usernamePassword = new HashMap(); Map> userRoles = new HashMap>(); public SecurityAspect() throws FileNotFoundException, IOException, URISyntaxException { //Initialise the usernamePassword and userRoles maps //with information from security.properties } public Object checkSecurity(Invocation invocation) throws Throwable { String username = LoginInfo.getUsername(); String password = usernamePassword.get(username); if (password == null) { throw new SecurityException("Unknown user"); } if (!password.equals(LoginInfo.getPassword())) { throw new SecurityException("Wrong password"); } Roles rolesAnnotaton = (Roles)invocation.resolveAnnotation(Roles.class); List hasRoles = userRoles.get(username); boolean hasRole = false; if (hasRoles != null) { for (String role : rolesAnnotaton.roles()) { if (hasRoles.contains(role)) { hasRole = true; break; } } } if (!hasRole) { throw new SecurityException("Wrong roles for user"); } return invocation.invokeNext(); } } The roles needed to invoke the target joinpoint are got from the invocation using this call: Roles rolesAnnotaton = (Roles)invocation.resolveAnnotation(Roles.class); This does the same as calling java.lang.reflect.Method.getAnnotation() or java.lang.reflect.Constructor.getAnnotation() for the called method or constructor, but also allows for annotation overrides as part of the aop configuration, which are beyond the scope of this article. Although the type of invocation used in this example is Invocation, the specific type created by JBoss AOP will be ConstructorInvocation or MethodInvocation depending on what we are calling. The referenced LoginInfo class is just a wrapper around some static fields containing the username and password. package bank; public class LoginInfo { private static String username; private static String password; public static void setUsernameAndPassword(String username, String password) { LoginInfo.username = username; LoginInfo.password = password; } public static String getUsername() { return username; } public static String getPassword() { return password; } } Now let us modify the Bank.main() method to populate the LoginInfo fields: public static void main(String[] args) { System.out.println("*** Log in as 'guest' - it does not have the correct roles to create an account"); LoginInfo.setUsernameAndPassword("guest", "password"); System.out.println("*** Attempting to create account 1"); try { BankAccount acc1 = new BankAccount(1); acc1.credit(150); bankAccounts.put(acc1.getAccountNumber(), acc1); } catch(SecurityException e) { System.out.println("!!! Expected SecurityException " + e.getMessage()); } System.out.println("*** Log in as 'admin' - the roles are fine for the rest now"); LoginInfo.setUsernameAndPassword("admin", "password"); System.out.println("*** Creating account 1"); BankAccount acc1 = new BankAccount(1); acc1.credit(150); bankAccounts.put(acc1.getAccountNumber(), acc1); System.out.println("*** Creating account 2"); BankAccount acc2 = new BankAccount(2); acc2.credit(230); bankAccounts.put(acc2.getAccountNumber(), acc2); System.out.println("*** Balance acount 1: " + acc1.getBalance()); System.out.println("*** Balance acount 2: " + acc2.getBalance()); //Transfer some money System.out.println("*** Transfer 50 from account 1 to account 2"); transfer(acc1, acc2, 50); System.out.println("*** Balance acount 1: " + acc1.getBalance()); System.out.println("*** Balance acount 2: " + acc2.getBalance()); } We first try to create a BankAccount with a user who does not have the required admin role, and then we do the rest, as before, with an user with the required roles. The output of running this application is: *** Log in as 'guest' - it does not have the correct roles to create an account *** Attempting to create account 1 !!! Expected SecurityException Wrong roles for user *** Log in as 'admin' - the roles are fine for the rest now *** Creating account 1 *** Bank Account constructor *** BankAccount.credit() *** Creating account 2 *** Bank Account constructor *** BankAccount.credit() *** Balance acount 1: 150 *** Balance acount 2: 230 *** Transfer 50 from account 1 to account 2 *** BankAccount.debit() *** BankAccount.credit() *** Balance acount 1: 100 *** Balance acount 2: 280 By using AOP to apply security, we have extracted the security checks into one place in our application, and used annotations to configure that. If we wanted to use a different mechanism of configuring the users we could leave the core application the same, write another aspect and easily change how we use security everywhere by modifying the jboss-aop.xml file. The code for this example can be found in the listing3/ folder of . Observer with Introductions and Mixins Say we want to be able to be notified somehow when BankAccount.balance is changed. An option would be to implement the Observer pattern, but we don't want to include all the Observable plumbing code in our BankAccount class. First of all let's add an annotation to the field we want to monitor. package bank; public class BankAccount { int accountNumber; @Observed int balance; ... } Next we can write an implementation of Observable: package bank; import java.util.ArrayList; import java.util.List; public class ObservableMixin implements Observable { List observers = new ArrayList(); public void addObserver(Observer listener) { observers.add(listener); } public void removeObserver(Observer listener) { observers.remove(listener); } public void notifyObservers(Object event) { for (Observer observer : observers) { observer.update(event); } } } This is a mixin class, which implements the Observable interface. It contains all the plumbing code needed for the Observable part of the pattern. It can be introduced into other POJOs using the following xml bank.Observable bank.ObservableMixin ... This does two things. It makes all classes that have a field annotated with @Observed implement the @Observable interface and implement those methods. Second, when anybody attempts to call the methods from the Observable interface, it delegates all the calls to an instance of the ObservableMixin. Next we have an aspect to trap when the annotated fields change their values bound using the following xml. ... The aspect is an around advice that captures the values before and after modifying the field. package bank; import java.lang.reflect.Field; import org.jboss.aop.joinpoint.FieldWriteInvocation; public class ObserverAspect { public Object fieldChanged(FieldWriteInvocation invocation) throws Throwable { Observable tgt = (Observable)invocation.getTargetObject(); Field fld = invocation.getField(); String fieldName = fld.getName(); fld.setAccessible(true); Object oldVal = invocation.getField().get(tgt); Object result = invocation.invokeNext(); Object newVal = invocation.getField().get(tgt); tgt.notifyObservers("Changed " + fieldName + " from " + oldVal + " to " + newVal); return result; } } Since the classes captured by the pointcut to select which classes should have the ObserverAspect applied are in the set of classes captured by the class expression to pick out classes that should have the Observable introduction and mixin, we can safely cast the target of the invocation to Observable. We then get the values before and after writing the field, and then use the Observable target object to notify the observers. As mentioned the call to Observable.notifyObservers() will end up inside BankAccount's ObservableMixin. Finally, let us modify the Bank.main() method to register an Observer with a BankAccount instance public static void main(String[] args) { System.out.println("*** Creating account 1"); BankAccount acc1 = new BankAccount(1); acc1.credit(150); bankAccounts.put(acc1.getAccountNumber(), acc1); System.out.println("*** Creating account 2"); BankAccount acc2 = new BankAccount(2); acc2.credit(230); bankAccounts.put(acc2.getAccountNumber(), acc2); System.out.println("Installing observer"); ((Observable)acc2).addObserver(new Observer(){ public void update(Object evt) { System.out.println("!!! Observer: " + evt); } }); System.out.println("*** Balance acount 1: " + acc1.getBalance()); System.out.println("*** Balance acount 2: " + acc2.getBalance()); //Transfer some money System.out.println("*** Transfer 50 from account 1 to account 2"); transfer(acc1, acc2, 50); System.out.println("*** Balance acount 1: " + acc1.getBalance()); System.out.println("*** Balance acount 2: " + acc2.getBalance()); } Although until woven the BankAccount class does not implement the Observable interface, the Java compiler does not perform any checks when casting to an interface (only to a superclass), so the cast from BankAccount to Observable will compile. (If the example is run without weaving you would get a ClassCastException since then BankAccount would not implement the Observable interface). When we run this example we can see the registered Observer gets triggered: *** Creating account 1 *** Bank Account constructor *** BankAccount.credit() *** Creating account 2 *** Bank Account constructor *** BankAccount.credit() Installing observer *** Balance acount 1: 150 *** Balance acount 2: 230 *** Transfer 50 from account 1 to account 2 *** BankAccount.debit() *** BankAccount.credit() !!! Observer: Changed balance from 230 to 280 *** Balance acount 1: 100 *** Balance acount 2: 280 The code for this example can be found in the listing5/ folder of . Conclusion We have taken a simple application, added extra behaviour to it using JBoss AOP, and explored a few of the features offered. Apart from adding a few annotations to help with our pointcut expressions (and there are even less intrusive, although more incovenient ways to achieve the similar effect), we have left the core application as is, and added extra cross-cutting behaviour such as logging and security by applying aspects, as well as using a combination of aspects, interface introductions and mixins to implement the Observer pattern. JBoss AOP can be downloaded from http://www.jboss.org/jbossaop/ and comes with a tutorial to get you started.
August 28, 2008
by Kabir Khan
· 85,056 Views · 2 Likes
article thumbnail
Using a Hibernate Interceptor To Set Audit Trail Properties
In almost every application I've done, the database tables have some kind of audit trail fields. Sometimes this is a separate "audit log" table where all inserts, updates, deletes, and possibly even queries are logged. Other times there are the four typical audit trail fields in each table, for example you might have created_by, created_on, updated_by, and updated_on fields in each table. The goal in the latter case is to update those four fields with the appropriate information as to who created or updated a record and when they did it. Using a simple Hibernate Interceptor this can be accomplished with no changes to your application code (with several assumptions which I'll detail next). In other words, you won't need to and definitely should not be manually setting those audit properties littered around your application code. The basic assumptions I'll make for this simple audit interceptor are that: (1) model objects contain the four audit properties mentioned above, and (2) there is an easy way to obtain the current user's information from anywhere in the code. The first assumption is needed since you need some way to identify which properties constitute the audit trail properties. The second assumption is required because you need some way to obtain the credentials of the person making the change in order to set the createdBy or updatedBy property in your Hibernate Interceptor class. So, for reference purposes, assume you have a (Groovy) base entity like this with the four audit properties: @MappedSuperclassclass BaseEntity implements Serializable { String createdBy Date createdOn String updatedBy Date updatedOn} I'm using the Hibernate ImprovedNamingStrategy so that camel case names are translated to underscored names, e.g. "createdBy" becomes "created_by". Next assume there is a BlogEntry entity class that extends BaseEntity and inherits the audit trail properties: @Entityclass BlogEntry extends BaseEntity { @Id @GeneratedValue (strategy = GenerationType.IDENTITY) Long id @Version Long version String title @Column (name = "entry_text") String text @Temporal (TemporalType.TIMESTAMP) Date publishedOn} To implement the interceptor, we need to implement the aforementioned Interceptor interface. We could do this directly, but it is better to extend EmptyInterceptor so we need only implement the methods we actually care about. Without further ado, here's the implementation (excluding package declaration and imports): class AuditTrailInterceptor extends EmptyInterceptor { boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) { setValue(currentState, propertyNames, "updatedBy", UserUtils.getCurrentUsername()) setValue(currentState, propertyNames, "updatedOn", new Date()) true } boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { setValue(state, propertyNames, "createdBy", UserUtils.getCurrentUsername()) setValue(state, propertyNames, "createdOn", new Date()) true } private void setValue(Object[] currentState, String[] propertyNames, String propertyToSet, Object value) { def index = propertyNames.toList().indexOf(propertyToSet) if (index >= 0) { currentState[index] = value } } So what did we do? First, we implemented the onFlushDirty and onSave methods because they are called for SQL updates and inserts, respectively. For example, when a new entity is first saved, the onSave method is called, at which point we want to set the createdBy and properties. And if an existing entity is updated, onFlushDirty is called and we set the updatedBy and updatedOn. Second, we are using the setValue helper method to do the real work. Specfically, the only way to modify the state in a Hibernate Interceptor (that I am aware of anyway) is to dig into the currentState array and change the appropriate value. In order to do that, you first need to trawl through the propertyNames array to find the index of the property you are trying to set. For example, if you are updating a blog entry you need to set the updatedBy and updatedOn properties within the currentState array. For a BlogEntry object, the currentState array might look like this before the update (the updated by and on propertes are both null in this case because the entity was created by Bob but has not been updated yet): { "Bob", 2008-08-27 10:57:19.0, null, null, 2008-08-27 10:57:19.0, "Lorem ipsum...", "My First Blog Entry", 0} You then need to look at the propertyNames array to provide context for what the above data represents: { "createdBy", "createdOn", "updatedBy", "updatedOn", "publishedOn", "text", "title", "version"} So in the above updatedBy is at index 2 and updatedOn is located at index 3. setValue() works by finding the index of the property it needs to set, e.g. "updatedBy," and if the property was found, it changes the value at that index in the currentState array. So for updatedBy at index 2, the following is the equivalent code if we had actually hardcoded the implementation to always expect the audit fields as the first four properties (which is obviously not a great idea): // Equivalent hard-coded code to change "updatedBy" in above example// Don't use in production!currentState[2] = UserUtils.getCurrentUsername() To actually make your interceptor do something, you need to enable it on the Hibernate Session. You can do this in one of several ways. If you are using plain Hibernate (i.e. not with Spring or another framework) you can set the interceptor globally on the SessionFactory, or you can enable it for each Session as in the following example code: // Configure interceptor globally (applies to all Sessions)sessionFactory = new AnnotationConfiguration() .configure() .setNamingStrategy(ImprovedNamingStrategy.INSTANCE) .setInterceptor(new AuditTrailInterceptor()) .buildSessionFactory()// Enable per SessionSession session = getSessionFactory().openSession(new AuditTrailInterceptor()) If you enable the interceptor globally, it must be thread-safe. If you are using Spring you can easily configure a global interceptor on your session factory bean: On the other hand, if you would rather enable the interceptor per session, you either need to use the openSession(Interceptor) method to open your sessions or alternatively implement your own version of CurrentSessionContext to use the getCurrentSession() method in order to set the interceptor. Using getCurrentSession() is preferable anyway since it allows several different classes (e.g. DAOs) to use the same session without needing to explicitly pass the Session object around to each object that needs it. At this point we're done. But, if you know about the Hibernate eventing system (e.g. you can listen for events such as inserts and updates and define event listener classes to respond to those events), you might be wondering why I didn't use that mechanism rather than the Interceptor. The reason is that, to the best of my current knowledge, you cannot alter state of objects in event listeners. So for example you would not be able to change an entity's state in a PreInsertEventListener implementation class. If anyone knows this is incorrect or has implemented it, I'd love to hear about it. Until next time, happy auditing! Originally posted on Scott Leberknight's blog
August 27, 2008
by Scott Leberknight
· 103,485 Views · 2 Likes
article thumbnail
EJB 3.0 and Spring 2.5
Why is it that developers from these two communities don't like to see eye to eye? I have been using both Spring from its inception, and EJB's from 2001. Just like everyone else did, I just dreaded the huge amount of XML we had to write for both of these; configuration files in Spring, and deployment descriptors in EJB 2.x. However, Java 5 came to our rescue and now annotations have mostly replaced XML files in both these. But, after having used these two latest versions Spring 2.5 and EJB 3.0, I think that they complement each other, rather than compete with each other. There are certain features which are powerful in Spring, and equal number of features powerful on the EJB side as well. Many developers fail to understand, that Spring is a popular non-standard framework created by Spring Source, while EJB 3.0 is a specification which is supported by major JEE vendors. There are a few developers with whom I have worked earlier, prefer to use standard specification, and they chose EJB2.x/ and are moving now to EJB 3.0. However, there isn't anything stopping you from using Spring along with EJB, is it? The complaint I have heard many times is: We can't use non-standard framework". The same developers who complain about Spring being non-standard use home grown frameworks, which was and will be forever so hard to even decipher. How can it be a specification when a couple of developers write several thousand lines of code? Also, a recent article published here at Javalobby by Adam Bien showed the trend moving towards EJB 3.0, right? Anyway, in this article we will see how by adding a few lines in your Spring configuration file, you can seamlessly use EJB 3.0 components within your Spring application. Back to our EJB 3.0 and Spring 2.5 article, we are going to see how easy and simple it is to access EJB 3.0 components in Spring by using its powerful dependency injection mechanism to inject an instance of our Customer session bean. This Customer session bean, in turn uses the Entity Manager for the CRUD operations on the Customer Entity. Here are the detailed steps: Step 1: Create a simple JPA Entity. The Java Persistence API (JPA) is defined as part of the Java EE 5 specification. Creating entities using JPA is as simple as creating a POJO with a few annotations as shown below: package com.ejb.domain; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; /** * * @author meerasubbarao */ @Entity @Table(name = "CUSTOMER", catalog = "", schema = "ADMIN") public class Customer implements Serializable { private static final long serialVersionUID = 1L; @Id @Column(name = "CUSTOMER_ID") private Long customerId; @Column(name = "FIRST_NAME") private String firstName; @Column(name = "LAST_NAME") private String lastName; @Column(name = "MIDDLE_NAME") private String middleName; @Column(name = "EMAIL_ID") private String emailId; public Customer() { } public Customer(Long customerId) { this.customerId = customerId; } public Long getCustomerId() { return customerId; } public void setCustomerId(Long customerId) { this.customerId = customerId; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getMiddleName() { return middleName; } public void setMiddleName(String middleName) { this.middleName = middleName; } public String getEmailId() { return emailId; } public void setEmailId(String emailId) { this.emailId = emailId; } } Step 2: Create a EJB 3.0 Session bean. This session beans uses the Entity Manager for the Create Read Update Delete (CRUD) operations for the Customer Entity we created in Step 1. The CRUD opertions are also published as web methods by adding a few basic annotations. The Interface: package com.ejb.service; import com.ejb.domain.Customer; import java.util.Collection; import javax.ejb.Remote; /** * * @author meerasubbarao */ @Remote public interface CustomerService { Customer create(Customer info); Customer update(Customer info); void remove(Long customerId); Collection findAll(); Customer[] findAllAsArray(); Customer findByPrimaryKey(Long customerId); } The Implementation Class: package com.ejb.service; import com.ejb.domain.Customer; import java.util.Collection; import javax.ejb.Stateless; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.Query; import javax.jws.WebMethod; /** * * @author meerasubbarao */ @WebService(name = "CustomerService", serviceName = "CustomerService", targetNamespace = "urn:CustomerService") @SOAPBinding(style = SOAPBinding.Style.RPC) @Stateless(name = "CustomerService") public class CustomerServiceImpl implements CustomerService { @PersistenceContext private EntityManager manager; @WebMethod public Customer create(Customer info) { this.manager.persist(info); return info; } @WebMethod public Customer update(Customer info) { return this.manager.merge(info); } @WebMethod public void remove(Long customerId) { this.manager.remove(this.manager.getReference(Customer.class, customerId)); } public Collection findAll() { Query query = this.manager.createQuery("SELECT c FROM Customer c"); return query.getResultList(); } @WebMethod public Customer[] findAllAsArray() { Collection collection = findAll(); return (Customer[]) collection.toArray(new Customer[collection.size()]); } @WebMethod public Customer findByPrimaryKey(Long customerId) { return (Customer) this.manager.find(Customer.class, customerId); } } Step 3. Compile, Package and Deploy to an application server. There are no server specific annotations in either the Entity class or the Session bean. Package the entity class, the session bean interface, implemetation class along with the persistence.xml file in a JAR file. Since I am deploying this application to GlassFish, I am using the default persistence provider which is TopLink. Start your application server, and deploy this JAR to it. The contents of persistence.xml file is as shown below: oracle.toplink.essentials.PersistenceProvider spring-ejb Once your application is deployed, make sure you check the JNDI name of your session bean. In GlassFish, click on the JNDI Browsing toolbar button to view the JNDI names. Step 4: Test the Stateless Session beans. Since my session beans are published as web services, I can just easily test them using either the test page provided by GlassFish application server, or by using SoapUI and make sure that my Customer entity can be persisted using the CustomerService session bean. I am using the default test page provided by Glass Fish for web services: Step 5: Create a Spring Bean. Here, I define a simple CustomerManager interface, and an implementation class; just to show how things are wired using Spring. package com.spring.service; import com.ejb.domain.Customer; /** * * @author meerasubbarao */ public interface CustomerManager { public void addCustomer(Customer customer); public void removeCustomer(Long customerId); public Customer[] listCustomers(); } package com.spring.service; import com.ejb.domain.Customer; import com.ejb.service.CustomerService; /** * * @author meerasubbarao */ public class CustomerManagerImpl implements CustomerManager { CustomerService customerService; public void setCustomerService(CustomerService customerService) { this.customerService = customerService; } public void removeCustomer(Long customerId) { customerService.remove(customerId); } public Customer[] listCustomers() { return customerService.findAllAsArray(); } public void addCustomer(Customer customer) { customerService.create(customer); } } Step 6: Injecting the EJB 3.0 Session bean into our Spring Beans. As seen above, I am using setter injection to inject an instance of Customer Service and in turn invoke a method on the Stateless session bean. How do we inject an EJB into a Spring bean? It is quite simple as shown below in the Spring configuration file: The most important aspect here is the wiring of the EJB within the Spring configuration using the element in the jee schema. Next, we need to wire this with our Spring bean which is done as shown below: Step 7: Test How do we know that it works. Lets create a simple class and test. package com.spring.client; import com.ejb.domain.Customer; import com.spring.service.CustomerManager; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringAndEJBMain { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("SpringXMLConfig.xml"); CustomerManager service = (CustomerManager) context.getBean("manageCustomer"); Customer customer = new Customer(); customer.setFirstName("Meera"); customer.setLastName("Subbarao"); customer.setMiddleName("B"); customer.setEmailId("[email protected]"); customer.setCustomerId(new Long(1)); service.addCustomer(customer); for (Customer cust : service.listCustomers()) { System.out.println(cust.getFirstName()); System.out.println(cust.getLastName()); System.out.println(cust.getMiddleName()); System.out.println(cust.getEmailId()); } service.removeCustomer(new Long(1)); } } And here is the sample output from my IDE: We can go back to our GlassFish web services test page, and test the findAll method. It should have two entities. In this article, we saw how quick and easy it was to create JPA entities, persist them using Entity Manager from within our session bean. We also saw how easy it was to publish web services by adding a few annotations to our session beans. Next, we saw how to create a simple Spring bean, inject our session bean, and finally call methods on this session bean from our Spring application. Spring isn't in my opinion a replacement for EJB 3.0, you can mix and match EJB 3.0 and Spring 2.5 components to get the best of both.
August 27, 2008
by Meera Subbarao
· 76,104 Views
article thumbnail
How Do NetBeans Extension Points Work?
One of the main benefits of the NetBeans Platform is its module system. Regardless of which module system is best (my guess is there will soon be a version of NetBeans that can also run as OSGi bundles), it’s important to have a system that enables you to create a modular architecture for your application. A module system is an invitation to create a clean and maintainable architecture with defined dependencies and nice APIs with clearly defined and easy-to-use extension points. If you follow these principles, others can extend your application easily. Maybe the easiest way to provide extension points in NetBeans is via the layer.xml file (also known as the "layer file"). In a NetBeans module (also known as a "plugin"), the layer file is its central configuration file. NetBeans IDE uses the layer file to provide extension points for APIs. Objects can be created declaratively in the layer file and you can use the NetBeans Lookup API to listen for changes. You will use this approach whenever you create new Actions (which are invoked via menu items, toolbar buttons, and/or shortcut keys) or TopComponents (which provide "views" or "windows"), for example. This quick tutorial shows how you can provide your own extension points via the layer file. The source code of the sample is found here in the NetBeans Plugin Portal. Prerequisites NetBeans (I’m using 6.1, but this will also work with older/newer versions). Create a new module suite: Choose File > New Project (Ctrl-Shift-N). Under Categories, select NetBeans Modules. Under projects, select "NetBeans Platform Application" or ("Module Suite Project" in older versions) and click Next. In the Name and Location panel, type "layerextensionpoints" in Project Name. Change the Project Location to any directory on your computer, to store the application. Click Finish. Now create four modules inside the suite, called "extensionpointinterface", "messagereader", "messageprovider1" and "messageprovider2": Choose File > New Project (Ctrl-Shift-N) again. Under Categories, select NetBeans Modules. Under Projects, select Module and click Next. In the Name and Location panel, type the name in Project Name (i.e., one of the four names listed at the start of this step). The default in the wizard should be to create the module underneath the directory where you just created the suite, which is fine. Click Next. In the Basic Module Configuration panel, replace the Code Name Base with de.eppleton.. Make sure to let the IDE create a layer file, by filling out the XML Layer field with de/eppleton//layer.xml. Click Finish. Here is what you should now see: Create a Service Provider Interface We will use the module "extensionpointinterface" to define an interface that will be used by the two extension point providers as well as by the "messagereader" module, which uses the two extension points. Inside that module create interface "MessageProviderInterface" with the single method getMessage() that returns a String: public interface MessageProviderInterface { public String getMessage(); } To make this part of the public API right click the project node, select API Versioning and select the check box of de.eppleton.extensionpointinterface. Now this package is accessible to other modules. Create Service Provider Implementations Now we need some modules that implement the MessageProviderInterface. We will use the modules "messageprovider1" and "messageprovider2" to do that. To implement the interface they both need a dependency on module "extensionpointinterface". For each of them do the following: Right click the project node, click Properties and, in the Project Properties dialog, select the "Libraries" category. Click "Add Dependency". Select "extensionpointinterface", and click "OK" twice. Now that we have access to the interface in our two message providers, we can implement it. Again, for both modules, do the following: Select "New" > "Java Class". In the Wizard type "MessageProvider1" or "MessageProvider2" in the Class Name field, respectively, and select the main package in each case, for stroring the new class. Implement the interface. Each of them should provide a different String. In other words, we will provide "Hello " in MessageProvider1 and then we will provide "World!" in MessageProvider2: import de.eppleton.extensionpointinterface.MessageProviderInterface; public class MessageProvider1 implements MessageProviderInterface { public String getMessage() { return "Hello "; } } import de.eppleton.extensionpointinterface.MessageProviderInterface; public class MessageProvider2 implements MessageProviderInterface { public String getMessage() { return "World!"; } } } In order to make our MessageProviders available as services, add these entries in the layer of the two modules. Between the the layer file's tags, add the following, i.e., in the first module add the first set of tags and add the second set of tags in the second module: and This will create an instance of our MessageProviders using the standard constructor. The trick is that those instances will be accessible from outside the modules, via the NetBeans System FileSystem. Now that you have created your services, the next step shows how you can access them, without even needing to set a module dependency for them. Find and Use the Service Providers We will use the module "messagereader" to display the messages provided by our two MessageProviders. To do so we will create a TopComponent, within the "messagereader" module: In the Project Properties dialog for "messagereader", set a dependency on "extensionpointinterface", exactly as shown earlier. Right-click on the "messagereader" project node and choose "New" > "Window Component". Choose "Output", which will determine where the new window will be displayed. Make it show on startup by ticking the checkbox. Click Next. Enter "MessageReader" for the class name prefix and click "Finish". The TopComponent class will open in Design View. Drop a JScrollPane from the palette in the window and make it fill the whole area. Add a JTextArea to it, making it fit the whole area too. In the source view (i.e., click "Source" at the top of the Design view) add this to the end of the constructor: Lookup lkp = Lookups.forPath("MessageProviders"); for (MessageProviderInterface mi : lkp.lookupAll(MessageProviderInterface.class)) { jTextArea1.append(mi.getMessage()); } The code above will lookup the folder you created via the layer file (Lookups.forPath("MessageProviders")), search for classes implementing the interface (lookupAll(MessageProviderInterface.class)) and call the interface method on all instances. Let’s try it out! Run the Module Suite. You will see the window either displaying "Hello World!" or "World!Hello ". As we can see in this very simple example, the order in which the ServiceProviders are called can be important for the result. So in the next step I will show you a trick to guarantee the correct order. Sort the Service Providers The NetBeans Platform provides a way to sort layer entries. This mechanism is used, for example, to provide the order of actions in menus and toolbars. Since 6.0, this is done via the position attribute in the layer file. So this won’t work in older versions: In the layer file of the two modules, insert the "position" attributes that you see below, i.e., the first set of tags below belongs to "messageprovider1", while the second belongs to "messageprovider2": and Now the messages will always be displayed in the correct order: "Hello world!". Simply swap these values to reverse the order of the messages. When you do something like this, make sure that you choose your values large enough to add services in between the initial ones, so that there’s room for your application to grow! Now try and see what happens when you set the same value for both attributes! Summary The intention of this article is to illustrate how simple it is to implement loose coupling in a NetBeans Platform application. Note that the module that uses the services (i.e., "messagereader") has no dependencies on the modules that provide the services ("messageprovider1" and "messageprovider2"). And not only does the NetBeans Platform provide a very simple mechanism to provide and lookup services, but it also provides an easy way to declaratively order them. Appendix: Alternative Registration Mechanism, Using "META-INF/services" In the previous sections, I showed how to register the Service Providers via the layer file. As stated correctly in the comment to this article, by Casper Bang, there's an alternative way to register the service providers. Using the META-INF/services folder is the standard approach that is supported by Java since version 1.3. This additional sections below show how it works. Register the Services There are only some small changes needed to change the registration mechanism: In module messageprovider1 create a folder via the context menu of "Source Packages" > "New" > "Other" > "Folder". Enter "META_INF/services" as Folder Name; the folder will show up like a normal package. Create a file via the context menu of this new package "META-INF.services" > "New" > "Other" > "Empty file", name the file "de.eppleton.extensionpointinterface.MessageProviderInterface". Edit the file and enter "de.eppleton.messageprovider1.MessageProvider1" Copy and paste the "META_INF" folder to the "Source packages" folder of module messageprovider2 and change the content of file "de.eppleton.extensionpointinterface.MessageProviderInterface" to "de.eppleton.messageprovider2.MessageProvider2" There are different ways to lookup the services. You can either use the default lookup to do so, or you can use the ServiceLoader mechanism introduced in Java 1.6. Let's begin with the method using the default lookup. Using Lookup to retrieve ServiceProviders The global lookup will automatically provide these services for you, so only a little change is needed. In the module "messagereader", edit "MessagereaderTopComponent", and replace this line: Lookup lkp = Lookups.forPath("MessageProviders"); with this line: Lookup lkp = Lookup.getDefault(); Afterwards, you can build and run the application as before. You may notice that the order of the services has changed. As before you can fix this by adding an additional position attribute when you define the ServiceProvider. Edit both "de.eppleton.extensionpointinterface.MessageProviderInterface" files in modules messageprovider1 and messageprovider2. Add the lines "#position=10" and "#position=20" respectively. Run the application and play with the values to change the order as before. Using ServiceLoader to Locate the ServiceProviders If you're using JDK 1.6 or later, you can edit "MessagereaderTopComponent" and replace the code we've added before with the following: ServiceLoader serviceLoader = ServiceLoader.load(MessageProviderInterface.class); for (MessageProviderInterface mi : serviceLoader) { jTextArea1.append(mi.getMessage()); } Note that the position attribute is now ignored, since it's not a part of the standard JDK but an extension added by the NetBeans Platform.
August 25, 2008
by Toni Epple
· 28,307 Views
article thumbnail
Reverse-Engineer Source Code into UML Diagrams
This article shows how easy and simple it is to include UML diagrams within your Javadoc and also keep them updated with every change in the source code repository.
August 22, 2008
by Meera Subbarao
· 220,977 Views · 1 Like
article thumbnail
The Concept of Mocking
Explore the importance of mocking, including mock objects.
August 16, 2008
by Michael Minella
· 65,197 Views · 5 Likes
article thumbnail
Execute Shell Command From Java
String cmd = "ls -al"; Runtime run = Runtime.getRuntime(); Process pr = run.exec(cmd); pr.waitFor(); BufferedReader buf = new BufferedReader(new InputStreamReader(pr.getInputStream())); String line = ""; while ((line=buf.readLine())!=null) { System.out.println(line); }
August 14, 2008
by Snippets Manager
· 105,985 Views · 2 Likes
article thumbnail
Creating SOAP Message Handlers in 3 Simple Steps - Part 1
This tutorial takes a look at SOAP Message handlers and how easy it is to write handlers using JAX-WS 2.0. JAX-WS 2.0 allows both regular Java classes and stateless EJBs(Session beans) to be exposed as web services. The JAX-WS 2.0 is the core specification that defines the web services standard for Java EE 5 specification. JAX-WS 2.0 is an extension of the Java API for XML-RPC (JAX-RPC) 1.0. SOAP message handlers are used to intercept the SOAP message as they make their way from the client to the end-point service and vice-versa. These handlers intercept the SOAP message for both the request and response of the Web Service. If you are familiar with EJB interceptors, handlers are similar to EJB interceptors and are defined in an XML file. A few typical scenarios where you would be using SOAP Message handlers are: to encrypt and decrypt messages, to support logging, caching and in some cases auditing, and in rare cases to provide transaction management as well. So much for the theory. Lets see the three basic steps to use a simple log handler to intercept and print our SOAP messages (request and response). In this tutorial, we are going to expose an EJB 3 stateless session bean as a web service which is simple and can be done by adding the @WebService annotation. So, here comes the source code for the interface as well as the implementation class which is self explanatory: Listing 1: Remote Interface package com.ws;import javax.ejb.Remote;/** * * @author meerasubbarao */@Remotepublic interface HelloWebServiceRemote { String sayHello(String name); } Listing 2: Bean Implementation package com.ws;import javax.ejb.Stateless;import javax.jws.WebMethod;import javax.jws.WebParam;import javax.jws.WebService;/** * * @author meerasubbarao */@WebService@Statelesspublic class HelloWebServiceBean implements HelloWebServiceRemote { @WebMethod(operationName = "sayHello") public String sayHello(@WebParam(name = "name") String name) { return "Hello " + name; } } You can package the two source files in a jar, deploy to your application server, and test it. Quite simple, right? For this tutorial, I am using GlassFish V2 application server and SoapUI to test my web services. Shown below are the request and response from SoapUI: Now that we know our web services work, lets start writing the message handler, which as I said earlier is just 3 steps. So, what are these SOAP message handlers? They are simple Java classes that can used to modify SOAP messages; both request as well as response. These handlers have access to both the SOAP header as well as the body of the message. Lets move on to create SOAP message handlers: Step 1. Implement the SOAPHandler interface. package com.ws;import java.io.IOException;import java.util.Collections;import java.util.Set;import java.util.logging.Level;import java.util.logging.Logger;import javax.xml.namespace.QName;import javax.xml.soap.SOAPException;import javax.xml.soap.SOAPMessage;import javax.xml.ws.handler.MessageContext;import javax.xml.ws.handler.soap.SOAPHandler;import javax.xml.ws.handler.soap.SOAPMessageContext;/** * * @author meerasubbarao */public class LogMessageHandler implements SOAPHandler { public boolean handleMessage(SOAPMessageContext messageContext) { return true; } public Set getHeaders() { return Collections.EMPTY_SET; } public boolean handleFault(SOAPMessageContext messageContext) { return true; } public void close(MessageContext context) { } The handleMessage() method is invoked for both incoming as well as outgoing messages. Lets add a new method called log() and invoke this method from the handleMessage method. Shown below are both the methods: private void log(SOAPMessageContext messageContext) { SOAPMessage msg = messageContext.getMessage(); //Line 1 try { msg.writeTo(System.out); //Line 3 } catch (SOAPException ex) { Logger.getLogger(LogMessageHandler.class.getName()).log(Level.SEVERE, null, ex); } catch (IOException ex) { Logger.getLogger(LogMessageHandler.class.getName()).log(Level.SEVERE, null, ex); } } In line 1, we are retrieving the SOAPMessage from the message context. Line 3 will print the incoming and outgoing messages in our GlassFish console. Invoke this method from within the handleMessage() as shown: public boolean handleMessage(SOAPMessageContext messageContext) { log(messageContext); return true; } Step 2: Create the XML file for the Handler Chain. Create this XML file in the same package as the web service with the name LogMessage_handler.xml. com.ws.LogMessageHandler com.ws.LogMessageHandler Lets take a close look at the various elements used above: 1. is the root element that will contain a list of all handler chains that are defined for the Web Service. 2. The child element of the element lists all the handlers in the handler chain. 3. Within the element is defined the , each handler element must in turn specify the name and also the fully qualified name of the Java class that implements the handler. If you have more than one handler, specify each one of them within the handler-chain element. Step 3: Invoking the Handler The @HandlerChain annotation is used to define a set of handlers that are invoked in response to a SOAP message. So, within our HelloWebServiceBean implementaion, you need to make a simple change to invoke the Log Handler as shown below in Line 1: package com.ws;import javax.ejb.Stateless;import javax.jws.HandlerChain;import javax.jws.WebMethod;import javax.jws.WebParam;import javax.jws.WebService;/** * * @author meerasubbarao */@WebService@Stateless@HandlerChain(file = "LogMessage_handler.xml") // Line 1public class HelloWebServiceBean implements HelloWebServiceRemote { @WebMethod(operationName = "sayHello") public String sayHello(@WebParam(name = "name") String name) { return "Hello " + name; } } We added the annotation for the handlers; lets recompile, repackage and redeploy the application. Now invoke the web service from SoapUI and see if it works. If it does, we should be able to see the request and response logged in our GlassFish console window. Here is the final output: **RemoteBusinessJndiName: com.ws.CustomerManagerRemote; remoteBusIntf: com.ws.CustomerManagerRemote LDR5010: All ejb(s) of [EJBWebServices] loaded successfully! Javalobby Hello Javalobby In this article, we saw how simple and easy it was to create and use SOAP Handlers to intercept request and response of SOAP messages. We implemented the SOAPHandler interface, wrote minimal XML to define the handler chain, and finally added one simple annotation to the web service implementation class. We were also able to test these web service using SoapUI. In Part 2 of this series, we will see how to actually parse the SOAP Headers, and also use multiple handlers. Stay tuned for more..
August 13, 2008
by Meera Subbarao
· 86,036 Views
article thumbnail
Service-Orientation vs. Object-Orientation: Understanding the Impedance Mismatch
Object-oriented programming languages and techniques provide a powerful means for designing and building applications. These techniques do not always translate well into a service oriented paradigm. Service orientation demands a different set of design guidelines and requirements than an object-oriented application. Understanding how an object-oriented design can negatively impact a service-oriented design is key to building services that support an agile enterprise. This article examines where the two designs impact each other as well as methods for addressing the incompatibilities between the two while still leveraging the power of both. by Larry Guger Introduction Object orientation is a good thing. I would like to believe that I write code in a well-defined object oriented manner, taking advantage of all the goodness that is provided, such as encapsulation, polymorphism and inheritance. These are important concepts that make modern software applications easier to develop, enhance and maintain. I’m sold. Service-orientation is a good thing too. As the industry moves toward service-orientation we naturally take along a lot of what we have learned over the years and apply this to the new way of doing things. Visual Studio, the .NET framework, and especially Windows Communication Foundation (WCF) support the development of service-oriented applications. This was one of the core design goals behind WCF, but moving from object-oriented design techniques to service-oriented design techniques is not without its challenges. Part of the reason can be apportioned towards the tooling. We have very mature tools to support object-oriented design and development but fewer tools that emphasize service-oriented design. This is partly because we, as an industry, are still really figuring out what service-orientation really means. This article explores what I am referring to as the “impedance mismatch” between the two design paradigms. Note: Most of the concepts and ideas presented are not specific to .NET or Visual Studio until I refer to the namespace generation problem later in the discussion (as it manifests itself in Visual Studio). However, it is worth noting that this problem can present itself on any platform. Designing an OO System Here is an example of one model that would make sense in the object-oriented world: Figure 1 Figure 1 is a simplified model designed to support some form of purchasing functionality provided by the application. A customer contains a mailing address and a shipping address and the customer can also hold many contracts with the company that is supplying products. The customer is able to place orders against these contracts with any given order containing one or more line items each of which is an order for a product. In addition, the model permits the developer to navigate from a PurchaseOrder object to the Contract under which the order was placed by using an object reference. Likewise, a Contract will contain a collection of all of the PurchaseOrders placed under it. This model is also repeated between the Customer and its Contracts as well as PurchaseOrders and OrderLineItems. We now have a nice object model that permits navigation between related objects in any direction. Service Enablement In a distributed computing environment such as is found in almost every enterprise today there is a business logic/service tier that resides on some central server farm that exposes services for working with the contained business functionality. This service tier is accessed by a client tier, whether the client is a Web application, a rich client application or a B2B service implementation. To support the object model above, one can imagine a collection of services that are targeted at a handful of business needs: customer services, contract services and order services. Each of these services has its own endpoint with a few methods to support working with each of the primary business types identified. To be specific, a service could be developed to support working with customer data that would contain methods such as CreateCustomer, SearchCustomers, and GetCustomer. Each of these methods would either accept or return customer objects and if you retrieved a customer object using the GetCustomer service you could inspect the contracts that the customer has as well as the orders placed under each contract. Chances are that if you retrieved a customer using the GetCustomer method you would not be getting the populated contract objects along with it at that time. You would need to make additional calls to retrieve individual contracts and associated orders if that was the information you were after. The same concept should hold for working with contracts or orders. As you can see, the object hierarchy is maintained. Assuming that this is the approach taken and the GetCustomer method returns a serialized object of type Customer once that customer object is deserialized in the client application it is easy enough to create contract objects, attach them to the contracts collection on the customer and create order objects and attach them to the contract objects and we have the same object oriented goodness on the client as we have on the server. This is a standard approach when first building service enabled applications. Unfortunately this does not work well for service-oriented applications that are intended to be reused throughout the enterprise for other purposes beyond the initial application. Here’s why. Service Referencing Let’s think about developing the client side portion of our application, whether it is a web, WinForms or WPF application does not matter. To begin, we create a user interface for dealing with all things related to customers. We can create new customers, modify existing ones and search for customers based on various criteria. Once we have the user interface defined we add a service reference, using Visual Studio, to our previously created service which in turn generates our classes and proxies. We instantiate objects, add data supplied by the user and submit these objects to our services. Pretty standard stuff. Next we move on to developing the portion of the user interface that deals with contracts. We follow the same pattern and things are working well until we get to a namespace collision. When we added a reference to the customer related service, Visual Studio generated code for the classes that make up the return types and the request types our service supports. This will include all of the serializable types in the customer object graph. When we add a reference to the contract service, Visual Studio will generate the code for the classes that make up the return and request types that this service supports. This will also include all of the serializable types in the contract object graph. In other words we end up with generated code for all of the classes described above twice! This is because each reference generates the classes in a distinct namespace. Even if you use the same reference name Visual Studio will alter them slightly to make them distinct. For example if both the first and second service references are given the name “localhost”, Visual Studio will append a “1” to the end of the first reference making the namespace begin with “localhost1”. You now have two Customer classes, localhost.Customer and localhost1.Customer, as well as two of every class in the respective object graphs. Now your code is duplicated and stored in different types. You cannot create an instance of a localhost.Customer object and assign it to a variable of type localhost1.Customer. Not only do you not get object compatibility but you also end up with a whole bunch of equivalent classes under different namespaces. There are a few commonly used ways to deal with this problem: 1. Add a reference to the assembly that contains your objects to your UI projects, and alter the service references to use that/those assemblies rather than generating the code. 2. Alter the generated code to remove the duplicates. 3. Alter the code generation process to reference the assemblies containing your data objects. 4. Develop mapping code to translate from one type to another. There are challenges with all of these. The first and third options may not be possible if you don’t have access to the assemblies, perhaps you are referencing services that you did not develop, and perhaps the objects contain code that shouldn’t reside on the UI side of things such as database access logic. The second option is simply fraught with perils as the code will be updated and need re-altering after every reference update, and if this is in mid development there may be many updates. The fourth option adds extra work and who needs extra work? The Service-oriented Approach The correct approach is to avoid these problems completely when developing your services. Here’s how. A Customer service should know about customers and data directly related to a customer only. Your Customer service methods should return a slightly different object graph than the object graph defined above. You will still have the customer object and you will still have the addresses for that customer but that’s it. Break the graph at the collection of contracts. When the client requires the contracts for a customer they need to submit a request to the Contract service asking for the contracts for a particular customer. This should actually be the same approach regardless of the object graph in use. Whether the customer explicitly asks for the contracts or the system hides the implementation details and makes the call to retrieve contracts are simply implementation details. The fact that the object graph does not contain direct links to the contracts would not impact the user experience. Let me explain. Regardless of the size of the object graph in use it should be a rare case in which the entire graph is populated and returned by a service call. Generally you will find that only a portion of the objects are in use for any given user action. To minimize the amount of data that is sent over a network only the relevant objects should be populated and returned. The code that is developed on the client side takes the responsibility for calling the appropriate services to populate further objects in the graph as the user requests them - this is often termed “lazy loading”. The goal of “lazy loading” is to retrieve only the data that is required so as to improve performance of the application. In fact, the simplified object graph better supports this design approach than the more complex graph does. With the complex graph, if you have a Contract object and need to perform some work with the related Customer for that contract you still need a sparsely populated Customer object that contains, at a minimum, the customer Id that can be used to retrieve the full customer object from the service. With the simplified graph the Contract class contains a customer Id directly. The relations between the objects are still maintained, however with the simplified version the relationships are more explicit than implicit, as they are with the complex version. To bring this back to the user experience, the user should not know whether the underlying code has been developed using the simplified or complex graph. They should be able to navigate from a contract to the related customer just as easily. It is up to you, the developer, to make this experience seemless. Figure 2 Again the object graph is kept simple as shown in Figure 2. As with the customer, contracts would not maintain a full customer object reference as part of the contract definition on the client side of the equation. A Contract object passed from the service would consist of only itself, no customer, and no PurchaseOrders. In place of the customer reference each contract object would maintain the customer identifier so as to be able to uniquely identify which customer the contract belongs to and provide the means to “navigate” to the customer object when required. As a side note, when requesting the collection of contracts for any given customer the collection of data returned should only consist of enough data in each object to uniquely identify the contract being sought, whether these objects are sparsely populated contract objects or a “light” version of the contract class does not really matter. You can then query for the full contract object based on the unique identifier that would be part of the collection of query results from the first request that returned the collection. Again, these are implementation details that are hidden from the user experience and need to be determined based on application needs. The End Result The end results of using this approach are: • Returned result data is kept to the relevant bits. Even though this goal can still be achieved with a more complex object graph this approach enforces it. • When adding a service reference using tools like Visual Studio the generated classes have a smaller object graph which avoids having multiple identical classes in different namespaces. • Cleaner separation of duties. Once you have adjusted to using this approach you will find that you need to create a mapping layer just behind the services - to map to and from the interfaces exposed by the services and your more complex object graphs. Either that or you can use simpler object graphs on the server side. However, these simple object graphs may not provide the functionality needed by the consumer of the service, especially if the consumer is a rich client application. In that case, a more complex object model can be designed and mapped to the simpler objects returned by the service. This keeps the service architecture simple while allowing the ability to use all of the OO principles that we’ve learned over the years. When it’s not needed, the simpler objects can simply be used as is with no additional work required. By keeping the server side object graphs at the same simplicity as the service interfaces you will find that your code becomes cleaner, more modular, your classes become more cohesive and there is less coupling between your objects. In addition, the flexibility to reuse the customer service with other services which rely on customer information, but are sourced from a different repository, is easier to achieve. Merging multiple customer data systems into a single customer service also becomes much easier if the customer data is de-coupled from any other data. This now leads to a potential increase in service-orientation reuse, and a happier enterprise. Conclusion Both object oriented and service-oriented design and develop techniques have their place in modern systems development. Object oriented systems fit well in a stateful environment while a service-oriented approach requires a stateless environment. There is nothing wrong with the strong object oriented approach as described at the start of this paper however it will not serve you well if you try and expose those object graphs through a service. With years of OO experience it’s easy to fall into OO design by default, but when designing systems we need to shift our mindset and think about what we are designing for. If it’s an SOA system, a traditional OO approach may not be the best. The tight coupling will get you in trouble as you expand the reach and reuse of your services throughout your enterprise. Keep the interfaces into your services simple and focused and you will find that your services become much easier to manage and become much more scalable. To summarize, OO is, by its nature, stateful while SOA is, by its nature, stateless. This is where the impedance mismatch shows itself.
July 31, 2008
by Masoud Kalali
· 43,753 Views
  • Previous
  • ...
  • 885
  • 886
  • 887
  • 888
  • 889
  • 890
  • 891
  • 892
  • 893
  • 894
  • ...
  • 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
×