Javabeans: Seminar Report Antoniol, Sandro, Tie04
Javabeans: Seminar Report Antoniol, Sandro, Tie04
Abstract This report has been written as a part of the seminar Enterprise Computing assignment. The aim of this report is to make a detailed examination of JavaBeans, a component model in the Java world. After giving a brief overview of what JavaBeans are and what they can be used for, we will look at the concepts of JavaBeans. This includes, but is not limited to: properties, events and methods, introspection, long term persistence, and BeanContexts. Samples are given to facilitate the comprehension of the topics. To avoid showing only loose code snippets with no or only little relation to each other, a FontSelector JavaBean will be developed step by step through this report. The resulting Bean allows selecting conveniently a font and setting the font-size. Image 1 depicts the nal product.
Figure 1: The FontSelector JavaBean Please note, that this report is target to experienced programmers. Keywords such as observer pattern, serialization, AWT, Swing and reection should be known by you.
Seminar Report
Contents
1. Introduction to JavaBeans 1.1. Denition of a software component 1.2. Denition of a builder tool . . . . . 1.3. JavaBeans at a glance . . . . . . . 1.4. JavaBeans basic rules . . . . . . . 2. Beans Architecture 2.1. Properties . . . . . . . 2.2. Simple Properties . . . 2.3. Indexed Properties . . 2.4. Bound Properties . . . 2.5. Constrained Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 4 4 5 6 6 6 7 7 8 9
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
3. Events and Methods 11 3.1. Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 4. Instrospection 4.1. Methods of the BeanInfo class . . . . . . . . . 4.1.1. Events . . . . . . . . . . . . . . . . . . 4.1.2. Properties . . . . . . . . . . . . . . . . 4.1.3. Method . . . . . . . . . . . . . . . . . 4.2. Personalized Bean information with BeanInfo 13 13 13 13 13 14
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
5. Persistence 15 5.1. Long-term persistence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 5.2. Bean Reconstitution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 6. BeanContext 7. The Beans class 8. Conclusion 9. References A. Sample BeanContext applicaton 16 17 18 19 20
Sandro Antoniol
Page 3/24
Seminar Report
1. Introduction to JavaBeans
To start with I would like to quote a sentence from the ocial JavaBeans API specication, which gives a rst denition of what JavaBeans are: A JavaBean is a reusable software component that can be manipulated visually in a builder tool. Even though this quote seams to be quite simple, we have to clarify what is meant by software component and builder tool in order to be able to fully understand the quotes statement.
Sandro Antoniol
Page 4/24
Seminar Report
which even allows you to develop an application consisting of JavaBeans without writing a single line of code (in best case). Figure 2 depicts the property sheet provided by NetBeans when the FontSelector JavaBean is selected.
Sandro Antoniol
Page 5/24
Seminar Report
cation ensures that builder tools can assist a developer to work with JavaBeans. Thus for many solutions you can either develop a conventional Java class where you have to write your own code for setting its properties or you can build a JavaBean which allows you to set the properties through the builder tool. Eventually both methods result in code just that in the latter case the builder tool creates the code automatically in the background according to your selection(s). And as already mentioned in the best case you do not even have to write a single line of code.
2. Beans Architecture
2.1. Properties
Properties are named public attributes which determine the internal state of a JavaBean and thus its behavior and appearance. For example, a GUI texteld might have a property named maxlength which restricts the number of characters one can insert into the texeld. There exist four dierent kinds of properties a JavaBean can expose: Simple Indexed Bound Constrained All types of property have in common that they are characterized by a pair of set/get methods. A getter method is used to read the value of a readable property. Its name has to start with get, as you will see later on. To update the propertys value a setter method has to be called. Analog to the getter-method its name has to start with set. If a property should be read-only the latter method has to be left out. On the other side, if the property should be write-only no getter-method has to be written. The propertys name is determined by the name used in the pair of methods. Typically the value of a
Sandro Antoniol
Page 6/24
Seminar Report
property is stored in a private instance variable whose name matches the name of the property. But this is not a requirement. How you name the instance variable used in conjunction with the property is up to you. The data type of the property can be a built-in type as well as a custom class or interface. The following code snippet shows the naming pattern for the discussed set/get methods:
public void set < Propertyname >( < Datatype > param ){?} public < Datatype > get < Propertyname >(){?}
Changing a property may also lead to other actions. For instance, updating the background color property of a JavaBean might cause a repainting of the bean with its new color.
If the propertys data-type is boolean the get methods can also be named is<Propertyname>. We use a boolean variable to dene whether the user can make a selection or not.
private boolean enabled ; public void setEnabled ( boolean enabled ){ this . enabled = enabled ; } public boolean isEnabled (){ return enabled ; }
Sandro Antoniol
Page 7/24
Seminar Report
public PropertyType g e t P r op e r t y N a me ( int position ) // indexed getter public void s e t Pr o p e r t y Na m e ( PropertyType element , int position ) // indexed setter public PropertyType [] g e t P r op e r t y N a me () // array getter public void s e t Pr o p e r t y Na m e ( PropertyType [] list ) // array setter
The indexed methods may throw a java.lang.ArrayIndexOutOfBoundsException runtime exception in case the requested index is outside the current array bounds. Our FontSelector bean has a string array of font names a user can choose from. The code for that looks as following:
private String [] fonts ; public void setFonts ( String [] fonts ) { this . fonts = fonts ; } public String [] getFonts () { return fonts ; } public String getFonts ( int pos ){ return fonts [ pos ]; }
PropertyChangeListener is an interface declared in the java.beans package. Observers which want to be notied of property changes have to implement this interface, which consists of only one method:
public interface P r o p e r t y C h a n g e L i s t e n e r extends EventListener { public void pr op er tyC ha ng e ( P r o p e r t y C h a n g e E v e n t e ); }
Even though we could organize the list of observers by ourselves the beans package oers a class named PropertyChangeSupport which takes over this job for us. Apart
Sandro Antoniol
Page 8/24
Seminar Report
from having methods to add/remove listeners it possesses various methods to notify the registered observers about a changed property. In the code shown above the variable referring an instance of this support class is named changes. The declaration code for it looks like this:
private P r o p e r t y C h a n g e S u p p o r t changes = new P r o p e r t y C h a n g e S u p p o r t ( this );
Our FontSelector informs about changes of the currently selected font. Of course it would be wise to make any property a bound property. However in our case we limit it to one property in order to keep it simple. As you will see in the code below, ring a notication requires the information which property has changed, what its old value was and what its new value is.
private boolean bold ; public void setBold ( boolean bold ){ if ( this . bold != bold ){ boolean wasBold = this . bold ; this . bold = bold ; boldBtn . setSelected ( bold ); // Notify P r o p e r t y C h a n g e L i s t e n e r s : f i r e P r o p e r t y C h a n g e ( " bold " , wasBold , bold ); } } public boolean isBold (){ return bold ; }
At this stage it is important to note that in this example there is only one instance for all bound properties. Thus an observer can not enroll just for the notication of a particular property. All enrolled observers are notied of any changed bound properties. As a result, every observer needs to check on notication whether the property that changed was the one the observer was expecting or something else. This can be easily done by using the getPropertyName() method of the PropertyChangeEvent object which is passed to the observer.
Sandro Antoniol
Page 9/24
Seminar Report
private V e t o a b l e C h a n g e S u p p o r t vetoes = new V e t o a b l e C h a n g e S u p p o r t ( this ); public void a d d V e t o a b l e C h a n g e L i s t e n e r ( V e t o a b l e C h a n g e L i s t e n e r v ) { vetoes . a d d V e t o a b l e C h a n g e L i s t e n e r ( v ); } public void r e m o v e V e t o a b l e C h a n g e L i s t e n e r ( V e t o a b l e C h a n g e L i s t e n e r v ) { vetoes . r e m o v e V e t o a b l e C h a n g e L i s t e n e r ( v ); }
By convention the set method must not handle the exception a vetoed observer threw, rather it has to be forwarded. Hence the set method has to be declared to throw the PropertyVetoException exception. private int currentFontSize;
private int fontSize = 11; public void setFontSize ( int newFontSize ) throws P r o p e r t y V e t o E x c e p t i o n { if ( fontSize != newFontSize ){ // Notify V e t o a b l e C h a n g e L i s t e n e r : f i r e V e t o a b l e C h a n g e ( " fontSize " , fontSize , newFontSize ); int oldFontSize = fontSize ; fontSize = newFontSize ; // Raise event : ( see chapter Events & Methods ) n o t i f y F o n t S i z e C h a n g e d L i s t e n e r s ( newFontSize ); // It s good practise to be a bound property as well : f i r e P r o p e r t y C h a n g e ( " fontSize " , oldFontSize , newFontSize ); } } public int getFontSize () { return fontSize ; }
As shown in the code above the property does not only notify the VetoableChangeListeners but also the PropertyChangeListeners after the change has been performed. Even though not beeing required it is recommend by the specication that if a property is constrained it is also bound.
Sandro Antoniol
Page 10/24
Seminar Report
In the following we create an event FontChanged which will be red when a user changes the font size.
import java . util . EventObject ; public class F o n t S i z e C h a n g e d E v e n t extends EventObject { private int newFontSize ; public F o n t S i z e C h a n g e d E v e n t ( Object source , int newFontSize ) { super ( source ); this . newFontSize = newFontSize ; } // Note : how you call the methods is up to you . public int ge tN ew Fon tS iz e () { return newFontSize ; } } public interface F o n t S i z e C h a n g e d L i s t e n e r extends java . util . EventListener {
Sandro Antoniol
Page 11/24
Seminar Report
public void f o n tS i z e C h a ng e d ( F o n t S i z e C h a n g e d E v e n t e ); }
// Code FontSelector JavaBean : // Note , that the code for the property has already been shown in the property chapter // and is just repeated at this point for completion . private LinkedList < FontSizeChangedListener > f o n t S i z e C h g L i s t e n e r s = new LinkedList < FontSizeChangedListener >(); private int fontSize = 11; public synchronized void a d d F o n t S i z e C h a n g e d L i s t e n e r ( F o n t S i z e C h a n g e d L i s t e n e r l ){ f o n t S i z e C h g L i s t e n e r s . add ( l ); } public synchronized void r e m o v e F o n t S i z e C h a n g e d L i s t e n e r ( F o n t S i z e C h a n g e d L i s t e n e r l ){ f o n t S i z e C h g L i s t e n e r s . remove ( l ); } protected void n o t i f y F o n t S i z e C h a n g e d L i s t e n e r s ( int newFontSize ){ LinkedList < FontSizeChangedListener > listeners = ( LinkedList < FontSizeChangedListener >) f o n t S i z e C h g L i s t e n e r s . clone (); for ( F o n t S i z e C h a n g e d L i s t e n e r l : listeners ) l . fo n t S i z e Ch a n g e d ( new F o n t S i z e C h a n g e d E v e n t ( this , newFontSize )); } // Constrained Property public void setFontSize ( int newFontSize ) throws P r o p e r t y V e t o E x c e p t i o n { if ( fontSize != newFontSize ){ // Notify V e t o a b l e C h a n g e L i s t e n e r : f i r e V e t o a b l e C h a n g e ( " fontSize " , fontSize , newFontSize ); int oldFontSize = fontSize ; fontSize = newFontSize ; fo nt Si zeS li de r . setValue ( newFontSize ); // Raise event : n o t i f y F o n t S i z e C h a n g e d L i s t e n e r s ( newFontSize ); // It s good practise to be a bound property as well : f i r e P r o p e r t y C h a n g e ( " fontSize " , oldFontSize , newFontSize ); } }
3.1. Methods
Regarding methods there are no special rules for JavaBeans. If a method is public it can be called from other components and it even allows a JavaBean to become a listener of other Beans event(s) provided it implements the appropriate interface.
Sandro Antoniol
Page 12/24
Seminar Report
4. Instrospection
As described in the introduction, builder tools typically provide a property sheet where one can conveniently set the properties of a JavaBean component or connect event listeners to an exposed event. In order to provide this service a builder tool needs to examine the component for its features (=properties, events and methods). This process is referred to as introspection. To obtain information about a specic JavaBean one can use the static getBeanInfo() method of the Introspector class. This method returns an instance of the BeanInfo class, which describes all features a JavaBean exposes. The use of this method is shown in the following code fragment:
FontSelector fs = new FontSelector (); BeanInfo bi = Introspector . getBeanInfo ( fs . getClass ());
The most important methods of the BeanInfo object will now be described in the following sections.
4.1.2. Properties The determination of properties works similar to the event determination. The method getPropertyDescriptors() returns an array of PropertyDescriptors reporting all properties of a Bean.
P r o p e r t y D e s c r i p t o r pd [] = bi . g e t P r o p e r t y D e s c r i p t o r s (); for ( int i =0; i < pd . length ; i ++) System . out . print ( pd [ i ]. getName () + " " );
4.1.3. Method Its no surprise that the methods determination works the same way just with dierent names. Note, that only public methods of the Bean will be reported. For each method
Sandro Antoniol
Page 13/24
Seminar Report
descriptor, the parameters types for the described methods can be discovered through the getParameterDescriptors() method.
M e t h o d D e s c r i p t o r md [] = bi . g e t M e t h o d D e s c r i p t o r s (); for ( int i =0; i < md . length ; i ++) System . out . print ( md [ i ]. getName () + " " );
Sandro Antoniol
Page 14/24
Seminar Report
5. Persistence
Persistence is the ability of an object to store its state. [5] JavaBeans use the Java Serialization API to gain this ability. The simplest way to enable serialization of a Bean is by implementing the Serializable interface. The points you have to consider when declaring a Bean to be serializable are the same as for any other serializable object (e.g. how to deal with transient and static variables, whether a validation is required upon deserialization etc.). The greatest strength of persistence regarding JavaBeans lies in the ability to create prototypes a new JavaBean can be instantiated from. For example, a Java application using our FontSelector Bean can serialize the Bean on a Microsoft Windows machine, the serialized le can be sent to a Linux machine, where another Java application can instantiate a new Bean with the exact state (same fonts, fontsize etc.) its counterpart had on the Windows machine. Although serialization is a convenient way to persist a JavaBean this method has a downside. Serialization is intended to persist an object for a short time, for example to transfer the object to a remote machine through Java RMI (Remote Machine Invocation). But JavaBeans are typically persisted to serve as a prototype that requires a mechanism for long-term persistence. The solution is to represent the JavaBean in a XML structure, which is topic of the next section.
Sandro Antoniol
Page 15/24
Seminar Report
< void index = " 0 " > < string > Arial </ string > </ void > < void index = " 1 " > < string > Verdana </ string > </ void > < void index = " 2 " > < string > Times </ string > </ void > </ array > </ void > </ object > </ java >
However, this method can not be used if a bean has been stored in XML format. In this case the XMLDecoder class has to be used for reading the XML le and returning the reconstituted object.
XMLDecoder decoder = new XMLDecoder ( new B u f f e r e d I n p u t S t r e a m ( new F i l eI n p u t S t re a m ( " FontSelector . xml " ) ) ); FontSelector fs = ( FontSelector ) decoder . readObject (); decoder . close ();
6. BeanContext
A set of related JavaBeans can be logically grouped into a context. This context can be thought of as a containing environment and is known as BeanContext. As stated in Suns tutorial about using the BeanContext API, there are two distinct types of BeanContexts: one which supports membership only (interface java.beans.beancontext.BeanContext) and one which supports membership and offers services (interface java.beans.beancontext.BeanContextServices) to its JavaBeans nested within. BeanContexts follow the Composite Pattern, where BeanContext classes are the composite. Thus a BeanContext can not only host JavaBeans but also BeanContext objects.
Sandro Antoniol
Page 16/24
Seminar Report
For each interface the BeanContext API oers a helper class with the basic BeanContext and the BeanContextServices functionality respectively. For the BeanContext interface the helper class is called BeanContextSupport and for the BeanContextServices interface BeanContextServicesSupport. As both classes implement the Collection interface, they can be handled like a collection in terms of adding, removing and retrieving JavaBeans. In case a JavaBean wishes to obtain a reference to its context when being added to the context it shall implement the BeanContextChild interface. In the following we focus on the BeanContextServicesSupport class. As already mentioned this class oers services to its hosted beans. The services are supplied by so called service providers, which can be registered with the context via the contexts addService() method. JavaBeans that implement the java.beans.beancontext.BeanContextServicesListener interface and have been registered as a BeanContextServicesListener will be notied of new added services. JavaBeans can query the context they are residing in for a list of available services (getCurrentServiceClasses() ), or ask for a specic service by name using the getService() method. In a hierarchy of contexts a service request will be forwarded to the parent context if the request can not be fullled. A registered service can also be removed from a context via the contexts removeService() method. In Appendix A an example application illustrates the use of the BeanContext functionality. The example has been taken from Suns JavaBean Tutorial and has no relation to the FontSelector JavaBean which has been referred to in other code fragments shown in this report.
Sandro Antoniol
Page 17/24
Seminar Report
8. Conclusion
This report addressed various aspects of the development of JavaBeans. We introduced the term of software components and got to know what JavaBeans are and what their aim is. We got acquainted with the JavaBean specication API and learned how to obtain information about a JavaBean and how we can inuence this information. Moreover we examined the methods to persist a JavaBean, described the BeanContexts and some methods of the Beans class. However, as already announced in the abstract, not all aspects could be covered in this report. The interested reader is kindly referred to Suns JavaBeans Tutorial for more information, for example, about how to provide a dialog for customizing a JavaBean (referred to as Bean Customization). The tutorial can be found at: http://java.sun.com/docs/books/tutorial/javabeans
Sandro Antoniol
Page 18/24
Seminar Report
9. References
[1] Cervantes, H. (2002). The JavaBeans Component Model Retrieved March 30, 2007, from http://www.humbertocervantes.net/beansdiscussion.html [2] Englander, R. (1997). Developing Java Beans Retrieved March 30, 2007, from http://www.oreilly.com/catalog/javabeans/chapter/ch01.html [3] Prof. Dr. Ostermann, K.; Dipl.-Inform. Aracic, I.; Dipl.-Inform. Kloppenburg, S. (2006). Introduction to JavaBeans Component Model Retrieved April 1, 2007, from http://www.st.informatik.tu-darmstadt.de/pages/lectures/sct/ss06/lectures/V2 JavaBeans.pdf [4] MageLang Institute. (1997). JavaBeans Short Course: Introduction to JavaBeans Retrieved March 24, 2007, from http://java.sun.com/developer/onlineTraining/Beans/JBShortCourse/beans.html [5] Sun. (2006). JavaBeans(TM) (The JavaT M Tutorials) Retrieved March 24, 2007, from http://java.sun.com/docs/books/tutorial/javabeans
Sandro Antoniol
Page 19/24
Seminar Report
Sandro Antoniol
Page 20/24
Seminar Report
DocumentBean.java: A JavaBean that encapsulates a File object. Create an instance of this bean by passing it a String indicating the name of the text file to represent. This bean extends BeanContextChildSupport, which allows it to listen for addition/revocation of services in its context. When the bean detects that a WordCount service has been added to the context, it requests the service to count the number of words it contains. WordCountServiceProvider.java: A class that acts as the factory for delivering the WordCount service. This class implements the BeanContextServiceProvider interface. WordCount.java: This interface defines the service itself. DocumentTester.java: The main test program.
import java.beans.beancontext.*; import java.io.*; import java.util.*; /** * A JavaBean that encapsulates a text file. When added to a bean context, * this bean listens for a WordCount service to become available. When * the service does become available, the DocumentBean requests an * instance of the service. The service then counts the number of words in the file, * and prints a report to standard output. */ public final class DocumentBean extends BeanContextChildSupport { private File document; private BeanContextServices context; /** * Creates a new DocumentBean given the name of the file to read from. * @param fileName the name of the file to read from */ public DocumentBean(String fileName) { document = new File(fileName); } /** * Called when this bean detects that a new service * has been registered with its context. * * @param bcsae the BeanContextServiceAvailableEvent */ public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) { System.out.println("[Detected a service being added to the context]"); // Get a reference to the context BeanContextServices context = bcsae.getSourceAsBeanContextServices(); System.out.println("Is the context offering a WordCount service? " + context.hasService(WordCount.class)); // Use the service, if it's available if (context.hasService(WordCount.class)) { System.out.println("Attempting to use the service..."); try { WordCount service = (WordCount)context.getService(this, this, WordCount.class, document, this); System.out.println("Got the service!"); service.countWords(); } catch(Exception e) { }
File: DocumentBean.java
Sandro Antoniol
Page 21/24
Seminar Report
} } /** * Called when this bean detects that a service * has been revoked from the context. * * @param bcsre the BeanContextServiceRevokedEvent */ public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) { System.out.println("[Detected a service being revoked from the context]"); } }
File: WordCountServiceProvider.java
import java.beans.beancontext.*; import java.util.*; import java.io.*; /** * This class is the factory that delivers a word counting service. * The 3 methods defined in this class are the concrete implementations * of the BeanContextServiceProvider interface. For this demonstration, the primary * method of interest is getService(). The getService() methods returns a new * WordCount instance. It is called by the bean context when a nested * JavaBean requests the service. */ public final class WordCountServiceProvider implements BeanContextServiceProvider { public Object getService(BeanContextServices bcs, Object requestor, Class serviceClass, Object serviceSelector) { // For this demo, we know that the cast from serviceSelector // to File will always work. final File document = (File)serviceSelector; /* Return an instance of the service. The service itself is * the WordCount interface, which is implemented here using * an anonymous inner class. */ return new WordCount() { public void countWords() { try { // Create a Reader to the DocumentBean's File BufferedReader br = new BufferedReader(new FileReader(document)); String line = null; int wordCount = 0; while ((line = br.readLine()) != null) { StringTokenizer st = new StringTokenizer(line); while (st.hasMoreTokens()) { System.out.println("Word " + (++wordCount) + " is: " + st.nextToken()); } } System.out.println("Total number of words in the document: " + wordCount); System.out.println("[WordCount service brought to you by WordCountServiceProvider]"); br.close(); } catch(Exception e) { } } }; }
Sandro Antoniol
Page 22/24
Seminar Report
public void releaseService(BeanContextServices bcs, Object requestor, Object service) { // do nothing } public Iterator getCurrentServiceSelectors(BeanContextServices bcs, Class serviceClass) { return null; // do nothing } }
File: WordCount.java
/** * The WordCount service. Implementations of the * countWords() method are provided by the * WordCountServiceProvider class. */ public interface WordCount { /** * Counts the number of words in the file. */ public abstract void countWords(); }
File: DocumentTester.java
import java.beans.beancontext.*; import java.util.*; /** * A test program that creates all of the objects, * a tests the service capabilities. Run this program * from the command line using java DocumentTester */ public class DocumentTester { public static void main(String[] args) { BeanContextServicesSupport context = new BeanContextServicesSupport(); // a bean context DocumentBean doc1 = new DocumentBean("Test.txt"); context.add(doc1); context.addBeanContextServicesListener(doc1); // listen for new services WordCountServiceProvider provider = new WordCountServiceProvider(); context.addService(WordCount.class, provider); // add the service to the context } }
File: Test.txt
This text will be analyzed by the WordCount service.
Output:
[Detected a service being added to the context] Is the context offering a WordCount service? true Attempting to use the service... Got the service! Word 1 is: This Word 2 is: text Word 3 is: will
Sandro Antoniol
Page 23/24
Seminar Report
Word 4 is: be Word 5 is: analyzed Word 6 is: by Word 7 is: the Word 8 is: WordCount Word 9 is: service. Total number of words in the document: 9 [WordCount service brought to you by WordCountServiceProvider]
Sandro Antoniol
Page 24/24