Sunday, 26 June 2016

Selenium vs Selenium (with Open Source Stack)

In the past I did a comparative Selenium vs Sahi vs HP QTP, finally our decision was to use Selenium because of its ecosystem and the possibility to execute the test with Java, this final point was one the keys of the success of the project as we could use some Java libraries to extend the testing functionalities and have integrated testing against WS, images comparative, pdf comparative...

This time, I'm in a new company, new project, and now we have a dilemma to use Ranorex or Selenium. Ranorex is a powerful tool that I like, but the question is if is it worthwhile using Selenium with a stack of open source tools instead of Ranorex. And after some proofs of concept over our application, we arrive to the conclusion that it is not worth it to pay for licences. But anyway, if we consider the amount necessary to buy licences irrelevant, which solution is better for us?

There are a lot of articles comparing automation testing tools, most of them talk about Selenium:
For some of them, it is easy to see that are totally partial as they were written by the private companies that Selenium is compared against. But, are those arguments true? Because I don't see too many comments against those comparatives.

From my point of view all that they say is true, at least at the time the articles were written, but with a trick, and It is that no one says that there are a lot of frameworks/tools ready to use that at least give us the same power (if not more) as the vendors tools give. With this in mind, today, you don't need to build a framework from scratch that can help you in the testing with Selenium, these days the mission of the developer is to choose the correct open source stack of tools for his/her needs.

So in the next lines I will show you a proof of concept between Ranorex and a stack of open source tools with Selenium.

POC: Selenium (with open source stack) vs Ranorex

Use cases:
  • Focused on browser testing.
  • Build the same test with Ranorex and Selenium.
  • Test the same grid in two different pages.
Challenges:
  • The rapid implementation of new tests by not high skilled developers.
  • Maintainability of the code.
  • Integration with existing solutions at the company: TFS / HPALM.
  • Integration with the rest of the tools of the project (AUT).

Selenium stack - Solution description


With Selenium you can choose to implement the solution in a wide range of languages, for this time we choose to use Java because the architecture in the AUT is implemented in Java, so in this case the solution will be closer to the experience of the developers.

Stack of tools: Cucumber + Serenity + Selenium + IntelliJ IDEA

  • Cucumber is a framework for writing and executing high level descriptions of the functionality of the software.
  • Serenity is an Open Source library for writing better quality automated acceptance tests faster. The final decision to choose Serenity was by the DI (dependency injection) already configured by the framework that ease the decoupling of the components. Another framework also highly considered was Selenide.
  • Selenium is a portable software testing framework for web applications. It provides commands for performing actions in a browser.
  • IntelliJ IDEA is a Java integrated development environment (IDE).

---------------------------------------------------
Off the record:
In C# there are also frameworks that can help in the development with a lot of functionalities, for example, this could be the stack of tools:
  • Specflow: is a framework for writing and executing high level descriptions of software's functionality.
  • ObjectivityBSS / Seleno...
  • Selenium is a portable software testing framework for web applications. It provides commands for performing actions in a browser.
  • Visual Studio: is a C# integrated development environment (IDE).
---------------------------------------------------

The designed solution is based on BDD and the Pattern, well-proven by being widely adopted in UI testing, “Page Object”.


The integration between layers is made by DI.

Ranorex - Solution description


Stack of tools: Ranorex and Visual Studio.
  • Ranorex Studio: tools for creating automated testing projects to test any desktop, web or mobile application.
  • Visual Studio: is a C# integrated development environment (IDE).

The main design idea: export Ranorex project to Visual Studio to use Ranorex as a library in the VS project to the interaction with the Browser.


The reason for using this kind of design is because the AUT is very old, plenty of iframes, duplicated id's (don't ask me please!), and so on; in a way that there are places where the only possibility to identify an element of the page  is by its shown text. The idea is to use the in18 properties files from the UAT (key/value) -> in the VS project load the correct value from a given in18 key and passes it as a parameter  to the Ranorex library.

  • In Visual Studio project structure we will follow the same name convention and structure as we did for the Selenium part 
  • The page components are stored in the Ranorex library.

Comparative


  • Support desktop applications: Selenium is based on the implementation of a WebDriver. Although there’s also an implementation to test WinForms and WPF and in this comparative we are talking about browsers.
  • Learning curve: for the punctuation this example was taken into account: the effort of an intern to automatize, from scratch, a page with a search form (with 5 fields) and a result list  (only following the documentation). This is a very interesting point, because the people at first glance can think that Ranorex maybe is easier because of its WYSIWYG style, but in the proof, the interns (without previous knowledge) said that they prefer the Selenium solution. Maybe this was because of the problems to get a good identifier directly through Ranorex that all the recorded things had to be re-written. Someone can say that those problems where because of the lack of knowledge, well, this is something to take into account in the "Learning curve" item. Another possible criticism of Selenium is that you need to do manual programming, but the fact is that once you have a template, the skill of the programmer needed is very low.
  • Maintainability & Reusability: in both solutions we have the components decoupled of from the test, so the implementation of the tests in both solutions are very similar. Maybe the people that like Ranorex can say that it is better and the people of Selenium can say the same. I think that it is very difficult to say which one is better. 
  • Results stability (retry capabilities): stability of results against false positive. With Selenium you have more control over the execution flow and the politics of retries can be configured before giving an error as a result in the Serenity framework.
  • Multi-language testing (i18n support): the implementation is based on getting the multilanguage properties as (locale strings:key/value) from the AUT and then use the value of the current language as a parameter in the test. In fact, this locale file can be loaded at 'runtime' from the AUT. This can be done by both solutions, but with Ranorex the cost of maintenance is higher.
  • Integration with other type of tests: the integration with other tools in the execution of a Test Case. As the design of the solution in Ranorex is with VS, it gives all the power of C#.
  • Integration with HPALM: the result of the execution can update the test cases at HPALM
  • Parallelization of the executions: the test can be executed in the same machine in parallel and against different servers. This is a key point in terms of resources, add VMs for parallelization means more maintenance of servers and more cost in terms of hardware and licences.
  • Multiplatform (Windows, Linux, “headless browser”): with “headless browser” and with Linux, it’s possible to execute the test in a Docker container maybe by the developer of the AUT (before a commit). This is another key point as it gives the possibility of the execution in the developer's machine, while the developer can do other tasks, This can be done also with VMs, but at the cost of more resources needed for the developers' machines.
  • Alignment with the company: use of this tool in the rest of the company projects to share knowledge. Until now, Selenium is not used, but as the intern reflects, once the structure of the framework is established, then its use is easy.
  • Alignment with the AUT: use of this solution in the AUT. The application is multiplatform with developer environment in Java, using Cucumber + Serenity + DBUnit + IntelliJ IDEA for testing the upgrade of the DB of the AUT.

Conclusions - The "Vision"


I don't want to get in into any kind of debate that "it seems" that this solution is better in someway and "bla bla bla", in something that can not be easily proved. If we are not talking about money, for me both solutions can give you very similar results, but there are some points to which no one can disagree (I hope!) and it is the parallelization and multiplatform execution. In the context of our AUT the parallelization is a key, the application is too big and the parallelization of the executions must be taken into account from the first steps.

Also, I don't want to say that this comparative can be applied to any project, for sure there are projects that the best approach is to use Ranorex (or some other tools like this), but in the context of this AUT the best choice is without doubts the stack of Selenium tools.

The "Vision":

