<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	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/"
	>

<channel>
	<title>Tech Rocket Science</title>
	<atom:link href="http://rocketscience.itteco.org/feed/" rel="self" type="application/rss+xml" />
	<link>http://rocketscience.itteco.org</link>
	<description>Itteco hackers tackle challenges and blog as the go</description>
	<lastBuildDate>Fri, 09 Jul 2010 12:26:17 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Integrating Magnolia CMS and custom application security</title>
		<link>http://rocketscience.itteco.org/2010/07/09/integrating-magnolia-cms-and-custom-application-security/</link>
		<comments>http://rocketscience.itteco.org/2010/07/09/integrating-magnolia-cms-and-custom-application-security/#comments</comments>
		<pubDate>Fri, 09 Jul 2010 12:26:17 +0000</pubDate>
		<dc:creator>Andrei Panasyuk</dc:creator>
				<category><![CDATA[Integration]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[j2ee]]></category>
		<category><![CDATA[magnolia]]></category>

		<guid isPermaLink="false">http://rocketscience.itteco.org/?p=826</guid>
		<description><![CDATA[We have an application integrated into Magnolia CMS. and it&#8217;s quite natural to have a single way of handling security. Both Magnolia and our application use JAAS for authentication. However magnolia uses JCR repository to store security data, while our application uses database. Since we didn&#8217;t want to cause some possible side effects in Magnolia [...]]]></description>
			<content:encoded><![CDATA[<p>We have an application integrated into Magnolia CMS. and it&#8217;s quite natural to have a single way of handling security. Both Magnolia and our application use JAAS for authentication. However magnolia uses JCR repository to store security data, while our application uses database. Since we didn&#8217;t want to cause some possible side effects in Magnolia &#8211; the following model was applied: users and a limited set of roles is synchronized between application and Magnolia.</p>
<p>Let&#8217;s look at how it looks like.</p>
<p>The first step is to edit login.conf file<br />
Initially it looks like:<br />
<code><br />
appRealm {<br />
com.app.security.AppLoginModule required;<br />
};</code><br />
<code><br />
magnolia {<br />
info.magnolia.jaas.sp.jcr.JCRAuthenticationModule requisite;<br />
info.magnolia.jaas.sp.jcr.JCRAuthorizationModule required;<br />
};<br />
</code></p>
<p>Lets change it to:<br />
<code><br />
appRealm {<br />
com.app.security.AppLoginModule requisite;<br />
};</code><br />
<code><br />
magnolia {<br />
com.app.security.CustomLoginModule requisite;<br />
info.magnolia.jaas.sp.jcr.JCRAuthorizationModule required;<br />
};<br />
</code></p>
<p>Where <i>com.app.security.CustomLoginModule,</i> is a new class which is inherited from <i>info.magnolia.jaas.sp.jcr.JCRAuthenticationModule</i>. Below is the code which is used to </p>
<p><code><br />
public&nbsp;class&nbsp;CustomLoginModule&nbsp;extends&nbsp;JCRAuthenticationModule&nbsp;{<br />
&nbsp;&nbsp;//&nbsp;Cached&nbsp;user&nbsp;data&nbsp;from&nbsp;the&nbsp;database<br />
&nbsp;&nbsp;UserDto&nbsp;cachedUser;<br />
&nbsp;&nbsp;//&nbsp;Cached&nbsp;entity<br />
&nbsp;&nbsp;Entity&nbsp;entity;</code></p>
<p><code>&nbsp;&nbsp;@Override<br />
&nbsp;&nbsp;protected&nbsp;void&nbsp;initUser()&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Get&nbsp;magnolia&nbsp;a&nbsp;chance&nbsp;to&nbsp;load&nbsp;it's&nbsp;own&nbsp;user.<br />
&nbsp;&nbsp;&nbsp;&nbsp;super.initUser();<br />
&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp;If&nbsp;the&nbsp;user&nbsp;is&nbsp;not&nbsp;available&nbsp;in&nbsp;Magnolia&nbsp;<br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // JCR&nbsp;repository&nbsp;-&nbsp;null&nbsp;is&nbsp;returned.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(getUser()&nbsp;!=&nbsp;null)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Lets&nbsp;synchronize&nbsp;data&nbsp;from&nbsp;JCR&nbsp;repository&nbsp;</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // </code><code>with&nbsp;the&nbsp;data&nbsp;in&nbsp;the&nbsp;app&nbsp;database.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;synchronizeUser(getUser(),&nbsp;User.class);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</code></p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Reading user data from DB<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;final&nbsp;InitialContext&nbsp;ic&nbsp;=&nbsp;new&nbsp;InitialContext();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;service&nbsp;=&nbsp;ic</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .lookup("com.app.service.users.AuthenticationService");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;final&nbsp;Class&nbsp;authenticationServiceClass&nbsp;</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =&nbsp;service.getClass();</code></p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;final&nbsp;Method&nbsp;authenticationMethod&nbsp;=<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;authenticationServiceClass.getMethod("authenticateUser",</code><br />
<code>&nbsp; &nbsp; &nbsp; &nbsp; String.class, String.class);</code></p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cachedUser&nbsp;=&nbsp;(UserDto)&nbsp;authenticationMethod.invoke(</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; service,&nbsp;name, new&nbsp;String(pswd));</code></p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;In&nbsp;case&nbsp;if&nbsp;the&nbsp;password&nbsp;of&nbsp;the&nbsp;user&nbsp;has&nbsp;been&nbsp;</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // changed&nbsp;in&nbsp;magnolia&nbsp;-&nbsp;synchronize&nbsp;it.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(getUser()&nbsp;==&nbsp;null)&nbsp;{&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cachedUser.password&nbsp;=&nbsp;new&nbsp;String(pswd);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</code></p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Add&nbsp;required&nbsp;roles&nbsp;into&nbsp;JAAS&nbsp;context<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;final&nbsp;RoleListImpl&nbsp;roleListImpl&nbsp;=&nbsp;new&nbsp;RoleListImpl();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(String&nbsp;group&nbsp;:&nbsp;cachedUser.groups)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;roleListImpl.add(group);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</code></p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;In&nbsp;case&nbsp;if&nbsp;the&nbsp;subject&nbsp;was&nbsp;intialized&nbsp;by&nbsp;</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // the&nbsp;Magnolia&nbsp;-&nbsp;initialize&nbsp;it.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(getUser()&nbsp;==&nbsp;null)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;subject.getPrincipals().add(getEntity());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;subject.getPrincipals().add(roleListImpl);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;subject.getPrincipals().add(new&nbsp;GroupListImpl());</code></p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Custom&nbsp;user&nbsp;implementation&nbsp;which&nbsp;extends&nbsp;</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // info.magnolia.cms.security.ExternalUser<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GenesUser&nbsp;genesUser&nbsp;=&nbsp;</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new&nbsp;GenesUser(subject,&nbsp;cachedUser);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;user&nbsp;=&nbsp;genesUser;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Synchronize&nbsp;user&nbsp;stored&nbsp;in&nbsp;Magnolia&nbsp;with&nbsp;</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp; // the&nbsp;data&nbsp;from&nbsp;app&nbsp;database.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;synchronizeUser(cachedUser,&nbsp;UserDto.class);</code></p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Since&nbsp;now&nbsp;the&nbsp;users&nbsp;are&nbsp;synchronized</code><br />
<code>&nbsp; &nbsp;&nbsp; // -&nbsp;login&nbsp;programatically&nbsp;into&nbsp;into&nbsp;application.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;ProgrammaticLogin().login(name,&nbsp;new&nbsp;String(pswd),&nbsp;"app"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MgnlContext.getWebContext().getRequest(),&nbsp;</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MgnlContext.getWebContext().getResponse(), true);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(Exception&nbsp;e)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LOGGER.error(e.getMessage());<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;}</code></p>
<p><code>&nbsp;//&nbsp;Builds&nbsp;entity&nbsp;object&nbsp;from&nbsp;the&nbsp;cached&nbsp;user.<br />
&nbsp;public&nbsp;Entity&nbsp;getEntity()&nbsp;{<br />
&nbsp;&nbsp;&nbsp;if(entity&nbsp;==&nbsp;null)&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;entity&nbsp;=&nbsp;new&nbsp;EntityImpl();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;entity.addProperty(Entity.NAME,&nbsp;this.cachedUser.username);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;entity.addProperty(Entity.FULL_NAME,&nbsp;</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.cachedUser.fullName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;entity.addProperty(Entity.PASSWORD,&nbsp;new&nbsp;String(this.pswd));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;entity.addProperty(Entity.EMAIL,&nbsp;cachedUser.email);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;entity.addProperty(Entity.ADDRESS_LINE,&nbsp;</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cachedUser.address);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(String&nbsp;group&nbsp;:&nbsp;cachedUser.groups)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;addRoleName(group);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;return&nbsp;entity;<br />
&nbsp;}</code></p>
<p><code>&nbsp;&nbsp;//&nbsp;Synchronizes&nbsp;users&nbsp;of&nbsp;Magnolia&nbsp;and&nbsp;app,&nbsp;</code><br />
<code>&nbsp; // It's&nbsp;a&nbsp;simple&nbsp;reflection&nbsp;call&nbsp;to&nbsp;some<br />
&nbsp;&nbsp;//&nbsp;other&nbsp;class&nbsp;which&nbsp;is&nbsp;responsible&nbsp;for&nbsp;synchronization.<br />
&nbsp;&nbsp;private&nbsp;void&nbsp;synchronizeUser(Object&nbsp;user,&nbsp;Class&nbsp;paramClass)&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;final&nbsp;Class&nbsp;classData =&nbsp;Class.forName(</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "com.soluter.genes.AccountSynchronizer");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;final&nbsp;Method&nbsp;method&nbsp;</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =&nbsp;classData.getMethod("synchronizeUser",&nbsp;paramClass);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;method.invoke(null,&nbsp;user);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(Exception&nbsp;ex)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;RuntimeException(ex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;}<br />
}<br />
</code></p>
<p>AccountSynchronizer does two-way synchronization between JCR repository and application database.<br />
<code><br />
public&nbsp;class&nbsp;AccountSynchronizer&nbsp;{<br />
&nbsp; // Gets data from the magnolia user and outs them into app database. </code><br />
<code>&nbsp; public&nbsp;static&nbsp;void&nbsp;synchronizeUser(User&nbsp;user)&nbsp;{</code><br />
<code>&nbsp;&nbsp;&nbsp; // Skip user synchronization for the default users<br />
&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(MgnlUserManager.ANONYMOUS_USER.equals(user.getName())<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;||&nbsp;MgnlUserManager.SYSTEM_USER.equals(user.getName()))&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;</code><br />
<code> &nbsp;&nbsp;&nbsp; // Reading user.</code><br />
<code>&nbsp;&nbsp;&nbsp; final&nbsp;UserService&nbsp;userService&nbsp;</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =&nbsp;getServiceLocator().getUserService();<br />
&nbsp;&nbsp;&nbsp;&nbsp;UserDetailsDto&nbsp;userData&nbsp;</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =&nbsp;userService.getUserDetails(user.getName());<br />
&nbsp;&nbsp;&nbsp;&nbsp;boolean&nbsp;newUser&nbsp;=&nbsp;userData&nbsp;==&nbsp;null;<br />
&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(newUser)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // In case if the user does not exist in app - create it.</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;userData&nbsp;=&nbsp;new&nbsp;UserDetailsDto();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</code></p>
<p><code>&nbsp;&nbsp;&nbsp; // Synchronizing data and roles.<br />
&nbsp;&nbsp;&nbsp;&nbsp;userData.password&nbsp;=&nbsp;user.getPassword();<br />
&nbsp;&nbsp;&nbsp;&nbsp;userData.username&nbsp;=&nbsp;user.getName();<br />
&nbsp;&nbsp;&nbsp;&nbsp;userData.email&nbsp;=&nbsp;user.getProperty(Entity.EMAIL);<br />
</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;</code><br />
<code>&nbsp;&nbsp;&nbsp; // Saving data.<br />
&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(newUser)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;userService.createUser(userData);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;userService.saveUser(userData);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(Exception&nbsp;ex)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;RuntimeException(ex);<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;}</code><br />
<code><br />
</code><br />
<code></code><br />
<code>&nbsp; // Synchronizes Magnolia user with the data from app data base&nbsp;<br />
&nbsp; public&nbsp;static&nbsp;void&nbsp;synchronizeUser(UserDto&nbsp;user)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;{</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Reading public branch of the USERS workspace<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;final&nbsp;HierarchyManager&nbsp;hierarchyManager&nbsp;</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =&nbsp;MgnlContext.getSystemContext()</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .getHierarchyManager(ContentRepository.USERS);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Content&nbsp;content&nbsp;=&nbsp;ContentUtil.getOrCreateContent(</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hierarchyManager.getRoot().getContent("public"),</code><br />
<code>&nbsp; &nbsp; &nbsp; &nbsp; user.username,&nbsp;ItemType.USER,&nbsp;true);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MgnlUser&nbsp;mgnlUser&nbsp;=&nbsp;new&nbsp;MgnlUser(content)&nbsp;{</code><br />
<code><br />
</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Change behaviour of what should happen in case of&nbsp;</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // adding role.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;addRole(String&nbsp;roleName)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;final&nbsp;HierarchyManager&nbsp;hierarchyManager&nbsp;</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =&nbsp;MgnlContext.getSystemContext()</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .getHierarchyManager(ContentRepository.USER_ROLES);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;{</code><br />
<code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; </code><code>// Change behaviour of what should&nbsp;</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // happen in case of adding role</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Content&nbsp;node&nbsp;=&nbsp;ContentUtil</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .getOrCreateContent(this.getUserNode(),&nbsp;</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "roles",&nbsp;ItemType.CONTENTNODE,&nbsp;true);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String&nbsp;value&nbsp;=&nbsp;hierarchyManager.getContent(</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "/"&nbsp;+&nbsp;roleName).getUUID();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HierarchyManager&nbsp;usersHM&nbsp;</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; =&nbsp;MgnlContext.getSystemContext()</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .getHierarchyManager(ContentRepository.USERS);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String&nbsp;newName&nbsp;=&nbsp;Path.getUniqueLabel(</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; usersHM,&nbsp;node.getHandle(),&nbsp;"0");</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // New node is created in repo<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; node.createNodeData(newName).setValue(value);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(Exception&nbsp;e)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p></code><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Change behaviour of what should happen&nbsp;</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // in case of removing&nbsp; role.<br />
</code><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @Override<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;removeRole(String&nbsp;roleName)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;final&nbsp;HierarchyManager&nbsp;hierarchyManager&nbsp;</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =&nbsp;MgnlContext.getSystemContext()</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .getHierarchyManager(</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ContentRepository.USER_ROLES);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Content&nbsp;node&nbsp;=&nbsp;ContentUtil</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .getOrCreateContent(this.getUserNode(),&nbsp;"roles",</code><br />
<code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ItemType.CONTENTNODE,&nbsp;true);<br />
</code><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Pass through all of the nodes and get&nbsp;</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // determine node to be deleted<br />
</code><code></code><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for&nbsp;(NodeData&nbsp;nodeData&nbsp;:&nbsp;</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; node.getNodeDataCollection())&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(hierarchyManager.getContentByUUID(</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nodeData.getString())</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .getName().equalsIgnoreCase(roleName))&nbsp;{<br />
</code><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Node is deleted from repo<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nodeData.delete();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(Exception&nbsp;e)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};</code></p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Syncronizing roles/profile data of the user.</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if&nbsp;(user.password&nbsp;!=&nbsp;null)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mgnlUser.setProperty(</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MgnlUserManager.PROPERTY_PASSWORD,</code><br />
<code>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; new&nbsp;String(Base64.encodeBase64(user.password.getBytes())));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mgnlUser.setProperty(MgnlUserManager.PROPERTY_EMAIL,</code><br />
<code>&nbsp; &nbsp; &nbsp; &nbsp; user.email);</code></p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </code><code>// determine roles to be added</code><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </code><br />
&nbsp;<code>&nbsp;&nbsp;&nbsp;&nbsp; final&nbsp;List rolesToAdd = ...;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </code><code>// determine roles to be removed</code><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; final&nbsp;List rolesToRemove = ...;</code><code>&nbsp; </code><br />
<code></code><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; final&nbsp;List&nbsp;currentRoles&nbsp;=&nbsp;Arrays.asList(user.groups);<br />
</code><br />
<code><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Remove roles.</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for&nbsp;(String&nbsp;roleName&nbsp;: </code><code>rolesToRemove</code><code>)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mgnlUser.removeRole(roleName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
</code></p>
<p><code><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Add roles.</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for&nbsp;(String&nbsp;roleName&nbsp;: </code><code>rolesToAdd</code><code>)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mgnlUser.addRole(roleName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</code></p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Save user data.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mgnlUser.getUserNode().save();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(Exception&nbsp;ex)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;RuntimeException(ex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;}<br />
}<br />
</code></p>
<p>Since we already have application UI which is used to create roles specific for the application, change user details and password - we call AccountSynchronizer#synchronizeUser every time we update user account.</p>
<p>Also we allow anonymous users to access web site and have a separate login form. To provide logins both into magnolia and application from the form - the following code is used:</p>
<p><code><br />
// Login into application<br />
new ProgrammaticLogin().login(username, password,<br />
&nbsp;&nbsp;"app", getThreadLocalRequest(), getThreadLocalResponse(),<br />
&nbsp;&nbsp;true);</code></p>
<p><code>// Login into magnolia<br />
CredentialsCallbackHandler callbackHandler = new PlainTextCallbackHandler(<br />
&nbsp;&nbsp;username, password.toCharArray(), "public");</code><br />
<code> SecuritySupport.Factory.getInstance().authenticate(<br />
&nbsp;&nbsp;callbackHandler, "magnolia");<br />
</code></p>
]]></content:encoded>
			<wfw:commentRss>http://rocketscience.itteco.org/2010/07/09/integrating-magnolia-cms-and-custom-application-security/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Java Resource File Editor</title>
		<link>http://rocketscience.itteco.org/2010/07/09/java-resource-file-editor/</link>
		<comments>http://rocketscience.itteco.org/2010/07/09/java-resource-file-editor/#comments</comments>
		<pubDate>Fri, 09 Jul 2010 09:01:41 +0000</pubDate>
		<dc:creator>Andrei Panasyuk</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Plugins]]></category>
		<category><![CDATA[Useful]]></category>
		<category><![CDATA[localization]]></category>

		<guid isPermaLink="false">http://rocketscience.itteco.org/?p=819</guid>
		<description><![CDATA[Localization support in Java is rather good. But what about the convenience of providing localized resource bundles?
I usually use NetBeans for the development and editing resource files. But what if you would like to provide this localization files for your customer? So we&#8217;ve decided to do some investigations on this topic. The primary criteria according [...]]]></description>
			<content:encoded><![CDATA[<p>Localization support in Java is rather good. But what about the convenience of providing localized resource bundles?</p>
<p>I usually use NetBeans for the development and editing resource files. But what if you would like to provide this localization files for your customer? So we&#8217;ve decided to do some investigations on this topic. The primary criteria according to which the tools were estimated are the following:</p>
<ol>
<li>Simplicity of use</li>
<li>Support of simultaneous display of multiple language data (required)</li>
<li>Detecting keys with the missed translations and highlighting them</li>
<li>Usually I group properties in some way, so that properties from the same screen are situated closely in the properties file. It would be nice not break this groups.</li>
<li>Stability</li>
<li>License should allow you to change the source-code in case if you need to fix some defects occur. (required)</li>
</ol>
<p>Let&#8217;s start with small standalone tools, which can be easily used if you already have JRE installed.</p>
<p><strong><a href="https://resourcebundleeditor.dev.java.net/">Resource Bundle Editor</a></strong></p>
<p><em> Pros:</em></p>
<ol>
<li>It&#8217;s a single tool in the review which does  versioning of the content by itself. It adds specific comments which  allow to track changes across files.</li>
<li>Good documentation. I personally believe that it was created because the  tool itself is rather complex to use.</li>
</ol>
<p><em>Cons:</em></p>
<ol>
<li>Not supported since 2006</li>
<li>Not stable. While playing for 10 minutes &#8211; I&#8217;ve noticed several defects.<strong></strong></li>
<li>No highlight of the missed items<strong></strong></li>
<li>Complex UI<strong><br />
</strong></li>
</ol>
<p style="text-align: center"><em> </em><a href="http://1.bp.blogspot.com/_8mJHR27FNWA/TDbIyUU7t9I/AAAAAAAAAEc/UjVoZWvM6LQ/s1600/Resource-1.png"><img class="aligncenter" src="http://1.bp.blogspot.com/_8mJHR27FNWA/TDbIyUU7t9I/AAAAAAAAAEc/UjVoZWvM6LQ/s640/Resource-1.png" border="0" alt="" width="640" height="403" /></a></p>
<p>After saving file &#8211; it&#8217;s totally changed and contains added comments required for versioning.</p>
<p style="text-align: center"><img class="aligncenter" src="http://1.bp.blogspot.com/_8mJHR27FNWA/TDbI9V2_f2I/AAAAAAAAAEk/Jo7hOqQL6to/s640/Resource-1a.png" border="0" alt="" width="640" height="462" /><br />
<a href="http://1.bp.blogspot.com/_8mJHR27FNWA/TDbI9V2_f2I/AAAAAAAAAEk/Jo7hOqQL6to/s1600/Resource-1a.png"></a></p>
<p><em>Personal Opinion:</em> Unstable tool which has a very complex UI and a unique versioning feature. Changes properties file incredibly. Not going to propose it to our customers.</p>
<p><a href="http://sourceforge.net/projects/popeye"><strong>Popeye</strong></a></p>
<p><em>Pros:</em></p>
<ol>
<li>Highlightning of the missed values</li>
<li>Cute and simple UI</li>
</ol>
<p><em>Cons:</em></p>
<ol>
<li>Not supported since 2007</li>
<li>Not very stable. I&#8217;ve observed several exceptions in the console but didn&#8217;t notice that it has influenced any functionality.</li>
</ol>
<div class="separator" style="clear: both;text-align: center"><a href="http://3.bp.blogspot.com/_8mJHR27FNWA/TDbMfO_yobI/AAAAAAAAAEs/PaDPaiBC8dY/s1600/Resource-2.png"><img src="http://3.bp.blogspot.com/_8mJHR27FNWA/TDbMfO_yobI/AAAAAAAAAEs/PaDPaiBC8dY/s640/Resource-2.png" border="0" alt="" width="640" height="436" /></a></div>
<p>After saving &#8211; the content of the properties files was reorganized but it was done in quite a smart way.</p>
<div class="separator" style="clear: both;text-align: center"><a href="http://2.bp.blogspot.com/_8mJHR27FNWA/TDbMkeFgaAI/AAAAAAAAAE0/5ssV0HXkf-c/s1600/Resource-2a.png"><img src="http://2.bp.blogspot.com/_8mJHR27FNWA/TDbMkeFgaAI/AAAAAAAAAE0/5ssV0HXkf-c/s640/Resource-2a.png" border="0" alt="" width="640" height="460" /></a></div>
<p><em><br />
</em><br />
<em>Personal Opinion: </em>If you need a simple and a smart tool &#8211; Popeye is your choice. Not absolutely sure about the general stability of it but it worked nicely in my case. Going to propose it for our customers.</p>
<p><strong><a href="https://prbeditor.dev.java.net/">prbeditor</a></strong></p>
<p><em>Pros:</em></p>
<ol>
<li>Simple and functional UI<em></em></li>
<li>Seems to be rather stable, no problems were observed during testing.<em><br />
</em></li>
</ol>
<p><em>Cons:</em></p>
<ol>
<li>Not supported since 2007<em> </em><strong></strong></li>
<li>Rows with the missed values are not highlighted<strong><br />
</strong></li>
</ol>
<div class="separator" style="clear: both;text-align: center"><a href="http://3.bp.blogspot.com/_8mJHR27FNWA/TDbOjPDWDZI/AAAAAAAAAE8/SZI4Ot2sAkM/s1600/Resource-3.png"><img src="http://3.bp.blogspot.com/_8mJHR27FNWA/TDbOjPDWDZI/AAAAAAAAAE8/SZI4Ot2sAkM/s640/Resource-3.png" border="0" alt="" width="640" height="400" /></a></div>
<p>The result after save was rather strange.</p>
<div class="separator" style="clear: both;text-align: center"><a href="http://3.bp.blogspot.com/_8mJHR27FNWA/TDbOm13rLMI/AAAAAAAAAFE/QMXTygZAPG0/s1600/Resource-3a.png"><img src="http://3.bp.blogspot.com/_8mJHR27FNWA/TDbOm13rLMI/AAAAAAAAAFE/QMXTygZAPG0/s640/Resource-3a.png" border="0" alt="" width="640" height="460" /></a></div>
<p><em>Personal Opinion: </em>Stable, simple and nice tool which lacks highlight of the missed items. The order of the saved values seems to be rather strange. Won&#8217;t propose to our customer because of the absent highlighting.</p>
<p><a href="http://www.zaval.org/products/jrc-editor/"><strong>Zaval</strong></a></p>
<p>Previously this tool was used by one of our customers.</p>
<p><em>Pros:</em></p>
<ol>
<li>Simple</li>
<li>Missed values are highlighted</li>
</ol>
<p><em>Cons:</em></p>
<ol>
<li>UI from the 90th</li>
<li>Not stable. A number of exception and problems were observed during testing</li>
<li>Last release occurred in 2004</li>
</ol>
<div class="separator" style="clear: both;text-align: center"><a href="http://2.bp.blogspot.com/_8mJHR27FNWA/TDbTg_OWZMI/AAAAAAAAAFM/ov2zhMBxOYg/s1600/Resource-4.png"><img src="http://2.bp.blogspot.com/_8mJHR27FNWA/TDbTg_OWZMI/AAAAAAAAAFM/ov2zhMBxOYg/s640/Resource-4.png" border="0" alt="" width="632" height="640" /></a></div>
<p>The order of the content became rather strange after editing in Zaval</p>
<div class="separator" style="clear: both;text-align: center"><a href="http://2.bp.blogspot.com/_8mJHR27FNWA/TDbTjDXltDI/AAAAAAAAAFU/F6oVo2ft9UM/s1600/Resource-4a.png"><img src="http://2.bp.blogspot.com/_8mJHR27FNWA/TDbTjDXltDI/AAAAAAAAAFU/F6oVo2ft9UM/s640/Resource-4a.png" border="0" alt="" width="640" height="462" /></a></div>
<p><em>Personal Opinion: </em>Not stable tool from the past. Won&#8217;t recommend it to our customer.</p>
<p><strong>Conclusion</strong></p>
<p>Based on the results of the review, Popeye was selected to be proposed for customer.</p>
<p>However as you can see, all of the mentioned tools are a bit outdated. So it was decided to look at a more dynamic and supported segment of IDEs. Three of the most popular IDEs were under review: NetBeans, Eclipse and IntelliJ IDEA Community Edition</p>
<p><a href="http://www.netbeans.org/"><strong>NetBeans</strong></a>: <a href="http://plugins.netbeans.org/PluginPortal/faces/PluginDetailPage.jsp?pluginid=11754"><span><span style="font-size: 14px;font-weight: bold">Resource Bundle Editor</span></span></a></p>
<p><em>Pros:</em></p>
<ol>
<li>Integrated into my favourite IDE <img src='http://rocketscience.itteco.org/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </li>
</ol>
<p><em>Cons:</em></p>
<ol>
<li>Rows with the missed values are not highlighted</li>
<li>Seems to be a bit outdated. Support for 6.5 is declared only. But works fine in 6.8</li>
</ol>
<div class="separator" style="clear: both;text-align: center"><a href="http://1.bp.blogspot.com/_8mJHR27FNWA/TDbW5O4cRBI/AAAAAAAAAFc/4AYdWBu4vyg/s1600/Resource-8.png"><img src="http://1.bp.blogspot.com/_8mJHR27FNWA/TDbW5O4cRBI/AAAAAAAAAFc/4AYdWBu4vyg/s640/Resource-8.png" border="0" alt="" width="640" height="372" /></a></div>
<p>The behaviour of the save operation is ideal. Everything remains on its own places.</p>
<div class="separator" style="clear: both;text-align: center"><a href="http://1.bp.blogspot.com/_8mJHR27FNWA/TDbXKiEyIfI/AAAAAAAAAFk/OO3zv9J6v1A/s1600/Resource-8a.png"><img src="http://1.bp.blogspot.com/_8mJHR27FNWA/TDbXKiEyIfI/AAAAAAAAAFk/OO3zv9J6v1A/s640/Resource-8a.png" border="0" alt="" width="640" height="458" /></a></div>
<p><em>Personal Opinion: </em>Nice plug-in which unfortunately does not highlight missed values.</p>
<p><a href="http://www.jetbrains.com/idea/"><strong>IntelliJ IDEA Community Edition</strong></a></p>
<p><em>Pros:</em></p>
<ol>
<li>Everything works perfectly. It fully meets specified criteria.</li>
<li>No need to install plug-in. It&#8217;s already bundled in the installation.</li>
</ol>
<div class="separator" style="clear: both;text-align: center"><a href="http://2.bp.blogspot.com/_8mJHR27FNWA/TDbYsuA30NI/AAAAAAAAAFs/yZXHo0_wqJU/s1600/Resource-7.png"><img src="http://2.bp.blogspot.com/_8mJHR27FNWA/TDbYsuA30NI/AAAAAAAAAFs/yZXHo0_wqJU/s640/Resource-7.png" border="0" alt="" width="640" height="448" /></a></div>
<p><strong><br />
</strong><br />
Order of the saved is also perfect.<strong> </strong><br />
<strong><br />
</strong></p>
<div class="separator" style="clear: both;text-align: center"><a href="http://3.bp.blogspot.com/_8mJHR27FNWA/TDbZR2ZXmAI/AAAAAAAAAF0/96m9kTyONwo/s1600/Resource-7a.png"><img src="http://3.bp.blogspot.com/_8mJHR27FNWA/TDbZR2ZXmAI/AAAAAAAAAF0/96m9kTyONwo/s640/Resource-7a.png" border="0" alt="" width="640" height="458" /></a></div>
<p><strong><br />
</strong><br />
<em>Personal Opinion:</em> I really like the way it&#8217;s implemented in IDEA. Simple, stable and rather smart.</p>
<p><strong><a href="http://www.eclipse.org/">Eclipse</a>: <a href="http://wiki.eclipse.org/Babel_/_Message_Bundle_Editor">Babel</a></strong></p>
<p><em>Pros:</em></p>
<ol>
<li>Babel is unbelievably smart and unbelievably integrated into Eclipse. Duplicated and missed entries are displayed in the Problems view.</li>
<li>Missed items are highlighted</li>
</ol>
<p><em>Cons:</em></p>
<ol>
<li>Binary bundles are not available on the official page. You&#8217;ll need either to build plug-in from sources or find built already somewhere else.</li>
</ol>
<div class="separator" style="clear: both;text-align: center"><a href="http://3.bp.blogspot.com/_8mJHR27FNWA/TDba9CYyVTI/AAAAAAAAAF8/amDoWd28xh0/s1600/Resource-6.png"><img src="http://3.bp.blogspot.com/_8mJHR27FNWA/TDba9CYyVTI/AAAAAAAAAF8/amDoWd28xh0/s640/Resource-6.png" border="0" alt="" width="640" height="480" /></a></div>
<p>I was absolutely disappointed by the sort order. It appeared to be sorted and added spaces.</p>
<div class="separator" style="clear: both;text-align: center"><a href="http://2.bp.blogspot.com/_8mJHR27FNWA/TDbbVEix7fI/AAAAAAAAAGM/-AdgUaeG8Gk/s1600/Resource-5a.png"><img src="http://2.bp.blogspot.com/_8mJHR27FNWA/TDbbVEix7fI/AAAAAAAAAGM/-AdgUaeG8Gk/s640/Resource-5a.png" border="0" alt="" width="640" height="460" /></a></div>
<p><em>Personal Opinion:</em> It&#8217;s the smartest plug-in I&#8217;ve seen. However the need to build from sources and order of the saved properties is a bit disappointing.</p>
<p><strong><a href="http://www.eclipse.org/"></a>Conclusion</strong><br />
<strong><br />
</strong><br />
In my point of view IntelliJ IDEA has the most stable and mature support of the localized files. It even has it without installing any additional plug-ins. From the other side, Babel demonstrates unique features which I would like to see in other IDEs<strong>. </strong>Unfortunately NetBeans plug-in is not the best option here.<strong><br />
</strong><br />
<strong><br />
</strong><br />
As a result, I can admit that there&#8217;s a bunch of tools which can help you and your customer in editing resource bundle files. Of course you can use one of the massive IDEs, but you can also select a small tool based on your needs.</p>
<p>It&#8217;s absolutely possible that I&#8217;ve missed some interesting features or even tools which still meet of needs. May be I&#8217;ve even missed something that meets our needs &#8211; but it means that usability is not so good to make this feature enabled very quickly.</p>
]]></content:encoded>
			<wfw:commentRss>http://rocketscience.itteco.org/2010/07/09/java-resource-file-editor/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Some words about JNDI</title>
		<link>http://rocketscience.itteco.org/2010/06/14/some-words-about-jndi/</link>
		<comments>http://rocketscience.itteco.org/2010/06/14/some-words-about-jndi/#comments</comments>
		<pubDate>Mon, 14 Jun 2010 10:41:58 +0000</pubDate>
		<dc:creator>Serge Zenevich</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[glassfish]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[jndi]]></category>

		<guid isPermaLink="false">http://rocketscience.itteco.org/?p=817</guid>
		<description><![CDATA[I think all Java-developers know JNDI (Java Naming and Directory Interface) and all of them use it. The common case of its use is getting datasource and getting JMS queue. In this post I&#8217;d discuss usage of JNDI for custom objects.

On one of our project we need to have access to one common knowledge base, [...]]]></description>
			<content:encoded><![CDATA[<p>I think all Java-developers know JNDI (Java Naming and Directory Interface) and all of them use it. The common case of its use is getting datasource and getting JMS queue. In this post I&#8217;d discuss usage of JNDI for custom objects.</p>
<p>
On one of our project we need to have access to one common knowledge base, which should be shared between several application deployed on this application server (it was glassfish v3, but it doesn&#8217;t matter).</p>
<p>
Thus our application is based on spring framework the first idea dealt with it. We thought about implement this recommendation: http://springtips.blogspot.com/2007/06/using-shared-parent-application-context.html. But after that we found that knowledge base should work like database, but uses another API (our own). So we decided to use JNDI and implement own ObjectFactory (http://java.sun.com/javase/6/docs/api/javax/naming/spi/ObjectFactory.html).</p>
<p>First we created simple Data Transfer Object, which should be created by ObjectFactory and provides all necessary data to our application. It looks like:</p>
<blockquote><p>public class Data {</p>
<div style="margin-left:30px">
private final byte[] idf;</p>
<p>public CkbData(final RealVector idf) {
</p></div>
<div style="margin-left:60px">this.idf = idf;</div>
<div style="margin-left:30px">}</p>
<p>public RealVector getIdf() {
</p></div>
<div style="margin-left:60px">return idf;</div>
<div style="margin-left:30px">}
</div>
<p>}
</p></blockquote>
<p>After that we created simple implementation of ObjectFactory:</p>
<blockquote><p>public class DataFactory implements ObjectFactory {</p>
<div style="margin-left:30px">
@Override<br />
public Object getObjectInstance(final Object obj, final Name name, final Context nameCtx, final Hashtable environment) throws Exception {
</div>
<div style="margin-left:60px">final Reference reference = (Reference) obj;<br />
final String property1 = (String) reference.get(&#8221;property1&#8243;).getContent();<br />
final String property2 = (String) reference.get(&#8221;property2&#8243;).getContent();<br />
// do something<br />
return result;
</div>
<div style="margin-left:30px">}</div>
<p>}
</p></blockquote>
<p>So here name provides name of necessary resource and using obj object you may read configuration properties of this resource. After that based on these data you make create required object and return it.</p>
<p>By the way glassfish provides good UI for configuration custom resources – it is illustrated on the following screen:</p>
<p><a href="http://4.bp.blogspot.com/_UJElbWeT0m4/TBYEMYNiZII/AAAAAAAAAmU/1iF_SEJhWXU/s1600/Screenshot-New+Custom+Resource+-+Chromium.png"><img style="margin:0px auto 10px;text-align:center;cursor:pointer;cursor:hand;width: 320px;height: 190px" src="http://4.bp.blogspot.com/_UJElbWeT0m4/TBYEMYNiZII/AAAAAAAAAmU/1iF_SEJhWXU/s320/Screenshot-New+Custom+Resource+-+Chromium.png" border="0" alt="" /></a></p>
<p>It was very easy task and does not take a lot of time, but effect was amazing, because:</p>
<p>
<ul>
<li>we have common knowledge base for all application – it significant decreased memory usage and deploying/starting time of new applications;</li>
<li>we can configure our knowledge base in runtime by changing properties of JNDI resource;</li>
<li>we should not change source of our application – we only need to change configuration files.</li>
</ul>
<p>Therefore I suggest to take into account possibility of JNDI – it may be very useful!</p>
]]></content:encoded>
			<wfw:commentRss>http://rocketscience.itteco.org/2010/06/14/some-words-about-jndi/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Improving GWT compilation speed</title>
		<link>http://rocketscience.itteco.org/2010/06/09/improving-gwt-compilation-speed/</link>
		<comments>http://rocketscience.itteco.org/2010/06/09/improving-gwt-compilation-speed/#comments</comments>
		<pubDate>Wed, 09 Jun 2010 07:14:29 +0000</pubDate>
		<dc:creator>Andrei Panasyuk</dc:creator>
				<category><![CDATA[GWT]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://rocketscience.itteco.org/?p=814</guid>
		<description><![CDATA[Yesterday we have moved one of our projects from GWT 1.7 to GWT 2.0. And GWT compilation appeared to run slower on my host.
So I&#8217;ve started looking for a way to make this process faster.
The initial compilation of the project took 207 seconds and permutation compilation 170 seconds
The main idea of speeding up compilation is [...]]]></description>
			<content:encoded><![CDATA[<p>Yesterday we have moved one of our projects from GWT 1.7 to GWT 2.0. And GWT compilation appeared to run slower on my host.</p>
<p>So I&#8217;ve started looking for a way to make this process faster.</p>
<p>The initial compilation of the project took 207 seconds and permutation compilation 170 seconds</p>
<p>The main idea of speeding up compilation is to reduce the number of the compiled permutations. Permutation is a combination of the supported browser and locale.</p>
<p>By default permutations for the following browsers are compiled: </p>
<ul>
<li>ie6</li>
<li>ie8</li>
<li>gecko</li>
<li>gecko1_8</li>
<li>safari</li>
<li>opera</li>
</ul>
<p>So in case of having three locales &#8211; 18 permutations are compiled.</p>
<p>But do we need all these during development? I guess no. Usually you develop within one browser and the rest are used once the development is completed.<br />
So lets reduce the list of the supported browsers by adding the following string in our *.gwt.xml file<br />
<code><br />
&lt;set-property name="user.agent" value="gecko"/&gt;<br />
</code><br />
This reduces the list of browsers to the gecko based ones, like FireFox or SeaMonkey.<br />
Now compilation takes 84 seconds and permutations compilation &#8211; 66 seconds. Not too bad, right?</p>
<p>Okay, lets go further.<br />
Lets add <i>draftCompile</i> GWT compiler flag. Since our project is built by Maven &#8211; go to pom.xml and put the following string into the configuration section of the GWT plugin:<br />
<code><br />
&lt;draftCompile&gt;true&lt;/draftCompile&gt;<br />
</code><br />
This option allows you to skip JavaScript optimization step. And the compilation time reduces to 65 seconds, permutation compilation &#8211; 48 seconds.</p>
<p>The next option which I&#8217;ve tried &#8211; is the <i>localWorkers</i> compilation option. This option specifies the number of parallel processes used to compile GWT permutations. The default value is quite fine and changing it didn&#8217;t bring any speed up.</p>
<p>So the last option I&#8217;ve tried was reducing permutations count by reducing count of the compiled locales. I&#8217;ve specified the following string in my *.gwt.xml file<br />
<code><br />
&lt;set-property name="locale" value="en"/&gt;<br />
</code><br />
So there&#8217;s only one english locale compiled. Now we have only one permutation compiling: English locale for Gecko-based browsers. The compilation time reduced to 48 seconds(30 seconds to compile permutations).</p>
<p>All of the results are combined into the table below</p>
<table border="1">
<tr>
<th align="center">Description</th>
<th align="center">Compilation (in sec.)</th>
<th align="center">Permutation Compilation (in sec.)</th>
</tr>
<tr>
<td>Initial</td>
<td align="center">207</td>
<td align="center">170</td>
</tr>
<tr>
<td>After specifying <i>user.agent</i> property</td>
<td align="center">84</td>
<td align="center">66</td>
</tr>
<tr>
<td>After specifying <i>draftCompile</i> parameter</td>
<td align="center">65</td>
<td align="center">48</td>
</tr>
<tr>
<td>After specifying <i>localWorkers</i> parameter</td>
<td align="center">66</td>
<td align="center">48</td>
</tr>
<tr>
<td>After specifying <i>locale</i> property</td>
<td align="center">48</td>
<td align="center">30</td>
</tr>
</table>
<p>As you can see &#8211; the compilation speed decreased more than 5 times. This difference is really vivid on a smal project and can bring you a huge benefit on a large project.</p>
<p>The following environment was used during the testing: Fedora 13 x86_64, Oracle JDK 1.6.0_20, GWT 2.0.3, Maven 2.1.0.</p>
]]></content:encoded>
			<wfw:commentRss>http://rocketscience.itteco.org/2010/06/09/improving-gwt-compilation-speed/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Working with JCR in Magnolia-CMS</title>
		<link>http://rocketscience.itteco.org/2010/06/08/working-with-jcr-in-magnolia-cms/</link>
		<comments>http://rocketscience.itteco.org/2010/06/08/working-with-jcr-in-magnolia-cms/#comments</comments>
		<pubDate>Tue, 08 Jun 2010 14:48:16 +0000</pubDate>
		<dc:creator>Serge Zenevich</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[JCR]]></category>
		<category><![CDATA[magnolia]]></category>

		<guid isPermaLink="false">http://rocketscience.itteco.org/?p=810</guid>
		<description><![CDATA[Magnolia CMS is popular Java-based CMS, but unfortunately there is not enough documentation regarding it. For example, I decide to store and load some data into built-in JCR repository and I did not find guide for it. Thus I decided to create this post.
So my goal is use JCR as storage for my custom data. [...]]]></description>
			<content:encoded><![CDATA[<p>Magnolia CMS is popular Java-based CMS, but unfortunately there is not enough documentation regarding it. For example, I decide to store and load some data into built-in JCR repository and I did not find guide for it. Thus I decided to create this post.</p>
<p>So my goal is use JCR as storage for my custom data. I want to store data into it and load data.</p>
<p>So let&#8217;s start. First I&#8217;d to get Content and then add same entities into it.</p>
<p>info.magnolia.cms.util.ContentUtil is main class, which we will use. Its getContent-method returns content by id of repository and path to content. The following screen illustrates where you may find name of repositories (by the way name of repository equals to id of repository <img src='http://rocketscience.itteco.org/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />  ) and how to use path.</p>
<p><a href="http://1.bp.blogspot.com/_UJElbWeT0m4/TA5ZQ0elxeI/AAAAAAAAAmM/9BIxII5FVhg/s1600/Screenshot-Magnolia+AdminCentral+-+Chromium.png"><img style="margin:0px auto 10px;text-align:center;cursor:pointer;cursor:hand;width: 320px;height: 222px" src="http://1.bp.blogspot.com/_UJElbWeT0m4/TA5ZQ0elxeI/AAAAAAAAAmM/9BIxII5FVhg/s320/Screenshot-Magnolia+AdminCentral+-+Chromium.png" border="0" alt="" /></a>
<p>So the following code check does “myfolder” (I will use this folder for storing my entities) exist and creates it if it doesn&#8217;t exist:</p>
<blockquote><div>Content myfolder = ContentUtil.getContent(&#8221;website&#8221;, &#8220;/myfolder&#8221;);</div>
<div>if (myfolder == null) {</div>
<div style="margin-left: 30px">final Content root = ContentUtil.getContent(&#8221;website&#8221;, &#8220;/&#8221;);<br />
myfolder = root.createContent(&#8221;myfolder&#8221;);<br />
root.save();</div>
<div>}</div>
</blockquote>
<p>Note that I call save-method of owner of created content – not of this content.</p>
<p>After that we have created myfolder and now we may start to add entities into it by the following way:</p>
</p>
<blockquote><p>final Content contentNode = myfolder.createContent(entityname, ItemType.CONTENTNODE);<br />
myfolder.save();</p>
<p>contentNode.createNodeData(&#8221;property1&#8243;, PropertyType.LONG).setValue(each.getId());<br />
                 contentNode.createNodeData(&#8221;property2&#8243;, PropertyType.STRING).setValue(each.getText());<br />
                 contentNode.createNodeData(&#8221;property3&#8243;, PropertyType.DATE).setValue(Calendar.getInstance());<br />
                 contentNode.save();</p></blockquote>
<p>So here entityname is name of entity, which should be created and contentNode is representation of it and you should call save-method of parent folder for creating this entity. After that you may specify properties of this entity by creating node data and setting values of it. When all properties are specified you may store all changes by calling save-method of contentNode.</p>
<p>In conclusion, I&#8217;d note that all ContentUtil uses Context, which is stored and managed by MgnlContext. By default it has right of current user.</p>
]]></content:encoded>
			<wfw:commentRss>http://rocketscience.itteco.org/2010/06/08/working-with-jcr-in-magnolia-cms/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Some words about domain name scams</title>
		<link>http://rocketscience.itteco.org/2010/06/04/some-words-about-domain-name-scams/</link>
		<comments>http://rocketscience.itteco.org/2010/06/04/some-words-about-domain-name-scams/#comments</comments>
		<pubDate>Fri, 04 Jun 2010 11:10:19 +0000</pubDate>
		<dc:creator>Alex Kutsko</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[domain name scams]]></category>

		<guid isPermaLink="false">http://rocketscience.itteco.org/?p=808</guid>
		<description><![CDATA[Yesterday we received a letter with such content: 

(If you are NOT CEO,please forward this to your CEO, because this is urgent.Thanks.)
Dear CEO,
We are the department of registration service in China. we have something need to confirm with you. We formally received an application on Jun. 2, 2010, One company which self-styled &#8220;Mintor(Japan)Venture Capital Co.,Ltd&#8221; [...]]]></description>
			<content:encoded><![CDATA[<p>Yesterday we received a letter with such content: </p>
<blockquote><p>
(If you are NOT CEO,please forward this to your CEO, because this is urgent.Thanks.)</p>
<p>Dear CEO,</p>
<p>We are the department of registration service in China. we have something need to confirm with you. We formally received an application on Jun. 2, 2010, One company which self-styled &#8220;Mintor(Japan)Venture Capital Co.,Ltd&#8221; are applying to register(softteco) as internet brand name and domain names as below (softteco.cn  softteco.com.cn  softteco.mobi  softteco.asia  softteco.in  softteco.hk  softteco.cc  softteco.tw  etc.).</p>
<p>After our initial checking, we found the internet brand name and these domain names being applied are as same as your company’s, so we need to get the confirmation from your company. If the aforesaid company is your business partner or your subsidiary company, please DO NOT reply us, we will approve the application automatically. If you have no any relationship with this company, please contact us within 15 workdays. If out of the deadline, we will approve the application  submitted by &#8220;Mintor(Japan)Venture Capital Co.,Ltd&#8221; unconditionally.</p>
<p>Please forward the email to your decision maker,and let them contact me in time,so that we can handle this in reasonable,Look forwarding to hearing from you.</p>
<p>Best Regards,</p>
<p>Kevin Wu<br />
Senior Director<br />
TEL: +86 21 69929440<br />
Fax:  +86 21 69929447<br />
Website:http://www.qp-world.org.cn</p>
<p>Address:Room 902,8th,nong 1518,Jinyuan 1st Road,Jiading District, Shanghai city.
</p></blockquote>
<p>It a bit worried me as a CEO. Despite we haven&#8217;t any business so far in asia, it is not very comfortable to have another one company with same name as yours.<br />
After viewing prices that are quite high (from 30 to 50 EUR per year), I started thinking that it&#8217;s a kind of new trend of Internet fraud. And really, after some googling I found quite a lot of sites about domain name scams from asia.<br />
One that I like with explanation of what domain name scams means:<br />
<a href="http://www.firetrust.com/en/blog/chris/domain-name-scams?page=13">http://www.firetrust.com/en/blog/chris/domain-name-scams?page=13</a></p>
]]></content:encoded>
			<wfw:commentRss>http://rocketscience.itteco.org/2010/06/04/some-words-about-domain-name-scams/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Simple web server in 5 seconds</title>
		<link>http://rocketscience.itteco.org/2010/05/21/simple-web-server-in-5-seconds/</link>
		<comments>http://rocketscience.itteco.org/2010/05/21/simple-web-server-in-5-seconds/#comments</comments>
		<pubDate>Fri, 21 May 2010 14:44:29 +0000</pubDate>
		<dc:creator>Artem Scorecky</dc:creator>
				<category><![CDATA[Useful]]></category>
		<category><![CDATA[Web Servers]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[tips]]></category>
		<category><![CDATA[web server]]></category>

		<guid isPermaLink="false">http://rocketscience.itteco.org/?p=799</guid>
		<description><![CDATA[Web server is a useful thing. Specially if it is instant:

Share files with neighbors
Try-out the latest &#8220;super-duper&#8221; site from designer (having resources at /xxx URLs)
Fix that site and see your changes

All you need is Python installed (you are developer, aren&#8217;t you?) and command line (console) opened:
cd MY_SITE_DIRECTORY
python -m SimpleHTTPServer

You will get a web server working:
Serving [...]]]></description>
			<content:encoded><![CDATA[<p>Web server is a useful thing. Specially if it is <strong>instant</strong>:</p>
<ul>
<li>Share files with neighbors</li>
<li>Try-out the latest &#8220;super-duper&#8221; site from designer (having resources at /xxx URLs)</li>
<li>Fix that site and see your changes</li>
</ul>
<p>All you need is Python installed (you are developer, aren&#8217;t you?) and command line (console) opened:</p>
<blockquote><p>cd MY_SITE_DIRECTORY<br />
python -m SimpleHTTPServer
</p></blockquote>
<p>You will get a web server working:</p>
<blockquote><p>Serving HTTP on 0.0.0.0 port 8000 &#8230;</p></blockquote>
<p><strong>Get your files! Open in your browser:</strong></p>
<blockquote><p>http://127.0.0.1:8000/</p></blockquote>
<p>To stop the server press [Ctrl-C] or just close the console window.</p>
<p>P. S. If you have <code>index.html</code> file it will be shown instead of directory index.<br />
P. P. S. You may use any IP that your machine have. For example, 127.0.x.x. You may change your hosts file to access this server at any domain you want.</p>
]]></content:encoded>
			<wfw:commentRss>http://rocketscience.itteco.org/2010/05/21/simple-web-server-in-5-seconds/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Try [Ubuntu] Linux in 5 minutes SAFELY</title>
		<link>http://rocketscience.itteco.org/2010/05/16/try-ubuntu-linux-in-5-minutes-safe/</link>
		<comments>http://rocketscience.itteco.org/2010/05/16/try-ubuntu-linux-in-5-minutes-safe/#comments</comments>
		<pubDate>Sun, 16 May 2010 12:13:44 +0000</pubDate>
		<dc:creator>Artem Scorecky</dc:creator>
				<category><![CDATA[Linux/Unix]]></category>
		<category><![CDATA[Useful]]></category>
		<category><![CDATA[flash]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<category><![CDATA[UNetbootin]]></category>

		<guid isPermaLink="false">http://rocketscience.itteco.org/?p=787</guid>
		<description><![CDATA[If you never tried Linux OS you should give it a try.
It is worth it:

Technically one the most advanced OS in the world
Very reliable, stable and secure
Pretty fast and high-performance
Virus-free
Support for almost all hardware is out-of-the-box
(Ubuntu) Pretty simple, easy-to-use and nice
Software for daily tasks is out-of-box (web browsers, Office applications, music and video players, image [...]]]></description>
			<content:encoded><![CDATA[<p>If you never tried Linux OS you should give it a try.</p>
<p>It is worth it:</p>
<ul>
<li>Technically one the most advanced OS in the world</li>
<li>Very reliable, stable and secure</li>
<li>Pretty fast and high-performance</li>
<li>Virus-free</li>
<li>Support for almost all hardware is out-of-the-box</li>
<li>(Ubuntu) Pretty simple, easy-to-use and nice</li>
<li>Software for daily tasks is out-of-box (web browsers, Office applications, music and video players, image viewers and editors)</li>
<li>Useful low-level tools for developers and administrators is out-of-box</li>
<li>Easy to try (no need to install)</li>
<li>Completely open-source</li>
<li>Completely customizable</li>
<li>FREE</li>
</ul>
<p><strong>Nowadays all you need to try it out is USB flash (at least 1Gb) and internet connection needed. It would not modify any of your HDD.</strong></p>
<p>Just few steps towards:</p>
<ol>
<li><strong>Get liveCD ISO image of Linux</strong><br />
You should download the liveCD image of the Linux distributive that you want to check. I advise you to try last release of Ubuntu from <a href="http://www.ubuntu.com/getubuntu/download">ubuntu.com</a> .<br />
You may skip this step and download the image automatically.</li>
<li><strong>Install UNetbootin</strong><br />
Go to UNetboot site, select your OS (Windows/Linux distributive/*BSD), download and install it to your machine. It may need administrative rights.</li>
<li><strong>Format USB flash</strong><br />
Format USB flash to FAT32. On Linux you may use <strong>gparted</strong> for that.</li>
<li><strong>Run UNetbootin</strong><br />
You may need administrative rights for that.</li>
<li><strong><strong>Provide ISO image</strong></strong><strong><strong><br />
</strong></strong>Provide the image &#8211; select &#8220;Disk Image&#8221;, &#8220;ISO&#8221;, select the image file you have.<br />
If you skipped step #1 you should download the image automatically &#8211; select &#8220;Distribution&#8221;, select distrubution and version.</li>
<li><strong>Write image to USB flash</strong><br />
Select Type =&gt; &#8220;USB drive&#8221;, Drive =&gt; your USB flash, and click &#8220;OK&#8221; button. Wait for image to write.</li>
<li><strong>Restart your computer</strong></li>
<li><strong>Boot from USB flash<br />
</strong>By default your computer should boot from your USB flash. If it doesn&#8217;t you should enter your BIOS settings and set up booting from remote devices. You may also enter BIOS boot menu (if any) and select to boot from your USB flash.</li>
<li><strong>Enjoy!</strong></li>
</ol>
<p>After you finished with Linux &#8211; just restart it, detach your USB flash and boot back to your common environment.</p>
<p><strong>You may use blank CD-R/RW instead of USB flash:</strong></p>
<ol>
<li>Get liveCD ISO image of Linux</li>
<li>Burn the image to your CD-R/RW or DVD-R/RW</li>
<li>Restart computer</li>
<li>Boot from CD/DVD</li>
<li>Enjoy!</li>
</ol>
<p><strong>Have a nice flight in Linux world!</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://rocketscience.itteco.org/2010/05/16/try-ubuntu-linux-in-5-minutes-safe/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Make a simple daemon</title>
		<link>http://rocketscience.itteco.org/2010/05/16/make-simple-daemon/</link>
		<comments>http://rocketscience.itteco.org/2010/05/16/make-simple-daemon/#comments</comments>
		<pubDate>Sun, 16 May 2010 11:08:35 +0000</pubDate>
		<dc:creator>Artem Scorecky</dc:creator>
				<category><![CDATA[Application Servers]]></category>
		<category><![CDATA[Linux/Unix]]></category>
		<category><![CDATA[Useful]]></category>
		<category><![CDATA[console]]></category>
		<category><![CDATA[daemon]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[nohup]]></category>

		<guid isPermaLink="false">http://rocketscience.itteco.org/?p=765</guid>
		<description><![CDATA[In large projects some daemons are always needed for processing routines tasks in background (clearing caches, reload application, push or pull data, etc.).
There are a lot of ways to daemonize an application in Linux &#8211; from simple to complicated. I&#8217;d like to show some simplest approaches from my experience that proved that they are simple, [...]]]></description>
			<content:encoded><![CDATA[<p>In large projects some daemons are always needed for processing routines tasks in background (clearing caches, reload application, push or pull data, etc.).</p>
<p>There are a lot of ways to daemonize an application in Linux &#8211; from simple to complicated. I&#8217;d like to show some simplest approaches from my experience that proved that they are simple, easy and reliable enough for staging or development purposes.</p>
<p>Let me walk trough them.</p>
<h3 style="margin-top: 10px;padding-top: 0">Application in screen</h3>
<p>It seems to be the most obvious approach, that is the most transparent to the user:</p>
<ul>
<li>Run screen command:<br />
<blockquote><p>screen -S your_label</p></blockquote>
</li>
<li>Execute command:<br />
<blockquote><p>./myapp</p></blockquote>
</li>
<li>Detach from the screen:<br />
<blockquote><p>Press [Ctrl-A], [Ctrl-D]</p></blockquote>
</li>
</ul>
<p>That&#8217;s it. You may manage your &#8220;daemons&#8221; at any time:</p>
<ul>
<li>See &#8220;daemons&#8221; list:<br />
<blockquote><p>screen -ls</p></blockquote>
</li>
<li>See last &#8220;daemon&#8221; output:<br />
<blockquote><p>screen -r your_label</p></blockquote>
</li>
<li>Stop (being on &#8220;daemon output&#8221; screen):<br />
<blockquote><p>Press [Ctrl-C]</p></blockquote>
</li>
<li>Restart (stop, then run application again):<br />
<blockquote><p>./myapp</p></blockquote>
</li>
<li>Don&#8217;t forget to close unneeded screen session after you stopped the daemon:<br />
<blockquote><p>exit</p></blockquote>
</li>
</ul>
<h3 style="margin-top: 10px;padding-top: 0">Run application in background</h3>
<p>That&#8217;s sound easy. Let&#8217;s try:</p>
<blockquote><p>./myapp</p></blockquote>
<p>But you can&#8217;t run anything else because application doesn&#8217;t go background itself. Let&#8217;s move it to background:</p>
<blockquote><p>./myapp &amp;</p></blockquote>
<p>But output goes to console and obstruct working. Let&#8217;s move output to the log file:</p>
<blockquote><p>./myapp &gt; myapp.log &amp;</p></blockquote>
<p>But errors output still goes to console. Let&#8217;s move error output to the log file too:</p>
<blockquote><p>./myapp &gt; myapp.log 2&gt;&amp;1 &amp;</p></blockquote>
<p>Pretty good. However, application would be killed if we close the console (for example, leave that SSH session). Also, your &#8220;daemon&#8221; application may capture your input if it needs input. Let&#8217;s try special application for solving these issues:</p>
<blockquote><p>nohup ./myapp &gt; myapp.log 2&gt;&amp;1 &amp;</p></blockquote>
<p>Now it works as expected &#8211; in complete background mode. You may manage it:</p>
<ul>
<li>See all application output:<br />
<blockquote><p>less myapp.log</p></blockquote>
</li>
<li>See recent application output (will add as application outputs):<br />
<blockquote><p>tail -f myapp.log</p></blockquote>
</li>
<li>See if it is running (first column is the process PID):<br />
<blockquote><p>ps -A | grep myapp</p></blockquote>
</li>
<li>Stop (using PID from the previous example):<br />
<blockquote><p>kill myapp_pid</p></blockquote>
</li>
</ul>
<h3 style="margin-top: 10px;padding-top: 0">Almost daemon</h3>
<p>Let&#8217;s expand previous method so it can be easily managed. I would just provide the final solution (save it as <strong>myapp_daemon.sh</strong>):</p>
<blockquote>
<pre><code>
#!/bin/sh
# you may need /bin/bash for that

if [ -z "$1" ]; then

  echo "Please provide daemon command to run: start, stop, restart, status"
  exit 1

fi

APP="./myapp"
APP_NAME="myapp"
APP_LOG="myapp.log"
APP_PID="myapp.pid"

function start(){
    echo "Starting ${APP_NAME}..."
    nohup ${APP} &gt; ${APP_LOG} 2&gt;&amp;1 &amp;
    echo $! &gt; ${APP_PID}
    echo "Started."
}

function stop(){
    echo "Stopping ${APP_NAME}..."
    kill `cat ${APP_PID}`
    rm -f ${APP_PID}
    echo "Stopped."
}

function restart(){
    stop
    start
}

function status(){
    echo "Gathering ${APP_NAME} status..."
    if [ -f ${APP_PID} ]; then
        pid=`cat ${APP_PID}`
        processes=`ps -no-headers --pid $pid`
        if [ "$?" -ne "0" ]; then
            echo "${APP_NAME} process is not found, possible crash"
        else
            echo "${APP_NAME} is running:"
            echo "$processes"
            tail ${APP_LOG}
        fi
    else
        echo "${APP_NAME} is not started"
    fi
    echo "Done."
}

$1
</code></pre>
</blockquote>
<p>Then make executable:</p>
<blockquote><p>chmod +x myapp_daemon.sh</p></blockquote>
<p>And enjoy &#8211; start / restart / see status / stop:</p>
<blockquote><p>./myapp_daemon.sh start<br />
./myapp_daemon.sh restart<br />
./myapp_daemon.sh status<br />
./myapp_daemon.sh stop</p></blockquote>
<h3 style="margin-top: 10px;padding-top: 0">Conclusion</h3>
<p><strong>You may easily create simple but powerful daemons yourself. However, you should look at more complex approaches for production environment when you need scheduled run and processes respawn.</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://rocketscience.itteco.org/2010/05/16/make-simple-daemon/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Model – View – Controller (MVC)</title>
		<link>http://rocketscience.itteco.org/2010/05/11/mvc/</link>
		<comments>http://rocketscience.itteco.org/2010/05/11/mvc/#comments</comments>
		<pubDate>Tue, 11 May 2010 05:43:40 +0000</pubDate>
		<dc:creator>Serge Zenevich</dc:creator>
				<category><![CDATA[GWT]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Python & Django]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[JSF]]></category>
		<category><![CDATA[mvc]]></category>
		<category><![CDATA[patterns]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[Spring Framework]]></category>

		<guid isPermaLink="false">http://rocketscience.itteco.org/?p=761</guid>
		<description><![CDATA[MVC is very old and very famous design pattern. It is used in web and desktop applications, in different programming languages (C++, Java, .NET, Python, etc.).
First I read about it in Design Patterns. Elements of Reusable Object-Oriented Software and since that time I have heart a lot of things about it and see a lot [...]]]></description>
			<content:encoded><![CDATA[<div>MVC is very old and very famous design pattern. It is used in web and desktop applications, in different programming languages (C++, Java, .NET, Python, etc.).</div>
<div>First I read about it in Design Patterns. Elements of Reusable Object-Oriented Software and since that time I have heart a lot of things about it and see a lot of realization of this pattern.</div>
<div>I decide to write this post thanks to statement of my good friend – he said that MVC is not used in Java web frameworks. Thus I want to show that it is used and MVC realization in Java is not worse than in Python/Django.</div>
<div>So let&#8217;s start from small review of MVC pattern.</div>
<div>The following diagram illustrates main concept of MVC pattern.</div>
<div><a href="http://1.bp.blogspot.com/_UJElbWeT0m4/S-geDv7c3II/AAAAAAAAAlo/BZq9Xk8uGw8/s1600/MVC.png%7C.jpg%7C.jpeg"><img style="margin: 0px auto 10px;text-align: center;cursor: pointer;width: 320px;height: 176px" src="http://1.bp.blogspot.com/_UJElbWeT0m4/S-geDv7c3II/AAAAAAAAAlo/BZq9Xk8uGw8/s320/MVC.png%7C.jpg%7C.jpeg" border="0" alt="" /></a></div>
<div>Here model is object, which contains information about domain. Model does not have visual interface and it contains all data, which does not link with visual interface. So it may be domain object or script.</div>
<div>View is responsible for showing data of model using UI mechanisms.</div>
<div>All changes of data should be handled by Controller, which receive data, make all necessary operations and refreshes view. So in this case graphical interface consists of view and controller. Thus division between view and controller is not so important and therefor sometime it is not visible.</div>
<div>Dependency between view and model is much more important, because they belong to different areas of software development. Because when you&#8217;re working on view you should care about user interface and its usability, but when you&#8217;re working on model you should concentrate on business logic. Moreover there are cases when the same information should be shown by different ways.</div>
<div>The following table shows model, view and controller in different web frameworks:</div>
<table border="0">
<tbody>
<tr>
<th>Frameworks</th>
<th>Model</th>
<th>View</th>
<th>Controlle</th>
</tr>
<tr>
<td>GWT</td>
<td>DTOs, which are placed in common part</td>
<td>Custom and standard widgets and composition of them</td>
<td>Listeners and callbacks within servlet-based services</td>
</tr>
<tr>
<td>Spring MVC</td>
<td>DTOs, which are placed in Spring Model class</td>
<td>JSP</td>
<td>Spring Controller classes</td>
</tr>
<tr>
<td>JSF</td>
<td>DTOs, which backing beans return</td>
<td>JSP</td>
<td>Backing beans</td>
</tr>
<tr>
<td>Python/Django</td>
<td>JSON-based DTOs</td>
<td>Template</td>
<td>Set of request handler methods</td>
</tr>
</tbody>
</table>
<div>Also notes that some frameworks need additional JavaScript-based mechanisms, which are responsible for processing AJAX calls. These mechanisms are also part of controller.</div>
<div>So as you can see Java web frameworks actively and successfully use MVC pattern.</div>
<div>May be my friend mean that we did not use RESTful services together with JavaScript libraries like jQuery or DOJO, but it is another story and I&#8217;d to describe it in one of next posts.</div>
]]></content:encoded>
			<wfw:commentRss>http://rocketscience.itteco.org/2010/05/11/mvc/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
