Introduction to Pop Framework

Lin Fang
Download pop3.1.0.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 is that a bean can be considered as the model of a web page. In viewpoints of Pop and Pop's MVC, a JSP or servlet is considered as a view of the bean. The model provides the data for the view, the view provides the way to render 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 and the bean is ready to be a model, 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 jump 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 all the 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 getScopedBean() 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. Use @BeanDef to annotate a bean of type AOP
  3. Use @AOPDef to annotate the bean.
  4. In @AOPDef, please declare at lease one interface the AOP can be applied to. The interface(s) is the only way for the AOP to affect a bean.
  5. If a bean is referenced through an interface (for example a field annotated by a @BeanRef and whose type is that interface), then any AOPs on that interface can affect it.
  6. A bean is affected by an AOP means whenever a method declared in the interface is invoked on the bean, the corresponding aspect methods defined in the AOP is also invoked just before or after the invocation.
  7. For your convenience, Pop provides some of the predefined implementations for AOP, such as AOPAdapter and DBTransactionAOP.

MVC

In Pop‘s MVC, a web page is something like a JSP or a servlet and is also named as view. A view is used to decorate a set of data while the data provider is name as model. In Pop's MVC the data provider, or say model, must be a bean.

In Pop's MVC, model is the core of a web page. The only task of a web page (or say view) is to render its model/bean to client side.

Hyperlink in Pop's MVC is not represented by link from one web page to another web page. It is represented by bean/model reference. When you reference the name of a bean in a hyperlink, Pop will locate the bean at first and then find a proper view for it. And finally use the view (JSP or servlet or anything else like them) to render the data provided by the bean to client side.

In Pop's MVC, a view needn't to transfer parameters to or from any other views. Again, the only task of a view is to render the data provided by the model. The model of the view is responsible for that, instead. A model is nothing but a bean, a bean is nothing but a Java object. It's very easy for developers to consider how to transfer parameters in Java language, and moreover, any syntax errors issued when transferring parameters, such as type mismatching, can be checked out in compiling time. In JSP, however, you may have to invoke request.setAttribute() to transfer parameters.

Model and View

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

  1. Insert the pop3.1.0.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 both @BeanDef and @ModelDef to annotate it:
    package abc.def;
    @ModelDef
    @BeanDef(value="ModelABC", scope=PrototypleScope.class)
    public class MyModel1() {...}

    Here the @ModelDef means that the bean is considered as the model of a web page. Without this annotation, the bean is only a bean and can be referenced only in Java codes. With the annotation, however, the bean can also be referenced by a url such as <a href="ModelABC.model">.
  4. Create a JSP as the view for the web page. The JSP should be located at abc/def/MyModel1.jsp under the root directory of your web content.
  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 decorator and renderer.
  7. Run the web application and then use a browser to visit http://localhost:8080/myproject/ModelABC.model, 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 model. The model object is bound to the JSP through the <jsp:useBean> declaration, as a result, the JSP can show the model object properly.

Please note, the default scope of a bean is SingletonScope. We suggest you to use PrototypeScope or SessionScopewhen annotating a model as in most cases you needn't to use a singleton model useless you want to share something among all users.

If you annotate a model with name MVCServlet.DEFAULT_MODEL, it means that the model is a default model and a hyperlink can reference it without explicit name such as '.model'. For more details about hyperlink in Pop, please refer to the next section.

Hyperlink

In Pop, developer can use the name of a model 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 bean exists and it is also annotated by @ModelDef, the MVCServlet will try to map it to a view (a JSP file by default), and finally, the view is rendered along with the model. If the view is not found, an 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 and @BeanDef 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 inconvenient. 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 define value.

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 encapsulate 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
@BeanDef(value="link1", scope=PrototypeScope.class)
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 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 shopping 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
@BeanDef("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 because you want to share the counter among all visitors.

Same to SessionScope, RequestScope is also only available in 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 4 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
_Response javax.servlet.http.HttpServletResponse 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 the current model when it is rendered.

Map a view to a model

Similar to using @BeanDef and @ModelDef, you can use @ViewDef along with @BeanDef to annotate a bean and then use it to render a model. Here is an example:

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

Please note:

  1. The view must implements the interface View.
  2. @ViewDef contains 2 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 class of the view and all the interfaces directly implemented 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 as well as all its directly-implemented interfaces. Pop will do it recursively until a 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.

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 several 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 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 along with @BeanDef to annotate a bean.

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/static 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.


pop3.1.0.jar    commons-logging.jar    log4j-1.2.15.jar    API