Nowadays we are facing to some kind of revolution in the IT world: microservices, nosql, react, docker containers...

In terms of functional testing I think that the future is that the developers can not only execute the unit test before any commit to the SCM, but also execute the integration tests and UI test; and the easier way to achieve this last point is with the execution of the UI test in a docker container or with a headless browser. And this only can be done with Selenium.

Thursday, 3 March 2016

Approaching to needs for an Automated Test Platform


By Automated Test Platform we mean the infrastructure, tools, applications and software that can be used to include the automated test (usually functional test) in the pipeline of the Continuous Delivery (CD).

There are different ways to set up an Automated Test Platform, we can find products like ExtensiveTestingAtestingpSmartbear,  ... on the other hand, you can build your customed platform integrating test management tools in your Continuous Integration (CI) process.



The aim of this article is not to compare different products, it is just to do a simplified exercise based on the checklist that an Automated Test Platform "must" have, i.e. a list of features you would think about, when you are searching for a solution.

From the users point of view

You must integrate different actors. The tools to be used have to be adaptable for the different kind of users.
  • QA: management of use cases, test cases, test plans...
  • Developers/testers: test cases implementation.
  • DevOps: integration with the CD pipeline.
  • Managers: reports, reports... and more reports.

From the testers point of view

First of all, tests have to be Robust  and Stable. But also the tests implementation has to have:
  • An easy learning curve for new developers.
  • Ease of development.
  • Easy of maintenance: be sure there will be changes, be ready for changes. 
  • Portable: tests have to be executed in an easy way, when developing, as the same way as it will be executed automatically by the automated platform. 

From the execution point of view

Here we are thinking about the ability to execute the test with different configurations and easy integration with deployment tools and continuous integration.
  • Adaptability. Integrate different testing assets: desktop applications, web applications, mobile applications, services... Therefore, it must be able to support different tools and programming languages (adaptable to the needs of each test): SikuliX, WebDriver (Selenium), JMeter, SoapUI...
  • Configuration flexibility. Environment of the execution configurable (parametrizable): execute the same test with different parameters / properties, different runtime environments, different application properties...
  • Parallelization.
    • "Fast enough" to be integrated into a CD
    • Running parallel test for different versions of the product. For example, we may need to do two releases at once (a patch and upgrade), the test platform should not be the bottleneck.
  • Scalability. Test cases can grow, but the total execution time should be maintained.
  • Availability: the platform must have at least the same criticality as the rest of the tools that allow us to obtain a CD.

From the reporting point of view

Finally, we have to think about monitoring the executions and in the generation of reports
  • Capable to sending email reports/alerts.
  • Traceability:
    • Visibility of the executions over the different environments to step into production.
    • Versioning test, test plans. The tests have to follow the same versions that you have in your product.
  • Diagnostic.  Easily diagnose issues, because the reason for having automated test is to find issues and to make finding issues easy (having logs...).
  • History. Historical repository of executions with details
  • Customizable reporting. 
    • Custom reports for managers, clients...
    • Testing coverage between versions.
    • Product Performance between version.
    • Compare different test executions over different software/product versions.

Well as I said this is a simplified exercise, but I hope this list will be helpful as a checkpoint for Automated Test Platform requirements.

Sunday, 7 February 2016

Improve your Local Env with Docker+Jenkins+Selenium to achieve Continuous Delirery

The path to Continuous Delivery (CD) happens to have stable execution results of automated test, so will be ideal if the developers could pass the automated test on their local machine before they integrate their code with the base code. But  if we want to execute the automated test on the developer local machine we have to be aware of:
  1. The executions of the tests must be not intrusive, allowing the developers to focus on other tasks while the tests are executing.
  2. The solution must be easily adaptable to changes, for example, if new tests suites are available or disabled,  this doesn't have to be an overhead work for the developers to synchronize with their local environment.
Sometimes these points are difficult to accomplish, i.e. if we have more than 500 automated functional test to be tested with a real browser (e.g. Firefox).  

Knowing the global solution explained in my previous post, it's easy with Docker and Jenkins to have a template that could build a "private platform" where execute 'locally'  all the  tests (unit, integrated, functional...)

You can see the simplified solution in the next diagram:

As you can see on the diagram, the solution is based on Docker compose which builds Jenkins in a Docker container: a Jenkins Master and n-slaves Jenkins  (depending on configuration parameters). It will execute the test with Selenium/Firefox, where the test live in the local filesystem of the host. In this case, for convenience and not to overload the developers' machines, we won't test on IE  (but we could use a Vagrant virtual-machine with Windows and IE)...

The key points of this kind of configuration are:
  • Run Automated Test in background.
  • Light GUI containers to run Firefox with Selenium.
  • Parallel execution of the tests. 
  • Easy installation and updates.
  • We can see the visual errors of the navigation in the pdfs generated by the framework of test (see previous post)

Some Technical details of the solution

Docker-Compose

With Docker-Compose we have a simplified configuration for the developer:
# Jenkins Master
jenkins:
  image: s2obcn/jenkins
  container_name: jenkins
  ports:
   - "8090:8080"
   - "50000"
  volumes:
        - /home/s2o/vDocker/jenkins:/jenkins
  env_file:
    - jenkins-master.env
# Jenkins Slave
slave:
  image: s2obcn/jenkins-swarm
  links:
    - jenkins:jenkins
  volumes:
      - /home/s2o/vDocker/jenkins_shared/workspace:/opt/jenkins/workspace
  env_file:
    - jenkins-slave.env

Jenkins docker image with swarm plugin

Speed up the execution of the tests by running them in parallel, grouping the tests by suites and executing any suite by a different job. A second level of parallelisms is splitting the execution of the jobs by different Jenkins slaves.
RUN wget --no-check-certificate --directory-prefix=${SWARM_HOME} \
      http://maven.jenkins-ci.org/content/repositories/releases/org/jenkins-ci/plugins/swarm-client/${SWARM_VERSION}/swarm-client-${SWARM_VERSION}-jar-with-dependencies.jar  && \
    mv ${SWARM_HOME}/swarm-client-${SWARM_VERSION}-jar-with-dependencies.jar ${SWARM_HOME}/swarm-client-jar-with-dependencies.jar && \
    mkdir -p ${SWARM_WORKDIR} && \
    mkdir -p ${SWARM_WORKDIR}/workspace/{TEST_PROJECT} && \
    chown -R jenkins:jenkins ${SWARM_HOME} && \
    chown -R jenkins:jenkins ${SWARM_WORKDIR} && \
    chmod +x ${SWARM_HOME}/swarm-client-jar-with-dependencies.jar

Docker with the correct Firefox configuration

To get a custom profile with Firefox the best way is execute Firefox, change the configuration as needed and save the current profile for the next executions.
  • Now I get Firefox running within a docker container and rendered by the local X Server, so in this way it can be easy configured:
docker run -it --privileged -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix -v /home/s2o/tmp/a:/opt/jenkins s2obcn/jenkins-swarm bash

Sharing local IDE workspace with Jenkins Job workspace

  • The test, to be executed, will be loaded from an SCM or shared from a local FS. The trick here is to share the workspace between all the jobs/Jenkins.

Naming conventions (Jenkins with Job DSL Plugin)

  • The jobs to execute will have the same name of the suites to execute. 
  • We can build/update the jobs in the local Jenkins with the plugin Job DSL




Sunday, 24 January 2016

Continuous integration: Functional Testing - Distributed Testing with Selenium and Jenkins

