Influencing AJAX-GUIs With Metadata +
This article explains how to create metadata that we use for scaffolding flexible AJAX GUIs . I keep the text as short as possible by providing a step-by-step cookbook based on code examples.
What you should know:
- Metadata for scaffoling your GUI (described here).
What you need to compile/run the examples:
- java1.5 or newer
- opensource framework: agimatec-validation : download agimatec-validation.jar
- optional: javax.servlet.jar (servlet-api)
- optional: opensource frameworks/tools: agimatec-tools : download annomark-dist.zip and annogen.jar
1. Create model classes
We start with a plain java class, our model, used to transport attributes from the server to the GUI. (You can use DWR for marshaling object instances between Java and JavaScript/JDOM).
Example class “Business”:
import javax.persistence.*;
public class Business {
@Id
@Column(name=”business_id”, nullable=false, unique=true)
Long businessId;
@Column(name=”name”, nullable=false, unique=true, length=200)
String name;
@Column(name=”active”, nullable=false)
boolean active;
// getters, setters follow…
}
2. Write or generate xml meta data
You can write the xml meta data manually, or – if your classes have javax.persistence.* annotations – you can generate them using agimatec-tools/annomark.jar (described here):
<bean id=”com.agimatec.Business” impl=”com.agimatec.Business”>
<feature key=”mainKey”>
<value class=”string”>businessId</value>
</feature>
<property name=”businessId”>
<feature key=”uniqueKey”>
<value class=”boolean”>true</value>
</feature>
</property>
<property name=”name” mandatory=”true” maxLength=”200″>
<feature key=”uniqueKey”>
<value class=”boolean”>true</value>
</feature>
</property>
<property name=”active” mandatory=”true”/>
</bean>
Store the file as “beaninfos-default.xml” in the classpath.
2. Access the MetaBean
This requires agimatec-validation.jar to compile:
import com.agimatec.validation.MetaBeanManagerFactory;
import com.agimatec.validation.model.MetaBean;MetaBeanManagerFactory.getRegistry().
addResourceLoader(“beaninfos-default.xml”);MetaBean metabean = MetaBeanManagerFactory.getFinder().findForClass(Business.class);
3. Generate JSon for metabean(s)
We want to use the meta data in the AJAX layer, to have information about the properties, their types and additional features (mandatory, max-length, …) as a JSON formatted string. agimatec-validation offers a JSONGenerator, based on a freemarker template:
import com.agimatec.validation.json.JSONGenerator;
JSONGenerator generator = new JSONGenerator();
String json = generator.toJSON(metabean);
System.out.println(json);
This prints this JSON string:
agimatec.namespace(“agimatec.metadata”);
(function(){
var metaBean0 = {
“id” : “com.agimatec.Business”,
“beanClass” : “com.agimatec.Business”,
“name” : “Business”,
“features” :{ “mainKey” : “businessId”},
“properties” :{
“active”:{
“name” : “active”,
“type” : “boolean”,
“features” : { “mandatory” : true }},
“businessId”:{
“name” : “businessId”,
“type” : “long”,
“features” : { “uniqueKey” : true }},
“name”:{
“name” : “name”,
“type” : “java.lang.String”,
“features” : { “maxLen” : 200, “mandatory” : true, “uniqueKey” : true }},
“version”:{
“name” : “version”,
“type” : “int”,
“features” : { }}}};agimatec.metadata.metaBeans = {“com.agimatec.Business” : metaBean0};})();
4. Write a servlet to deliver JSON for the AJAX GUI
The java code for the servlet should not be a surprise, for it consists of what we have seen so far:
public void init() throws ServletException {
super.init();
MetaBeanManagerFactory.getRegistry().addResourceLoader(“beaninfos-default.xml”);
}public void service(HttpServletRequest servletRequest, HttpServletResponse res)
throws ServletException, IOException {
Map<String, MetaBean> metaBeans = MetaBeanManagerFactory.getFinder().findAll();
// output JSON:
res.setContentType(“text/javascript”);
PrintWriter writer = res.getWriter();
String json = new JSONGenerator().toJSON(metaBeans.values());
writer.write(json);
}
Thats basically all! With this infrastructure your AJAX GUIs have access to meta information about the model classes.
5. Enrich meta data with information for the GUI-layer
You can enrich the xml meta data with additional hints (field sequence, formats, …) – whatever your GUI needs. If hhe additional information cannot be generated automatically, you should keep them in a separate xml-file:
<bean id=”com.agimatec.Business”>
<feature key=”DESCRIPTION”>
<value class=”string”>{name}</value>
</feature>
<feature key=”SORTING”>
<value class=”list”>
<string>name</string>
<string>active</string>
</value>
</feature>
<!–Visualisation as table–>
<feature key=”TABLE_COLUMNS”>
<value class=”list”>
<string>name</string>
<string>active</string>
</value>
</feature>
</bean>
Save this as “beaninfos-gui.xml ” in the classpath and register the file in the init() method of the servlet, too:
MetaBeanManagerFactory.getRegistry().addResourceLoader(“beaninfos-gui.xml”);
You see, that the JSON code will contain the additional information as well, because the MetaBeanManager merges them.
So far, we have the infrastructure to support meta data that allows us to build generic AJAX GUIs. The JSON string can be cached, because it will never change while the application is running.
6. User-specific meta data
We can go one step further: We can also support user-specific meta data! A usual requirement in a web application is, that – depending on the role of a user that is logged in – field-level permissions must be supported:
User A is allowed to change the “active”-state of our “Business” entity, while User B has read-only access to the field and the field is hidden for User C, …
This could also be useful, when a user can customize its GUI (disable fields) by himself or when the application is used by different companies with different settings for their users….
How does it work? – Use additional xml files and merge them in the JSON servlet. (You can also generate the meta beans during runtime programmatically).
beaninfos-role1.xml:
<bean id=”com.agimatec.Business”>
<property name=”active”>
<feature key=”readonly”>
<value class=”boolean”>true</value>
</feature>
</property>
</bean>
Extension of the servlet:
String customInfos = “beaninfos-role1.xml”; // determine this from session or request dynamically!
XMLMetaBeanInfos xmlInfos =
new XMLMetaBeanURLLoader(getClass().getResource(customInfos)).load();
Map<String, MetaBean> metaBeans =
MetaBeanManagerFactory.getEnricher().enrichCopies(xmlInfos);
The statements after “// output JSON” stay the same (see previous code fragment).
More information?
We already got some more posts in German about metadata and code generation, explaining the concepts and giving examples:
- TransferObjects generieren
- agimatec-tools als OpenSource auf google.code released!
- Statt Modellieren: Annotieren und generieren
- Klassen mit Mehrwert: Validierung und Metadaten
The open-source frameworks have a WIKI and additional examples or junit testcases, that help you.
If you have questions, do not hesitate to contact us!
This is the fifth article in our mini-series about developing highly ajaxified portlets. Other articles are:
[...] Influencing AJAX-GUIs With Metadata internet advertising [...]