<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>agimatec</title>
	
	<link>http://www.agimatec.de/blog</link>
	<description>Clash of realities</description>
	<lastBuildDate>Tue, 22 Dec 2009 16:50:43 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/agimatec" /><feedburner:info uri="agimatec" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>agimatec-validation implements all features of JSR-303</title>
		<link>http://feedproxy.google.com/~r/agimatec/~3/c_z4zugI5jc/</link>
		<comments>http://www.agimatec.de/blog/2009/12/agimatec-validation-implements-all-features-of-jsr-303/#comments</comments>
		<pubDate>Fri, 11 Dec 2009 15:33:33 +0000</pubDate>
		<dc:creator>roman.stumm</dc:creator>
				<category><![CDATA[English]]></category>

		<guid isPermaLink="false">http://www.agimatec.de/blog/?p=684</guid>
		<description><![CDATA[In its current release 0.9.5, the bean validation framework agimatec-validation, published as open-source on code.google.com/p/agimatec-validation/ implements all features of the JSR-303 bean-validation specification. This release now fully supports XML-based constraint definitions and all JSR-303 constraint-annotations. If you download and test this release, we welcome your feedback. If you think you found a bug, you can [...]]]></description>
			<content:encoded><![CDATA[<p>In its current release 0.9.5, the bean validation framework agimatec-validation, published as open-source on <a title="code.google/agimatec-valiation" href="http://code.google.com/p/agimatec-validation/ ">code.google.com/p/agimatec-validation/ </a>implements all features of the JSR-303 bean-validation specification.</p>
<p>This release now fully supports XML-based constraint definitions and all JSR-303 constraint-annotations.</p>
<p>If you download and test this release, we welcome your feedback. If you think you found a bug, you can post an issue at <a title="agimatec-validation/issues" href="http://code.google.com/p/agimatec-validation/issues/list">agimatec-validation/issues</a>.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/agimatec?a=c_z4zugI5jc:DGzZime4Yn4:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/agimatec?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=c_z4zugI5jc:DGzZime4Yn4:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/agimatec?i=c_z4zugI5jc:DGzZime4Yn4:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=c_z4zugI5jc:DGzZime4Yn4:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/agimatec?i=c_z4zugI5jc:DGzZime4Yn4:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=c_z4zugI5jc:DGzZime4Yn4:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/agimatec?i=c_z4zugI5jc:DGzZime4Yn4:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=c_z4zugI5jc:DGzZime4Yn4:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/agimatec?d=TzevzKxY174" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.agimatec.de/blog/2009/12/agimatec-validation-implements-all-features-of-jsr-303/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.agimatec.de/blog/2009/12/agimatec-validation-implements-all-features-of-jsr-303/</feedburner:origLink></item>
		<item>
		<title>Painless DOM building with mkup</title>
		<link>http://feedproxy.google.com/~r/agimatec/~3/iqYjM3A85GY/</link>
		<comments>http://www.agimatec.de/blog/2009/09/painless-dom-building-with-mkup/#comments</comments>
		<pubDate>Mon, 21 Sep 2009 09:22:33 +0000</pubDate>
		<dc:creator>Sebastian Schuth</dc:creator>
				<category><![CDATA[English]]></category>
		<category><![CDATA[javasc]]></category>

		<guid isPermaLink="false">http://www.agimatec.de/blog/?p=650</guid>
		<description><![CDATA[Creating DOM nodes from Javascript can be painful. The amount of code needed to create nodes and to reference each other as needed is non-acceptable, and the resulting code is far away from being readable or maintainable. There are some projects out there that try to solve this issue, but their API feels alien inside [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignnone size-full wp-image-671" title="mkup" src="http://www.agimatec.de/blog/wp-content/uploads/2009/09/mkup.jpg" alt="mkup" width="420" height="357" /></p>
<p>Creating DOM nodes from Javascript can be painful. The amount of code needed to create nodes and to reference each other as needed is non-acceptable, and the resulting code is far away from being readable or maintainable.</p>
<p>There are some projects out there that try to solve this issue, but their API feels alien inside a Javascript environment because of their declarative nature. So i decided to try to create my own library. The result is mkup, which you can find as open source project at google code: <a href=" http://code.google.com/p/mkup/">http://code.google.com/p/mkup/</a>.</p>
<p>You can try out all examples listed here inside your browser using the mkup workbench: <a href="http://mkup.googlecode.com/svn/trunk/workbench.html">http://mkup.googlecode.com/svn/trunk/workbench.html</a>.</p>
<h2>Design goals</h2>
<p>Mkup was written with some things in mind that make a node builder useful.</p>
<ul>
<li>code should reflect what is being built</li>
<li>easy access to the nodes created</li>
<li>code should be as short as possible</li>
</ul>
<h2>Target one: code should reflect what is being built</h2>
<p>This code:</p>
<pre name="code" class="javascript">var mkup = Mkup.mkup($('results'));
mkup
  .div()
  .childSpan('note_this')
  .text('Inside Span')
  .write();</pre>
<p>creates the following nodes:</p>
<pre name="code" class="html">&lt;div&gt;
  &lt;span class="note_this"&gt;Inside Span&lt;/span&gt;
&lt;/div&gt;</pre>
<p>As you can see calls to mkup are designed to be chained. This removes clutter when specifying what should be done. Of course, chaining is optional, to make using mkup with loops comfortable:</p>
<pre name="code" class="javascript">var mkup = Mkup.mkup($('results'));
mkup.ul().child();
for(var i=0; i&lt;3;i++){
    mkup.li().text('Item #'+i);
}
mkup.write();</pre>
<p>creates:</p>
<pre name="code" class="html">&lt;ul&gt;
  &lt;li&gt;Item #0&lt;/li&gt;
  &lt;li&gt;Item #1&lt;/li&gt;
  &lt;li&gt;Item #2&lt;/li&gt;
&lt;/ul&gt;</pre>
<h2>Target two: easy access to nodes created</h2>
<p>After building up the nodes you need, getting a reference to one ore more nodes just created is often needed to -for example- change node contents or add listeners. This can be done using mkup:</p>
<pre name="code" class="javascript">var mkup = Mkup.mkup($('results'));
mkup
  .div()
  .childA({href:"#"},"link")
  .text("Trigger some fancy stuff");
var createdNodes = mkup.write();
createdNodes.link.observe("click", function(event){
  Event.stop(event);
  alert("Fancy! Wow!");
});</pre>
<p>creates:</p>
<pre name="code" class="html">&lt;div&gt;
  &lt;a href="#"&gt;Trigger some fancy stuff&lt;/a&gt;
&lt;/div&gt;</pre>
<h2>Target three: code should be as short as possible</h2>
<p>Well judge yourself:</p>
<p>Without mkup:</p>
<pre name="code" class="javascript">var div = new Element("div");
var link = new Element("a",{href:"#"});
div.appendChild(link);
link.appendChild(document.createTextNode("Link"));
$('results').appendChild(div);</pre>
<p>using mkup:</p>
<pre name="code" class="javascript">var mkup = Mkup.mkup($('results'));
mkup.div().childA({href:"#"}).text("Link").write();</pre>
<h2>How to help</h2>
<p>If you are interested in mkup, you can help us to improve it:</p>
<ul>
<li><strong>tell us that you use it</strong> &#8211; because it&#8217;s motivating to know that mkup is useful to someone</li>
<li><strong>tell the world that you use it</strong> &#8211; see above</li>
<li><strong>run the test suite in your browser and report bugs <a href="http://code.google.com/p/mkup/issues/list">here</a></strong> &#8211; you can find the test page <a href="http://mkup.googlecode.com/svn/trunk/test/Mkup_test.html">here</a></li>
<li><strong>add a feature</strong> &#8211; mkup is a small project, so this is your chance to participate in a open source project without a steep learning curve. Checking out the code using subversion is easy and explained <a href="http://code.google.com/p/mkup/source/checkout">here</a></li>
</ul>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/agimatec?a=iqYjM3A85GY:cN0QHKD6IgU:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/agimatec?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=iqYjM3A85GY:cN0QHKD6IgU:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/agimatec?i=iqYjM3A85GY:cN0QHKD6IgU:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=iqYjM3A85GY:cN0QHKD6IgU:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/agimatec?i=iqYjM3A85GY:cN0QHKD6IgU:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=iqYjM3A85GY:cN0QHKD6IgU:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/agimatec?i=iqYjM3A85GY:cN0QHKD6IgU:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=iqYjM3A85GY:cN0QHKD6IgU:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/agimatec?d=TzevzKxY174" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.agimatec.de/blog/2009/09/painless-dom-building-with-mkup/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://www.agimatec.de/blog/2009/09/painless-dom-building-with-mkup/</feedburner:origLink></item>
		<item>
		<title>Auditing and entity versioning based on triggers and hibernate</title>
		<link>http://feedproxy.google.com/~r/agimatec/~3/FRJmDLhIeMU/</link>
		<comments>http://www.agimatec.de/blog/2009/07/auditing-and-entity-versioning-based-on-triggers-and-hibernate/#comments</comments>
		<pubDate>Fri, 03 Jul 2009 13:11:20 +0000</pubDate>
		<dc:creator>roman.stumm</dc:creator>
				<category><![CDATA[English]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.agimatec.de/blog/?p=644</guid>
		<description><![CDATA[If you are looking for a framework for auditing the versions and changes of your hibernate objects, you might probably be satisfied with Envers (http://www.jboss.org/envers/), a solution based on hibernate. In this blog entry I want to give you an impression of an alternative solution by agimatec, that is slightly different. It is the solution [...]]]></description>
			<content:encoded><![CDATA[<p>If you are looking for a framework for auditing the versions and changes of your hibernate objects, you might probably be satisfied with <em><strong>Envers</strong></em> (http://www.jboss.org/envers/), a solution based on hibernate.</p>
<p>In this blog entry I want to give you an impression of an <strong><em>alternative solution</em><em> by agimatec</em></strong>, that is slightly different. It is the solution we are using in our products for more than two years and with which we are satisfied. It would be interesting to hear your options on this.</p>
<p><strong>The concept</strong></p>
<p><em>Database:</em><strong><br />
</strong></p>
<p>We generate history tables for each table for which we need auditing. We generate database triggers (oracle or postgres) to automatically insert data in the history tables when entities are stored/deleted.</p>
<p>We do not store duplicate data, which means that our history tables contain only OLD data. All current data is ONLY stored in the application&#8217;s tables (usually mapped by hibernate/Ejb3).</p>
<p><em>Configuration:</em></p>
<p>We have a XML configuration, that contains the table names for which we want to enable our history solution. This configuration lets you specify:</p>
<ul>
<li>name of history table (or a default name will be used)</li>
<li>which columns to exclude from history (default is that all columns are historised)</li>
<li>optionally you can turn off history for insert and/or update, change trigger names etc.</li>
</ul>
<p>The XML configuration controls the tables and triggers generated by freemarker templates.</p>
<p><em>Features:</em></p>
<p>It is not only important to version the changes, but also to store, the timestamp of a change and some context information about the change (e.g. who is the actor, which application, from which sessionID etc.). Any context information can be associated with a version record by storing a contextID in the history table&#8217;s rows.</p>
<p>This is also a way to separate changes from user-specific data, which might be a judical requirement. An extended Hibernate event handler stores the contextID into the database session by calling a stored procedure, so that the history triggers and access the contextID to store it together with the history data.</p>
<p>Each history table has additional columns:</p>
<ul>
<li>HIST_TIME (timestamp of change)</li>
<li>HIST_CONTEXTID (ID of context providing additional information)</li>
<li>HIST_TYPE (to distinguish INSERT, UPDATE and DELETION)</li>
</ul>
<p>A simple java API exists to query historical data. It returns the same classes as you use for your hibernate entities, but it materializes the objects itself. Hibernate does not know anything about the history tables or mappings.</p>
<p><strong>The benefits</strong></p>
<p>There are some differences between the solution provided by Envers and agimatec:</p>
<ul>
<li>Envers needs a global _revision table, agimatec&#8217;s history rows are identified by the primary key and a version number (@Version) incremented from 1 for each entity/no global _revision</li>
<li>You can change data with any SQL tool.Historisation does not rely on hibernate as the only API to change the database.</li>
<li>Whenever you increment a row&#8217;s version, the history triggers will automatically write historical data. By this way, you can use migration scripts that can control whether history data will be stored.</li>
<li>Envers stores current data in history tables, which makes it a bit easier to query the data, but with means redundancy (and potential data inconsistencies).</li>
<li>Both framework are integrated with Hibernate by extending the Hibernate Events (to provide context information).</li>
</ul>
<p><strong>Examples</strong></p>
<p><em>History configuration</em><br />
<code><br />
&lt;historyConfig&gt;<br />
&lt;tableConfig&gt;<br />
&lt;tableName&gt;booking&lt;/tableName&gt;<br />
&lt;/tableConfig&gt;<br />
&lt;tableConfig&gt;<br />
&lt;tableName&gt;customer&lt;/tableName&gt;<br />
&lt;historyTable&gt;h_cust&lt;/historyTable&gt;<br />
&lt;insertTrigger&gt;TR_I_cust&lt;/insertTrigger&gt;<br />
&lt;updateTrigger&gt;TR_U_cust&lt;/updateTrigger&gt;<br />
&lt;/tableConfig&gt;<br />
</code></p>
<p><em>Generated tables</em><br />
<code><br />
CREATE TABLE H_JOURNAL (<br />
ID INTEGER NOT NULL,<br />
HIST_TABLE VARCHAR(50) NOT NULL,<br />
HIST_TIME TIMESTAMP NOT NULL,<br />
HIST_CONTEXTID VARCHAR(40),<br />
CONSTRAINT H_JOURNAL_PK PRIMARY KEY (ID, HIST_TABLE)<br />
);</code></p>
<p><code>CREATE TABLE H_booking (<br />
VERSION INTEGER NOT NULL,<br />
booking_id INTEGER NOT NULL,<br />
price NUMBER,<br />
HIST_TIME TIMESTAMP NOT NULL,<br />
HIST_CONTEXTID VARCHAR(40),<br />
HIST_TYPE CHAR(1) NOT NULL,<br />
CONSTRAINT H_booking_PK PRIMARY KEY (VERSION, booking_id)<br />
);<br />
CREATE TABLE H_cust (<br />
VERSION INTEGER NOT NULL,<br />
cust_id INTEGER NOT NULL,<br />
first_name VARCHAR2(40),<br />
last_name VARCHAR2(40),<br />
HIST_TIME TIMESTAMP NOT NULL,<br />
HIST_CONTEXTID VARCHAR(40),<br />
HIST_TYPE CHAR(1) NOT NULL,<br />
CONSTRAINT H_cust_PK PRIMARY KEY (VERSION, card_id)<br />
);</code></p>
<p><em>Generated triggers</em><br />
<code><br />
CREATE OR REPLACE TRIGGER TR_I_cust<br />
AFTER INSERT ON customer<br />
REFERENCING NEW AS NEW<br />
FOR EACH ROW<br />
BEGIN<br />
setTATime();<br />
INSERT INTO H_JOURNAL (ID,  HIST_TIME, HIST_CONTEXTID, HIST_TABLE)<br />
select :NEW.card_id, h.ts, h_session.getContextId, 'customer' from h_tatime h;<br />
END;<br />
/</code><br />
<code><br />
CREATE OR REPLACE TRIGGER TR_U_cust<br />
AFTER DELETE OR UPDATE<br />
ON customer<br />
REFERENCING NEW AS NEW OLD AS OLD<br />
FOR EACH ROW<br />
BEGIN<br />
IF(DELETING) THEN<br />
setTATime();<br />
INSERT INTO H_cust (<br />
cust_id,<br />
version,<br />
first_name,<br />
last_name,<br />
HIST_TIME, HIST_CONTEXTID, HIST_TYPE)<br />
select<br />
:OLD.cust_id,<br />
:OLD.version,<br />
:OLD.first_name,<br />
:OLD.last_name,<br />
h.ts, h_session.getContextId, 'D' from h_tatime h;<br />
ELSIF (UPDATING AND :OLD.VERSION != :NEW.VERSION) THEN<br />
setTATime();<br />
INSERT INTO H_cust (<br />
cust_id,<br />
version,<br />
first_name,<br />
last_name,<br />
HIST_TIME, HIST_CONTEXTID, HIST_TYPE)<br />
select<br />
:OLD.cust_id,<br />
:OLD.version,<br />
:OLD.first_name,<br />
:OLD.last_name,<br />
h.ts, h_session.getContextId, 'U' from h_tatime h;<br />
END IF;<br />
END;<br />
/</code></p>
<p><strong>Java API</strong></p>
<p>The implementation of class <strong><em>HibernateHistoryReader</em></strong> was rather complex, because of the need to resolve the relationships through the current tables and the history tables. All changes done inside a single transaction are joined together by using a timestamp in HIST_TIME that is unique inside the running database transaction.</p>
<p>Here is interface <strong><em>HistoryReader</em></strong>:</p>
<p><code>interface HistoryReader {</code><br />
<code><br />
void open(EntityManager entityManager);<br />
void close();</code><br />
<code><br />
List&lt;EntityRevision&gt; getRevisions(Class entityClass, Object primaryKey, Timeframe timeframe);<br />
EntityRevision getRevision(Class entityClass, Object primaryKey, int version);</code></p>
<p><code>Map&lt;Object, List&lt;EntityRevision&gt;&gt; getChildrenRevisions(Class parentEntityClass,EntityRevision parentRevision,String relationship);</code></p>
<p><code>&lt;E&gt; HistoryEntity&lt;E&gt; loadEntity(Class&lt;E&gt; entityClass, Object primaryKey,Timestamp time);<br />
&lt;E&gt; List&lt;HistoryEntity&lt;E&gt;&gt; loadChildren(Class parentEntityClass, String relationship,<br />
Object parentPrimaryKey, Timestamp time);</code></p>
<p><code>}</code></p>
<p>Where class HistoryEntity contains the entity instance for a given point of time and some additional information, such as the contextID and the foreignKey values to load some to-one-references.</p>
<p>If you are interested in more details contact us.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/agimatec?a=FRJmDLhIeMU:35yDposq9Fg:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/agimatec?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=FRJmDLhIeMU:35yDposq9Fg:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/agimatec?i=FRJmDLhIeMU:35yDposq9Fg:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=FRJmDLhIeMU:35yDposq9Fg:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/agimatec?i=FRJmDLhIeMU:35yDposq9Fg:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=FRJmDLhIeMU:35yDposq9Fg:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/agimatec?i=FRJmDLhIeMU:35yDposq9Fg:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=FRJmDLhIeMU:35yDposq9Fg:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/agimatec?d=TzevzKxY174" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.agimatec.de/blog/2009/07/auditing-and-entity-versioning-based-on-triggers-and-hibernate/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://www.agimatec.de/blog/2009/07/auditing-and-entity-versioning-based-on-triggers-and-hibernate/</feedburner:origLink></item>
		<item>
		<title>Java code of the week…</title>
		<link>http://feedproxy.google.com/~r/agimatec/~3/BJ94gd4f6UQ/</link>
		<comments>http://www.agimatec.de/blog/2009/06/java-code-of-the-week/#comments</comments>
		<pubDate>Thu, 18 Jun 2009 08:02:03 +0000</pubDate>
		<dc:creator>roman.stumm</dc:creator>
				<category><![CDATA[Deutsch]]></category>

		<guid isPermaLink="false">http://www.agimatec.de/blog/?p=633</guid>
		<description><![CDATA[private void log(String message) { Logger log = Logger.getLogger(this.getClass()); if(log.isDebugEnabled()) { if(Thread.currentThread() != null) { log.debug(Thread.currentThread().getName()  + ": " +  message); } else { log.debug(message); } } }]]></description>
			<content:encoded><![CDATA[<pre>private void log(String message) {
  Logger log = Logger.getLogger(this.getClass());
  if(log.isDebugEnabled()) {
    if(Thread.currentThread() != null) {
      log.debug(Thread.currentThread().getName()  + ": " +  message);
    } else {
      log.debug(message);
    }
  }
}</pre>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/agimatec?a=BJ94gd4f6UQ:YuzgTJiHFEI:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/agimatec?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=BJ94gd4f6UQ:YuzgTJiHFEI:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/agimatec?i=BJ94gd4f6UQ:YuzgTJiHFEI:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=BJ94gd4f6UQ:YuzgTJiHFEI:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/agimatec?i=BJ94gd4f6UQ:YuzgTJiHFEI:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=BJ94gd4f6UQ:YuzgTJiHFEI:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/agimatec?i=BJ94gd4f6UQ:YuzgTJiHFEI:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=BJ94gd4f6UQ:YuzgTJiHFEI:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/agimatec?d=TzevzKxY174" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.agimatec.de/blog/2009/06/java-code-of-the-week/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.agimatec.de/blog/2009/06/java-code-of-the-week/</feedburner:origLink></item>
		<item>
		<title>Influencing AJAX-GUIs With Metadata</title>
		<link>http://feedproxy.google.com/~r/agimatec/~3/sCgur0UI2gU/</link>
		<comments>http://www.agimatec.de/blog/2009/04/influencing-ajax-guis-with-metadata/#comments</comments>
		<pubDate>Tue, 28 Apr 2009 16:13:43 +0000</pubDate>
		<dc:creator>roman.stumm</dc:creator>
				<category><![CDATA[English]]></category>
		<category><![CDATA[Add new tag]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[Codegenerierung]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[metadata]]></category>
		<category><![CDATA[Portlet]]></category>
		<category><![CDATA[Validierung]]></category>

		<guid isPermaLink="false">http://www.agimatec.de/blog/?p=606</guid>
		<description><![CDATA[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 [...]]]></description>
			<content:encoded><![CDATA[<p>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.</p>
<p>What you should know:</p>
<ul>
<li>Metadata for scaffoling your GUI (described <a title="Generate Your UI Using Metadata " href="http://www.agimatec.de/blog/2009/03/generate-your-ui-using-metadata/">here</a>).<span id="more-606"></span></li>
</ul>
<p>What you need to compile/run the examples:</p>
<ul>
<li>java1.5 or newer</li>
<li><a href="http://code.google.com/p/agimatec-validation/">opensource framework: agimatec-validation</a> : download agimatec-validation.jar</li>
<li>optional: javax.servlet.jar (servlet-api)</li>
<li>optional: <a href="http://code.google.com/p/agimatec-tools/">opensource frameworks/tools: agimatec-tools</a> : download annomark-dist.zip and annogen.jar</li>
</ul>
<p><strong>1. Create model classes</strong></p>
<p>We start with a plain java class, our model, used to transport attributes from the server to the GUI. (You can use <a title="Direct Web Remoting" href="http://directwebremoting.org/">DWR</a> for marshaling object instances between Java and JavaScript/JDOM).</p>
<p><strong>Example class &#8220;Business&#8221;:</strong></p>
<blockquote><p>import javax.persistence.*;</p></blockquote>
<blockquote><p>public class Business {<br />
@Id<br />
@Column(name=&#8221;business_id&#8221;, nullable=false, unique=true)<br />
Long businessId;<br />
@Column(name=&#8221;name&#8221;, nullable=false, unique=true, length=200)<br />
String name;<br />
@Column(name=&#8221;active&#8221;, nullable=false)<br />
boolean active;<br />
// getters, setters follow&#8230;<br />
}</p></blockquote>
<p><strong>2. Write or generate xml meta data</strong></p>
<p>You can write the xml meta data manually, or &#8211; if your classes have javax.persistence.* annotations &#8211; you can generate them using agimatec-tools/annomark.jar (described <a title="annomark explained" href="http://code.google.com/p/agimatec-tools/wiki/annomark">here</a>):</p>
<blockquote><p>&lt;bean id=&#8221;com.agimatec.Business&#8221; impl=&#8221;com.agimatec.Business&#8221;&gt;<br />
&lt;feature key=&#8221;mainKey&#8221;&gt;<br />
&lt;value class=&#8221;string&#8221;&gt;businessId&lt;/value&gt;<br />
&lt;/feature&gt;<br />
&lt;property name=&#8221;businessId&#8221;&gt;<br />
&lt;feature key=&#8221;uniqueKey&#8221;&gt;<br />
&lt;value class=&#8221;boolean&#8221;&gt;true&lt;/value&gt;<br />
&lt;/feature&gt;<br />
&lt;/property&gt;<br />
&lt;property name=&#8221;name&#8221; mandatory=&#8221;true&#8221; maxLength=&#8221;200&#8243;&gt;<br />
&lt;feature key=&#8221;uniqueKey&#8221;&gt;<br />
&lt;value class=&#8221;boolean&#8221;&gt;true&lt;/value&gt;<br />
&lt;/feature&gt;<br />
&lt;/property&gt;<br />
&lt;property name=&#8221;active&#8221; mandatory=&#8221;true&#8221;/&gt;<br />
&lt;/bean&gt;</p></blockquote>
<p>Store the file as &#8220;beaninfos-default.xml&#8221; in the classpath.</p>
<p><strong>2. Access the MetaBean</strong></p>
<p>This requires agimatec-validation.jar to compile:</p>
<blockquote><p>import com.agimatec.validation.MetaBeanManagerFactory;<br />
import com.agimatec.validation.model.MetaBean;</p>
<p>MetaBeanManagerFactory.getRegistry().<br />
addResourceLoader(&#8220;beaninfos-default.xml&#8221;);</p>
<p>MetaBean metabean = MetaBeanManagerFactory.getFinder().findForClass(Business.class);</p></blockquote>
<p><strong>3. Generate JSon for metabean(s)</strong></p>
<p>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, &#8230;) as a JSON formatted string. agimatec-validation offers a JSONGenerator, based on a freemarker template:</p>
<blockquote><p>import com.agimatec.validation.json.JSONGenerator;</p>
<p>JSONGenerator generator = new JSONGenerator();<br />
String json = generator.toJSON(metabean);<br />
System.out.println(json);</p></blockquote>
<p>This prints this JSON string:</p>
<blockquote><p>agimatec.namespace(&#8220;agimatec.metadata&#8221;);</p>
<p>(function(){</p>
<p>var metaBean0 = {<br />
&#8220;id&#8221; : &#8220;com.agimatec.Business&#8221;,<br />
&#8220;beanClass&#8221; : &#8220;com.agimatec.Business&#8221;,<br />
&#8220;name&#8221; : &#8220;Business&#8221;,<br />
&#8220;features&#8221; :{   &#8220;mainKey&#8221; : &#8220;businessId&#8221;},<br />
&#8220;properties&#8221; :{<br />
&#8220;active&#8221;:{<br />
&#8220;name&#8221; : &#8220;active&#8221;,<br />
&#8220;type&#8221; : &#8220;boolean&#8221;,<br />
&#8220;features&#8221; : {       &#8220;mandatory&#8221; : true       }},<br />
&#8220;businessId&#8221;:{<br />
&#8220;name&#8221; : &#8220;businessId&#8221;,<br />
&#8220;type&#8221; : &#8220;long&#8221;,<br />
&#8220;features&#8221; : {       &#8220;uniqueKey&#8221; : true       }},<br />
&#8220;name&#8221;:{<br />
&#8220;name&#8221; : &#8220;name&#8221;,<br />
&#8220;type&#8221; : &#8220;java.lang.String&#8221;,<br />
&#8220;features&#8221; : {       &#8220;maxLen&#8221; : 200,       &#8220;mandatory&#8221; : true,       &#8220;uniqueKey&#8221; : true       }},<br />
&#8220;version&#8221;:{<br />
&#8220;name&#8221; : &#8220;version&#8221;,<br />
&#8220;type&#8221; : &#8220;int&#8221;,<br />
&#8220;features&#8221; : {       }}}};</p>
<p>agimatec.metadata.metaBeans = {&#8220;com.agimatec.Business&#8221; : metaBean0};})();</p></blockquote>
<p><strong>4. Write a servlet to deliver JSON for the AJAX GUI</strong></p>
<p>The java code for the servlet should not be a surprise, for it consists of what we have seen so far:</p>
<blockquote><p>public void init() throws ServletException {<br />
super.init();<br />
MetaBeanManagerFactory.getRegistry().addResourceLoader(&#8220;beaninfos-default.xml&#8221;);<br />
}</p>
<p>public void service(HttpServletRequest servletRequest, HttpServletResponse res)<br />
throws ServletException, IOException {<br />
Map&lt;String, MetaBean&gt; metaBeans = MetaBeanManagerFactory.getFinder().findAll();<br />
// output JSON:<br />
res.setContentType(&#8220;text/javascript&#8221;);<br />
PrintWriter writer = res.getWriter();<br />
String json = new JSONGenerator().toJSON(metaBeans.values());<br />
writer.write(json);<br />
}</p></blockquote>
<p>Thats basically all! With this infrastructure your AJAX GUIs have access to meta information about the model classes.</p>
<p><strong>5. Enrich meta data with information for the GUI-layer</strong></p>
<p>You can enrich the xml meta data with additional hints (field sequence, formats, &#8230;) &#8211; whatever your GUI needs. If hhe additional information cannot be generated automatically, you should keep them in a separate xml-file:</p>
<blockquote><p>&lt;bean id=&#8221;com.agimatec.Business&#8221;&gt;<br />
&lt;feature key=&#8221;DESCRIPTION&#8221;&gt;<br />
&lt;value class=&#8221;string&#8221;&gt;{name}&lt;/value&gt;<br />
&lt;/feature&gt;<br />
&lt;feature key=&#8221;SORTING&#8221;&gt;<br />
&lt;value class=&#8221;list&#8221;&gt;<br />
&lt;string&gt;name&lt;/string&gt;<br />
&lt;string&gt;active&lt;/string&gt;<br />
&lt;/value&gt;<br />
&lt;/feature&gt;<br />
&lt;!&#8211;Visualisation as table&#8211;&gt;<br />
&lt;feature key=&#8221;TABLE_COLUMNS&#8221;&gt;<br />
&lt;value class=&#8221;list&#8221;&gt;<br />
&lt;string&gt;name&lt;/string&gt;<br />
&lt;string&gt;active&lt;/string&gt;<br />
&lt;/value&gt;<br />
&lt;/feature&gt;<br />
&lt;/bean&gt;</p></blockquote>
<p>Save this as &#8220;beaninfos-gui.xml &#8221; in the classpath and register the file in the init() method of the servlet, too:</p>
<blockquote><p>MetaBeanManagerFactory.getRegistry().addResourceLoader(&#8220;beaninfos-gui.xml&#8221;);</p></blockquote>
<p>You see, that the JSON code will contain the additional information as well, because the MetaBeanManager merges them.</p>
<p>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.</p>
<p><strong>6. User-specific meta data</strong></p>
<p>We can go one step further: We can also support user-specific meta data! A usual requirement in a web application is, that &#8211; depending on the role of a user that is logged in &#8211; field-level permissions must be supported:<br />
User A is allowed to change the &#8220;active&#8221;-state of our &#8220;Business&#8221; entity, while User B has read-only access to the field and the field is hidden for User C, &#8230;</p>
<p>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&#8230;.</p>
<p>How does it work? &#8211; Use additional xml files and merge them in the JSON servlet. (You can also generate the meta beans during runtime programmatically).</p>
<p>beaninfos-role1.xml:</p>
<blockquote><p>&lt;bean id=&#8221;com.agimatec.Business&#8221;&gt;<br />
&lt;property name=&#8221;active&#8221;&gt;<br />
&lt;feature key=&#8221;readonly&#8221;&gt;<br />
&lt;value class=&#8221;boolean&#8221;&gt;true&lt;/value&gt;<br />
&lt;/feature&gt;<br />
&lt;/property&gt;<br />
&lt;/bean&gt;</p></blockquote>
<p>Extension of the servlet:</p>
<blockquote><p>String customInfos = &#8220;beaninfos-role1.xml&#8221;; // determine this from session or request dynamically!<br />
XMLMetaBeanInfos xmlInfos =<br />
new XMLMetaBeanURLLoader(getClass().getResource(customInfos)).load();<br />
Map&lt;String, MetaBean&gt; metaBeans =<br />
MetaBeanManagerFactory.getEnricher().enrichCopies(xmlInfos);</p></blockquote>
<p>The statements after &#8220;// output JSON&#8221; stay the same (see previous code fragment).</p>
<p><strong>More information?</strong></p>
<p>We already got some more posts in German about metadata and code generation, explaining the concepts and giving examples:</p>
<ul>
<li><strong></strong><strong><a title="TransferObjects generieren" href="http://www.agimatec.de/blog/2008/05/transferobjects-generieren/">TransferObjects generieren</a></strong></li>
<li><strong></strong><strong><a title="agimatec-tools als OpenSource auf google.code released!" href="http://www.agimatec.de/blog/2008/06/agimatec-tools-als-opensource-auf-googlecode-released/">agimatec-tools als OpenSource auf google.code released!</a></strong></li>
<li><strong></strong><strong><a title="Statt Modellieren: Annotieren und generieren" href="http://www.agimatec.de/blog/2008/04/statt-modellieren-annotieren-und-generieren/">Statt Modellieren: Annotieren und generieren</a></strong></li>
<li> <strong><a title="Klassen mit Mehrwert: Validierung und Metadaten" href="http://www.agimatec.de/blog/2008/04/klassen-mit-mehrwert-validierung-und-metadaten/">Klassen mit Mehrwert: Validierung und Metadaten</a></strong></li>
</ul>
<p>The open-source frameworks have a WIKI and additional examples or junit testcases, that help you.</p>
<p>If you have questions, do not hesitate to contact us!</p>
<p><span style="color: #333333;"><strong>This is the fifth article in our mini-series about developing highly ajaxified portlets. Other articles are:</strong></span></p>
<ul>
<li><strong><a href="http://www.agimatec.de/blog/2009/03/generate-your-ui-using-metadata/">Generate Your UI Using Metadata </a></strong></li>
<li><strong><a href="http://www.agimatec.de/blog/2009/02/client-side-inter-portlet-communication-done-right/">Inter Portlet Communication</a></strong></li>
<li><strong><a href="http://www.agimatec.de/blog/2009/01/using-yui-to-load-your-javascript-modules/">Using YUI loader for your own javascript modules</a></strong></li>
<li><strong><a href="http://www.agimatec.de/blog/2008/10/advanced_javascript_namespaces_for_portlets/">Portlet namespaces and javascript</a></strong></li>
</ul>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/agimatec?a=sCgur0UI2gU:5NGzPLdvN0o:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/agimatec?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=sCgur0UI2gU:5NGzPLdvN0o:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/agimatec?i=sCgur0UI2gU:5NGzPLdvN0o:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=sCgur0UI2gU:5NGzPLdvN0o:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/agimatec?i=sCgur0UI2gU:5NGzPLdvN0o:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=sCgur0UI2gU:5NGzPLdvN0o:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/agimatec?i=sCgur0UI2gU:5NGzPLdvN0o:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=sCgur0UI2gU:5NGzPLdvN0o:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/agimatec?d=TzevzKxY174" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.agimatec.de/blog/2009/04/influencing-ajax-guis-with-metadata/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://www.agimatec.de/blog/2009/04/influencing-ajax-guis-with-metadata/</feedburner:origLink></item>
		<item>
		<title>Generate Your UI Using Metadata</title>
		<link>http://feedproxy.google.com/~r/agimatec/~3/dGt8dCwv9V4/</link>
		<comments>http://www.agimatec.de/blog/2009/03/generate-your-ui-using-metadata/#comments</comments>
		<pubDate>Fri, 13 Mar 2009 13:31:54 +0000</pubDate>
		<dc:creator>Sebastian Schuth</dc:creator>
				<category><![CDATA[English]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[metadata]]></category>

		<guid isPermaLink="false">http://www.agimatec.de/blog/?p=560</guid>
		<description><![CDATA[The team is small but tasks are legion. Business changes and you have to keep up. And you are doing ajax. You have to keep up. This is the situation we are in. And here is how we ease the pain: we are generating the user interface. Generating a Form To generate a form using [...]]]></description>
			<content:encoded><![CDATA[<p>The team is small but tasks are legion. Business changes and you have to keep up. And you are doing ajax. You have to keep up.</p>
<p>This is the situation we are in. And here is how we ease the pain: we are generating the user interface.</p>
<p><span id="more-560"></span></p>
<h1>Generating a Form</h1>
<p>To generate a form using our framework, you need to tell it :</p>
<ul>
<li>what should be edited</li>
<li>the type of what is edited</li>
</ul>
<p>Say we are building a form to edit a user object that contains user ip addresses:</p>
<pre name="code" class="javascript">
var user = {
	name:"Sebastian Schuth",
	ipAddress:"192.168.1.33",
	active:true
}
</pre>
<p>The form fields needed are described using object literals:</p>
<pre name="code" class="javascript">
var fields = [
	{
		key:'name', //name of the edited property
		label:'User name', //label to use in the form
		type: 'string',//type information
		permissioning:{denied: false, readonly: false}
	},
	{
		key:'active',
		label:'User is active',
		type: 'boolean',
		permissioning:{denied: false, readonly: false}
	},
	{
		key:'ipAddress',
		label:'IP Address',
		type: 'ipAddress',//this is a custom type
		permissioning:{denied: false,readonly: false}
	}
];
</pre>
<p>The properties needed for each field are:</p>
<ul>
<li><b>key</b> &#8211; name of the property that gets described by the entry</li>
<li><b>label</b> &#8211; description shown as label inside the form</li>
<li><b>type</b> &#8211; the type of the data stored in the property. This information is used by the framework to choose an editor implementation</li>
<li><b>permissioning</b> &#8211; data about what the user is allowed to do with the entry. This reflects what the server allows the user to do.</li>
</ul>
<p>Using this information, we can create a form using the following API:</p>
<pre name="code" class="javascript">
/**
 *

Adds a form with into the given container element using the given fieldDefinitions.

 *

The structure of the form's contents depend on the editor implementation inside fieldDefinitions. This
 * function creates just a form element as container for the elements the editors return and which it adds to the DOM.

 *

A Save button is added to the form as long as the <tt>addSaveBtn</tt>
 * config option is not set to <tt>false</tt>.
 * The <tt>fnOkCallback</tt> function must takes one parameter: it gets a new object filled with the values from the
 * created form.
 * 

 *
 * @param {object} namespace                The javascript portlet namespace (used to get I18N information)
 * @param {Element} container               HTML node to which the form is added
 * @param {object[]} fieldDefinitions       The definitions of the form fields
 * @param {function} fnOkCallback           Function which is called when the form's save button is clicked
 *                                          (if no save button is added (oConfig.addSaveBtn === false),
 *                                          this function is never called!)
 * @param {object} [oConfig]                Optional configuration.
 * @config {object} [formAttributes]        Attribute definitions for the form as key/value object.
 * @config {boolean} [addSaveBtn]           If <tt>false</tt>, no save button gets added to the form. Defaults to <tt>true</tt>.
 * @config {object[]} [additionalButtons]   Array of additional buttons that should get added left of the save button
 *                                          (if a save button is added) to the form.
 *                                          The contained objects need to members:
 *
<ul>
 *
<li><tt>label</tt> {string} Label of the button.</li>

 *
<li><tt>callback</tt> {function} Function called if the button gets clicked.</li>

 *                                          </ul>

 *                                          <b>Note:</b> Make sure to stop the click event inside the callback function
 *                                          to make sure that the form does not get send!
 *
 * @return {function} An error handling function that can be called to check for errors and add error messages to the
 * form as needed.
 */
agimatec.scaffolding.createForm = function(namespace, container, fieldDefinitions, fnOkCallback, oConfig){
	// ...
}
</pre>
<p>(as you can see, we are using JSdoc toolkit to generate our API docs)</p>
<p>So, let&#8217;s create a form:</p>
<pre name="code" class="javascript">
agimatec.scaffolding.createForm(this, formContainer, fields, null);
</pre>
<p>This call does two things: it creates a form inside <tt>formContainer</tt> and adds editor objects (read on to learn more about them!) to the field description objects given to it. </p>
<p>Now, we need to fill the form:</p>
<pre name="code" class="javascript">
agimatec.scaffolding.fillFields(user, fields);
</pre>
<p>Now, we can see what we have constructed:</p>
<div id="attachment_565" class="wp-caption alignleft" style="width: 573px"><img src="http://www.agimatec.de/blog/wp-content/uploads/2009/03/example-generated-form.png" alt="Form generated by the example code" title="From generated by the example code" width="563" height="171" class="size-full wp-image-565" /><p class="wp-caption-text">Form generated by the example code</p></div>
<p>Reading the values from the form is as easy as:</p>
<pre name="code" class="javascript">
var objectFromForm = {};
agimatec.scaffolding.readValues(objectFromForm, fields, callbackWhenDone);
</pre>
<p>After this call, <tt>objectFromForm</tt> contains all data as edited by the user.</p>
<h1>About Editors</h1>
<p>Inside the framework, editor objects are used to create the form parts needed to edit object properties. All an editor does is create a fieldset which is added to the form created by <tt>agimatec.scaffolding.createForm()</tt>, which itself gets added to the DOM.<br />
This means that if a special kind of data entry is needed, you will need to implement a special editor, which has to provide the following functions:</p>
<ul>
<li><tt>getReadWriteElement()</tt> &#8211; returns the DOM element used to edit entries</li>
<li><tt>getReadElement() - returns the DOM element used to display </tt></li>
<li><tt>setValue()</tt> &#8211; this is called by the framework when using <tt>agimatec.scaffolding.fillFields()</tt></li>
</ul>
<p>We have put together some editors (current count: 21), including ones to connect objects to other objects, upload files, entering IP addresses, weekdays, dates, times and so on. This makes maintaining our webapp much easier and guarantees the consistency our customers appreciate.</p>
<h1>Now entering the stage: Metadata</h1>
<p>Well, as easy defining fields using object literals is, this does not solve the issue of additions and changes to existing objects. This is where we added metadata to the mix. The metadata we get from the server tells us enough to create the field definitions we need to generate the forms! </p>
<p>So here we go:</p>
<pre name="code" class="javascript">
	/**
	 * Gets the field definitions for a dynamic form element (@see scaffolding.js).
	 * This function returns the sorted field definitions for a specified object. These describe which
	 * editor is used and adds further information like key and label to it.
	 * If we have an enum type, it adds also the options to an feature object.
	 * Features:
	 *
<ul>
	 *
<li>sorting of field definitions using a bean's SORTING feature</li>

	 *
<li>AJF type matching for root type and all related beans (depends if the feature "include" is set)</li>

	 *
<li>adding type of modelObject AJF type as feature "refBeanId"</li>

	 * </ul>

	 *
	 * @param {object} namespace    The javascript portlet namespace (used to get I18N information)
	 * @param {string} beanInfoId   The bean info id (e.g. 'com.agimatec.connecta.model.XFireTemplate')
	 *
	 * @return {object[]} Field definitions for the given beanInfoId.
	 */
	agimatec.metadata.getFieldDefinitions = function(namespace, beanInfoId) {/*...*/};
</pre>
<p>All you need to pass is which kind of object you want to display, the rest is handled by the framework.</p>
<h1>Whats next</h1>
<p>In this post, i explained how our framework makes creating forms for data entry easy and how we use metadata to make things even more &#8220;magic&#8221;. But this is not the end of the story. Our metadata is generated in a multi-step process, which will be described in a future post. To wet you appetite: we are generating metadata from multiple sources: Java Beans and XML descriptors and are able to merge multiple descriptors and user-based permissions.</p>
<p>Of course, generated UIs always need to be highly configurable to meet your user&#8217;s needs. Our framework offers a lot of options for this, up to defining rules that can manipulate the form reflecting what the user entered (and it looks like: <tt>formManager.when("lifecycleStatus").isSetTo("ACTIVE").changeForm(/*...actions...*/)</tt>). This makes the forms more friendly to use and prevents the user from doing things that make no sense. If you are interested, i would like to hear from you, just leave a comment.</p>
<p>Another theme i did not mention in the example is client-side validation. This is built in, too. And it is not hard to use, but explaining it would have made this article even longer. Again: if you are interested, leave a comment. If there is interest, i will blog about it. </p>
<p><span style="color: #333333;"><strong><br />
This is the fourth article in my mini-series about developing highly ajaxified portlets. In this blog, you can also find articles about:</p>
<ul>
<li><a href="http://www.agimatec.de/blog/2009/02/client-side-inter-portlet-communication-done-right/">Inter Portlet Communication</a></li>
<li><a href="http://www.agimatec.de/blog/2009/01/using-yui-to-load-your-javascript-modules/">Using YUI loader for your own javascript modules</a></li>
<li><a href="http://www.agimatec.de/blog/2008/10/advanced_javascript_namespaces_for_portlets/">Portlet namespaces and javascript</a></li>
</ul>
<p></strong></span></p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/agimatec?a=dGt8dCwv9V4:NAPKZzqvC-Q:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/agimatec?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=dGt8dCwv9V4:NAPKZzqvC-Q:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/agimatec?i=dGt8dCwv9V4:NAPKZzqvC-Q:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=dGt8dCwv9V4:NAPKZzqvC-Q:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/agimatec?i=dGt8dCwv9V4:NAPKZzqvC-Q:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=dGt8dCwv9V4:NAPKZzqvC-Q:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/agimatec?i=dGt8dCwv9V4:NAPKZzqvC-Q:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=dGt8dCwv9V4:NAPKZzqvC-Q:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/agimatec?d=TzevzKxY174" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.agimatec.de/blog/2009/03/generate-your-ui-using-metadata/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		<feedburner:origLink>http://www.agimatec.de/blog/2009/03/generate-your-ui-using-metadata/</feedburner:origLink></item>
		<item>
		<title>Dependency Management in Maven done right</title>
		<link>http://feedproxy.google.com/~r/agimatec/~3/yCsYG5r7iZ8/</link>
		<comments>http://www.agimatec.de/blog/2009/02/dependency-management-in-maven-done-right/#comments</comments>
		<pubDate>Fri, 20 Feb 2009 12:23:15 +0000</pubDate>
		<dc:creator>Simon Tiffert</dc:creator>
				<category><![CDATA[English]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Maven]]></category>
		<category><![CDATA[Open Source]]></category>

		<guid isPermaLink="false">http://www.agimatec.de/blog/?p=552</guid>
		<description><![CDATA[Despair, anger, perplexity, pain &#8211; I think we all know this moments when dealing with large Maven projects. I have seen a lot of posts in the lasts months who use some of this words. After years with Maven we learned how to deal with it. Not the pain, I mean to deal with Maven. [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.agimatec.de/blog/2009/02/dependency-management-in-maven-done-right/what/" rel="attachment wp-att-553"><img src="http://www.agimatec.de/blog/wp-content/uploads/2009/02/what.jpg" alt="what" title="what" width="424" height="283" class="alignleft size-full wp-image-553" /></a>Despair, anger, perplexity, pain &#8211; I think we all know this moments when dealing with large Maven projects. I have seen a lot of posts in the lasts months who use some of this words. After years with Maven we learned how to deal with it. Not the pain, I mean to deal with Maven. I want to share a way to avoid some pitfalls or give you some advices if you are in trouble.</p>
<p>Maven is a good tool to handle your dependencies. You shouldn&#8217;t copy the necessary artifacts by hand in your lib folder. It is the beginning of the end for your project. Transitive dependencies could ease the management of your dependencies and Maven is the right tool for this. But sometimes it is to much magic behind the scenes. There could be a lot of transitive dependencies and there could be conflicts. Even more if your projects gets larger and uses more and more open source frameworks. We had problems with two actions:</p>
<ul>
<li>Change the version of a dependency</li>
<li>Update the version of Maven</li>
</ul>
<p><span id="more-552"></span></p>
<p><strong>Change the version of a dependency</strong></p>
<p>If you update the version of a dependency this could cause completely different transitive dependencies to be fetched. Normally no big deal, but you need to clean your artifacts. Often you just use <em>mvn install</em> to install your artifact. But without the <em>clean</em> target, the old dependencies are still in your target folder. Remember to use <em>mvn clean install</em> when changing the version of a dependency. But there is also another place, where old dependencies can survive. If you hot deploy your artifacts to your server, you should also delete the old artifacts and extracted folders. After that you are in a really clean condition.</p>
<p><strong>Update the version of Maven</strong></p>
<p>We had problems with transitive dependencies when changing the version of Maven. Make sure that every team member and build server uses the same version. Then you can still have problems, but there are no different transitive resolutions on different computers. Can be very confusing if one person in the team has version A and another one has version B. I think the Maven team tries to reduce this, but if there are changes in the dependency resolution, it could happen that conflicts are solved in a different way.</p>
<h2>What about real trouble?</h2>
<p>If you have a lot open source dependencies, there are much more transitive dependencies. Maven tries to resolve conflicts, but you will often find a situation, where dependencies A and B needs the same transitive dependency but in a different version. This can produce situations, described in the post: <a href="http://agilesoftwaredevelopment.com/blog/pbielicki/maven-supports-jar-hell">Maven supports JAR hell</a>. Something is wrong and you have a lot of unwanted dependencies in your library folder. The next step is to find out, where they come from. This can be complicated, because transitive dependencies also have own transitive dependencies.</p>
<h2>Find out where the dependencies come from</h2>
<p>There are different solutions for this and Maven has improved the detection of dependencies for users. Most of the time I use the Maven site. It is always a good idea to use this feature, because it can give you a nice overview of your project. Take the time and configure your site, it is very helpful for the team.</p>
<p>To generate the Maven site just use: <em>mvn site</em></p>
<p>This will generate a linked web site, where you can use a lot plugins. There is also the section dependencies, where you can have a look what dependencies exist and watch the transitive dependencies tree.</p>
<p>But there are also command line options. First of all the <a href="http://maven.apache.org/plugins/maven-dependency-plugin/">Maven Dependency Plugin</a>. To get the transitive dependencies tree just type: <em>mvn dependency:tree</em></p>
<p>It will display where the dependencies come from. It is also possible to <a href="http://maven.apache.org/plugins/maven-dependency-plugin/examples/filtering-the-dependency-tree.html">filter the output</a> or <a href="http://maven.apache.org/plugins/maven-dependency-plugin/examples/resolving-conflicts-using-the-dependency-tree.html">find conflicts</a>.</p>
<p>We also use the concept of parent POMs with a deeper hierarchy. Sometimes you need to know, how your effective POM in the sub-project looks like. To get this information use: <em>mvn help:effective-pom</em></p>
<p>You should have a look at the <a href="http://maven.apache.org/plugins/maven-help-plugin/index.html">Maven Help Plugin</a>, because there are some interesting other options.</p>
<h2>Start your own dependency management</h2>
<p>That doesn&#8217;t mean that you don&#8217;t use Maven. But most of the time you know your artifacts and their actual version. And you want a specific version to be included. You also want to have a consistent version of an artifact used through all sub-projects, then you can use declarative dependency management in Maven. That can avoid classpath issues. It is also very easy to upgrade a version, because the child-POMs don&#8217;t have a version included. They use the version defined in the parent POM.</p>
<p>We manage our dependencies in our master parent POM. There is a section in the XML called dependencyManagement. There you can list your dependencies and add the group, the artifactId and very important: the version. Now every time Maven tries to resolve a dependency it is using this specified version. Easy, isn&#8217;t it? Yes, the dependency management list is getting larger, but in a large project you are very pleased to find always the correct version of your dependencies.</p>
<p>Read more about this in the <a href="http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Management">Maven documentation</a>.</p>
<p>For us it was a great time saver, because we had less problems with Maven. You don&#8217;t need your own dependency management, but if you run in trouble think about using it.</p>
<p>If you want the know about the best Maven plugins, check out the <a href="http://www.agimatec.de/blog/2008/08/top-10-maven-plugins/">Top 10 Maven plugins on our blog</a>.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/agimatec?a=yCsYG5r7iZ8:oLAq1P7uLLI:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/agimatec?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=yCsYG5r7iZ8:oLAq1P7uLLI:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/agimatec?i=yCsYG5r7iZ8:oLAq1P7uLLI:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=yCsYG5r7iZ8:oLAq1P7uLLI:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/agimatec?i=yCsYG5r7iZ8:oLAq1P7uLLI:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=yCsYG5r7iZ8:oLAq1P7uLLI:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/agimatec?i=yCsYG5r7iZ8:oLAq1P7uLLI:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=yCsYG5r7iZ8:oLAq1P7uLLI:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/agimatec?d=TzevzKxY174" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.agimatec.de/blog/2009/02/dependency-management-in-maven-done-right/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.agimatec.de/blog/2009/02/dependency-management-in-maven-done-right/</feedburner:origLink></item>
		<item>
		<title>Client-Side Inter Portlet Communication Done Right</title>
		<link>http://feedproxy.google.com/~r/agimatec/~3/2bnZjlhSxlU/</link>
		<comments>http://www.agimatec.de/blog/2009/02/client-side-inter-portlet-communication-done-right/#comments</comments>
		<pubDate>Tue, 10 Feb 2009 13:00:20 +0000</pubDate>
		<dc:creator>Sebastian Schuth</dc:creator>
				<category><![CDATA[English]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Portlet]]></category>

		<guid isPermaLink="false">http://www.agimatec.de/blog/?p=449</guid>
		<description><![CDATA[Using our framework, we are able to develop extremely modular portlet-based solutions that fit no matter how we combine them by using a service-publishing pattern.]]></description>
			<content:encoded><![CDATA[<p><img class="size-full wp-image-525 alignright" title="gears" src="http://www.agimatec.de/blog/wp-content/uploads/2009/02/istock_000002874245xsmall.jpg" alt="gears" width="425" height="282" />Using portlets, you are able to develop tiny little applications that are suitable for a small subset of the actual functionality your customer wants. By combining them, they make it possible to create powerful but still modular applications that meet exactly the use cases your customer needs help with.</p>
<p>In theory.</p>
<p>In practice, you will be faced with a problem that is obviously a blind spot of the portlet definition (at least, the &#8220;old&#8221; JSR-186): how to communicate between portlets. The ability to mix-and-match portlets is key to a truly pluggable application formed of portlets.</p>
<p>To solve the communication problem, we have developed a solution much like the one <a href="http://www.liferay.com/web/jferrer/blog/-/blogs/1031319">developed by the folks at liferay</a>, but a bit more tuned and optimized for a fully pluggable solution.</p>
<p><span id="more-449"></span></p>
<h1>Portlet Services and Invokers</h1>
<p>Our implementation follows a simple pattern: Portlets are able to promote services to a page-central instance and can include interaction elements that are used to invoke services that match certain criteria:</p>
<ul>
<li>the type of object the service must be able to handle</li>
<li>the type of operation the service offers</li>
</ul>
<p>Promoting a service to other portlets includes:</p>
<ul>
<li>specifying what type of operation (CREATE/READ/UPDATE/DELETE) is offered</li>
<li>a text telling the user what happens when invoking the service</li>
<li>the function that should get called on service activation</li>
</ul>
<p>Using these simple building blocks we can offer users a list of actions that are available for a specific object:</p>
<h1>Completely discoupled</h1>
<p>The major advantage of our solution is that we do not hard-wire which portlets offers what to other portlets. All you have to do is insert a service invoker into the UI and the framework does the work for you. All people working on the project can work in parallel, the communication overhead is minimal. All the developers must do is offering a portlets services using the framework and give services a name that speaks.</p>
<p>This makes turns our product into a completely customizable platform that fits exactly our users&#8217;s needs.</p>
<h1>Maximum flexibility</h1>
<p>The framework makes splitting up responsibilities between portlets easy and puzzling just the right application for the job together possible. After adding a new portlet to a page, all service menus are automatically updated to offer new services that may have been added by the new portlet.</p>
<div id="attachment_451" class="wp-caption alignnone" style="width: 313px"><img class="size-full wp-image-451 " title="Service menu showing some services that may be invoked" src="http://www.agimatec.de/blog/wp-content/uploads/2009/01/service-menu2.jpg" alt="Service menu" width="303" height="223" /><p class="wp-caption-text">A generated service menu</p></div>
<div id="attachment_452" class="wp-caption alignnone" style="width: 415px"><img class="size-full wp-image-452 " title="Service menu for another set of portlets, showing additional &quot;Ping&quot; service" src="http://www.agimatec.de/blog/wp-content/uploads/2009/01/service-menu.jpg" alt="Service menu for a different set of portlets" width="405" height="172" /><p class="wp-caption-text">Service menu for a different set of portlets</p></div>
<p>What you see in these screenshots is that depending on which portlets are available, the portlet will offer different actions for an object (for Screenshot 2, the &#8220;Ping&#8221; portlet was added). All information about which services are available is calculated client-side and for the current setup. Adding a new portlet will add its services to the actions list. The text that appears inside the menu is set by the portlet offering the service.</p>
<p><img class="size-full wp-image-534 alignnone" title="Service menu and service button" src="http://www.agimatec.de/blog/wp-content/uploads/2009/02/servicemenuandbutton.png" alt="Service menu and service button" width="629" height="147" /></p>
<p>Invoking services is not limited to the context menus. We also use buttons for services that enable the creation of new items.</p>
<h1>Impacts on portlet design</h1>
<p>All this makes it easy to develop portlets that are designed to fulfill small tasks the right way. Reusability of portlets is massively increased. And on top of all this you get a consistent usage pattern that your customers will be familiar with when you are adding more functionality.</p>
<p><span style="color: #333333;"><br />
</span></p>
<p><span style="color: #333333;"><strong>This is the third article in my mini-series about developing highly ajaxified portlets. In this blog, you can also find articles about:</strong></span></p>
<ul>
<li><span style="color: #333333;"><strong><a href="http://www.agimatec.de/blog/2009/01/using-yui-to-load-your-javascript-modules/">Using YUI loader for your own javascript modules</a><br />
</strong></span></li>
<li><span style="color: #333333;"><strong><a href="http://www.agimatec.de/blog/2008/10/advanced_javascript_namespaces_for_portlets/">Portlet namespaces and javascript</a></strong></span></li>
</ul>
<p><span style="color: #333333;"><strong>In my next post in this series, i will give a little insight into how we use metadata generated by our server to make creating a fully ajax portlet a breeze. Meanwhile, check out our posts about testing our Ajax frontends using <a href="http://www.agimatec.de/blog/2008/08/selenium-testing-of-massive-ajax-apps/">Selenium</a> and the <a href="http://www.agimatec.de/blog/2009/01/javascript-unit-tests-with-the-yui-testmanager/">YUI Test framework</a>.</strong></span><em><br />
</em></p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/agimatec?a=2bnZjlhSxlU:W-zxDsoQ20o:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/agimatec?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=2bnZjlhSxlU:W-zxDsoQ20o:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/agimatec?i=2bnZjlhSxlU:W-zxDsoQ20o:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=2bnZjlhSxlU:W-zxDsoQ20o:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/agimatec?i=2bnZjlhSxlU:W-zxDsoQ20o:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=2bnZjlhSxlU:W-zxDsoQ20o:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/agimatec?i=2bnZjlhSxlU:W-zxDsoQ20o:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=2bnZjlhSxlU:W-zxDsoQ20o:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/agimatec?d=TzevzKxY174" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.agimatec.de/blog/2009/02/client-side-inter-portlet-communication-done-right/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		<feedburner:origLink>http://www.agimatec.de/blog/2009/02/client-side-inter-portlet-communication-done-right/</feedburner:origLink></item>
		<item>
		<title>I love Oracle!</title>
		<link>http://feedproxy.google.com/~r/agimatec/~3/lH6jBB8UQA4/</link>
		<comments>http://www.agimatec.de/blog/2009/02/i-love-oracle/#comments</comments>
		<pubDate>Thu, 05 Feb 2009 16:11:31 +0000</pubDate>
		<dc:creator>roman.stumm</dc:creator>
				<category><![CDATA[English]]></category>
		<category><![CDATA[Database]]></category>

		<guid isPermaLink="false">http://www.agimatec.de/blog/?p=516</guid>
		<description><![CDATA[I execute this SQL with an Oracle 10g database with the latest JDBC driver (Oracle Thin 10.2.0.4). Can you guess the difference between select * from dual d where  d.dummy &#60;= &#8216;X&#8217; /* {} */ and select * from dual d where  d.dummy &#60;= &#8216;X&#8217; ? Just a comment? - Well, the surprise is, that [...]]]></description>
			<content:encoded><![CDATA[<p>I execute this SQL with an Oracle 10g database with the latest JDBC driver (Oracle Thin 10.2.0.4).</p>
<p>Can you guess the difference between</p>
<blockquote><p>select * from dual d where  d.dummy &lt;= &#8216;X&#8217; /* {} */</p></blockquote>
<p>and</p>
<blockquote><p>select * from dual d where  d.dummy &lt;= &#8216;X&#8217;</p></blockquote>
<p>?</p>
<p>Just a comment? -</p>
<p>Well, the surprise is, that the driver throws</p>
<p>java.lang.NullPointerException  at oracle.jdbc.driver.T4C8Oall.getNumRows(T4C8Oall.java:876)</p>
<p>in the first case that contains the comment and executes the statement correctly in the second case.</p>
<p>Thanks, Oracle!</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/agimatec?a=lH6jBB8UQA4:HDwT8Upi5uk:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/agimatec?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=lH6jBB8UQA4:HDwT8Upi5uk:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/agimatec?i=lH6jBB8UQA4:HDwT8Upi5uk:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=lH6jBB8UQA4:HDwT8Upi5uk:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/agimatec?i=lH6jBB8UQA4:HDwT8Upi5uk:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=lH6jBB8UQA4:HDwT8Upi5uk:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/agimatec?i=lH6jBB8UQA4:HDwT8Upi5uk:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=lH6jBB8UQA4:HDwT8Upi5uk:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/agimatec?d=TzevzKxY174" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.agimatec.de/blog/2009/02/i-love-oracle/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://www.agimatec.de/blog/2009/02/i-love-oracle/</feedburner:origLink></item>
		<item>
		<title>Javascript Unit Tests with the YUI TestManager</title>
		<link>http://feedproxy.google.com/~r/agimatec/~3/NuLam-xeRFk/</link>
		<comments>http://www.agimatec.de/blog/2009/01/javascript-unit-tests-with-the-yui-testmanager/#comments</comments>
		<pubDate>Thu, 29 Jan 2009 14:02:30 +0000</pubDate>
		<dc:creator>Simon Tiffert</dc:creator>
				<category><![CDATA[English]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Selenium]]></category>
		<category><![CDATA[Test]]></category>
		<category><![CDATA[YUI]]></category>

		<guid isPermaLink="false">http://www.agimatec.de/blog/?p=473</guid>
		<description><![CDATA[Testing your Javascript is very important. Especially when the amount of code is growing and growing. The easiest method are unit tests. We have tried several JS unit test frameworks. Including JSUnit, Scriptaculous Unit Test Runner and YUI test. With a lot of YUI components like the YUI Loader and many YUI widgets we refactored [...]]]></description>
			<content:encoded><![CDATA[<p><a rel="attachment wp-att-474" href="http://www.agimatec.de/blog/2009/01/javascript-unit-tests-with-the-yui-testmanager/steps-2/"><img class="alignleft size-full wp-image-474" title="steps" src="http://www.agimatec.de/blog/wp-content/uploads/2009/01/steps.jpg" alt="steps" width="425" height="282" /></a>Testing your Javascript is very important. Especially when the amount of code is growing and growing.</p>
<p>The easiest method are unit tests. We have tried several JS unit test frameworks. Including JSUnit, Scriptaculous Unit Test Runner and YUI test. With a lot of YUI components like the <a href="http://www.agimatec.de/blog/2009/01/using-yui-to-load-your-javascript-modules/">YUI Loader</a> and many <a href="http://developer.yahoo.com/yui/">YUI widgets</a> we refactored our unit tests to use YUI Test. We like the Yahoo User Interface because of its documentation and also of its code quality.</p>
<p>YUI Test is not bundled with YUI. You can use it with YUI but we also use other frameworks like Prototype and DWR. To learn more about YUI Test you can <a href="http://developer.yahoo.com/yui/yuitest/">watch the presentation of Nicholas C. Zakas</a>.</p>
<p>Ok, this is great, now I can test my Javascript. But wait, what is if I have a lot of Javascript. I can group my tests in test cases and test cases in test suites. This is supported. But while the amount of Javascript is growing one file for all tests isn&#8217;t enough. We have a lot of different modules. Each consists of a lot of test cases. Sure, you can copy them all together in a file which is several thousand lines long. But every test run takes then a lot of time, debugging is more complex and it is more complicated to manage this file.</p>
<p><span id="more-473"></span></p>
<h2>YUI TestManager</h2>
<p>Wouldn&#8217;t it be great to have a test runner. A script which takes a lot of unit test files and run them one after another.  Our first approach was based on the Scriptaculous Unit Test Runner embedded in a frameset. We had a navigation frame and some Javascript included to run one unit test file in the main frame. One problem was to collect the results of all unit test files. We patched the Unit Test Runner and collected the data. It was ok and I wanted to refactor the solution to publish it. After starting I suddenly found an undocumented feature of YUI Test &#8211; The <a href="http://developer.yahoo.com/yui/docs/YAHOO.tool.TestManager.html">YUI TestManager</a>. It is exactly what I wanted to do, define the unit test files, run through all of them and collect the results. I think Yahoo is using this feature internally and didn&#8217;t talk a lot about it. But it is included in the <a href="http://developer.yahoo.com/yui/docs/YAHOO.tool.TestManager.html">API</a>, so please YUI team, include it to the documentation. It is a great piece of code.</p>
<h2>Continuous Integration of Javascript with Selenium</h2>
<p>Before I will show you how to use it, some more thoughts about this. We are coming from the agile Java world. So continuous integration is very important for us. Please search for &#8220;Continuous Integration Javascript&#8221; in your search machine. There are just a few hits and no ready to use solution. Yes, you can try to go back to the Java world and run tests with Rhino. There are some Java based unit test frameworks for Javascript. But there are two downsides. You are leaving the Javascript world and you are leaving the browser. It can be ok for you but I don&#8217;t trust the different browsers. I want to be able to run the tests fast in the browser when I&#8217;m developing and I want to test as many browsers as I can. We searched for a solution and what we have running is a suite of Selenium tests. They are at another level. Functional tests which run through use cases in the web frontend. But if we could give them a result of our unit tests we are able to include this in our setup. Then we can run the unit tests in IE, Firefox and Opera automatically.</p>
<p>YUI Test gives you the logger to view the results of your tests. It is not the best view for test results but it is ok. Also there are a lot of events which include the results of the tests after running them. We have implemented a little script which displays a nice summary which we test with Selenium.</p>
<h2>Source code</h2>
<p>Now let&#8217;s head to the source code.</p>
<p>At the beginning we need a unit test. Because I&#8217;m want to concentrate on the TestManager you will find a very very simple test.</p>
<pre name="code" class="javascript">
&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
&lt;html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"&gt;
&lt;head&gt;
    &lt;title&gt;String test&lt;/title&gt;

    &lt;!--CSS--&gt;
	&lt;link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.6.0/build/logger/assets/logger.css"&gt;
	&lt;link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.6.0/build/yuitest/assets/testlogger.css"&gt;

	&lt;!-- Dependencies --&gt;
	&lt;script type="text/javascript" src="http://yui.yahooapis.com/2.6.0/build/yahoo-dom-event/yahoo-dom-event.js"&gt;&lt;/script&gt;
	&lt;script type="text/javascript" src="http://yui.yahooapis.com/2.6.0/build/logger/logger-min.js"&gt;&lt;/script&gt;

	&lt;!-- Source File --&gt;
	&lt;script type="text/javascript" src="http://yui.yahooapis.com/2.6.0/build/yuitest/yuitest-min.js"&gt;&lt;/script&gt;

    &lt;script type="text/javascript"&gt;
    YAHOO.tool.TestRunner.add(new YAHOO.tool.TestCase({

        name: "String test",

        testEqualityAsserts : function () {
            var Assert = YAHOO.util.Assert;

            Assert.areEqual("hel"+"lo", "hello");     //passes
            Assert.areEqual("YUI test".substr(0,3), "YUI");     //passes
        }
    }));

    YAHOO.util.Event.onDOMReady(function (){

	    if (parent &#038;&#038; parent.TestManager) {
            parent.TestManager.load();
        }
        else {
            var logger = new YAHOO.tool.TestLogger();

            //run the tests
            YAHOO.tool.TestRunner.run();
        }
  	});
  	&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>In the first part we define our tests. In the second part you will see that the test will be called after the DOM is ready. It is a little bit different from the normal examples, because we call <em>parent.TestManager.load()</em> if it is available. Now you can copy this code, write your own tests, define test suites, &#8230; It starts to get interesting, if you have so many tests, that you want to group them into different files. With the code above you can go ahead and  create multiple tests. In the example code I have created to test files calcTest.html and stringTest.html.</p>
<p>To run all tests in all your test files you need to call the TestManager:</p>
<pre name="code" class="html">
&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
&lt;html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"&gt;
&lt;head&gt;
    &lt;title&gt;JS Unit Tests&lt;/title&gt;
    &lt;meta http-equiv="content-type" content="text/html; charset=utf-8"/&gt;

    &lt;!--CSS--&gt;
    &lt;link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.6.0/build/logger/assets/logger.css"&gt;
    &lt;link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.6.0/build/yuitest/assets/testlogger.css"&gt;

    &lt;!-- Dependencies --&gt;
    &lt;script type="text/javascript" src="http://yui.yahooapis.com/2.6.0/build/yahoo-dom-event/yahoo-dom-event.js"&gt;&lt;/script&gt;
    &lt;script type="text/javascript" src="http://yui.yahooapis.com/2.6.0/build/logger/logger-min.js"&gt;&lt;/script&gt;

    &lt;!-- Source File --&gt;
    &lt;script type="text/javascript" src="http://yui.yahooapis.com/2.6.0/build/yuitest/yuitest-min.js"&gt;&lt;/script&gt;

    &lt;!-- Source file --&gt;
    &lt;script type="text/javascript"&gt;
    	var TestManager = YAHOO.tool.TestManager;

        TestManager.setPages([
            "./stringTest.html",
            "./calcTest.html"
            ]);

        YAHOO.util.Event.onDOMReady(function() {
        	TestManager.start();
        });
    &lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;h1&gt;JS Unit Tests&lt;/h1&gt;

&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>That&#8217;s simple, isn&#8217;t it?</p>
<p>That will give you the following output:<br />
<img src="http://www.agimatec.de/blog/wp-content/uploads/2009/01/logger.png" alt="logger" title="logger" width="656" height="303" class="alignnone size-full wp-image-491" /></p>
<p>We wanted to give it more the feeling of a unit test suite. As I told you there is an event after test completion, which includes the test results. With our script we are building a summary table which gives you a nice overview for your test results.<br />
<img src="http://www.agimatec.de/blog/wp-content/uploads/2009/01/testrunner.png" alt="testrunner" title="testrunner" width="713" height="502" class="alignnone size-full wp-image-492" /></p>
<p>With the overview table we also can track the results with a simple Selenium test:</p>
<pre name="code" class="java">
package com.agimatec.ostium.portlets.jsunit;

import com.agimatec.ostium.portlets.util.ScreenshottingSelenium;
import com.thoughtworks.selenium.Selenium;
import org.testng.Assert;
import org.testng.Reporter;
import org.testng.annotations.*;

public class JsUnitTest {
    Selenium selenium;

    @BeforeMethod
    @Parameters({"selenium.host", "selenium.port", "browser", "baseUrl", "ostium.login",
            "ostium.password"})
    public void startSelenium(
            @Optional("localhost")String host,
            @Optional("4444")int port,
            @Optional("*firefox")String browser,
            @Optional("http://localhost:8080")String baseUrl
    ) throws Exception {
        Reporter.log("Running selenium");
        selenium = new ScreenshottingSelenium(host, port, browser, baseUrl);
        selenium.start();
    }

    @Test
    public void checkPassedJsUnitTests() throws InterruptedException {
        selenium.open("/portlets/ostium/utilities/ajf/src/test/javascript/testrunner.html");
        for (int second = 0; ; second++) {
            if (second >= 60) Assert.fail("timeout");
            try {
                if (selenium.isElementPresent("//div[@id='testcontainer']/div/h2")) break;
            } catch (Exception e) {
            }
            Thread.sleep(1000);
        }

        Assert.assertTrue(
                selenium.isTextPresent("exact:Result: Passed"),
                "The result of the JS tests should be 'PASSED'.");
    }

    @AfterMethod
    public void stopSelenium() {
        Reporter.log("Stopping selenium");
        selenium.stop();
    }
}
</pre>
<p>The only thing to do is to run the files on a local server. We use a Jetty with Maven to host the files because Selenium needs to include a proxy which didn&#8217;t work if you access the file directly. </p>
<p>Find more to Selenium on our other posts:</p>
<ul>
<li><a href="http://www.agimatec.de/blog/2008/08/selenium-testing-of-massive-ajax-apps/">Selenium testing of massive Ajax Apps</a></li>
<li><a href="http://www.agimatec.de/blog/2008/07/selenium-ci-tests-with-teamcity/">Selenium CI tests with TeamCity</a></li>
<li><a href="http://www.agimatec.de/blog/2008/07/robust-portlet-testing/">Robust portlet testing</a></li>
</ul>
<p><a href='http://www.agimatec.de/blog/wp-content/uploads/2009/01/yuitestmanager.zip'>Download the script and some examples here.</a> We are planning to release it with some other JS stuff as a Google code project, but we are still searching for a name. </p>
<p>If this post was helpful or you have additional ideas, please don&#8217;t hesitate to comment. </p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/agimatec?a=NuLam-xeRFk:lO_Dj3paNl0:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/agimatec?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=NuLam-xeRFk:lO_Dj3paNl0:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/agimatec?i=NuLam-xeRFk:lO_Dj3paNl0:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=NuLam-xeRFk:lO_Dj3paNl0:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/agimatec?i=NuLam-xeRFk:lO_Dj3paNl0:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=NuLam-xeRFk:lO_Dj3paNl0:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/agimatec?i=NuLam-xeRFk:lO_Dj3paNl0:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/agimatec?a=NuLam-xeRFk:lO_Dj3paNl0:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/agimatec?d=TzevzKxY174" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.agimatec.de/blog/2009/01/javascript-unit-tests-with-the-yui-testmanager/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		<feedburner:origLink>http://www.agimatec.de/blog/2009/01/javascript-unit-tests-with-the-yui-testmanager/</feedburner:origLink></item>
	</channel>
</rss>