A way to distribute Selenium tests can be use Selenium Grid alone or Jenkins and the Selenium Jenkins plugin. However if more control is required, there's another way with Jenkins. You can configure a Jenkins Master with n-Jenkins Slaves that will execute the Selenium tests like local execution. In other words, Jenkins Slave will execute exactly as developers do in their local environment without any overhead configuration.

So, which are the pros to use this technique instead of Selenium Grid:
  • Easy integration: it can be integrated seamlessly into the continuos integration (CI) of our product. 
  • Distribution: the same infrastructure can be used to distribute the execution of ANY functional test (jMeter, SoupUI, Selenium...). 
  • Dynamic: assignment different browsers capabilities test are more dynamic than with Selenium Grid. With Jenkins Master/Slave, the slave has the labels to conform different tests types that can be executed by any node. For example, the number of executors (instances of browsers) or node labels can be changed directly in Jenkins without restarting the node.
  • Reporting: the execution and post execution (reports..) are distributed overall Jenkins nodes. 
  • Centralized control: the distribution control is centralized in Jenkins.
Knowing that solution, we can implement this solution with:
  • TestNg as core test framework:
    • Group functional test in suites (that will be executed directly by the Jenkins jobs).
    • Filter test execution by parameters ("@Test(groups='demoUser','pro'"... where we can have different kind of groups, such as different type of users, different environments... ) 
    • Definition of executions  "timeouts" (at different levels).
    • An easy way to execute the test (from maven, directly with java...)
    • Data Driven Test
    • Reports
    • ...
  • Test will be built following the Page Object Pattern. 
  • A custom core framework that:
    • Centralize configuration management of the test execution (main homepage, main browser type, user, password....).
    • Centralize the startup of the browser (select browser by configuration properties)
    • Automate the login of the test: every test will only take care of the page to test, navigation through the pages will managed by the core framework
    • Execution retry policy (you know that test over IE may fail without reason)
    • Manage errors 
    • Data Driven Test: data stored in excels organized by 'tables'
    • Custom detailed reports
    • ...
  • Testlink as Test Management.

This is a simplified picture of the platform to automate the execution of Selenium with Jenkins:


You can follow this tutorial to configure Jenkins with Selenium and this other tutorial to configure the Jenkins Slaves.

To sum up,  the main goal of this solution is to use the  Jenkins node "labels" to assign the web browser that will be executed by any node and configure the Jenkins Slaves to execute the Selenium WebDriver without problems (I will write a post about how to configure the Jenkins Slave  properly to execute IE as a service without problems).

Tuesday, 7 December 2010

Flex: Chimp security solution (use it without metadata on source code!!!)

"Chimp is permission based filtering component for Adobe Flex and AIR. Applications implement Chimp by adding metadata within the Flex UIComponents. Based on the metadata it will remove components completely, enable/disable, and update visibility."


In this post I will show you an extension for the Chimp component that will provide a transparent implementation of the security for the developers. With this extension the permissions metadata is no longer needed to be in the source code. The permissions will be loaded dynamically at runtime.


First of all, let me give you a short view of the architecture we are using in our applications:
- the main application navigation is made in a superTabNaviagtion: every conversartion (screen) is loaded in a separate tab.
This is done by the core of the architecture (our framework), every developer's team only have to take care of their conversations (screens), that will be loaded by the framework in a client workbench.

What I will do is, before every new screen (new tab) is loaded, I will call a service that will give the permissions (permitted actions) for that screen and then I will set those permissions to the Chimp component.

Of course, I will need a separate application to carry on those permissions actions of our components (that otherwise must to be written in the source code of the application as metadata), and this application will be managed by an administrator.

Finally, the only thing needed for working correctly is that every button or component to be securiced must have an unique id in the whole application. This could be done easily with naming conventions.

The next code is added to Chimp.as:
/**
* Load chimp before the UIComponents are added with permission strings
*/
public static function load(permissions:ArrayCollection, metadataPermissions:Boolean=true):void {
  if(permissions != null) {
    _permissions = permissions;
    _permissions.addEventListener(CollectionEvent.COLLECTION_CHANGE, updateDisplay);
  } else {
    permissions = new ArrayCollection();
  }
  _metadataPermissions= metadataPermissions;

  //add chmip system add handler  
  FlexGlobals.topLevelApplication.addEventListener(Event.ADDED_TO_STAGE, processComponenet, true);
}

/**
 * @author s2o
 * 
 * 
 *  
   
  
  
 
 * 
 * @param screenActions
 * 
 */
public static function addScreenPermissionActions( screenActions:XML ):void{
 var screenId:String = screenActions.@id;
 
 for each (var metadata:XML in screenActions.descendants("metadata")) {
  // the ChimpConstants.ACTION_REMOVE_CHILD is not considered
  var chimpAction:ChimpAction = getAction(metadata);
  chimpAction.parentId = screenId;
  ChimpActionCache.instance.addDelayLoadAction(chimpAction);
 }   
}

/**
 * @author s2o
 * 
 * Removes permission from cache    
 * @param screenId
 * 
 */
public static function removeScreenPermissionActions(screenId:String):void {
  ChimpActionCache.instance.freeCachedActionById(screenId);
}

//process ui object
private static function process(obj:Object):void {
 if(obj is UIComponent) {           
  if (_metadataPermissions) {
   processMetadataPermissions(obj);      
  } else {
   processDelayPermissions(obj);
  }
 }
}


/**
 * @author s2o
 *  
 * @param obj
 * 
 */
private static function processDelayPermissions(obj:Object):void {  
 var comp:UIComponent = obj as UIComponent;      
 for each(var delayedChimpAction:ChimpAction in ChimpActionCache.instance.getDelayLoadActionById(comp.id)) {
  delayedChimpAction.comp = comp;
  doAction(delayedChimpAction);
  // for updates display on changes to the roles
  ChimpActionCache.instance.addAction(delayedChimpAction);                                                       
 }   
}

Thursday, 2 September 2010

AndroMDA vs Acceleo (MDA)

Objective

The aim of this paper is a brief introduction to MDA technology and a summary / comparison to the approachments to MDA of AndroMDA and Acceleo, intending to be a practical and understandable summary

Introduction

Model-driven architecture (MDA) is a software design approach for the development of software systems. It provides a set of guidelines for the structuring of specifications, which are expressed as models. It was launched by the Object Management Group (OMG) in 2001

The Model-Driven Architecture approach defines system functionality using a platform-independent model (PIM) using an appropriate domain-specific language (DSL).

One of the main aims of the MDA is to separate design from architecture. As the concepts and technologies used to realize designs and the concepts and technologies used to realize architectures have changed at their own pace, decoupling them allows system developers to choose from the best and most fitting in both domains. The design addresses the functional (use case) requirements while architecture provides the infrastructure through which non-functional requirements like scalability, reliability and performance are realized. MDA envisages that the platform independent model (PIM), which represents a conceptual design realizing the functional requirements, will survive changes in realization technologies and software architectures.

To sum up:

  • Models are produced at business level, and translated into code using code generation tools
  • The skill to move from model to implementation reduces most of the coding efforts
  • By having the models in the first iteration of software construction, allows the possibility of obtaining an executable prototype system in early stages of project life cycle
  • The transformation's rules for going from model to code are common to all similar projects, therefore the same rules apply to any project developing software allows a consistent software related to its quality and use of standards
