Introduction to Pop Framework

Lin Fang
Download pop2.0.3.jar View API online
  commons-logging.jar Get offline API
  log4j-1.2.15.jar

Content

  1. What's Pop Framework
  2. Bean
  3. MVC

What's Pop Framework

Pop Framework (or shortly, Pop) is a bean-based MVC framework for Java/J2EE web applications. Similar to other frameworks, Pop implements IoC, Dependency Injection, and AOP. Pop also provides some annotations for users to define and reference a bean. The difference is that the Pop can help users to customize a bean, a scope, a factory and a reference in object-oriented way.

The 2nd major difference between Pop and other MVC framework is that the beans can be referenced by MVC of Pop directly. In viewpoint of Pop MVC, the model of a web page (such as a JSP or a servlet) is a bean. The JSP/servlet itself is considered as a view of the bean. The model provides the data for the view, the view is responsible for rendering the data. The Pop itself acts as the general-purposed controller for all views and models.

The 3rd major difference is that the hyperlink in Pop is represented by bean reference instead of URL. You can, for example, set the href of an <a> to a bean name, in a JSP or a servlet. That means, when the <a> is clicked by an end-user in a browser, the Pop in server-side will try to look for the bean of that name. If the bean is found, the corresponding view for the bean will be rendered to the client-side along with the data the bean provides.

By this way, a view needn't to know about any other models/views including those it comes from and those it will go to, needn't to worry about the number and the types of the parameters it transfers to or gets from other models/views. The only task of a view is to decorate and render the data the model provides. View developers and model developers can therefore focus on their own works. Models and views are all loosely coupled, and can be developed in parallel. Each view and each model can therefore be maintained and optimized independently.

Because models and views are loosely coupled in Pop, a model can have multiple views. The views in different devices can therefore share a same model. And moreover, you can provide multiple languages of views for a same model without necessary to worry about how to update the corresponding hyperlinks defined in other views.

For more details about Pop's Bean and MVC, please refer to the related sections shown in below.


Bean

Class BeanCenter

Class BeanCenter is the only entry point for you to use Pop. In a normal Java application, please invoke the BeanCenter.loadBeans() method to load beans defined in a package, and then invoke one of the getBeans methods to reference them. In Pop's MVC, BeanCenter is already involved in the MVCServlet, beans are loaded automatically and can be referenced by hyperlinks directly. So you needn't to use it directly in most cases.

Define a bean

There are three ways to define a bean in Pop:

Attributes of @BeanDef

There are 3 attributes for a @BeanDef:

Please note that the 3 attributes are all optional.

Scope

The scope of a bean means the lifetime and the access scope of a bean. For example, the SessionScope means that the bean is stored in an HTTP session once it is created. So the bean is accessible only in current session and will be destroyed automatically as soon as the session is expired. Any other sessions can not access it.

From the viewpoint of a programmer, the scope of a bean tells how to locate a bean, including how to create it first time it is located and how to locate it next time. So in Pop, the scope is represented by the interface Scope. The getBean() method is used to answer the questions. Please assign an implementation of the interface to the attribute scope of the annotation @BeanDef. If omitted, the default value for it is SingletonScope.class which means that the bean is permanent once it is created.

There are 4 predefined implementations in Pop for the Scope interface:

Reference a bean

The getBean() methods of class BeanCenter provides a normal way for you to access a bean which is created through annotation @BeanDef. However, you needn't to call the method directly in most cases. You can use the annotation @BeanRef instead. There are three ways for you to use it:

Reference many beans

To reference many beans in one @BeanRef, please announce the type of the field or parameter to an array. Here is an example:

class OneClass {
    @BeanRef
    MyClass[] myField;
    ...
}

Pop will collect all beans of MyClass and then assign them to the field. An array which length is zero will be assigned to the field if there is no bean of that class found. Please note, Pop allows you to use a single name to name multiple beans. So you can use a single name to reference many beans in an array field/parameter:

class OneClass {
    @BeanRef("beanName")
    MyClass[] myField;
    ...
}

AOP(Aspect-Oriented Programming)

The steps to define and use AOP in Pop are:

  1. Build a class to implement the interface AOP. Class AOPAdapter can help to finish this task.
  2. Call BeanCenter.setAOP(AOP) method to set the AOP object into a bean center. To get a bean center, you can call the getBeanCenter() method of MVCServlet.
  3. AOP takes effects only through the methods of interface. AOP does not influent any beans which has no interface.
  4. For your convenience, Pop provides some of the predefined implementations for AOP, such as AOPAdapter and DBTransactionAOP.
  5. Normally, an AOP is available for all interfaces of all beans in a BeanCenter. If you want to change this, please implements AOPFilter interface and then call BeanCenter.setAOPFilter(AOPFilter) method to set the AOPFilter object into a BeanCenter.

