tag:blogger.com,1999:blog-80620613588815960542024-03-13T21:58:26.854+00:00The Bright Side of Java & LinuxPersonal experiences as Software Engineer.Anonymoushttp://www.blogger.com/profile/01075792712991750280noreply@blogger.comBlogger41125tag:blogger.com,1999:blog-8062061358881596054.post-19560549167533072942012-10-26T20:21:00.002+01:002012-10-26T20:21:13.419+01:00Git and Maven release:prepareI don't know if it happens to me only due to my complex source control configuration (which uses SSH keys like Github), but it happens quite often to me that the release process gets stuck right when it's time to push changes.<br />
<br />
When this happens you are left with almost no choice but to perform a release:rollback and start again, but today I've found a good solution to this problem: <span style="font-family: Courier New, Courier, monospace;">git reset</span>.<br />
<br />
So, if your release preparation process is interrupted for some reason and you want to restart it again, but when you try you get a message saying the git commit command failed, then just do the following:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">git reset --soft HEAD~1</span><br />
<br />
This command will remove the commit from your local clone leaving all the Maven changes intact, thus allowing you to recover the process where you left it.<br />
<br />
Have fun!Anonymoushttp://www.blogger.com/profile/01075792712991750280noreply@blogger.com0tag:blogger.com,1999:blog-8062061358881596054.post-3309855684620328912012-10-25T15:49:00.003+01:002012-10-25T15:52:14.138+01:00Jacoco code coverage toolToday I discovered with great pleasure a great project for gathering unit, integration and automation tests code coverage: <a href="http://www.eclemma.org/jacoco/" target="_blank">Jacoco</a>!<br />
<br />
I was so excited that I decided to give it a try on my <a href="https://bitbucket.org/rlogiacco/atdd" target="_blank">template Maven project</a> and the POM went down 150 lines with greatly improved readability!<br />
<br />
No more tricky profiles or instrumented artifacts you need to include explicitly and solely to gather coverage: everything works like a charm!<br />
<br />
Obviously my previous post regarding <a href="http://rlogiacco.blogspot.it/2012/08/a-few-cucumber-tricks.html" target="_blank">Cucumber tricks</a> is still totally valid.<br />
<br />
Thanks Jacoco!Anonymoushttp://www.blogger.com/profile/01075792712991750280noreply@blogger.com0tag:blogger.com,1999:blog-8062061358881596054.post-13498470741820605022012-10-18T07:32:00.002+01:002012-10-18T07:32:22.969+01:00Gherkin syntax quicksheetI found an interesting article containing a nicely presented and very well described <a href="http://docs.behat.org/guides/1.gherkin.html" target="_blank">Gherking syntax guide</a> and I want to support it.Anonymoushttp://www.blogger.com/profile/01075792712991750280noreply@blogger.com1tag:blogger.com,1999:blog-8062061358881596054.post-23306630439596942362012-10-17T16:02:00.000+01:002012-10-26T10:25:42.824+01:00Embedding screenshots in Cucumber JVMI was trying to improve our automated test suite and I thought that it could be useful to capture a screenshot of the browser whenever a test fails.<br />
The current Cucumber JVM implementation highly simplifies this task, but the task is not achieved the way I thought, so this is the reason for this post.<br />
<br />
Normally you would use a <a href="http://cwd.dhemery.com/2010/12/junit-rules/" target="_blank">JUnit TestRule</a> to augment all your test cases with a feature to take screenshots, but for Cucumber JVM it's much easier thankfully to the Execution Hooks:<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> public class ScreenshotHook {
@Autowired
private WebDriver driver;
@After
public void embedScreenshot(Scenario scenario) {
if (scenario.isFailed()) {
try {
byte[] screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES);
scenario.embed(screenshot, "image/png");
} catch (WebDriverException wde) {
System.err.println(wde.getMessage());
} catch (ClassCastException cce) {
cce.printStackTrace();
}
}
}
}
</code></pre>
<br />
As you can see I'm injecting the WebDriver instance (I'm using the Cucumber JVM Spring integration) and defining an <span style="font-family: Courier New, Courier, monospace;">embedScreenshot</span> method which is annotated with <span style="font-family: Courier New, Courier, monospace;">cucumber.annotation.After</span>: this is the important bit because methods annotated as such will be executed after each cucumber scenario.<br />
<br />
For sake of completeness I want to tell you there is another hook <span style="font-family: Courier New, Courier, monospace;">cucumber.annotation.Before</span> that can be used for things like logging into your application eliminating those repetitive log in steps.<br />
<br />
<b><span style="color: red;">UPDATE</span></b>: <span style="font-family: Courier New, Courier, monospace;">Scenario </span>was <span style="font-family: Courier New, Courier, monospace;">ScenarioResult </span>in pre 1.0.0 versions of Cucumber JVM.Anonymoushttp://www.blogger.com/profile/01075792712991750280noreply@blogger.com6tag:blogger.com,1999:blog-8062061358881596054.post-10271468836181647292012-10-16T19:00:00.003+01:002012-10-16T19:00:41.200+01:00Agile and the Definition of QualityIf you are interested in software quality, if you want to improve your agile process output, if you like to have satisfied customers you want to read <a href="http://secretsofconsulting.blogspot.com.au/2012/09/agile-and-definition-of-quality.html?utm_source=agilebench&utm_medium=linkedin&utm_campaign=thirdparty" target="_blank">this article</a> and, after reading it once, you might want to read it a second time: what he's saying is not obvious at all.Anonymoushttp://www.blogger.com/profile/01075792712991750280noreply@blogger.com0tag:blogger.com,1999:blog-8062061358881596054.post-5540409082019798392012-10-10T16:32:00.001+01:002012-10-17T12:47:26.422+01:00Selenium tests on JenkinsIt's not uncommon to have a CI server running tests based on Selenium and it's not uncommon to get in troubles with Linux headless (without a windows manager) servers.<br />
<div>
<br /></div>
<div>
Usually you get errors like:</div>
<blockquote class="tr_bq">
<span style="white-space: pre-wrap;"><span style="font-family: Courier New, Courier, monospace;">Error: no display specified</span></span></blockquote>
or
<br />
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;">Error: cannot open display: :0.0</span></blockquote>
<br />
The following is what I think is a solution that should be portable and does not require a lot of configuration skills.<br />
First of all you need to install the <a href="https://wiki.jenkins-ci.org/display/JENKINS/Xvfb+Plugin" target="_blank">Jenkins Xvfb Plugin</a>, which allows you to easily start a new virtual screen per Jenkins job. Please do not forget to properly configure this plugin in the Jenkins System Configuration screen as described in the plugin page: if you don't know the path of the Xvfb executable you just run the following command in a shell on your CI server<br />
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;">which Xvfb</span></blockquote>
Usually the value you will use as <i>Directory in which to find the Xvfb executable</i> is <span style="font-family: Courier New, Courier, monospace;">/usr/bin</span>.<br />
<br />
Once you have this you just need to activate the Xvfb plugin for your job and that should be it, without any modification in your POMs or any other hassle: the plugin will create a new virtual screen, set the DISPLAY environment variable and execute your build.<br />
<br />
If you are using the FirefoxDriver, as I do, and you still have issues, but you can see in your output lines like the following ones, then your problems are not any longer related with being on a headless server and my suggestion is to ensure you are using the latest version of the selenium drivers:<br />
<blockquote class="tr_bq">
<pre style="background-color: white; white-space: pre-wrap; word-wrap: break-word;"><span style="font-family: Courier New, Courier, monospace;">Xlib: extension "RANDR" missing on display ":32".
failed to create drawable
*** LOG addons.xpi: startup
*** LOG addons.xpi: Ignoring file entry whose name is not a valid add-on ID: /tmp/.../webdriver-staging
*** LOG addons.xpi: checkForChanges
*** LOG addons.xpi: No changes found</span></pre>
</blockquote>
<br />
Please note the initial two lines are perfectly fine and not related to your issues!<br />
I struggled with an error which actually went away right after I updated my selenium-java dependency to the current latest!Anonymoushttp://www.blogger.com/profile/01075792712991750280noreply@blogger.com1tag:blogger.com,1999:blog-8062061358881596054.post-74207288552630510582012-08-30T09:32:00.004+01:002012-10-25T15:43:08.955+01:00A few Cucumber tricksI've been a fan of <a href="http://en.wikipedia.org/wiki/Test-driven_development" target="_blank">TDD</a> since I discovered it a few years ago. Thankfully to my friend and colleague <a href="http://www.linkedin.com/in/augustoevangelisti" target="_blank">Augusto </a>a few months ago I've discovered the
beauty of <a href="http://en.wikipedia.org/wiki/Behavior-driven_development" target="_blank">BDD</a> and <a href="http://en.wikipedia.org/wiki/Test-driven_development" target="_blank">ATDD</a>: I got so fascinated by this practice I started
an Open Source project for an Eclipse plugin featuring a rich editor
for Cucumber feature files. It's called <a href="https://github.com/rlogiacco/Natural" target="_blank">Natural</a> and I think it's pretty cool if you want to <a href="https://github.com/rlogiacco/Natural/wiki/Screenshots" target="_blank">check it out</a>.<br />
<br />
After having used <a href="http://cukes.info/" target="_blank">Cucumber</a> for a while and many, many mistakes I now have got some experience
I wish to share with you.<br />
<br />
One of the key features of feature files is that they
represent a live project documentation, something developers write
and maintain and everyone can understand. We believe so much in this concept that we wanted to give our product owner and business partners a nice view on those files, that's why we used <a href="http://relishapp.com/" target="_blank">Relish </a>to publish them in a pretty colored format. At the same time we had to
face some problems while practically use these files for automation
testing.<br />
<br />
After a few development cycles we were so excited by Cucumber and ATDD
that our automation test suite counted hundreds of tests: it was
consuming too much time to be completely executed on each commit by
our <a href="http://en.wikipedia.org/wiki/Continuous_integration" target="_blank">CI</a> system.<br />
My suggestion is to track in your feature files the development cycle each test has been developed: this can be easily achieved by using a
<a href="https://github.com/cucumber/cucumber/wiki/Tags" target="_blank">tag</a>, something like <span style="background-color: #eeeeee; font-family: Courier New, Courier, monospace;">@sprint-7</span>.<br />
This way you can instruct your CI
system to execute the current sprint automation on each commit and
schedule a full test nighttime (and launch time possibly).<br />
<br />
Another issue was we were developing automation test <i>before </i>the
functionality was implemented, so following TDD principles. By doing
this our CI was reporting a build failure until the functionality was
completely implemented. This is not a problem as it is expected to have failing
tests during development, but the continuous failure messages received
by the team members brought us to the point we were starting to ignore
those messages, vanquishing the purpose of the automation suite and
the CI system itself. The solution I suggest is to temporarily
annotate the tests that are expected to fail with <span style="background-color: #eeeeee; font-family: Courier New, Courier, monospace;">@future</span>, instructing
your CI to skip any test annotated as such: the developers can still
execute those tests, but the CI will just ignore them. Once a feature is completed it will be developer's responsibility to remove such annotation.<br />
<br />
With hundreds of tests we had problems in having the tests properly
organized so here comes the folder structure and naming convention.
Please consider those files not as test, but as your application
documentation: as such you want to organize then in a manner they are
easily accessible by a business person. My suggestion is to organize the
tests in files describing different features, grouping the features
into folders representing functional areas. Considering <i>company search</i> and <i>report search</i> capabilities I can imagine a <span style="background-color: #eeeeee; font-family: Courier New, Courier, monospace;">search.feature</span> and an <span style="background-color: #eeeeee; font-family: Courier New, Courier, monospace;">advanced-search.feature</span>, both inside a <span style="background-color: #eeeeee; font-family: Courier New, Courier, monospace;">company</span> folder and the same file names in a <span style="background-color: #eeeeee; font-family: Courier New, Courier, monospace;">report</span> folder.<br />
<br />
Defect and user stories tracking, if desirable, can be once again achieved by using tags like <span style="background-color: #eeeeee; font-family: Courier New, Courier, monospace;">@US1234</span> and <span style="background-color: #eeeeee; font-family: Courier New, Courier, monospace;">@DE9876</span>, but I would rather avoid cluttering the feature files with such information as they will tend to distract a business person from the real value of those files: application documentation.<br />
<br />
Automation test coverage is a report we found business users find quite valuable, but it was tricky to achieve considering our application was a web one. Nevertheless we managed to have it running on our CI thankfully to <a href="http://maven.apache.org/" target="_blank">Maven</a> and its amazing set of plugins.<br />
<br />
I've prepared a <a href="https://bitbucket.org/rlogiacco/atdd" target="_blank">template Maven project</a> for those reading this post to use as a starting point and guideline if you like the solutions we adopted: it will definitely help me in the future to avoid redoing all the steps from scratch! Please, read the README file before asking for clarifications :-)<br />
<br />
<br />Anonymoushttp://www.blogger.com/profile/01075792712991750280noreply@blogger.com0tag:blogger.com,1999:blog-8062061358881596054.post-15000359942272419012012-02-23T18:28:00.000+00:002012-02-23T18:28:13.135+00:00Maven POM version managementA friend and colleague pointed me to a great Maven plugin I wasn't aware of and that is probably going to save me some headaches: the Codehaus hosted <a href="http://mojo.codehaus.org/versions-maven-plugin/" target="_blank">versions-maven-plugin</a> brings to Maven users some very nice functionality!<br />
<br />
I'm not going to copy here the full documentation, but just to make you wishing more, here is the goals list:<br />
<br />
<ul><li><span style="font-family: inherit;"><a href="http://mojo.codehaus.org/versions-maven-plugin/compare-dependencies-mojo.html" style="color: #4477aa; text-decoration: none;">versions:compare-dependencies</a> compares the dependency versions of the current project to the dependency management section of a remote project.</span></li>
<li><span style="font-family: inherit;"><a href="http://mojo.codehaus.org/versions-maven-plugin/display-dependency-updates-mojo.html" style="color: #4477aa; text-decoration: none;">versions:display-dependency-updates</a> scans a project's dependencies and produces a report of those dependencies which have newer versions available.</span></li>
<li><span style="font-family: inherit;"><a href="http://mojo.codehaus.org/versions-maven-plugin/display-plugin-updates-mojo.html" style="color: #4477aa; text-decoration: none;">versions:display-plugin-updates</a> scans a project's plugins and produces a report of those plugins which have newer versions available.</span></li>
<li><span style="font-family: inherit;"><a href="http://mojo.codehaus.org/versions-maven-plugin/display-property-updates-mojo.html" style="color: #4477aa; text-decoration: none;">versions:display-property-updates</a> scans a projectand produces a report of those properties which are used to control artifact versions and which properies have newer versions available.</span></li>
<li><span style="font-family: inherit;"><a href="http://mojo.codehaus.org/versions-maven-plugin/update-parent-mojo.html" style="color: #4477aa; text-decoration: none;">versions:update-parent</a> updates the parent section of a project so that it references the newest available version. For example, if you use a corporate root POM, this goal can be helpful if you need to ensure you are using the latest version of the corporate root POM.</span></li>
<li><span style="font-family: inherit;"><a href="http://mojo.codehaus.org/versions-maven-plugin/update-properties-mojo.html" style="color: #4477aa; text-decoration: none;">versions:update-properties</a> updates properties defined in a project so that they correspond to the latest available version of specific dependencies. This can be useful if a suite of dependencies must all be locked to one version.</span></li>
<li><span style="font-family: inherit;"><a href="http://mojo.codehaus.org/versions-maven-plugin/update-child-modules-mojo.html" style="color: #4477aa; text-decoration: none;">versions:update-child-modules</a> updates the parent section of the child modules of a project so the version matches the version of the current project. For example, if you have an aggregator pom that is also the parent for the projects that it aggregates and the children and parent versions get out of sync, this mojo can help fix the versions of the child modules. (Note you may need to invoke Maven with the -N option in order to run this goal if your project is broken so badly that it cannot build because of the version mis-match).</span></li>
<li><span style="font-family: inherit;"><a href="http://mojo.codehaus.org/versions-maven-plugin/lock-snapshots-mojo.html" style="color: #4477aa; text-decoration: none;">versions:lock-snapshots</a> searches the pom for all -SNAPSHOT versions and replaces them with the current timestamp version of that -SNAPSHOT, e.g. -20090327.172306-4</span></li>
<li><span style="font-family: inherit;"><a href="http://mojo.codehaus.org/versions-maven-plugin/unlock-snapshots-mojo.html" style="color: #4477aa; text-decoration: none;">versions:unlock-snapshots</a> searches the pom for all timestamp locked snapshot versions and replaces them with -SNAPSHOT.</span></li>
<li><span style="font-family: inherit;"><a href="http://mojo.codehaus.org/versions-maven-plugin/resolve-ranges-mojo.html" style="color: #4477aa; text-decoration: none;">versions:resolve-ranges</a> finds dependencies using version ranges and resolves the range to the specific version being used.</span></li>
<li><span style="font-family: inherit;"><a href="http://mojo.codehaus.org/versions-maven-plugin/set-mojo.html" style="color: #4477aa; text-decoration: none;">versions:set</a> can be used to set the project version from the command line.</span></li>
<li><span style="font-family: inherit;"><a href="http://mojo.codehaus.org/versions-maven-plugin/use-releases-mojo.html" style="color: #4477aa; text-decoration: none;">versions:use-releases</a> searches the pom for all -SNAPSHOT versions which have been released and replaces them with the corresponding release version.</span></li>
<li><span style="font-family: inherit;"><a href="http://mojo.codehaus.org/versions-maven-plugin/use-next-releases-mojo.html" style="color: #4477aa; text-decoration: none;">versions:use-next-releases</a> searches the pom for all non-SNAPSHOT versions which have been a newer release and replaces them with the next release version.</span></li>
<li><span style="font-family: inherit;"><a href="http://mojo.codehaus.org/versions-maven-plugin/use-latest-releases-mojo.html" style="color: #4477aa; text-decoration: none;">versions:use-latest-releases</a> searches the pom for all non-SNAPSHOT versions which have been a newer release and replaces them with the latest release version.</span></li>
<li><span style="font-family: inherit;"><a href="http://mojo.codehaus.org/versions-maven-plugin/use-next-snapshots-mojo.html" style="color: #4477aa; text-decoration: none;">versions:use-next-snapshots</a> searches the pom for all non-SNAPSHOT versions which have been a newer -SNAPSHOT version and replaces them with the next -SNAPSHOT version.</span></li>
<li><span style="font-family: inherit;"><a href="http://mojo.codehaus.org/versions-maven-plugin/use-latest-snapshots-mojo.html" style="color: #4477aa; text-decoration: none;">versions:use-latest-snapshots</a> searches the pom for all non-SNAPSHOT versions which have been a newer -SNAPSHOT version and replaces them with the latest -SNAPSHOT version.</span></li>
<li><span style="font-family: inherit;"><a href="http://mojo.codehaus.org/versions-maven-plugin/use-next-versions-mojo.html" style="color: #4477aa; text-decoration: none;">versions:use-next-versions</a> searches the pom for all versions which have been a newer version and replaces them with the next version.</span></li>
<li><span style="font-family: inherit;"><a href="http://mojo.codehaus.org/versions-maven-plugin/use-latest-versions-mojo.html" style="color: #4477aa; text-decoration: none;">versions:use-latest-versions</a> searches the pom for all versions which have been a newer version and replaces them with the latest version.</span></li>
<li><span style="font-family: inherit;"><a href="http://mojo.codehaus.org/versions-maven-plugin/commit-mojo.html" style="color: #4477aa; text-decoration: none;">versions:commit</a> removes the <tt>pom.xml.versionsBackup</tt> files. Forms one half of the built-in "Poor Man's SCM".</span></li>
<li><span style="font-family: inherit;"><a href="http://mojo.codehaus.org/versions-maven-plugin/revert-mojo.html" style="color: #4477aa; text-decoration: none;">versions:revert</a> restores the <tt>pom.xml</tt> files from the <tt>pom.xml.versionsBackup</tt> files. Forms one half of the built-in "Poor Man's SCM".</span></li>
</ul>Anonymoushttp://www.blogger.com/profile/01075792712991750280noreply@blogger.com0tag:blogger.com,1999:blog-8062061358881596054.post-68809799221331525652011-07-08T10:31:00.001+01:002011-07-08T11:42:05.500+01:00IE 8 and CSS: localhost vs rest of the worldOk, I have to admit it, I'm not a big fan of Microsoft, but this time they really made me nuts!<br />
<br />
One of the most common answer a software developer give against a defect is "it works on my machine" and we all know this is not really true as usually the answer should be "I didn't test this scenario", but this is not the case.<br />
Yesterday I was trying to fix a layout problem in an HTML popup and I thought I had it sorted I then pushed the change into the team repository and the CI system had it built and deployed, but when the tester gave it a try.... it wasn't sorted. After 6 hours of research this is what I came to: Internet Explorer 8 switches between IE8 mode and IE7 mode depending if you are accessing the resource on localhost or with another name/address!<br />
<br />
Let me make it a little more clear. Write a simple HTML page, the content does not really matter, and put it into any web server you like, I was using JBoss, but it doesn't really matter, the only thing you need is the ability to access the page both as localhost and with your IP address (this means that you have to start JBoss with -b 0.0.0.0).<br />
<br />
Now open IE8 and access that page using localhost, when it is loaded press F12 to load the Developer Tools and look at the last element in the menu bar, it should be like in the following picture:<br />
<div class="separator" style="clear: both; text-align: center;"></div><br />
<a href="http://1.bp.blogspot.com/-zNVLXmSzhtY/Thbesg2fwFI/AAAAAAAAK_0/keex9lVAYxQ/s1600/IE8.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="92" src="http://1.bp.blogspot.com/-zNVLXmSzhtY/Thbesg2fwFI/AAAAAAAAK_0/keex9lVAYxQ/s640/IE8.png" width="640" /></a><br />
Close both windows and repeat the same process but using your IP address in the URL, the result should be the following:<br />
<br />
<a href="http://1.bp.blogspot.com/-vl84NK96bsI/ThbesSv8a7I/AAAAAAAAK_w/5SAaZk3xFu0/s1600/IE7.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="92" src="http://1.bp.blogspot.com/-vl84NK96bsI/ThbesSv8a7I/AAAAAAAAK_w/5SAaZk3xFu0/s640/IE7.png" width="640" /></a>This is <b>magic</b>! It took me 6 hours to figure out what was the problem!<br />
And if you are trying to layout stuff in a DIV using CSS, this small Document Mode change can make a huge difference in what it's rendered on the screen!<br />
<br />
So imagine you, as a developer, see your code working as you expect, you push your changes and suddenly the page seems to appear wrong, again, and again, and again.... All the files are perfectly the same, on your machine and on the server you are checking against.... but what you see is different!<br />
<br />
Thank you again Microsoft, now we can really trust our work. When it comes to IE8, the What You See Is What You Get paradigm is completely fulfilled!Anonymoushttp://www.blogger.com/profile/01075792712991750280noreply@blogger.com2tag:blogger.com,1999:blog-8062061358881596054.post-81232357557165195702010-09-02T08:40:00.000+01:002010-09-02T08:40:53.979+01:00Subversion and "Could not authenticate to server"Yesterday I was trying to release the latest stable version of the <a href="http://www.dbunit.org/">dbUnit project</a> through Maven and I lost some time trying to solve a stupid problem with Subversion: everytime I ran the mvn release:prepare command I got an error saying I wasn't able to authenticate to the Sourceforge SVN server.<br />
As I was previously more than able to release the project through this same exact procedure I think the very source of the problem was the upgrade of the Subversion client. This operation infact made the project checkout directory incompatible with the command line client I was using since my last release and I decided to upgrade to the latest 1.6 version of Subversion CLI.<br />
<br />
Everything was working fine but I forgot something: suversion command line tools caches the user credentials and the Maven release goal is performed in an unattend fashion!<br />
<br />
If you encounter such a problem I suggest you issue the following command providing your credentials when prompted:<br />
<br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">svn lock <an a="" file="" in="" pointing="" repo="" to="" url="" your=""></an></span><br />
<br />
In my case the command was:<br />
<br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">svn lock https://dbunit.svn.sourceforge.net/svnroot/dbunit/trunk/dbunit/pom.xml</span><br />
<br />
This should prompt you for credentials which will be cached by the SVN client.<br />
<br />
Do not forget to unlock the file issuing the unlock command, or none else will be able to commit on that file anymore!<br />
<br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">svn unlock <the exact="" file="" in="" pointing="" repo="" same="" the="" to="" url="" your=""></the></span>Anonymoushttp://www.blogger.com/profile/01075792712991750280noreply@blogger.com0tag:blogger.com,1999:blog-8062061358881596054.post-752229437984015612010-08-29T12:27:00.005+01:002010-08-29T13:34:52.598+01:00Development EnvironmentThis is the set of tools available to the development team, all configured for authentication against the corporate LDAP:<div><ul><li><a href="http://www.jfrog.org/products.php">Artifactory</a> is the maven repository mirror and corporate artifact repository;</li><li><a href="http://subversion.tigris.org/">Subversion</a> behind Apache Web Server serves as source code management;</li><li><a href="http://continuum.apache.org/">Apache Continuum</a> behind the usual Apache Web Server runs continous integration build and testing using the projects Maven and Ant configurations;</li><li><a href="http://www.redmine.org/">Redmine</a> revealed itself as the perfect solution for project issue and time tracking with the addition of internal documentation;</li><li>source code analysis, code test coverage and code quality in general is available through <a href="http://www.sonarsource.org/">Sonar</a>;</li><li>performance issues are found through the <a href="http://www.hyperic.com/community">HypericHQ</a> monitoring system, whose reports are available to the system administrators too;</li><li><a href="http://www.eclipse.org/">Eclipse</a> is the choosen IDE supported by <a href="http://rlogiacco.blogspot.com/2008/08/eclipse-plugins.html">this</a> minimum plugins set.</li></ul></div>Anonymoushttp://www.blogger.com/profile/01075792712991750280noreply@blogger.com0tag:blogger.com,1999:blog-8062061358881596054.post-87905552965004892332010-05-31T13:39:00.015+01:002010-11-22T23:14:39.890+00:00java.util.Calendar and last, not exactly, day of month<div><span class="Apple-style-span" style="font-family: Georgia, serif;"><span class="Apple-style-span" style="font-family: georgia;"></span></span><br />
<span class="Apple-style-span" style="font-family: georgia;">Consider the following code :</span><br />
<br />
<pre class="brush:java">Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, 2009);
calendar.set(Calendar.MONTH, Calendar.FEBRUARY);
calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
return calendar.getTime();
</pre><br />
<span class="Apple-style-span" style="font-family: georgia;">What's strange or wrong with this? This code looks correct at first look and expected</span><br />
<span class="Apple-style-span" style="font-family: georgia;"> result should be </span><b style="font-family: georgia;">28 Feb 2009</b><span class="Apple-style-span" style="font-family: georgia;">. Unfortunately it's not always so!!</span><br />
<br />
<span class="Apple-style-span" style="font-family: georgia;"> Suppose to run the above code on </span><b style="font-family: georgia;">31-May-2009 at 12:00 AM</b><span class="Apple-style-span" style="font-family: georgia;">, the result will be </span><b style="font-family: georgia;">3 Mar 2009</b><span class="Apple-style-span" style="font-family: georgia;">!</span><br />
<br />
<span class="Apple-style-span" style="font-family: georgia;"> The reason have to be found on </span><b style="font-family: georgia;">lenient </b><span class="Apple-style-span" style="font-family: georgia;">Calendar mechanism. This Calendar property, infact, by default is set to </span><i style="font-family: georgia;">true</i><span class="Apple-style-span" style="font-family: georgia;"> and doesn't throw any kind of Exception when time interpretation is not correct.</span><br />
<br />
<span class="Apple-style-span" style="font-family: georgia;"> This is javadoc about it:</span><br />
<br />
<br />
<blockquote><span class="Apple-style-span" style="font-family: Georgia, serif;"><span class="Apple-style-span" style="font-family: georgia;">When a Calendar is lenient, it accepts a wider range of field values than it produces. For example, a lenient GregorianCalendar interprets MONTH == JANUARY, DAY_OF_MONTH == 32 as February 1. A non-lenient GregorianCalendar throws an exception when given out-of-range field settings. When calendars recompute field values for return by get(), they normalize them. For example, a GregorianCalendar always produces DAY_OF_MONTH values between 1 and the length of the month.</span></span></blockquote><span class="Apple-style-span" style="font-family: Georgia, serif;"><span class="Apple-style-span" style="font-family: georgia;">It means that,in our case, if we really want to get the last day of month, we have to<br />
write this simple code:<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span></span></span><br />
<br />
<pre class="brush:java">Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, 2009);
calendar.set(Calendar.MONTH, Calendar.FEBRUARY);
calendar.set(Calendar.DAY_OF_MONTH, 1);
calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
return calendar.getTime();
</pre><br />
<span class="Apple-style-span" style="font-family: georgia;"> and however, it's not a so bad idea, sometimes, to set lenient property to </span><i style="font-family: georgia;">false </i><span class="Apple-style-span" style="font-family: georgia;">and getting an IllegalArgumentsException, always better then abnormal runtime behavior.</span><br />
<br />
<span class="Apple-style-span" style="font-family: georgia;"> Hope it can be helpful.</span></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8062061358881596054.post-89803488439629243602010-05-25T10:55:00.003+01:002010-05-25T13:58:20.008+01:00Five reasons to hate DTOsI finally came to it: I hate Data Transfer Objects.<div><br /></div><div>I can't explain why a lot of people still stick with this unconfortable pattern and most of them continue to ignore the cons of this choice. Now I'll try to explain my opinion by listing why I think this should be enlisted as anti-pattern.</div><div><br /></div><div><ol><li>whenever you have to return or receive an object you must always copy it using almost double heap memory than normal (yeah, I know it's not really double, but it is something near it)</li><li>if you should return or receive a complex structure you have two choices: deep copy the structure or use multiple interactions, in both cases you are loosing heap space and processing time</li><li>almost any change to the business model interfaces will be reflected on the transfer objects AND on the code which maps the two (the latter does not apply in case you use introspection which is slower and lesser customizable) more than doubling the maintenance time and is error prone</li><li>programmers tend to confuse the difference between model objects and DTOs adding utility methods to the former and business logic to the latter</li><li>if in certain situations you need additional info on the client side from a returned DTO you have two choices: embed a service call into the DTO (which hides the complexity but expose to a performance hit as your users don't know they are starting another interaction) or call another service to obtain the additional infos (which adds complexity to your service interface)</li></ol> Now let explain my way to replace DTOs with interfaces:</div><div><ol><li>if you need to return or receive almost all the informations stored in your business model object just do it, return or receive your business model object</li><li>whenever you need to return a DTO, may be to reduce the informations providen by hiding some properties/methods, return an interface which your business model object will implement</li><li>whenever you need to receive a DTO you have two choices: use a business model object ancestor or use a business model object component; the choice depends on your business model design, if you are used to build by composition or inheritance</li><li>when you need to return a complex structure just initialize the structure before returning it (this is needed to avoid lazy initialization errors)</li></ol><div>Four simple rules to avoid class and memory duplication with a lot of processing time spent copying datas from one object to another.</div><div><br /></div><div>Do you see situations where this solution is not applicable? Let me know, I'm sure I can find a non DTO based solution.</div></div>Anonymoushttp://www.blogger.com/profile/01075792712991750280noreply@blogger.com3tag:blogger.com,1999:blog-8062061358881596054.post-75570472863699386942010-04-14T22:55:00.004+01:002011-07-08T11:31:24.363+01:00Password meterIt's a good and recent practice to place a password strenght meter on registration forms, something like the one depicted below.<br />
<div><div class="separator" style="clear: both; text-align: center;"><a href="http://4.bp.blogspot.com/-GIMCwSYyv_s/S8Y7ac98KxI/AAAAAAAAAB4/uiSPwxDW_qY/s1600/password.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="129" src="http://4.bp.blogspot.com/-GIMCwSYyv_s/S8Y7ac98KxI/AAAAAAAAAB4/uiSPwxDW_qY/s640/password.png" width="640" /> </a></div><div class="separator" style="clear: both; text-align: center;"><br />
</div><u><br />
</u><br />
<div><div><div>To achieve such a result could be very easy adapting something freely available on the web, like the one provided <a href="http://justwild.us/examples/password/">here</a>.</div></div></div></div>Anonymoushttp://www.blogger.com/profile/01075792712991750280noreply@blogger.com0tag:blogger.com,1999:blog-8062061358881596054.post-61404499366088607682010-02-12T08:53:00.003+00:002010-02-15T12:42:10.946+00:00Test Environment: OpenSSO + JBoss + WSO2 ESB + Liferay<div xmlns="http://www.w3.org/1999/xhtml">Today I'm trying to setup a test environment for an architecture we thought could solve some project problems.<br /><br />The architecture is the following:<br /><ul><li>JBoss 4.2 or 5.1 (the choice is delayed)<br /></li><li>OpenSSO 8<br /></li><li>WSO2 ESB</li><li>Liferay 5.2<br /></li></ul>As first start I installed OpenSSO 8 Enterprise (the Express version is not working for me under any environment I tried: Tomcat 5.5, Tomcet 6, JBoss 4.2, JBoss 5.1, Glassfish 2.1) on top of Tomcat 6.<br />The installation is easy, just deploy the <span style="font-family:monospace;">opensso.war</span> inside the <span style="font-family:monospace;">tomcat/webapps</span> folder, giving Tomcat one gigabyte of memory (add <span style="font-family:monospace;">JAVA_OPTS=-Xmx1024m</span> in <span style="font-family:monospace;">catalina.sh</span>) and a fully qualified domain name to the host running tomcat (<span style="font-family:monospace;">sso.smartlab.net</span> alias for <span style="font-family:monospace;">127.0.0.1</span> in <span style="font-family:monospace;">/etc/hosts</span>). On first access to the <i>http://sso.smartlab.net/opensso</i> url (it's very important you use the fully qualified domain name on your first access as it's used for configuration) I simply ran the Default Configuration (suggested for test environments only) which requires just two passwords: the amAdmin credentials will be used to access the administration console while the amAgent credentials will be used .<br /><br />After I installed the OpenSSO policy agent on top of JBoss 4.2. First of all you need to create the J2EE policy agent profile in OpenSSO. To perform this you have to access the OpenSSO administration console (username amAdmin, password the one you specified during initial configuration) and <a href="http://docs.sun.com/app/docs/doc/820-4578/gfxjk?a=view" target="_blank">follow the official instructions</a> replacing the informations providen there with your test environment infos; mine were:<br /><ul><li>Name : <i>JBoss</i></li><li>Server URL : <i>http://sso.smartlab.net:8080/opensso</i></li><li>Agent URL : <i>http://test.smartlab.net:8180/opensso-agent</i><br /></li></ul>Please note the Agent URL has a different name and port: the name is resolved through <span style="font-family:monospace;">/etc/host</span> to <span style="font-family:monospace;">127.0.0.1</span> (but MUST share the same domain with the Server URL or additional configuration is needed) while the port MUST be different because I'm running both servers on the same machine.<br /><br />I'm just performing an initial test of the architecture so I'm cloning the <span style="font-family:monospace;">server/default</span> folder of my JBoss 4.2 installation to <b><span style="font-family:monospace;">server/sso</span></b>, cleaning it up from previous work and editing the <span style="font-family:monospace;">deploy/jboss-web.deployer/server.xml</span> to switch the connector ports to <span style="font-family:monospace;">8180</span> (HTTP) and <span style="font-family:monospace;">8109</span> (AJP).<br /><br />I unzipped the <a href="https://cds.sun.com/is-bin/INTERSHOP.enfinity/WFS/CDS-CDS_SMI-Site/en_US/-/USD/ViewProductDetail-Start?ProductRef=Agt-3.0-JBOSS-4.2-G-F@CDS-CDS_SMI" target="_blank">JBoss Policy Agent 3.0 package</a> (unpacked in<span style="font-family:monospace;"> /opt/jboss/opensso</span> removing the messing directory structure <span style="font-family:monospace;">j2ee_agents/jboss_v42_agent</span>) then I created a file with the agent password<br /><br /><span style="font-size:85%;"><span style="font-family:courier new;">$> echo "agent password" > /opt/jboss/opensso/agent.pwd</span></span><br /><br />then I ran the bin/agentadmin script using this informations:<br /><ul><li>JBoss Server Config Directory :<i> /opt/jboss/server/sso/conf </i></li><li>JBoss Server Home Directory : <i>/opt/jboss </i></li><li>OpenSSO server URL : <i>http://sso.smartlab.net:8080/opensso </i></li><li>Agent URL : <i>http://test.smartlab.net:8180/opensso-agent </i></li><li>Agent Profile name : <i>JBoss </i></li><li>Agent Profile Password file name : <i>/opt/jboss/opensso/agent.pwd </i></li><li>Agent permissions gets added to java permissions policy file : <i>false</i></li></ul>Upon procedure completion some files were added to my <span style="font-family:monospace;">server/sso</span> JBoss instance, but I had to:<br /><ul><li>rename the <span style="font-family:monospace;">deploy/agentapp.war</span> file to <span style="font-family:monospace;">deploy/opensso-agent.war</span> because I used a non standard name;</li><li>change the <span style="font-family:monospace;">jboss/bin/run.sh</span> script because the suggested procedure to add the agent classpath wasn't good for my environment; I used <a href="http://pastebin.com/f1821ba8b" target="_blank">this script excerpt</a> in place of the suggested one (please note that this excerpt need you to change the first line of run.sh from <span style="font-family:monospace;"><b>#!/bin/sh</b></span> to <span style="font-family:monospace;"><b>#!/bin/bash</b></span>.<br /><br /></li></ul><img src="http://lh4.ggpht.com/_i3EJUvEf35o/Sx14yMbKIeI/AAAAAAAAABs/E0ByKfCeBnA/%5BUNSET%5D.png?imgmax=800" style="max-width: 800px; float: right; margin-top: 10px; margin-bottom: 10px; margin-left: 10px;" height="274" width="464" />I then ran my JBoss test instance with <span style="font-family:monospace;">/opt/jboss/bin/run.sh -c sso</span> and everything seems working: I tested it trying to access the <i>http://test.smartlab.net:8180/opensso-agent</i> application being redirected to the OpenSSO login page on <i>http://sso.smartlab.net/opensso</i>.<br /><br />The last test was about securing the JBoss JMX Console through OpenSSO. The activity required me to:<br /><ul><li>add <a href="http://pastebin.com/f79bc3f8f" target="_blank">this snippet</a> to the <span style="font-family:monospace;">deploy/jmx-console.war/WEB-INF/web.xml</span> file<br /></li><li>add <a href="http://pastebin.com/f20c6baf" target="_blank">this snippet</a> to the <span style="font-family:monospace;">deploy/jmx-console.war/WEB-INF/jboss-web.xml</span> file<br /></li></ul>Upon completion the same OpenSSO login page should be displayed before trying to access the <i>http://test.smartlab.net:8180/jmx-console</i> url.<br /><br />Ok, then let's try to log into the JBoss JMX Console, but with which credentials?!? On my first try I used the OpenSSO Administration Console superuser credentials (amAdmin/adminadmin) but I encountered a <b>redirection loop failure</b> thus discovering my setup wasn't ready yet. Googling a little bit I discovered this error can be simply solved adding an addition parameter for the JVM to the Tomcat configuration: <span style="font-family:monospace;">JAVA_OPTS="$JAVA_OPTS -Dcom.iplanet.am.cookie.c66Encode=true"</span>.<br /><br />Solved the problem and going back to the JMX Console I got a 403 (resource forbidden) error and after some investigations I discovered the easiest solution was to tell OpenSSO to simply apply a limited policy of type SSO_ONLY (<i>Access Control > Top Level Realm > Agents > J2EE > JBoss > General</i> add a <span style="font-family:monospace;">jmx-console=SSO_ONLY</span> map entry).<br /><br />In the near future I wish to try the usage of the OpenID 2 standard on OpenSSO, I've found some <a href="http://bug4free.wordpress.com/2009/08/24/openid2-o-opensso/" target="_blank">instructions on another blog</a> but I hadn't the time to investigate yet.<br /><br /><div class="zemanta-pixie"><img src="http://img.zemanta.com/pixy.gif?x-id=511a8452-68ec-8bde-a6e3-6c638b441507" alt="" class="zemanta-pixie-img" /></div></div>Anonymoushttp://www.blogger.com/profile/01075792712991750280noreply@blogger.com1tag:blogger.com,1999:blog-8062061358881596054.post-1096289862214360892010-02-05T12:53:00.001+00:002010-02-05T12:53:19.008+00:00Redmine Installation on Ubuntu 9.04<div xmlns='http://www.w3.org/1999/xhtml'>I decided to give a try to Redmine 0.9.1 and decided to test it on my own notebook running Ubuntu 9.04 (64 bit). As a Ruby newby I had a few issues that's why I'm going to post here my experience. By the way: Redmine is running fine on my notebook authenticating users against my corporate OpenLDAP!<br/><br/>First of all I installed the gem and ruby packages from the Ubuntu repos:<br/><br/>sudo apt-get install rubygems ruby <br/><br/>I decided to perform te remaining installation steps from gem (which, by the way, is a good tool to install ruby packages, something like apt):<br/><br/>sudo gem install rails<br/>sudo gem install rake<br/>sudo gem install rack -v=1.0.1<br/><br/>By default Redmine runs on top of mySQL, but I prefer PostgreSQL as RDBMS so I followed the <a href='http://www.redmine.org/wiki/1/RedmineInstall' target='_blank'>Redmine wiki instructions</a> to configure PostgreSQL as backend.<br/><br/>sudo gem install pg<br/><br/>Here I got the first problem as a native library I haven't installed on my PC was required, but the outputted message was unclear: something regarding a missing pg_config parameter or command.<br/>After some search I discovered pg_config is a command line utility available through the Ubuntu repositories, so the problem is easily solved running:<br/><br/>sudo apt-get install libpq-dev<br/><br/>Now the previous installation command should finish properly and you can continue with the instructions available on the Redmine wiki.<br/><br/>Once started the WEBrick server I started playing with the web application but I encountered another problem: the OpenLDAP integration. I entered all the parameters in the fields and get a succesfult connection test but I was unable to log into the system with OpenLDAP accounts: I discovered the problem was I entered too much informations in the LDAP Authentication definition!<br/><br/>Strange but solving: in the Redmine LDAP Authentication definition page you MUST NOT insert any credentials (I was erroneusly populating those fields with LDAP administrator credentials) but leave those fields blank and voilà, LDAP integration works!<br/><br/><div class='zemanta-pixie'><img src='http://img.zemanta.com/pixy.gif?x-id=d33d16fa-6485-8db8-9539-e3a00aa17a7d' alt='' class='zemanta-pixie-img'/></div></div>Anonymoushttp://www.blogger.com/profile/01075792712991750280noreply@blogger.com1tag:blogger.com,1999:blog-8062061358881596054.post-33570157023032904622009-11-16T13:19:00.001+00:002009-11-16T13:19:19.071+00:00JBoss 4 on CentOS 5<div xmlns='http://www.w3.org/1999/xhtml'>Following the step by step instructions to have JBoss 4 starting on boot on a CentOS 5 server.<br/><br/>1. create a jboss user with the command<br/><b><font face='monospace'>useradd --system -d <font color='#cc0000'>/your/jboss/root/dir</font> jboss</font></b><br/><br/>2. copy the init script already available in the jboss distribution into the /etc/init.d folder with the command<br/><b><font face='monospace'>cp </font></b><b><font face='monospace'><font color='#cc0000'>/your/jboss/root/dir</font></font></b><b><font face='monospace'>/bin/jboss_init_redhat.sh /etc/init.d/jboss</font></b><br/><br/>3. alter the /etc/init.d/jboss file to match with the CentOS 5 SELinux distribution feature changing the line<br/><font face='monospace'> SUBIT="su - $JBOSS_USER -c "</font><br/>to the equivalent SELinux of su<br/><b><font face='monospace'> SUBIT="runuser - $JBOSS_USER -c "</font></b><br/><br/>4. ensure the jboss user is capable of read and writing all the files in it's home folder executing the command<br/><b><font face='monospace'>chown jboss.jboss </font></b><b><font face='monospace'><font color='#cc0000'>/your/jboss/root/dir</font></font></b><b><font face='monospace'><i/> -Rf<br/>chmod u+rw </font></b><b><font face='monospace'><font color='#cc0000'>/your/jboss/root/dir</font></font></b><b><font face='monospace'><i/> -Rf</font></b><br/><br/>5. (optional) ensure the deployers are capable of read and writing all the files in the jboss server dirs<br/><b><font face='monospace'>chown jboss.devel </font></b><b><font face='monospace'><font color='#cc0000'>/your/jboss/root/dir</font></font></b><b><font face='monospace'>/server -Rf<br/>chmod g+rws </font></b><b><font face='monospace'><font color='#cc0000'>/your/jboss/root/dir</font></font></b><b><font face='monospace'>/server/ -Rf</font></b> <br/><br/>6. (optional) ensure the jboss server is listening on the correct address specifing the -b option on startup changing the /etc/init.d/jboss script adding the bolded line (the non bolded line is placed as a positional reference):<br/><font face='monospace'>JBOSS_HOME=${JBOSS_HOME:-"/usr/local/jboss"}<br/><b>JBOSS_HOST=<font color='#cc0000'>0.0.0.0</font></b></font><br/> <br/><br/><div class='zemanta-pixie'><img src='http://img.zemanta.com/pixy.gif?x-id=d33d16fa-6485-8db8-9539-e3a00aa17a7d' alt='' class='zemanta-pixie-img qdtrmbsnmgtyqlplfsrz'/></div></div>Anonymoushttp://www.blogger.com/profile/01075792712991750280noreply@blogger.com0tag:blogger.com,1999:blog-8062061358881596054.post-29782414080138685512009-10-15T17:25:00.003+01:002009-10-15T17:49:23.969+01:00EJB 2.x maximum performances and flexibility: abstract from Remote vs Local<div xmlns='http://www.w3.org/1999/xhtml'>I think the following should be a best practice whenever you should implement EJB 2.x specifications as this will allow to transparently switch between local and remote interfaces without any change.<br/><br/>In EJB 2.x you need to write the following classes/interfaces to support both remote and local deployment:<br/><ul><li>public class <b>MyComponentBean</b> implements javax.ejb.SessionBean</li><li>public interface <b>MyComponentRemoteHome</b> extends javax.ejb.EJBRemoteHome</li><li>public interface <b>MyComponentRemote</b> extends javax.ejb.EJBObject</li><li>public interface <b>MyComponentLocalHome</b> extends javax.ejb. EJBLocalHome</li><li>public interface <b>MyComponentLocal</b> extends javax.ejb.EJBLocalObject</li></ul>If you want to be able to switch between local and remote deployment you need to change every place where you retrieve the EJB, usually this action is concentrated in a ServiceLocator implementation like:<br/><pre><br />public class MyComponentServiceLocator {<br /> public final static String MY_COMPONENT_LOCATION = "ejb/myComponent";<br /><br /> public static MyComponentLocal getLocal(Properties properties) throws Exception {<br /> InitialContext context = new InitialContext(properties);<br /> MyComponentLocalHome home = (MyComponentRemoteHome)context.lookup(MY_COMPONENT_LOCATION + "/local");<br /> return home.create();<br /> }<br /> public static MyComponentRemote getRemote(Properties properties) throws Exception {<br /> InitialContext context = new InitialContext(properties);<br /> MyComponentRemoteHome home = (MyComponentRemoteHome)context.lookup(MY_COMPONENT_LOCATION + "/remote");<br /> return home.create();<br /> }<br />}<br /></pre><br/><br/>With this approach you can switch from local to remote just switching from MyComponentServiceLocator.getLocal(...) to MyComponentServiceLocator.getRemote(...) on every place you need to switch, but in addition you need to switch the type you declared for the variable to which you are going to assign the MyComponentServiceLocator call result: from MyComponentLocal to MyComponentRemote.<br/><br/>In addition you need to manually track down all interfaces are exposing the same methods.<br/>Wouldn't it easier if we can have some sort of automatic check and avoid the need to switch the code? Couldn't be possible to switch between local and remote at deployment time without <b>any</b> change at compile time?<br/><br/>Well, the answer is in the following structure:<br/><ul><li>public interface <b>MyComponent<br/></b><i>declares all shared functional methods, each method will throws java.rmi.RemoteException in addition to any exception it should normally throw</i></li><li>public interface <b>MyComponentHome</b><i><br/>declares all shared creation methods throwing both java.rmi.RemoteException and javax.ejb.CreateException</i><b><br/></b></li><li>public class <b>MyComponentBean</b> implements javax.ejb.SessionBean, MyComponentRemote, MyComponentLocal<br/><i>the MyComponentRemote and MyComponentLocal interfaces have been added here to ensure the implementation class provides code for all the declared methods: be careful, all methods <b>must not</b> throw java.rmiRemoteException</i><br/></li><li>public interface <b>MyComponentRemoteHome</b> extends javax.ejb.EJBRemoteHome, MyComponentHome<br/><i>the MyComponentHome interface has been added here to ensure all shared creation methods are supported by the remote home: if <b>all</b> the remote creation methods are shared than this interface will be completely empty!</i><br/></li><li>public interface <b>MyComponentRemote</b> extends javax.ejb.EJBObject, MyComponent<br/><i>the MyComponent interface has been added here to ensure all the shared methods are supported through the remote interface: if <b>all</b> the remote methods are shared than this interface will be completely empty!</i><br/></li><li>public interface <b>MyComponentLocalHome</b> extends javax.ejb. EJBLocalHome, MyComponentHome<br/><i>the MyComponentHome interface has been added here to ensure all shared creation methods are supported by the local home: all methods defined in the MyComponentHome interface <b>must be overriden</b> here to remove the java.rmi.RemoteException declaration; if you forget this step your application server should warn you when you deploy this EJB.</i><br/></li><li>public interface <b>MyComponentLocal</b> extends javax.ejb.EJBLocalObject, MyComponent<br/><i>the MyComponent interface has been added here to ensure all shared methods are supported through the local interface: all methods defined in the MyComponent interface <b>must be overriden</b> here to remove the java.rmi.RemoteException declaration; if you forget this step your application server should warn you when you deploy this EJB.</i></li></ul>This is harder to say than to put in practice and the advantages are:<br/><ul><li>one place for shared creation methods: if you add a method to MyComponentHome interface you automatically get it on the remote home and if you forget to override it in the local home (to remove the java.rmi.RemoteException) your application server will warn you on your first deployment;</li><li>one place for shared functional methods: if you add a method to MyComponent interface you automatically get it on the remote interface and if you forget to override it in the local interface (to remove the java.rmi.RemoteException) your application server will warn you on your first deployment;</li><li>your clients will no more have to deal with remote or local differences as they will use the MyComponent interface (unless they need some methods not available on both interfaces)</li><li>you can still produce different interfaces for local and remote deployments;</li><li>your implementation will always implement the required methods;<br/></li><li>you can switch between local and remote deployment using the <a target='_blank' href='http://docs.sun.com/source/816-5831-10/sessionejb/ejbref.html'>ejb-ref</a> directive (in your web.xml or in your ejb.xml)</li><li>you can have a ServiceLocator like the following one which completely masks the remote vs local<br/></li></ul><br /><pre>public class MyComponentServiceLocator {<br /> public final static String MY_COMPONENT_LOCATION = "ejb/myComponent";<br /> public static MyComponent get(Properties properties) throws NamingException, CreateException, RemoteException {<br /> InitialContext context = new InitialContext(properties);<br /> MyComponentHome home = (MyComponentHome)context.lookup("java:comp/env/" + MY_COMPONENT_LOCATION);<br /> return home.create();<br /> }<br />}</pre><br/><br/>If you don't want to deal with the ejb-ref at all you can consider the following ServiceLocator implementation which allows any deployment combination and automatically uses the local interface if available (with lesser performances as two JNDI lookups are performed in the worst case)<br/><br /><pre>public class MyComponentServiceLocator {<br /> public final static String MY_COMPONENT_LOCATION = "ejb/myComponent";<br /> public static MyComponent get(Properties properties) throws NamingException, CreateException, RemoteException {<br /> try {<br /> return MyComponentServiceLocator.getLocal(properties);<br /> } catch (Exception e) {<br /> return MyComponentServiceLocator.getRemote(properties);<br /> }<br /> }<br /> public static MyComponentLocal getLocal(Properties properties) throws NamingException, CreateException {<br /> InitialContext context = new InitialContext(properties);<br /> MyComponentLocalHome home = (MyComponentRemoteHome)context.lookup(MY_COMPONENT_LOCATION + "/local");<br /> return home.create();<br /> }<br /> public static MyComponentRemote getRemote(Properties properties) throws NamingException, CreateException, RemoteException {<br /> InitialContext context = new InitialContext(properties);<br /> MyComponentRemoteHome home = (MyComponentRemoteHome)context.lookup(MY_COMPONENT_LOCATION + "/remote");<br /> return home.create();<br /> }<br />}<br /></pre><br/>Be careful, the last solution can produce unwanted exception traces in your application server when the local lookup fails: those exceptions are normal unless produced by the remote lookup. Those unwanted exceptions can bring you mad when you try to understand why your EJB is not working.<br/><br/><div class='zemanta-pixie'><img src='http://img.zemanta.com/pixy.gif?x-id=dba14376-2046-8ebf-aa34-e2a1f341b6d0' alt='' class='zemanta-pixie-img'/></div></div>Anonymoushttp://www.blogger.com/profile/01075792712991750280noreply@blogger.com0tag:blogger.com,1999:blog-8062061358881596054.post-41062795032886575292009-10-06T00:49:00.004+01:002009-10-06T01:19:08.881+01:00JBoss Production Environment<div xmlns="http://www.w3.org/1999/xhtml">In my humble opinion a JBoss production environment should be something like the one depicted in the following diagram<br /><br /><img src="http://lh5.ggpht.com/_i3EJUvEf35o/SsqC5wU3WaI/AAAAAAAAABM/xcW0xW7K4JQ/%5BUNSET%5D.png?imgmax=800" style="max-width: 600px;" /><br /><br />I recommend to use mod_proxy, mod_proxy_balancer and mod_proxy_ajp apache modules both for load balancing and request forwarding with directives like:<br /><br /><blockquote><pre>ProxyRequests Off<br /><Proxy balancer://webapp-cluster><br /> Order deny,allow<br /> Allow from all<br /> BalancerMember ajp://instance1:8009/webapp-name loadfactor=1<br /> BalancerMember ajp://instance2:8009/webapp-name loadfactor=1<br /> ProxySet lbmethod=bytraffic<br /></Proxy><br />ProxyPass /webapp-name balancer://webapp-cluster<br />ProxyPassReverse /webapp-name balancer://webapp-cluster<br /></pre></blockquote>System dimensions and load can vary the numbers, but the architecture should be sufficient and enough scalable for many situations.<br /><br /><div class="zemanta-pixie"><img src="http://img.zemanta.com/pixy.gif?x-id=a902a46f-dd46-8492-bc11-072ca80639da" alt="" class="zemanta-pixie-img hgikxugzfwgffkzohkya hgikxugzfwgffkzohkya hgikxugzfwgffkzohkya hgikxugzfwgffkzohkya hgikxugzfwgffkzohkya hgikxugzfwgffkzohkya hgikxugzfwgffkzohkya hgikxugzfwgffkzohkya hgikxugzfwgffkzohkya" /></div></div>Anonymoushttp://www.blogger.com/profile/01075792712991750280noreply@blogger.com0tag:blogger.com,1999:blog-8062061358881596054.post-67091259145760659562009-10-05T01:57:00.001+01:002009-10-06T00:51:41.446+01:00Java Serialization & final class attributes<div xmlns='http://www.w3.org/1999/xhtml'>Today I had to face a problem with Java Serialization and here is the report of what I've achieved.<br/>The SmartWeb BusinessObject class defines a protected attribute named <font face='monospace'>logger</font> carrying the logger for subclasses. The <font face='monospace'>BusinessObject</font> class implements <font face='monospace'>Serializable</font> thus it needs to define the <font face='monospace'>logger</font> attribute as transient because Commons Logging loggers are non serializable.<br/><br/>The problem arises whenever you deserialize a <font face='monospace'>BusinessObject</font> subclass because the <font face='monospace'>logger</font> attribute will not be deserialized (it has not be serialized at all!) and this makes all your logging statements producing <font face='monospace'>NullPointerException</font>s! BTW, those errors are very difficult to understand for two reasons:<br/><ol><li>you always consider that attribute valid and you will hardly consider tha logger attribute to be null</li><li>every logging statement you try to add to your code to understand what's going wrong will fail on it's own</li></ol>Well, the solution to the problem is re initialize the <font face='monospace'>logger</font> attribute upon object deserialization implementing a custom <i>readObject</i> method as stated in the <a href='http://java.sun.com/j2se/1.4.2/docs/api/java/io/Serializable.html'>Serializable interface documentation</a>:<br/><pre>private void readObject(java.io.ObjectInputStream in)<br /> throws IOException, ClassNotFoundException;<br /></pre>The preceeding code is not going to work in my specific case because the <font face='monospace'>logger</font> attribute has been declared as <font face='monospace'>final</font> to avoid unwanted replacements and potential errors. The first option I took in consideration was "<i>ok, I've no exit, let's make that attribute non final</i>" but the idea was suddenly replaced by "<i>but standard Java Serialization is normally able to deserialize final fields... how?</i>" and I googled and digged a little bit into the problem ending to the following solution:<br/><pre><br /> /**<br /> * Custom deserialization. We need to re-initialize a logger instance as loggers<br /> * can't be serialized.<br /> */<br /> private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {<br /> try {<br /> Class type = BusinessObject.class;<br /> // use getDeclaredField as the field is non public<br /> Field logger = type.getDeclaredField("logger");<br /> // make the field non final<br /> logger.setAccessible(true);<br /> logger.set(this, LogFactory.getLog(type));<br /> // make the field final again<br /> logger.setAccessible(false);<br /> } catch (Exception e) {<br /> LogFactory.getLog(this.getClass())<br /> .warn("unable to recover the logger after deserialization: logging statements will cause null pointer exceptions", e);<br /> }<br /> in.defaultReadObject();<br /> }<br /></pre><br/><br/><div class='zemanta-pixie'><img src='http://img.zemanta.com/pixy.gif?x-id=365afb97-f1e8-8a8a-b47c-ef3a9e1a0dc5' alt='' class='zemanta-pixie-img'/></div></div>Anonymoushttp://www.blogger.com/profile/01075792712991750280noreply@blogger.com0tag:blogger.com,1999:blog-8062061358881596054.post-65861373388177658632009-09-30T12:25:00.001+01:002009-10-06T00:54:21.343+01:00Subversion + LDAP read only and read write<div xmlns='http://www.w3.org/1999/xhtml'><div style='float: right;' class='zemanta-image'><a title='Public domain' href='http://commons.wikipedia.org/wiki/Image:Goyathlay.jpeg'><img src='http://upload.wikimedia.org/wikipedia/commons/thumb/8/89/Goyathlay.jpeg/300px-Goyathlay.jpeg'/></a><br/><small>Image via <a href='http://commons.wikipedia.org/wiki/Image:Goyathlay.jpeg'>Wikipedia</a></small></div>Here follows the Apache configuration I found working to set a repository read-only and read-write permissions. Consider read-write permissions are given by adding a user to <b>both</b> <i>read-allowed</i> <u><b>and</b></u> <i>write-allowed</i> LDAP groups, while read-only permissions are given through the <i>read-allowed</i> LDAP group.<br/><br/><font face='monospace'><location test=''><br/> AuthType basic<br/> AuthBasicProvider ldap<br/> AuthBasicAuthoritative On<br/> AuthName "SmartLab Directory Server"<br/> AuthLDAPURL ldap://ldap/ou=people,dc=smartlab,dc=net<br/> AuthLDAPGroupAttributeIsDN off<br/> AuthLDAPGroupAttribute memberUid<br/> <limit report='' options='' propfind='' get=''><br/> Require ldap-group cn=read-allowed,ou=groups,dc=smartlab,dc=net<br/> </limit><br/> <limitexcept report='' options='' propfind='' get=''><br/> Require ldap-group cn=write-allowed,ou=groups,dc=smartlab,dc=net<br/> </limitexcept><br/></location><br/></font><br/><br/><div class='zemanta-pixie'><a title='Reblog this post [with Zemanta]' href='http://reblog.zemanta.com/zemified/869b7a70-bfe1-4fb5-84bb-b5bc4eb0858c/' class='zemanta-pixie-a'><img alt='Reblog this post [with Zemanta]' src='http://img.zemanta.com/reblog_e.png?x-id=869b7a70-bfe1-4fb5-84bb-b5bc4eb0858c' class='zemanta-pixie-img'/></a></div></div>Anonymoushttp://www.blogger.com/profile/01075792712991750280noreply@blogger.com1tag:blogger.com,1999:blog-8062061358881596054.post-57200177114885440102009-09-24T15:53:00.002+01:002009-10-06T00:58:16.507+01:00Subversion merge after refactor<div xmlns='http://www.w3.org/1999/xhtml'>I recently discovered the popular Subversion VCS has a problem to apply differences to moved files. Unfortunately I discovered this after a big and time consuming refactor process so I had to find out an "easy-to-apply" solution to this problem.<br/><br/><div class='zemanta-image'><a href='http://commons.wikipedia.org/wiki/Image:Subversion_project_visualization.svg' title='GNU Free Documentation License'><img src='http://upload.wikimedia.org/wikipedia/commons/thumb/4/4e/Subversion_project_visualization.svg/500px-Subversion_project_visualization.svg.png' style='float: none;'/></a><br/><small>Image via <a href='http://commons.wikipedia.org/wiki/Image:Subversion_project_visualization.svg'>Wikipedia</a></small></div><span style='font-family: georgia;'><br/><br/>My repository layout is something like:</span><br/><br/><span style='font-family: monospace;'><big>project<br/> +-- trunk<br/> +-- branches<br/> +-- refactoring</big></span><br/><br/><span style='font-family: georgia;'>The target operation is to merge the refactoring branch onto the trunk, but to avoid blocking all other people I decide to perform the inverse: apply all updates on the trunk to the refactoring branch. On merge completion I'm going to switch the twos.<br/><br/>First of all I started merging the trunk onto the branch ignoring all the "Skipped missing target" messages which whould occur for each file you moved/renamed: in my case this was happening for 99% percent of the files, as it was a massive refactor, and only downloading added files (which you may still need to review).<br/><span style='font-family: courier new;'><br/>svn merge -r 3855:HEAD http://svn.smartlab.net/project/trunk</span><br/><br/>Then I moved on the trunk working copy and performed a huge diff starting from the revision in which I created the branch and stopping to the HEAD revision:</span><br/><br/><span style='font-family: monospace;'><big>svn diff -r 3855:HEAD . > rev.3855-HEAD.diff</big></span><br/><br/><span style='font-family: georgia;'>Next step was to open the diff file both in eclipse (right click on the checkout folder, Team/Apply patch...) and within a text editor (I used gedit, but vi or notepad++ should get you to the same results): I used eclipse to easily find unmatched entries (shown with a red cross) and applied a textual search & replace on the diff file in the text editor.<br/><br/>At the end of my process I had a diff file I could use to patch my branch to have it up to date against the trunk, with a few missing/unappliable patches against those files I had removed definitely from my branch.<br/><br/>The process was easy, but needed time and the results depends on the accuracy you perform it. But at least all my work has not been void!<br/><br/>BTW: if you are not mass refactorying you can use the Eclipse support to select an unmatched diff entry and <b>move</b> it to another file, this can be really usefull if you have moved only a few files.</span><br/><br/><div class='zemanta-pixie'><img src='http://img.zemanta.com/pixy.gif?x-id=2e69252b-cc5c-813e-9be7-6c6f9d539016' alt='' class='zemanta-pixie-img'/></div></div>Anonymoushttp://www.blogger.com/profile/01075792712991750280noreply@blogger.com0tag:blogger.com,1999:blog-8062061358881596054.post-54910222896166804462009-09-03T20:08:00.005+01:002009-09-03T20:43:07.950+01:00RTMPT on Tomat + Red5 as a war<div><blockquote></blockquote>I'm recently developing a Flex application and, as an Open Source addicted, I choosen to use Red5 as streaming server.</div><div><br /></div><div>The network architecture actually is a Tomcat 6 servlet container with some wars deployed within, one of which is the Red5 streaming server.</div><div><br /></div><div>To ensure my application could be used through internet the default RTMP protocol is not the best choice as some firewalls blocks its port, so I opted for the RTMP over HTTP, also known as <a href="http://en.wikipedia.org/wiki/Real_Time_Messaging_Protocol">RTMPT</a> (notice the final additional T) which is able to tunnel RTMP inside HTTP.</div><div><br /></div>I found a bit of confusion when I googled to configure my Red5 war so I'm going to report here the simple four steps I did to make my configuration working.<div><br /></div><div><ol><br /><li>Open your WEB-INF/web.xml file and add the RTMPT servlet definition and mappings (if RTMP is going to be tunneled inside HTTP we need an HTTP endpoint able to forward packets)<br /><blockquote><span class="Apple-style-span" style="font-size: small;"><span class="Apple-style-span" style="font-family:'courier new';"><br /> <servlet><br /> <servlet-name>rtmpt</servlet-name><br /> <servlet-class>org.red5.server.net.rtmpt.RTMPTServlet</servlet-class><br /> <load-on-startup>1</load-on-startup><br /> </servlet><br /><br /> <servlet-mapping><br /> <servlet-name>rtmpt</servlet-name><br /> <url-pattern>/fcs/*</url-pattern><br /> </servlet-mapping><br /><br /> <servlet-mapping><br /> <servlet-name>rtmpt</servlet-name><br /> <url-pattern>/open/*</url-pattern><br /> </servlet-mapping><br /><br /> <servlet-mapping><br /> <servlet-name>rtmpt</servlet-name><br /> <url-pattern>/close/*</url-pattern><br /> </servlet-mapping><br /><br /> <servlet-mapping><br /> <servlet-name>rtmpt</servlet-name><br /> <url-pattern>/send/*</url-pattern><br /> </servlet-mapping><br /><br /> <servlet-mapping><br /> <servlet-name>rtmpt</servlet-name><br /> <url-pattern>/idle/*</url-pattern><br /> </servlet-mapping><br /></span></span></blockquote></li><br /><br /><li>Inside your WEB/lib you should have a Red5 jar (well, this is not my case as I use Maven for build, but Maven users will understand what I mean, right?) and you need to open it up and edit the red5.properties file it contains:<br /><blockquote><span class="Apple-style-span" style="font-size: small;"><span class="Apple-style-span" style="font-family:'courier new';"><br />http.port = 8080<br /></span></span></blockquote></li><br /><br /><li>Open your Tomcat 6 folder and edit the file conf/server.xml adding, if needed, an HTTP/1.1 connector for the port you want to use for RTMPT (the default port is 80, but you can set it accordingly to your needs):<br /><blockquote><span class="Apple-style-span" style="font-size: small;"><span class="Apple-style-span" style="font-family:'courier new';"><br /><!-- RTMPT connector redirecting to your HTTP port --><br /> <Connector port="8088" protocol="HTTP/1.1"<br /> maxThreads="150" connectionTimeout="20000"<br /> redirectPort="8080" /></span></span><br /></blockquote><br /></li><br /><li>The last and very bothering part is you need to have your streaming server war binded to the root context, so you can simply rename it to <b>ROOT.war</b></li></ol>--- </div>Anonymoushttp://www.blogger.com/profile/01075792712991750280noreply@blogger.com3tag:blogger.com,1999:blog-8062061358881596054.post-57063751705414381592009-07-24T12:31:00.000+01:002009-07-24T12:32:01.835+01:00OpenSSL CA-Infrastructure<div xmlns='http://www.w3.org/1999/xhtml'>Generate your own private key and make sure none will ever get access to your private key:<br/><code>openssl genrsa -des3 -out private.key 2048</code><br/><br/>If you need your public key outside of a certificate issue this command:<br/><code>openssl rsa -in private.key -pubout -out public.key</code><br/><br/>To generate a certificate request for your key:<br/><code>openssl req -new -key private.key -out certificate.csr</code><br/><br/>Now you should send your certificate request ONLY to the certification authority; someone, on the other side will view your request:<br/><code>openssl req -text -noout -in certificate.csr</code><br/><br/>and then will decide to sign your request sending a valid certificate <br/><code>openssl x509 -days 365 -in certificate.csr -out certificate.crt -sha1 -CA ca.crt -CAkey ca.key -req -extfile user.ext</code></div>Anonymoushttp://www.blogger.com/profile/01075792712991750280noreply@blogger.com0tag:blogger.com,1999:blog-8062061358881596054.post-32157764505979035642009-03-20T17:58:00.001+00:002009-03-20T17:58:19.611+00:00HSQLDB No such table Exception<div xmlns='http://www.w3.org/1999/xhtml'>I've encountered a strange problem using HSQLDB which became totally weird when using that database in conjunction with Hibernate formulas. Here is the problem and the specific issue.<br/><br/>I've a table named <font face='monospace'>group</font> (lower case) and a table named <font face='monospace'>property</font> (lower case) in a schema named <font face='monospace'>auth</font> (lower case too, for naming convention) and I want to create them both on HSQLDB. I know <b>group</b> is a reserved word in SQL so I've created my DDL statements accordingly:<br/><blockquote><font face='monospace'> create schema auth authorization DBA;</font><br/><br/><font face='monospace'> create table auth."group" (</font><br/><font face='monospace'> "id" bigint </font><font face='monospace'>generated by default as identity (start with 1)</font><font face='monospace'>,</font><br/><font face='monospace'> "description" longvarchar,</font><br/><font face='monospace'> primary key ("id")</font><br/><font face='monospace'> );</font><br/><br/><font face='monospace'> create table auth."property" (</font><br/><font face='monospace'> id bigint generated by default as identity (start with 1),</font><br/><font face='monospace'> handler varchar(255),</font><br/><font face='monospace'> primary key (id)</font><br/><font face='monospace'> );</font><br/></blockquote>As you can see I've double quoted the structure element names in table group to avoid the reserved word problem (I could limit myself to the table name, but this doesn't make any difference) and I've used the same notation for the table property name too (not needed but this clarifies my example). Now I wish to query that database with a query like<br/><blockquote><font face='monospace'>select * from auth."group"</font><br/></blockquote>which correctly executes and returns the results, but a query like<br/><blockquote><font face='monospace'>select * from auth.property</font><br/></blockquote>fails with a <b>No such table exception</b> !?!<br/><br/>Well the problem is HSQLDB converts all identifiers to upper case unless you use the double quote notation!!!! The query then should be issued as<br/><blockquote><font face='monospace'>select * from auth."property"</font><br/></blockquote>If you query the database meta data you can see the problem in the auth schema name: it's real name is AUTH, all uppercase letters!<br/><br/>The problem here is HSQLDB is case sensitive <b>but</b> implicitly converts all your table names and column names to upper case! Yes the problem occur on column names too, in fact the following query fails with a No such column exception:<br/><blockquote><font face='monospace'>select "id" from auth."property"</font><br/></blockquote>Thats because the id column was implicitly renamed to ID... sigh!<br/><br/>Ok, this is a problem, but it's still not a great problem, you just use double quotes consistently through all your project (I had no choice to use double quotes everywhere) and you can forget the problem just treating HSQLDB as a case sensitive database.<br/><br/>If you wish to use Hibernate to query such a database you have to use the special single quote character ` (sorry, I haven't found a better name for it) instead of double quotes inside your HBMs to let Hibernate substitute the ` char with the " char (to avoid XML issues).<br/><br/>Well, still no unresolvable problem until now, but if you want to write an Hibernate formula property... <b>BANG</b>! With an Hibernate formula property in fact you can write your own SQL statement which will be executed to populate that property, but you can't use nor double quotes nor the ` char to escape a column name there! Well the last statement is not completely true as you can use the ` tinstead of the double quotes, but in this case you can use only fields of the table your class is mapped onto... which makes formulas quite unuseful.<br/><br/>I'm actually trying to help the Hibernate developers to solve the problem... I'll update this post if I found a solution as Hibernate user or developer.<br/><br/><div class='zemanta-pixie'><img src='http://img.zemanta.com/pixy.gif?x-id=d195e8e0-8901-4679-8707-f036af947ddd' class='zemanta-pixie-img'/></div></div>Anonymoushttp://www.blogger.com/profile/01075792712991750280noreply@blogger.com2