Pros of MDA:

  • Focus on the business
  • Updated documentation. The process is, first change the model and then, regenerate the code.
  • Less application errors: “The best way to avoid dangerous coding errors is to code less”
  • Portability of the technology: If there's a new technology, by updating the PSM we can generate the code in the new technology
Cons of MDA:

  • If we don't have code generated by the MDA, we can't apply MDA.
  • The creation of components for the code automation is very complex
  • Refactoring. A change in the model involves a change in the code, therefor the sincronization between the new code generted and the original code implemented by the developer is always a delicate step (despite having tools that facilitate this task, this step is always delicate).

ANDROMDA:

Creator: Matthias Bohlen
Current state of the project:

  • AndroMDA 3.3 ( 2009-04-02) is the latest stable release (only supports UML 1.x)
  • AndroMDA 3.4 -snapshot (2010-02-14) supports UML 2.x: all the modern versions of uml tools use UML 2.x
  • AndroMDA 4: is on hold
  • AndroMDA-eclipse plugin: seems to be hold, version 1.0-M3 since 2006

Features:

  1. Open source framework that receives as an input a UML model that combined with suitable cartridges AndroMDA (model for technology mapping. NET, J2EE …), generates the source.
  2. AndroMDA cartridges are developed in velocty template (http://velocity.apache.org/). AndroMDA comes with a series of cartridges for the comprehensive code generation: BPM4Struts, jBPM, JSF, EJB, EJB3, Hibernate, Java, Meta, Spring, WebService and Xmlschema
  3. The sincronice of the model and the code generated by AndroMDA is done by taking into account that the code generated by AndroMDA consists of final classes that can't be modified by developers and abstract classes / interfaces, on which the developer implements the logic of business.That is the strategy for code generation is the direct heritange and delegation, therefore we depend on the final language and on the language structures to be able to generate final code, complex or not.
  4. AndroMDA is integrated with maven, but not with eclipse. Therefore, the management of new projects and code's generation will be done through the command line or ant task. For implementing a project with AndroMDA, we'll subdivid into: a MDA project (where AndroMDA generates code from the model) and a Development Project (where development and testing take place).




Community support: AndroMDA has maybe, one of biggest community of a MDA framework



ACCELEO

Creator: Obeo
Current state of the project:


Features (Acceleo 3):

  1. Acceleo is an implementation of the Object Management Group (OMG) MOF Model to Text Language (MTL) standard. This component is an entirely new development of the OMG MOF Model to Text (Mof2Text) http://www.omg.org/spec/MOFM2T/1.0/ language. The implementation will be compliant
  2. The development of the code generation's modules is done by acceleo type projects in eclipse.There are currently very basic examples of code generation for Python and Java. In version 2 we can find more complex modules of generation. Acceleo focuses on supporting the creation of code generation, so it is really easy to create new modules: preview of the final result of the generation, debug, launch generation integrated in eclipse.
  3. The sincronization between the model and the code generated by Acceleo is done through special tag's (in the code generation templates) that shows the developer where to enter the specific new code. This makes that the final code generated by Acceleo can be very complex.. It could happened as well that a non-skillfull (clueless) developer removes special tags and then, the new code generated by Acceleo will not repect the code created by the developer.
  4. Code generation from a model and code generation module is done through an integrated implementation task in eclipse. And configured through a wizard of the eclipse. The implementation of an Acceleo project would be the usual with eclipse, because the generated code is integrated into the development of the developer.




Community support: it's not as big as AndroMDA's community, but I have to say that was great to make a question in its forum and have a quick reponse






That's all folks! 
Please if you see any incoherent, feel free to make corrections / suggestions.


Thursday, 8 April 2010

email: spring + velocity

One of the best ways to send e-mails is with spring and velocity template. With this technique sending an e-mail is as easy as make a jsp.

In this sample I'm integrating the spring & velocity with struts2 and portlets, but could be extrapolated to any other environment.

The recipe consists of:
- applicationContextBeans.xml -> the sprig config file (the glue)
- registrarse.vm -> a velocity template of our e-mail
- EmailService.java & EmailServiceImpl.java -> the classes to apply the data to the template and send the e-mail. These classes will be the same for all the e-mails, so could be in a separate jar.
- RegistrarseAction.java -> the struts2 action

-applicationContextBeans.xml:
<bean id="emaiInformacionlService" class="es.project.miGestion.administracionDatos.service.EmailServiceImpl" scope="prototype">
        <property name="velocityEngine" ref="velocityEngine"></property>
        <property name="velocityTpl" value="es/project/velocity/solicitudInformacion.vm"></property>
            <property name="inlineFiles">   
         <map>              
             <entry>  
                 <key>  
                     <value>id001</value>  
                 </key>  
                 <value>classpath:es/project/velocity/logoproject.png</value>  
             </entry>  
         </map>  
       </property>  
    </bean>
    <bean id="emailRegistrarseService" class="es.project.miGestion.administracionDatos.service.EmailServiceImpl" scope="prototype">
        <property name="velocityEngine" ref="velocityEngine"></property>
        <property name="velocityTpl" value="es/project/velocity/registrarse.vm"></property>
        <property name="inlineFiles">   
         <map>              
             <entry>  
                 <key>  
                     <value>id001</value>  
                 </key>  
                 <value>classpath:es/project/velocity/logoproject.png</value>  
             </entry>  
         </map>  
       </property>  
    </bean>

- registrarse.vm:
<div id="logo">
        <p align="right"><img src="cid:id001" /></p>
    </div>
    <div id="header">
        <font size="2" style="font-family: Arial; color: rgb(51, 90, 143);">
            A la Atenci&oacute;n del Servicio de Atenci&oacute;n Telef&oacute;nica
            <br><br>
            Cliente registrado en el formulario de la web. 
            #set ($bar = "cliente")
            #if (${cliente} == $bar)
                Ya es cliente de  project y desea que un comercial se encarge de darle de alta en la Web de  project:
            #else
                No es cliente de  project y desea que un comercial se encarge de darle de alta en la Web de  project:
            #end
        </font>
    </div>
    <br>
    <div id="content">
        <font size="2" style="font-family: Arial; color: rgb(51, 90, 143);">
            <table class="width100" border="0" cellspacing="0" cellpadding="0">    
                <tr>
                    <td style="font-size: 9pt; font-family: Arial; color: rgb(51, 90, 143);" width="110">Nombre</td>
                    <td style="font-size: 9pt; font-family: Arial; color: rgb(51, 90, 143);" >${nombre} ${apellidos}</td>
                </tr>
                <tr>
                    <td style="font-size: 9pt; font-family: Arial; color: rgb(51, 90, 143);" >DNI</td>
                    <td style="font-size: 9pt; font-family: Arial; color: rgb(51, 90, 143);" >${dni}</td>
                </tr>
                <tr>
                    <td style="font-size: 9pt; font-family: Arial; color: rgb(51, 90, 143);" >Direcci&oacute;n:</td>                
                    <td style="font-size: 9pt; font-family: Arial; color: rgb(51, 90, 143);" >${direccion},${cp} ${poblacion} - ${pais}</td>
                </tr>
                <tr>
                    <td style="font-size: 9pt; font-family: Arial; color: rgb(51, 90, 143);" >Telefono:</td>                
                    <td style="font-size: 9pt; font-family: Arial; color: rgb(51, 90, 143);" >${telefono}</td>
                </tr>
                <tr>
                    <td style="font-size: 9pt; font-family: Arial; color: rgb(51, 90, 143);" >Movil:</td>                
                    <td style="font-size: 9pt; font-family: Arial; color: rgb(51, 90, 143);" >${movil}</td>
                </tr>        
                <tr>
                    <td style="font-size: 9pt; font-family: Arial; color: rgb(51, 90, 143);" >Email:</td>                
                    <td style="font-size: 9pt; font-family: Arial; color: rgb(51, 90, 143);" >${mail}</td>
                </tr>    
                #if (${cliente} == $bar)        
                    <tr>
                        <td style="font-size: 9pt; font-family: Arial; color: rgb(51, 90, 143);" >N&uacute;mero cuenta:</td>                
                        <td style="font-size: 9pt; font-family: Arial; color: rgb(51, 90, 143);" >${numeroCuenta}</td>
                    </tr>    
                #end
            </table>
        </font>        
    </div>
    <br>
    <hr size="2" width="100%" align="left">
    <span style="font-size: 7.5pt; font-family: Arial; color: rgb(51, 90, 143);">
        .....
    </span>

- EmailServiceImpl.java
...
    private VelocityEngine velocityEngine;    
    private JavaMailSender javaMailSender;
    private String velocityTpl;
    
    private Map<String,Resource> inlineFiles;
    
    /**
     * Creaci�n y env�o de e-mail.
     * @param from E-mail de origen
     * @param recipients E-mails de destino
     * @param subject Asunto del e-mail
     * @param params Par�metros para la generaci�n del cuerpo del e-mail
     */
    public void sendEmail(String from, String[] recipients, String subject, Map<String,Object> params) {
        log.debug("sendEmail inicio");
        
        final String f = from;        
        final String s = subject;
        final Map<String,Object> p = params;
        
        for(final String to : recipients){
            MimeMessagePreparator preparator = new MimeMessagePreparator(){
                public void prepare(MimeMessage mimeMessage) throws Exception{
                    MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true);
                    helper.setFrom(f);
                    helper.setTo(to);
                    helper.setSubject(MimeUtility.encodeText(s, "iso-8859-1", "B"));                        
                    Map<String,Object> model = p;
                    String text = VelocityEngineUtils.mergeTemplateIntoString(velocityEngine,velocityTpl,model);
                    helper.setText(text, true);
                    
                    // añadiendo los ficheros "en línea"
                    if (getInlineFiles() != null) {
                        for (String key :getInlineFiles().keySet()) {
                            Resource value = getInlineFiles().get(key);
                            helper.addInline(key, value);
                            if (log.isDebugEnabled()) {
                                log.debug("File '" + value + "' added.");
                            }
                        }
                    }
                }
            };
            javaMailSender.send(preparator);
        }
        
        log.debug("sendEmail fin");
    }
    
    /**
     * Create and setup the mail sender component
     *  @param mailTO

     */
    public void initializeJavaMailSender(MailTO mailTO){        
        log.debug("initializeJavaMailSender inicio");
        
        //Create and setup the mail sender component
        JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
        mailSender.setHost(mailTO.getHostMail());
        mailSender.setPort(Integer.valueOf(mailTO.getPort()));    
        mailSender.setUsername(mailTO.getUsername());    
        mailSender.setPassword(mailTO.getPassword());
        
        //We need this setting for force Javamail to pass the login
        boolean mailSmtpAuth = mailTO.getMailSmtpAuth().equals("true");
        boolean starttls = mailTO.getStarttls().equals("true");
        
        Properties props = new Properties();
        if(mailSmtpAuth){
            log.debug("mailSmtpAuth true:"+mailTO.getMailSmtpAuth());
            props.setProperty("mail.smtp.auth", mailTO.getMailSmtpAuth());
        }
        if(starttls){
            log.debug("starttls true:" + mailTO.getStarttls());
            props.setProperty("mail.smtp.starttls.enable", mailTO.getStarttls());
        }
        mailSender.setJavaMailProperties(props);
        
        javaMailSender = mailSender;            
        
        log.debug("initializeJavaMailSender fin");
    }