MVC

In Pop MVC, the model of a web page (such as a JSP or a servlet) must be a bean. Here the model means a Java object that provides data for the web page. The JSP/servlet itself is treated as a view of the bean. The view is responsible for rendering the data to client side.

So in Pop MVC, bean (or say model) is the core of any web pages. The only task of a web page (or say view) is to render its model/bean to client side.

As a result, navigation rule in Pop is not represented by connection between two web pages. It is represented by bean references. When you reference the name of a bean in a hyperlink, it means that the bean is the model of the destination web page. Pop will find a proper view for the bean and then use it to render the data of the bean to client side if the hyperlink is clicked.

By this way, Pop separates view from model and navigation rule, and releases web page developers from answering the questions shown in below:

The questions shown above, as you know, are very important for a web application. Now we can use Java object, instead of JSP or servlet, to answer them.

Model and View

Here are sample steps to build a model and a JSP view for a web page:

  1. Insert the pop2.0.3.jar and commons-logging.jar and log4j-1.2.15.jar into the lib directory of your web application.
  2. Create a servlet of type pop.mvc.MVCServlet in your web application. Please map the url-pattern *.model to it, and then set '.model' as welcome file. Here is an example of web.xml:
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    	id="WebApp_ID" version="2.5">
    	<welcome-file-list>
    		<welcome-file>.model</welcome-file>
    	</welcome-file-list>
    	<servlet>
    		<servlet-name>MVCServlet</servlet-name>
    		<servlet-class>pop.mvc.MVCServlet</servlet-class>
    		<!-- 
    		<init-param>
    			<param-name>beansRoot</param-name>
    			<param-value>com.app</param-value>
    		</init-param>
    		 -->
    	</servlet>
    	<servlet-mapping>
    		<servlet-name>MVCServlet</servlet-name>
    		<url-pattern>*.model</url-pattern>
    	</servlet-mapping>
    </web-app>
    

    The init-param beansRoot is optional. It is useful if not all the beans defined in this web application need to be loaded. The value of beansRoot should be a serial of package names separated by semi-colon (;), such as cn.com.abc;net.xyz. Only the beans defined in the packages as well as any of their sub-packages can be loaded by this servlet. So in the above example, all beans defined in net.xyz.rst are also loaded. Beans defined in cn.net.abc are ignored. If this param is not found, all beans defined in any user-defined packages are loaded. Normally, you can find the user-defined classes and packages in the directory 'WEB-INF/classes' of the web application.
  3. Create a class abc.def.MyModel1 which represents the model of a web page. And then use @ModelDef to annotate it:
    package abc.def;
    @ModelDef
    public class MyModel1() {...}

  4. Create a JSP as the view for the web page. The JSP should be located at abc/def/MyModel1.jsp under your web content directory.
  5. Use <jsp:useBean name="model" type="abc.def.MyModel1"> in MyModel1.jsp to bind the model with the view.
  6. In the JSP file, please use the Java variable model to reference the model object. Please treat the model as data provider, and JSP as data exihibitor.
  7. Run the web application, you may find that the abc/def/MyModel1.jsp is loaded automatically, and the no-arg constructor of the class MyModel1 is invoked automatically to construct a page model-object. The model object is bound to the JSP through the <jsp:useBean> declaration, as a result, the JSP can show the model object properly.

Similar to the @BeanDef the annotation @ModelDef is also used to define a bean, and also contains 3 attributes: value, types, and scope. Their meanings are same to those of @BeanDef and the beans defined by @ModelDef can be accessed by IoC and AOP and BeanCenter in the same way to accessing a bean defined by @BeanDef. The differences are:

Here is a table comparing @BeanDef and @ModelDef:

  @BeanDef @ModelDef
Usage Define a bean Define a model
Referenced by @BeanRef only @BeanRef or a url like 'http://localhost/myApp/myModel.model'
Attributes value, types, and scope value, types, and scope
Default value Empty string ("") MVCServlet.DEFAULT_MODEL
Default types Zero length of array ({}) Zero length of array ({})
Default scope Singleton.class PrototypeScope.class
value can be empty? Yes No
value can be ignored? Yes Yes
Default model in URL Not available Means the model which name is MVCServlet.DEFAULT_MODEL
Duplicated names Allowed Not allowed

Hyperlink

In Pop, developer can use the name of a bean to represent a hyperlink. for example:

http://localhost:8080/myapp/beanABC.model

'beanABC' is the name of the destination model, which will be used by MVCServlet to locate the model (please note there exists an inner BeanCenter in MVCServlet). If the model exists, the MVCServlet will try to map it to a view (a JSP file by default), and finally, the view is rendered to the browser with the data provided by the model. If the view is not found, en exception is thrown.

Here are sample steps to create a hyperlink:

  1. Suppose we have created the views and the models for abc.def.MyModel1 and abc.def.MyModel2, and now we want to create a hyperlink from MyModel1 to MyModel2
  2. Open the class abc.def.MyModel2
  3. Create a constructor (or a static method) and then use @ModelDef to annotate it:
    @ModelDef("link1")
    public MyModel2() {...}
  4. In JSP abc/def/MyModel1.jsp, define an anchor (<a>):
    <a href="link1.model">Click Me</a>
  5. Run the web application. When user clicks the 'Click Me', the MVCServlet will try to locate the model with the name "link1". If the model is found, its view (abc/def/MyModel2.jsp) will be rendered to client side.
  6. Please note that the name of the model must be globally unique, otherwise, an exception will be thrown.

Parameters

We can transfer parameters along with a hyperlink, here are sample steps:

  1. In JSP abc/def/MyModel1.jsp, define a <form>:
    <form action="">
        <input type="hidden" name="beanName" value="link1"/>
        <input name="p1" value="a string value"/>
        <input name="p2" value="3456"/>
        <input type="submit"/>
    </form>

    The parameters p1 and p2 will be transfered to the back end.
  2. Use @ModelDef to annotate a static method (or a constructor), and then define two parameters:
    @ModelDef("link1")
    public static MyModel2 myLinkToModel2(
        @Param("p1") String param1,
        @Param("p2") int param2) {
      ...
    }
  3. Please note:

Upload a file

To accept file uploaded from client side, please use @Param (or @ParamObject, see below sections) to annotate a method-parameter of an @BeanDef, and the type of the method-parameter must be FormFile. Here is an example of using @Param:

@ModelDef("link1")
public static MyModel2 myLinkToModel2(
    @Param("p1") FormFile param1,
    @Param("p2") int param2) {
  ...
}

In above example, the parameter param1 is of type FormFile and will be used to accept the file uploaded from client side. For more detail about FormFile please visit here.

In client side, when writing a <form> to upload file, the method of the <form> must be "Post", case insensitive. The enctype must be "multipart/form-data". The type of the <input> must be "file". Google can give you more details about how to write an <input> to transfer file. Here is an example which is corresponding to the server-side codes shown in above:

<form action="link1.model" method="Post" enctype="multipart/form-data">
    p1: <input type="file" name="p1"/>
    p2: <input name="p2" />
    <input type="submit"/>
</form>

Transfer many parameters

@Param can be used to convert and transfer only one parameter. If the JSP needs to transfer a lot of parameters, @Param is inconvenience. Please use ParamObject instead:

  1. Define a normal Java class which contains all the input-parameters as properties:
    public class InputParams {
        private int p1;
        private double p2;
        private char p3;
        ...

        public void setP1(int p1) {...}
        public void setP2(double p2) {...}
        public void setP3(char p3) {...}
        ...
    }
  2. When defining a model, please declare a parameter of InputParams and then use @ParamObject to annotate it:
    @ModelDef("link1")
    public static MyModel2 myLinkToModel2(@ParamObject InputParams params) {...}
  3. When the model is referenced, the names of the properties of the InputParams are used to search the values from the input parameters. The type of the property is used to convert the string value. The property is ignored if the corresponding string-value is null. By this way, many values can be set into a single object.
  4. When using @Param, the value attribute is mandatory. When using @ParamObject, however, you needn't to declare a name.

A very interesting thing is that you can use @BeanRef in the class InputParams shown in above, e.g., annotate a field with @BeanRef. This can help you to encapsolate all parameters and referenced beans into one class.

Transfer beans

Not only @Param and @ParamObject, but also @BeanRef can be used to annotate a parameter so that to reference a bean or a model. For example:

@ModelDef("link1")
public static MyModel2 myLinkToModel2(@ParamObject InputParams params, @Param("p6") float param6, @BeanRef MyBeanType beanParam) {...}

SessionScope and RequestScope

Besides PrototypeScope and SingletonScope, you can use another two predefined scopes: SessionScope and RequestScope.

If you set the scope of an @BeanDef or an @ModelDef to SessionScope.class, that means the bean/model is shared only within a session. Different sessions will contain different bean/model. So if you want to implement the class Cart for an e-business web application, you'd better to define it as a SessionScope bean like this:

@BeanDef(scope=SessionScope.class)
public class Cart {
    ...
}

And then you can reference it in a model or a bean like this:

@ModelDef("AddProduct")
public class AddProduct {
    @BeanRef
    Car cart;
    ...
}

If you want to implement a visiting counter for a web page the SessionScope is, however, not a good choice. Please use SingletonScope instead.

Same to SessionScope, RequestScope is also only available to a web application using MVCServlet. The difference is that the latter is used to define a bean which is accessible only within a request.

Predefined beans in MVCServlet

For your convenience, there exist 3 predefined beans in the BeanCenter of the MVCServlet:

Name Class Scope
_BeanCenter pop.bean.BeanCenter SingletonScope
_Config pop.mvc.MVCServletConfig SingletonScope
_Request javax.servlet.http.HttpServletRequest RequestScope

You can reference them directly through using @BeanRef in your web application. In most cases, however, you seldom need to do so. For example, if you need to access a parameter of the current request, @Param and @ParamObject are enough and more convenient. If you want to get a bean from the BeanCenter, @BeanRef is enough.

Predefined model interfaces

In Pop, you can annotate any POJO as a model. For your convenience, there exist two predefined interfaces that can help you to create usfule models:

  1. OutputStreamModel. This interface must be used along with OutputStreamView so that to help you to render binary data such as image, vedio, PDF, and etc. For more details please refer to the sections below.
  2. ReplaceModel. This interface is used to define a model which will be replaced by another model when it is rendered. Please implements the replaceWith() method, the return object will be used to replace this model when it is rendered.

Map a view to a model

Similar to using @BeanDef and @ModelDef, you can use @ViewDef to annotate a class, a constructor, or a static method, so that to define a bean and then use it to render a model. Here is an example:

@ViewDef
public class MyView implements View<MyModel> {
    ...
}

Please note:

  1. The view class must implements the interface View.
  2. @ViewDef contains 3 attributes. The value attribute is used to define the model classes that can use this view. If it is not defined, Pop will visit the super class of the view and all the interfaces directly implented by it, and try to get the model type defined as a type-parameter (see MyModel in above example). If the model type is not found, Pop will visit the super class of the super class as well as all its directly-implemented interfaces. Pop will do it recursively until the model type is found. Otherwise an exception is thrown. In above example, the model type is MyModel.
  3. The categories attribute of @ViewDef is used to distinguish different categories of views. The default value is HTML_PAGE, which is used by all views that will be rendered as normal HTML pages. If you want to build views for IPhone, for example, you may need to set it to "IPHONE". Please note that you can override the method MVCServlet.getCategory() so that to return a category for a model. By default this method returns HTML_PAGE.
  4. The 3rd attribute, beanDef, is an annotation constant of @BeanDef. You can use it to define bean attributes for this view.

When MVCServlet is looking the view for a model in a certain category, if there exists multiple views for the model, the view closest to the model will be used. For example, suppose there exist two views: view V1 for models of class Object and view V2 for models of class A. If we are now looking view for models of class B which is a sub class of A, the V2 will be used.

For user's convenience, MVCServlet already provides two predefined views:

Be default, the JSPView is used for all models except those implementing the interface OutputStreamModel. The JSPView tries to locate a JSP file for the model according to the qualified name of the type of the model. For example, suppose the type of the model is abc.def.MyModel1, the JSPView will try to find abc/def/MyModel.jsp under the web content directory of your web application.

If the JSP file is found, the JSPView will set the current model into the attribute list of the request with the name "model". As a result, you can use

<jsp:useBean name="model" type="YourModelClass">

in your JSP file to reference the model. The model should provides data for the view.

The OutputStreamView is used for the models that implementing the interface OutputStreamModel. Unlike JSPView, it does not turn to a JSP file, it outputs the binary data provided by the model to client side directly.

Of course, you're encouraged to build your own views. You need only to implement the interface View and then use @ViewDef to annotate your class.

Parameters of view

As discussed in above section, a view is in fact a bean. So it is possible for a view to contains parameters (which are in fact the parameters of the constructor/method that is annotated by @ViewDef). So of course @BeanRef can be used to annotate a parameter so that to reference another bean. The only question is: how about @Param and @ParamObject?

You may guess that the annotations @Param and @ParamObject can not be used to annotate a view's parameter. This is, however, incorrect. A good news is that the annotations are both permitted to annotate a view's parameter. This means you can use HTTP parameter to customize a view.


pop2.0.3.jar    commons-logging.jar    log4j-1.2.15.jar    API