...

- RegistrarseAction.java
// Enviar los datos por mail
        emailRegistrarseService.initializeJavaMailSender(mailTO);
        
        String[] recipients = mailTO.getToMail().split(";");
        String[] emailUsuario = mail.split(";");

        Map<String, Object> params = new HashMap<String, Object>();
        params.put("cliente", cliente);
        params.put("nombre", nombre);
        params.put("apellidos", apellidos);
        params.put("dni", dni);
        params.put("direccion", direccion);
        params.put("poblacion", poblacion);
        params.put("mail", mail);
        params.put("telefono", telefono);
        params.put("pais", pais);
        params.put("cp", cp);
        params.put("movil", movil);
        params.put("numeroCuenta", numeroCuenta);

        emailRegistrarseService.sendEmail(mail, recipients, 
                mailTO.getSubject(), params);

Monday, 15 March 2010

Integrate struts2-jquery and portlets

In this FAQ we can see how to install the struts2-jquery plugin, but we have to make some little changes if we are developing porlets:

1.Add the next servlet-mapping to the web.xml file:
<servlet>
        <servlet-name>struts2servlet</servlet-name>
        <servlet-class>org.apache.struts2.dispatcher.ng.servlet.StrutsServlet</servlet-class>
</servlet>
<servlet-mapping>
        <servlet-name>struts2servlet</servlet-name>
        <url-pattern>*.action</url-pattern>
</servlet-mapping> 
<servlet>
        <servlet-name>struts2Resources</servlet-name>
        <servlet-class>org.apache.struts2.dispatcher.ng.servlet.StrutsServlet</servlet-class>
</servlet>
<servlet-mapping>
        <servlet-name>struts2Resources</servlet-name>
        <url-pattern>/struts/*</url-pattern>
</servlet-mapping> 

This could be done by a filter-mapping too, but with filter-mapping we can have some problems in a Websphere server.

2.Define some pakage in the struts2 config to manage the ajax request
<package name="ajax" extends="json-default" namespace="/ajax">
...
</package>

3.To make a valid ajax request from the portlet, all the request must be as the next examples:
<form id="compraVentaForm" action='<s:url value="/ajax/compraVentaSave.action"/>'  method="post">
...
</form>
<s:url id="ordenesActivasResultado" value="/ajax/ordenesActivas.action"/>
<sj:div href="%{ordenesActivasResultado}" indicator="indicator" onCompleteTopics="completeDiv" reloadTopics="reloadDiv">
 <img id="loading" src="<s:url value='/img/ajax-loader.gif'/>" alt="Loading..."/>
</sj:div>

Saturday, 27 February 2010

SAP Java Connector (SAP JCo) : sample

Here's a sample code to get the currency list of the BAPI ZBAPI_GET_CURRENCY_LIST:

ArrayList desMoneda = new ArrayList();
ArrayList ideMoneda = new ArrayList();

//Creamos la función de la BAPI
com.sap.mw.jco.JCO.Function funcionDivisas = repository.getFunctionTemplate("ZBAPI_GET_CURRENCY_LIST").getFunction();

//Declaramos los parámetros que se le enviarán a la BAPI
com.sap.mw.jco.JCO.ParameterList listParams = funcionDivisas.getImportParameterList();      
listParams.setValue("ES","LANGU");

//Ejecutamos la BAPI
connection.execute(funcionDivisas);

//Recuperamos la tabla de SAP
Table tablaDivisas = funcionDivisas.getTableParameterList().getTable("CURRENCYLIST");
desMoneda.add(Text.getText("language.messages", "ActividadRegistro.comboDivisa", oLocale));
ideMoneda.add("");

//Recorremos la tabla de divisas y seteamos los arrays del formulario
for (int i = 0; i < tablaDivisas.getNumRows(); i++){
 ideMoneda.add(tablaDivisas.getValue("WAERS"));
 desMoneda.add(tablaDivisas.getValue("LTEXT"));  
 tablaDivisas.nextRow();
}
And here's the connectSap() and disconnectSap() functions:
/** Conexion */
protected JCO.Client connection;   // Connection con SAP
/** Repositorio */
protected IRepository repository;   // Repostorio de funciones SAP

/**
 * Iniciamos la conexion y el repositorio con el SAP
 *
 */
public void connectSap(String client, String user, String pass, String lang, String host, String nSystem, String name) {
 try {
  /** Creamos la conexion con el SAP   */  
  connection = JCO.createClient(client, user, pass, lang, host, nSystem);
  connection.connect();

  /** Creamos el repositorio con el SAP   */
  repository = new JCO.Repository(name, connection);
 } catch(Exception e) {
  log.error("Error -> connectSAP: " + e.getMessage(),e); 
 }
}

public void disconnectSap() {
 if(connection != null) {
  try {
   connection.disconnect();
  }catch(Exception e) {
  log.error("Error -> disconnectSap: " + e.getMessage(),e);
  }
 }
}

Monday, 18 January 2010

WebService client: automating the generation of all java classes

The problem:
Sometimes when we have to make a webservice client, we have the wsdl definition file and we have to choose some tecnique to generate the java client classes. But after all the code generated automatically by the framework we have an xmlStream to treat with... So finally, we have to implement the model classes of the part of the xml that we're interested in.

To automate this final step we can generate the java classes to unmarshall the xml into java classes that matches data.

In my last project I had the requirement to do this with axis (Axis2) and xmlbeans (XMLBeans). The webService was a Sharepoint service: lists.asmx.

The solution:
Create an xml ant to transform the wsdl to java: wsdl2java-SharepointList.xml. And create another xml ant to transform the xml returned by the webService: buildSharepointListItems.xml

1.-wsdl2java-SharepointList.xml:
<!DOCTYPE project>

<project name="wsdl2java-WebXXXX_Service" default="usage" basedir=".">

<property name="project-name" value="XXXX.ws.XXXXNet"/>
<property name="definicionDelWebService" value="input/webXXXX_Service.wsdl"/>
<property name="packageDestino" value="es.XXXX.ws.XXXXNet"/>
<property file="build.properties"/>

<property name="build" value="build"/>
<property name="src" value="src"/>
<property name="build.classes" value="build/classes" />

<path id="axis.classpath">
<pathelement location="build/classes" />
<fileset dir="${axis.home}/lib">
<include name="**/*.jar" />
</fileset>
<fileset dir="${xmlBeans.home}/lib">
<include name="**/*.jar" />
</fileset>
<pathelement location="${build.classes}" />
</path>

<path id="axis_client.classpath">
<pathelement location="build/classes" />
<fileset dir="${axis.home}">
<include name="**/*.jar" />
</fileset>
<fileset dir="lib">
<include name="*.jar" />
</fileset>
<pathelement location="${build.classes}" />
</path>

<target name="usage" description="Build file usage info (default task)">
<echo message=" " />
<echo message="${project-name} " />
<echo message="-------------------------------------------------------" />
<echo message=" " />
<echo message="Available Targets:" />
<echo message=" Cleaning up:" />
<echo message="  clean             - Delete class files" />
<echo message=" " />
<echo message=" WSDL:" />
<echo message="  wsdl2java         - Generate source from WSDL" />
<echo message=" " />
<echo message=" Compiling:" />
<echo message="  compile           - Compiles the WSDL2Java source code" />
<echo message=" " />
<echo message=" jar final:" />
<echo message="  jar_wsdl          - Generate the jar from WSDL2Java source code" />
</target>

<target name="prepare" >
<mkdir dir="${build.classes}" />
</target>

<target name="clean" >
<delete dir="${build}" />
<delete dir="output" />
</target>

<target name="wsdl2java" depends="clean,prepare">
<java classname="org.apache.axis2.wsdl.WSDL2Java" fork="true">
<classpath refid="axis.classpath"/>          
<arg value="-uri"/>
<arg file="${definicionDelWebService}"/>
<arg value="-o"/>
<arg file="output"/>
<arg value="-d"/>
<arg value="xmlbeans"/>
<arg value="-p"/>
<arg value="${packageDestino}"/>
<arg value="-s"/>
<arg value="-u"/>
</java>

<!-- Move the schema folder to classpath-->
<move todir="${build.classes}">
<fileset dir="output/resources">
<include name="**/*schema*/**/*.class"/>
<include name="**/*schema*/**/*.xsb"/>
</fileset>
</move>

</target>

<target name="compile">
<echo message="Compiling wsdl2 files"/>
<javac
       srcdir="output"
       destdir="${build.classes}"
       deprecation="true"
      source="1.5"
          target="1.5"
    failonerror="true" debug="false">
<classpath refid="axis.classpath"/> 
</javac>
</target>

<target name="jar_wsdl" depends="compile">
<jar jarfile="lib/${project-name}.jar" >
<fileset dir="${build.classes}" />
</jar>
</target>

<target name="all" depends="wsdl2java,jar_wsdl">
<echo message="Generando el jar desde el wsdl"/>
</target>
</project>


2.-buildSharepointListItems.xml:
<!DOCTYPE project>

<project name="buildSharepointListItems" default="usage" basedir=".">

 <property name="project-name" value="torres.ws.shareponint.listItems"/>
 <property name="xmlDeDatosInput" value="input/listItemsRetorn.xml"/>
 <property name="xmlDeDatos" value="listItemsRetorn"/>
 <property file="build.properties"/>

 <property name="build" value="build"/>
 <property name="src" value="src"/>
 <property name="build.classes" value="build/classes" />

 <path id="xmlBean.classpath">
  <pathelement location="build/classes" />
  <fileset dir="${xmlBeans.home}/lib">
   <include name="**/*.jar" />
  </fileset>
  <pathelement location="${build.classes}" />
 </path>

 <target name="usage" description="Build file usage info (default task)">
  <echo message=" " />
  <echo message="${project-name} " />
  <echo message="-------------------------------------------------------" />
  <echo message=" " />
  <echo message="Available Targets:" />
  <echo message=" Cleaning up:" />
  <echo message="  clean             - Delete class files" />
  <echo message=" " />
  <echo message=" returned XML:" />
  <echo message="  xml2xsd               - Generate xsd from xml" />  
  <echo message=" " />
  <echo message=" generate java binding:" />
  <echo message="  xsd2java           - Generate java from xsd" />  
  <echo message=" " />
  <echo message=" Compiling:" />
  <echo message="  compile           - Compiles the xsd2java source code" />
  <echo message=" " />
  <echo message=" jar final:" />
  <echo message="  exportJar               - Generate the from WSDL2Java source code" />
 </target>

 <target name="prepare" >
  <mkdir dir="${build.classes}" />
  <mkdir dir="output" />
  <mkdir dir="src" />
 </target>

 <target name="clean" >
  <delete dir="${build}" />
  <delete dir="output" />
  <delete dir="src" />
 </target>

 <target name="xml2xsd" depends="clean,prepare">
  <java classname="org.apache.xmlbeans.impl.inst2xsd.Inst2Xsd" fork="true">
   <classpath refid="xmlBean.classpath"/>
   <arg value="-design"/>
   <arg value="rd"/>
   <arg value="-outDir"/>
   <arg file="src"/>
   <arg value="-outPrefix"/>
   <arg value="${xmlDeDatos}"/>
   <arg value="${xmlDeDatosInput}"/>
  </java>
 </target>

 <target name="xsd2java">
  <java classname="org.apache.xmlbeans.impl.tool.SchemaCompiler" fork="true">
   <classpath refid="xmlBean.classpath"/>
   <arg value="-d"/>
   <arg file="output"/>
   <arg value="-javasource"/>
   <arg value="1.5"/>
   <arg value="-srconly"/>
   <arg file="src"/>
   <arg value="input/${xmlDeDatos}.xsdconfig"/>
  </java>
 </target>

 <target name="compile" depends="xsd2java">
  <echo message="Compiling files"/>
  <javac
       srcdir="output"
       destdir="${build.classes}"
       deprecation="true"
      source="1.5"
          target="1.5"
    failonerror="true" debug="false">
   <classpath refid="xmlBean.classpath"/>
  </javac>
   <!-- Move the schema folder to classpath-->
       <move todir="${build.classes}">
           <fileset dir="output">
               <include name="**/*schema*/**/*.class"/>
               <include name="**/*schema*/**/*.xsb"/>
           </fileset>
       </move>
 </target>

 <target name="exportJar" depends="compile">
  <jar jarfile="lib/${project-name}.jar" >
   <fileset dir="${build.classes}" />
  </jar>
 </target>

 <target name="all" depends="xml2xsd,exportJar">
  <echo message="Generando el jar desde el wsdl"/>
 </target>
</project>

3. And finally, the java that call the sharepoint service:

HttpTransportProperties.Authenticator auth = new HttpTransportProperties.Authenticator();
auth.setUsername(username);
auth.setPassword(password);
auth.setDomain(domain);
auth.setHost(host);
auth.setRealm(realm);

// Ensure NTLM authentication used
List authPrefs = new ArrayList(1);
authPrefs.add(AuthPolicy.NTLM);
auth.setAuthSchemes(authPrefs);

// Get stub
ListsStub stub = new ListsStub(sharepoinService  + "_vti_bin/lists.asmx");

// Set authenticator
stub._getServiceClient().getOptions().setProperty(org.apache.axis2.transport.http.HTTPConstants.AUTHENTICATE, auth);
// Get request and execute

com.microsoft.schemas.sharepoint.soap.GetListItemsDocument getListItems112 =com.microsoft.schemas.sharepoint.soap.GetListItemsDocument.Factory.newInstance();
GetListItems listaInput = GetListItems.Factory.newInstance();
listaInput.setListName(laguajeList[0]);
getListItems112.setGetListItems(listaInput );

GetListItemsResponseDocument listaResultado = stub.getListItems(getListItems112);
GetListItemsResult result = listaResultado.getGetListItemsResponse().getGetListItemsResult();
String resultString = result.xmlText();
log.debug(resultString);

resultString = resultString.replaceFirst("http://schemas.microsoft.com/sharepoint/soap/", "http://XXXXX/sharepoint/listItems");      
ListitemsDocument root= ListitemsDocument.Factory.parse(resultString);
List lista = root.getListitems().getData().getRowList();

Saturday, 12 December 2009

Spring + ibatis: calling a sql procedure

This post is a sample of a procedure call from ibatis, when we're under the spring influence!

This is the ibator generator xml. Used with the eclipse plugin.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE ibatorConfiguration PUBLIC "-//Apache Software Foundation//DTD Apache iBATIS Ibator Configuration 1.0//EN" "http://ibatis.apache.org/dtd/ibator-config_1_0.dtd" >
<ibatorConfiguration >
 <classPathEntry location="C:\eclipse\extra\BDD\SQLServer\sqljdbc_2.0\esn\sqljdbc4.jar" />
 <ibatorContext id="test" >
     <jdbcConnection driverClass="com.microsoft.sqlserver.jdbc.SQLServerDriver" connectionURL="jdbc:sqlserver://...:1433;databaseName=...." userId="..." password="..."/>
     <javaModelGenerator targetPackage="es.test.model.WebProd" targetProject="test.negocio" />
     <sqlMapGenerator targetPackage="es.test.dao.WebProd.sqlMap" targetProject="test.negocio" />
 <daoGenerator targetPackage="es.test.dao.WebProd" targetProject="test.negocio" type="SPRING" />
 <table schema="dbo" catalog="WebProd" tableName="aliasCuentas">
   <property name="useActualColumnNames" value="true"/>
 </table>    
  </ibatorContext>
</ibatorConfiguration>

To the generated code of ibator, just add the next items:


In WebProd_dbo_aliasCuentas_SqlMap.xml:
<parameterMap id="getAccountsCall" class="map">
 <parameter property="titular" jdbcType="VARCHAR" javaType="java.lang.String" mode="IN"/>
 <parameter property="permiso" jdbcType="VARCHAR" javaType="java.lang.String" mode="IN"/>
</parameterMap>
<resultMap id="cuentaAlias" class="es.test.model.WebProd.Aliascuentas">
 <result property="aliasCuenta" column="aliasCuenta" />
 <result property="idCuenta" column="idCuenta" />
</resultMap>
<procedure id="getAccounts" resultMap="cuentaAlias" parameterMap="getAccountsCall">
 {call WebProd.dbo.sp_web_getCuenstasUsuarioAlias(?, ?)}
</procedure>


In AliascuentasDAO:
List<es.test.model.WebProd.Aliascuentas> selectCuentas(Map example);


In AliascuentasDAOImpl:
public List<es.test.model.WebProd.Aliascuentas> selectCuentas(Map example) {
 List<es.test.model.WebProd.Aliascuentas> list = getSqlMapClientTemplate().queryForList("WebProd_dbo_aliasCuentas.getAccounts", example);
 return list;
}


Now, the configurations files of spring and the java source of the call.


In applicationContext*.xml:
<bean id="aliascuentasDAO" class="es.test.dao.WebProd.AliascuentasDAOImpl">
 <property name="sqlMapClient">
  <ref bean="sqlMapWebProd"/>
 </property>
</bean>
<bean id="aliasServicio" class="es.test.miGestion.administracionDatos.service.AliasCuentasServiceImpl">
 <property name="aliascuentasDAO">
  <ref bean="aliascuentasDAO"/>
 </property>
</bean>

And finally the AliasCuentasServiceImpl.java:
public List<Aliascuentas> getCuentas(String usuario) {
 log.debug("getCuentas: inicio. usuario:" + usuario);
 List<Aliascuentas> cuentasList;

 Map<String, String> map = new HashMap<String, String>();
 map.put("titular", usuario);
 map.put("permiso", "Consultas");
 cuentasList = aliascuentasDAO.selectCuentas(map);
 log.debug("getCuentas: fin");
 return cuentasList;
}

That's all!.

Friday, 13 November 2009

Ajax Cross-domain

We have a web project that the 90% of the data it's taken from an outer domain. As the client forced us to make the queries directly to the other domain, we decided to use flXHR.

flXHR is a *client-based* cross-browser, XHR-compatible tool for cross-domain Ajax (Flash) communication.”

As we used jquery for build the tables, the right solution seems to use the flXHR jQuery plugin. And all seems right while we were testing in firefox and IE 8, but when we began to test it in IE7 we saw that "sometimes" after the refresh of the page... we had the CPU up to 100% and the IE7 blocked.

After a refactorization and finally a total simplification of the page, we saw that the only way to use safely flXHR was putting the include of the flXHR.js file at the end of the page, or at least the last one of all the js includes of the page.

The next simple example ends with 100% CPU if you refresh the page quickly so many times (source):


Sunday, 4 October 2009

Developing Portlets using Eclipse. Part II


As I told you, the architecture that I use for these post, has iBATIS for it's persistence layer.

The main reason for use this framework was that iBatis give you the flexibility of write your own optimized sql code, and an easy way to call directly to a sql procedure. Not to mention, the existence of iBator, the code generator for iBatis :)

Spring will be a pivotal piece for the application, the reason for use of this framework it's as simple as I want to sleep as a baby. Some of the things that I want accomplish with spring is to have transparency over my data-source connection, jms..,, to make uncouple implementations from each other...

Well, the first interaction between ibatis and spring it's done in the configuration files, the next example show you how to make a configuration that also makes the application container independent.

Extract from applicationContext.xml:
<!-- obtain datasource  -->   
<jee:jndi-lookup id="dataSourceWebProd" jndi-name="jdbc/webProd" cache="true" resource-ref="true" lookup-on-startup="false" proxy-interface="javax.sql.DataSource"/>

<!-- map iBatis to datasource  -->   
<bean id="sqlMapBaseWeb" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
 <property name="configLocation"><value>classpath:/config/sqlmap-configWebProd.xml</value></property>
 <property name="dataSource"><ref bean="dataSourceWebProd" /></property>
</bean> 

<bean id="aliascuentasDAO" class="es.struts2PortletTemplate.dao.WebProd.AliascuentasDAOImpl">
 <property name="sqlMapClient">
  <ref bean="sqlMapWebProd"/>
 </property>
</bean>
<bean id="informesServicio" class="es.struts2PortletTemplate.miGestion.informes.service.InformesServiceImpl">
 <property name="aliascuentasDAO">
  <ref bean="aliascuentasDAO"/>
 </property>
</bean>

sqlmap-configWebProd.xml:
<settings cachemodelsenabled="true" enhancementenabled="true" usestatementnamespaces="true">
    <sqlmap resource="es/struts2PortletTemplate/dao/WebProd/sqlMap/WebProd_dbo_aliasCuentas_SqlMap.xml">
</sqlmap></settings>

And of course, you may well decide to use the Spring Framework's declarative transactions offer...
<bean id="txManagerWebProd" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
 <property name="dataSource" ref="dataSourceWebProd"/>
</bean>
<tx:advice id="txAdviceWebProd" transaction-manager="txManagerWebProd">
 <tx:attributes>
  <tx:method name="get*" read-only="true"/>
  <tx:method name="find*" read-only="true"/>
  <tx:method name="view*" read-only="true"/>
  <tx:method name="save*" propagation="REQUIRED"/>
  <tx:method name="*" propagation="REQUIRED"/>
 </tx:attributes>
</tx:advice>

Saturday, 12 September 2009

Easy developing and debuging portlets with eclipse WTP

This little entry is just to show you how quickly I have my new environment up and running. As I told you in my firt post, I develop the portlets with:

Eclipse with WTP
JetSpeed 2.2.0

And I will use Struts2 (Struts 2.1.7) portltes (JSR 168)...

The next log it's from a start up of the jetSpeed in debug mode.

INFO: JetspeedContainerServlet: attemping to start Portlet Application at: /Struts2PortletTemplate
12-Sep-2009 01:49:02 org.apache.catalina.core.ApplicationContext log
INFO: JetspeedContainerServlet: started Portlet Application at: /Struts2PortletTemplate
12-Sep-2009 01:49:03 org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring root WebApplicationContext
12-Sep-2009 01:49:04 org.apache.catalina.core.ApplicationContext log
INFO: JetspeedContainerServlet: starting initialization of Portlet Application at: j2-admin
JetspeedContainerServlet: starting initialization of Portlet Application at: j2-admin12-Sep-2009 01:49:04 org.apache.catalina.core.ApplicationContext log
INFO: JetspeedContainerServlet: Could not yet start portlet application at: j2-admin. Starting back ground thread to start when the portal comes online.

12-Sep-2009 01:49:04 org.apache.catalina.core.ApplicationContext log
INFO: JetspeedContainerServlet: initialization done for Portlet Application at: j2-admin
JetspeedContainerServlet: initialization done for Portlet Application at: j2-admin
12-Sep-2009 01:49:04 org.apache.catalina.core.ApplicationContext log
INFO: JetspeedContainerServlet: attemping to start Portlet Application at: /j2-admin
12-Sep-2009 01:49:05 org.apache.coyote.http11.Http11Protocol start
INFO: Starting Coyote HTTP/1.1 on http-8080
12-Sep-2009 01:49:05 org.apache.jk.common.ChannelSocket init
INFO: JK: ajp13 listening on /0.0.0.0:8009
12-Sep-2009 01:49:05 org.apache.jk.server.JkMain start
INFO: Jk running ID=0 time=0/267  config=null
12-Sep-2009 01:49:05 org.apache.catalina.startup.Catalina start
INFO: Server startup in 14474 ms
12-Sep-2009 01:49:06 org.apache.catalina.core.ApplicationContext log
INFO: JetspeedContainerServlet: started Portlet Application at: /j2-admin


It takes only 14474 ms
can you do this with websphere?? ;)

Wednesday, 19 August 2009

Developing Portlets using Eclipse. Part I

On this entries I will show you how to develop portlets, create and debug portlets, in Eclipse with the WTP plugin and Jetspeed-2 . Lately I will deploy those portlets for the Websphere Portal 6.1.

Some frameworks that I will use:
The environmentLocations that I use to use with Linux:
  • /data/eclipse/eclipseWTP -> here's the eclipse.exe
  • /data/eclipse/eXtra/Jetspeed-2.2.0 -> for Jetspeed
  • /data/workspace/groupA -> for development
Locations that I use to use with Windows:
  • c:\eclipse\eclipseWTP -> here's the eclipse.exe
  • c:\eclipse\eXtra\Jetspeed-2.2.0 -> for Jetspeed
  • c:\apps\workspace\groupA -> for developement
OK, now it's time to configure our eclipse:
  • Add a new server runtime. In eclipse "Preferences/Sever/Runtime Enviroment", add "Apache Tomcat v6.0" and use the installation of the Jetspeed as "Tomcat installation directory "/data/eclipse/eXtra/Jetspeed-2.2.0".
  • Configure the new server. Here's the most important thing, just after we create the new server, we have to edit the server configuration and then "use Tomcat installation" (the default could be "use workspace") and change the "deploy path" to point where we had the "webapps" in our Jetspeed installation "/data/eclipse/eXtra/Jetspeed-2.2.0/webapps". Also we have to change the timeout to start the server.

The portlet

In eclipse, create a new Dynamic Web Project with target runtime: "Jetspeed 2.2.0". Project name: Struts2PortletTemplate :)
OK, now change the project properties, in "Java build path"... I like this "Struts2PortletTemplate/WebContent/WEB-INF/classes" as the output folder.

This will be the web.xml: